You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
digikam/digikam/digikam/searchwidgets.cpp

603 lines
18 KiB

/* ============================================================
*
* 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 <renchi@pooh.tam.uiuc.edu>
* Copyright (C) 2005 by Tom Albers <tomalbers@kde.nl>
* Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
*
* 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 <tqhbox.h>
#include <tqvbox.h>
#include <tqlabel.h>
#include <tqcheckbox.h>
#include <tqcombobox.h>
#include <tqlineedit.h>
#include <tqgroupbox.h>
#include <tqvgroupbox.h>
#include <tqlayout.h>
#include <tqdatetime.h>
// KDE includes.
#include <klocale.h>
#include <kurl.h>
#include <kdialog.h>
// 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, TQT_SIGNAL( signalDoubleClick( TQMouseEvent* ) ),
this, TQT_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, TQT_SIGNAL( activated(int) ),
this, TQT_SLOT(slotKeyChanged(int)));
connect( m_key, TQT_SIGNAL( activated(int) ),
this, TQT_SIGNAL( signalPropertyChanged() ));
connect( m_operator, TQT_SIGNAL( activated(int) ),
this, TQT_SIGNAL( signalPropertyChanged() ));
connect( m_check, TQT_SIGNAL( toggled( bool ) ),
this, TQT_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, Qt::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<int,int> 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<TQString, int> 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, TQT_SIGNAL( dateChanged(const TQDate& ) ),
this, TQT_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, TQT_SIGNAL ( textChanged(const TQString&) ),
this, TQT_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, TQT_SIGNAL( activated(int) ),
this, TQT_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, TQT_SIGNAL( activated(int) ),
this, TQT_SIGNAL( signalPropertyChanged() ));
}
else if (newType == RATING)
{
m_ratingWidget = new RatingWidget( m_valueBox );
m_ratingWidget->show();
connect( m_ratingWidget, TQT_SIGNAL( signalRatingChanged(int) ),
this, TQT_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(Qt::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, TQT_SIGNAL( toggled( bool ) ),
this, TQT_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, TQT_SIGNAL( toggled( bool ) ),
this, TQT_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<SearchAdvancedRule*> 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<SearchAdvancedRule*> 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