/* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2005-01-01 * Description : search widgets collection. * * Copyright (C) 2005 by Renchi Raju * Copyright (C) 2005 by Tom Albers * Copyright (C) 2006-2007 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ /** @file searchwidgets.cpp */ // TQt includes. #include #include #include #include #include #include #include #include #include #include // KDE includes. #include #include #include // Local includes. #include "ddebug.h" #include "album.h" #include "albuminfo.h" #include "albummanager.h" #include "ratingwidget.h" #include "squeezedcombobox.h" #include "kdateedit.h" #include "searchwidgets.h" #include "searchwidgets.moc" namespace Digikam { static const int RuleKeyTableCount = 11; static const int RuleOpTableCount = 18; static struct { const char *keyText; TQString key; SearchAdvancedRule::valueWidgetTypes cat; } RuleKeyTable[] = { { I18N_NOOP("Album"), "album", SearchAdvancedRule::ALBUMS }, { I18N_NOOP("Album Name"), "albumname", SearchAdvancedRule::LINEEDIT }, { I18N_NOOP("Album Caption"), "albumcaption", SearchAdvancedRule::LINEEDIT }, { I18N_NOOP("Album Collection"), "albumcollection", SearchAdvancedRule::LINEEDIT }, { I18N_NOOP("Tag"), "tag", SearchAdvancedRule::TAGS }, { I18N_NOOP("Tag Name"), "tagname", SearchAdvancedRule::LINEEDIT }, { I18N_NOOP("Image Name"), "imagename", SearchAdvancedRule::LINEEDIT }, { I18N_NOOP("Image Date"), "imagedate", SearchAdvancedRule::DATE }, { I18N_NOOP("Image Caption"), "imagecaption", SearchAdvancedRule::LINEEDIT }, { I18N_NOOP("Keyword"), "keyword", SearchAdvancedRule::LINEEDIT }, { I18N_NOOP("Rating"), "rating", SearchAdvancedRule::RATING }, }; static struct { const char *keyText; TQString key; SearchAdvancedRule::valueWidgetTypes cat; } RuleOpTable[] = { { I18N_NOOP("Contains"), "LIKE", SearchAdvancedRule::LINEEDIT }, { I18N_NOOP("Does Not Contain"), "NLIKE", SearchAdvancedRule::LINEEDIT }, { I18N_NOOP("Equals"), "EQ", SearchAdvancedRule::LINEEDIT }, { I18N_NOOP("Does Not Equal"), "NE", SearchAdvancedRule::LINEEDIT }, { I18N_NOOP("Equals"), "EQ", SearchAdvancedRule::ALBUMS }, { I18N_NOOP("Does Not Equal"), "NE", SearchAdvancedRule::ALBUMS }, { I18N_NOOP("Contains"), "LIKE", SearchAdvancedRule::ALBUMS }, { I18N_NOOP("Does Not Contain"), "NLIKE", SearchAdvancedRule::ALBUMS }, { I18N_NOOP("Equals"), "EQ", SearchAdvancedRule::TAGS }, { I18N_NOOP("Does Not Equal"), "NE", SearchAdvancedRule::TAGS }, { I18N_NOOP("Contains"), "LIKE", SearchAdvancedRule::TAGS }, { I18N_NOOP("Does Not Contain"), "NLIKE", SearchAdvancedRule::TAGS }, { I18N_NOOP("After"), "GT", SearchAdvancedRule::DATE }, { I18N_NOOP("Before"), "LT", SearchAdvancedRule::DATE }, { I18N_NOOP("Equals"), "EQ", SearchAdvancedRule::DATE }, { I18N_NOOP("At least"), "GTE", SearchAdvancedRule::RATING }, { I18N_NOOP("At most"), "LTE", SearchAdvancedRule::RATING }, { I18N_NOOP("Equals"), "EQ", SearchAdvancedRule::RATING }, }; SearchRuleLabel::SearchRuleLabel(const TQString& text, TQWidget *parent, const char *name, WFlags f ) : TQLabel(text, parent, name, f) { } void SearchRuleLabel::mouseDoubleClickEvent( TQMouseEvent * e ) { emit signalDoubleClick( e ); } SearchAdvancedRule::SearchAdvancedRule(TQWidget* parent, SearchAdvancedRule::Option option) : SearchAdvancedBase(SearchAdvancedBase::RULE) { m_box = new TQVBox(parent); m_box->layout()->setSpacing( KDialog::spacingHint() ); m_box->setSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Minimum ); m_optionsBox = 0; m_option = option; if (option != NONE) { m_optionsBox = new TQHBox( m_box ); m_label = new SearchRuleLabel( option == AND ? i18n("As well as") : i18n("Or"), m_optionsBox); TQFrame* hline = new TQFrame( m_optionsBox ); hline->setFrameStyle( TQFrame::HLine|TQFrame::Sunken ); m_label->setSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Minimum ); hline->setSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Minimum ); connect( m_label, TQ_SIGNAL( signalDoubleClick( TQMouseEvent* ) ), this, TQ_SLOT( slotLabelDoubleClick() )); } m_hbox = new TQWidget( m_box ); m_hbox->setSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Minimum ); m_key = new TQComboBox( m_hbox, "key" ); m_key->setSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Minimum ); for (int i=0; i< RuleKeyTableCount; i++) m_key->insertItem( i18n(RuleKeyTable[i].keyText), i ); m_operator = new TQComboBox( m_hbox ); m_operator->setSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Minimum ); // prepopulate the operator widget to get optimal size for (int i=0; i< RuleOpTableCount; i++) m_operator->insertItem( i18n(RuleOpTable[i].keyText), i ); m_operator->adjustSize(); m_valueBox = new TQHBox( m_hbox ); m_widgetType = NOWIDGET; slotKeyChanged( 0 ); m_check = new TQCheckBox( m_hbox ); m_hboxLayout = new TQHBoxLayout( m_hbox ); m_hboxLayout->setSpacing( KDialog::spacingHint() ); m_hboxLayout->addWidget( m_key ); m_hboxLayout->addWidget( m_operator ); m_hboxLayout->addWidget( m_valueBox ); m_hboxLayout->addWidget( m_check, 0, TQt::AlignRight ); m_box->show(); connect( m_key, TQ_SIGNAL( activated(int) ), this, TQ_SLOT(slotKeyChanged(int))); connect( m_key, TQ_SIGNAL( activated(int) ), this, TQ_SIGNAL( signalPropertyChanged() )); connect( m_operator, TQ_SIGNAL( activated(int) ), this, TQ_SIGNAL( signalPropertyChanged() )); connect( m_check, TQ_SIGNAL( toggled( bool ) ), this, TQ_SIGNAL( signalBaseItemToggled() )); } void SearchAdvancedRule::setValues(const KURL& url) { if (url.isEmpty()) return; // set the key widget for (int i=0; i< RuleKeyTableCount; i++) { if (RuleKeyTable[i].key == url.queryItem("1.key")) { m_key->setCurrentText( i18n(RuleKeyTable[i].keyText) ); } } // set the operator and the last widget slotKeyChanged( m_key->currentItem() ); for (int i=0; i< RuleOpTableCount; i++) { if ( RuleOpTable[i].key == url.queryItem("1.op") && RuleOpTable[i].cat == m_widgetType ) { m_operator->setCurrentText( i18n(RuleOpTable[i].keyText) ); } } // Set the value for the last widget. TQString value = url.queryItem("1.val"); if (m_widgetType == LINEEDIT) m_lineEdit->setText( value ); if (m_widgetType == DATE) m_dateEdit->setDate( TQDate::fromString( value, TQt::ISODate) ); if (m_widgetType == RATING) { bool ok; int num = value.toInt(&ok); if (ok) m_ratingWidget->setRating( num ); } if (m_widgetType == TAGS || m_widgetType == ALBUMS) { bool ok; int num = value.toInt(&ok); if (ok) { TQMapIterator it; for (it = m_itemsIndexIDMap.begin() ; it != m_itemsIndexIDMap.end(); ++it) { if (it.data() == num) m_valueCombo->setCurrentItem( it.key() ); } } } } SearchAdvancedRule::~SearchAdvancedRule() { delete m_box; } void SearchAdvancedRule::slotLabelDoubleClick() { if (m_option == AND) { m_option=OR; m_label->setText( i18n("Or") ); } else { m_option=AND; m_label->setText( i18n("As well as") ); } emit signalPropertyChanged(); } void SearchAdvancedRule::slotKeyChanged(int id) { TQString currentOperator = m_operator->currentText(); valueWidgetTypes currentType = m_widgetType; // we need to save the current size of the operator combobox // otherise clear() will shrink it TQSize curSize = m_operator->size(); m_operator->clear(); m_widgetType = RuleKeyTable[id].cat; for (int i=0; i< RuleOpTableCount; i++) { if ( RuleOpTable[i].cat == m_widgetType ) { m_operator->insertItem( i18n(RuleOpTable[i].keyText) ); if ( currentOperator == RuleOpTable[i].key ) m_operator->setCurrentText( currentOperator ); } } m_operator->setFixedSize(curSize); setValueWidget( currentType, m_widgetType ); } void SearchAdvancedRule::setValueWidget(valueWidgetTypes oldType, valueWidgetTypes newType) { // this map is used to sort album and tag list combobox typedef TQMap SortedList; if (oldType == newType) return; if (m_lineEdit && oldType == LINEEDIT) delete m_lineEdit; if (m_dateEdit && oldType == DATE) delete m_dateEdit; if (m_ratingWidget && oldType == RATING) delete m_ratingWidget; if (m_valueCombo && (oldType == ALBUMS || oldType == TAGS)) delete m_valueCombo; if (newType == DATE) { m_dateEdit = new KDateEdit( m_valueBox,"datepicker"); m_dateEdit->setSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Minimum ); m_dateEdit->show(); connect( m_dateEdit, TQ_SIGNAL( dateChanged(const TQDate& ) ), this, TQ_SIGNAL(signalPropertyChanged())); } else if (newType == LINEEDIT) { m_lineEdit = new TQLineEdit( m_valueBox, "lineedit" ); m_lineEdit->setSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Minimum ); m_lineEdit->show(); connect( m_lineEdit, TQ_SIGNAL ( textChanged(const TQString&) ), this, TQ_SIGNAL(signalPropertyChanged())); } else if (newType == ALBUMS) { m_valueCombo = new SqueezedComboBox( m_valueBox, "albumscombo" ); m_valueCombo->setSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Minimum ); AlbumManager* aManager = AlbumManager::instance(); AlbumList aList = aManager->allPAlbums(); m_itemsIndexIDMap.clear(); // First we need to sort the album list. // We create a map with the album url as key, so that it is // automatically sorted. SortedList sAList; for ( AlbumList::Iterator it = aList.begin(); it != aList.end(); ++it ) { PAlbum *album = (PAlbum*)(*it); if ( !album->isRoot() ) { sAList.insert(album->url().remove(0,1), album->id()); } } // Now we can iterate over the sorted list and fill the combobox int index = 0; for ( SortedList::Iterator it = sAList.begin(); it != sAList.end(); ++it ) { m_valueCombo->insertSqueezedItem( it.key(), index ); m_itemsIndexIDMap.insert(index, it.data()); index++; } m_valueCombo->show(); connect( m_valueCombo, TQ_SIGNAL( activated(int) ), this, TQ_SIGNAL( signalPropertyChanged() )); } else if (newType == TAGS) { m_valueCombo = new SqueezedComboBox( m_valueBox, "tagscombo" ); m_valueCombo->setSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Minimum ); AlbumManager* aManager = AlbumManager::instance(); AlbumList tList = aManager->allTAlbums(); m_itemsIndexIDMap.clear(); // First we need to sort the tags. // We create a map with the album tagPath as key, so that it is // automatically sorted. SortedList sTList; for ( AlbumList::Iterator it = tList.begin(); it != tList.end(); ++it ) { TAlbum *album = (TAlbum*)(*it); if ( !album->isRoot() ) { sTList.insert(album->tagPath(false), album->id()); } } // Now we can iterate over the sorted list and fill the combobox int index = 0; for (SortedList::Iterator it = sTList.begin(); it != sTList.end(); ++it) { m_valueCombo->insertSqueezedItem( it.key(), index ); m_itemsIndexIDMap.insert( index, it.data() ); ++index; } m_valueCombo->show(); connect( m_valueCombo, TQ_SIGNAL( activated(int) ), this, TQ_SIGNAL( signalPropertyChanged() )); } else if (newType == RATING) { m_ratingWidget = new RatingWidget( m_valueBox ); m_ratingWidget->show(); connect( m_ratingWidget, TQ_SIGNAL( signalRatingChanged(int) ), this, TQ_SIGNAL( signalPropertyChanged() )); } } TQString SearchAdvancedRule::urlKey() const { return RuleKeyTable[m_key->currentItem()].key; } TQString SearchAdvancedRule::urlOperator() const { TQString string; int countItems = 0; for (int i=0; i< RuleOpTableCount; i++) { if ( RuleOpTable[i].cat == m_widgetType ) { if ( countItems == m_operator->currentItem() ) string = RuleOpTable[i].key; ++countItems; } } return string; } TQString SearchAdvancedRule::urlValue() const { TQString string; if (m_widgetType == LINEEDIT) string = m_lineEdit->text() ; else if (m_widgetType == DATE) string = m_dateEdit->date().toString(TQt::ISODate) ; else if (m_widgetType == TAGS || m_widgetType == ALBUMS) string = TQString::number(m_itemsIndexIDMap[ m_valueCombo->currentItem() ]); else if (m_widgetType == RATING) string = TQString::number(m_ratingWidget->rating()) ; return string; } TQWidget* SearchAdvancedRule::widget() const { return m_box; } bool SearchAdvancedRule::isChecked() const { return (m_check && m_check->isChecked()); } void SearchAdvancedRule::addOption(Option option) { if (option == NONE) { removeOption(); return; } m_box->layout()->remove(m_hbox); m_optionsBox = new TQHBox(m_box); new TQLabel(option == AND ? i18n("As well as") : i18n("Or"), m_optionsBox); TQFrame* hline = new TQFrame(m_optionsBox); hline->setFrameStyle(TQFrame::HLine|TQFrame::Sunken); hline->setSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Minimum); m_optionsBox->show(); m_box->layout()->add(m_hbox); m_option = option; } void SearchAdvancedRule::removeOption() { m_option = NONE; delete m_optionsBox; m_optionsBox = 0; } void SearchAdvancedRule::addCheck() { m_check = new TQCheckBox(m_hbox); m_check->setSizePolicy(TQSizePolicy::Minimum, TQSizePolicy::Minimum); m_hboxLayout->addWidget( m_check, 0, TQt::AlignRight ); m_check->show(); connect( m_check, TQ_SIGNAL( toggled( bool ) ), this, TQ_SIGNAL( signalBaseItemToggled() )); } void SearchAdvancedRule::removeCheck() { delete m_check; m_check = 0; } SearchAdvancedGroup::SearchAdvancedGroup(TQWidget* parent) : SearchAdvancedBase(SearchAdvancedBase::GROUP) { m_box = new TQHBox(parent); m_box->layout()->setSpacing(KDialog::spacingHint()); m_groupbox = new TQVGroupBox(m_box); m_check = new TQCheckBox(m_box); m_option = SearchAdvancedRule::NONE; m_box->show(); connect( m_check, TQ_SIGNAL( toggled( bool ) ), this, TQ_SIGNAL( signalBaseItemToggled() )); } SearchAdvancedGroup::~SearchAdvancedGroup() { delete m_box; } TQWidget* SearchAdvancedGroup::widget() const { return m_box; } bool SearchAdvancedGroup::isChecked() const { return m_check->isChecked(); } void SearchAdvancedGroup::addRule(SearchAdvancedRule* rule) { if (m_childRules.isEmpty() && rule->option() != SearchAdvancedRule::NONE) { // this is the first rule being inserted in this group. // get its option and remove its option addOption(rule->option()); rule->removeOption(); } rule->removeCheck(); m_childRules.append(rule); rule->widget()->reparent(m_groupbox, TQPoint(0,0)); rule->widget()->show(); } void SearchAdvancedGroup::removeRules() { typedef TQValueList RuleList; for (RuleList::iterator it = m_childRules.begin(); it != m_childRules.end(); ++it) { SearchAdvancedRule* rule = (SearchAdvancedRule*)(*it); if (it == m_childRules.begin()) { rule->addOption(m_option); } rule->addCheck(); rule->widget()->reparent((TQWidget*)m_box->parent(), TQPoint(0,0)); rule->widget()->show(); } m_childRules.clear(); removeOption(); } TQValueList SearchAdvancedGroup::childRules() const { return m_childRules; } void SearchAdvancedGroup::addOption(Option option) { m_option = option; m_groupbox->setTitle(m_option == SearchAdvancedRule::AND ? i18n("As well as") : i18n("Or")); } void SearchAdvancedGroup::removeOption() { m_option = NONE; m_groupbox->setTitle(""); } } // namespace Digikam