summaryrefslogtreecommitdiffstats
path: root/src/dialogs/ingredientmatcherdialog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dialogs/ingredientmatcherdialog.cpp')
-rw-r--r--src/dialogs/ingredientmatcherdialog.cpp353
1 files changed, 353 insertions, 0 deletions
diff --git a/src/dialogs/ingredientmatcherdialog.cpp b/src/dialogs/ingredientmatcherdialog.cpp
new file mode 100644
index 0000000..b994ec8
--- /dev/null
+++ b/src/dialogs/ingredientmatcherdialog.cpp
@@ -0,0 +1,353 @@
+/***************************************************************************
+* Copyright (C) 2003 by *
+* Unai Garro ([email protected]) *
+* *
+* 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 of the License, or *
+* (at your option) any later version. *
+***************************************************************************/
+
+#include "ingredientmatcherdialog.h"
+
+#include "datablocks/recipelist.h"
+#include "widgets/ingredientlistview.h"
+#include "datablocks/elementlist.h"
+#include "backends/recipedb.h"
+#include "widgets/krelistview.h"
+#include "widgets/unitcombobox.h"
+#include "widgets/fractioninput.h"
+#include "widgets/amountunitinput.h"
+#include "datablocks/mixednumber.h"
+#include "recipeactionshandler.h"
+
+#include <tqheader.h>
+#include <tqpainter.h>
+#include <tqstringlist.h>
+#include <tqlayout.h>
+#include <tqgroupbox.h>
+
+#include <tdeapplication.h>
+#include <kcursor.h>
+#include <kiconloader.h>
+#include <tdelocale.h>
+#include <knuminput.h>
+#include <tdeconfig.h>
+#include <tdeglobal.h>
+#include <kdebug.h>
+#include <kdialogbase.h>
+
+#include "profiling.h"
+
+IngredientMatcherDialog::IngredientMatcherDialog( TQWidget *parent, RecipeDB *db ) : TQWidget( parent )
+{
+ // Initialize internal variables
+ database = db;
+
+ //Design the dialog
+
+ TQVBoxLayout *dialogLayout = new TQVBoxLayout( this, 11, 6 );
+
+ // Ingredient list
+ TQHBoxLayout *layout2 = new TQHBoxLayout( 0, 0, 6, "layout2" );
+
+ allIngListView = new KreListView( this, TQString::null, true, 0 );
+ StdIngredientListView *list_view = new StdIngredientListView(allIngListView,database);
+ list_view->setSelectionMode( TQListView::Multi );
+ allIngListView->setListView(list_view);
+ layout2->addWidget( allIngListView );
+
+ TQVBoxLayout *layout1 = new TQVBoxLayout( 0, 0, 6, "layout1" );
+
+ TDEIconLoader il;
+
+ addButton = new TQPushButton( this, "addButton" );
+ addButton->setIconSet( il.loadIconSet( "forward", TDEIcon::Small ) );
+ addButton->setFixedSize( TQSize( 32, 32 ) );
+ layout1->addWidget( addButton );
+
+ removeButton = new TQPushButton( this, "removeButton" );
+ removeButton->setIconSet( il.loadIconSet( "back", TDEIcon::Small ) );
+ removeButton->setFixedSize( TQSize( 32, 32 ) );
+ layout1->addWidget( removeButton );
+ TQSpacerItem *spacer1 = new TQSpacerItem( 51, 191, TQSizePolicy::Minimum, TQSizePolicy::Expanding );
+ layout1->addItem( spacer1 );
+ layout2->addLayout( layout1 );
+
+ ingListView = new KreListView( this, TQString::null, true );
+ ingListView->listView() ->addColumn( i18n( "Ingredient (required?)" ) );
+ ingListView->listView() ->addColumn( i18n( "Amount Available" ) );
+ layout2->addWidget( ingListView );
+ dialogLayout->addLayout( layout2 );
+
+ // Box to select allowed number of missing ingredients
+ missingBox = new TQHBox( this );
+ missingNumberLabel = new TQLabel( missingBox );
+ missingNumberLabel->setText( i18n( "Missing ingredients allowed:" ) );
+ missingNumberSpinBox = new KIntSpinBox( missingBox );
+ missingNumberSpinBox->setMinValue( -1 );
+ missingNumberSpinBox->setSpecialValueText( i18n( "Any" ) );
+ dialogLayout->addWidget(missingBox);
+
+ // Found recipe list
+ recipeListView = new KreListView( this, i18n( "Matching Recipes" ), false, 1, missingBox );
+ recipeListView->listView() ->setSizePolicy( TQSizePolicy::Ignored, TQSizePolicy::Ignored );
+ recipeListView->listView() ->setAllColumnsShowFocus( true );
+
+ recipeListView->listView() ->addColumn( i18n( "Title" ) );
+
+ TDEConfig *config = TDEGlobal::config();
+ config->setGroup( "Advanced" );
+ bool show_id = config->readBoolEntry( "ShowID", false );
+ recipeListView->listView() ->addColumn( i18n( "Id" ), show_id ? -1 : 0 );
+
+ recipeListView->listView() ->addColumn( i18n( "Missing Ingredients" ) );
+
+ recipeListView->listView() ->setSorting( -1 );
+ dialogLayout->addWidget(recipeListView);
+
+ RecipeActionsHandler *actionHandler = new RecipeActionsHandler( recipeListView->listView(), database, RecipeActionsHandler::Open | RecipeActionsHandler::Edit | RecipeActionsHandler::Export );
+
+ TQHBox *buttonBox = new TQHBox( this );
+
+ okButton = new TQPushButton( buttonBox );
+ okButton->setIconSet( il.loadIconSet( "button_ok", TDEIcon::Small ) );
+ okButton->setText( i18n( "Find matching recipes" ) );
+
+ //buttonBox->layout()->addItem( new TQSpacerItem( 10,10, TQSizePolicy::MinimumExpanding, TQSizePolicy::Fixed ) );
+
+ clearButton = new TQPushButton( buttonBox );
+ clearButton->setIconSet( il.loadIconSet( "edit-clear", TDEIcon::Small ) );
+ clearButton->setText( i18n( "Clear" ) );
+ dialogLayout->addWidget(buttonBox);
+
+ // Connect signals & slots
+ connect ( okButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( findRecipes() ) );
+ connect ( clearButton, TQ_SIGNAL( clicked() ), recipeListView->listView(), TQ_SLOT( clear() ) );
+ connect ( clearButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( unselectIngredients() ) );
+ connect ( actionHandler, TQ_SIGNAL( recipeSelected( int, int ) ), TQ_SIGNAL( recipeSelected( int, int ) ) );
+ connect( addButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( addIngredient() ) );
+ connect( removeButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( removeIngredient() ) );
+ connect( ingListView->listView(), TQ_SIGNAL( doubleClicked( TQListViewItem*, const TQPoint &, int ) ), TQ_SLOT( itemRenamed( TQListViewItem*, const TQPoint &, int ) ) );
+}
+
+IngredientMatcherDialog::~IngredientMatcherDialog()
+{
+}
+
+void IngredientMatcherDialog::itemRenamed( TQListViewItem* item, const TQPoint &, int col )
+{
+ if ( col == 1 ) {
+ KDialogBase amountEditDialog(this,"IngredientMatcherAmountEdit",
+ false, i18n("Enter amount"), KDialogBase::Cancel | KDialogBase::Ok, KDialogBase::Ok);
+
+ TQGroupBox *box = new TQGroupBox( 1, Horizontal, i18n("Amount"), &amountEditDialog );
+ AmountUnitInput *amountEdit = new AmountUnitInput( box, database );
+ // Set the values from the item
+ if ( !item->text(1).isEmpty() ) {
+ amountEdit->setAmount( MixedNumber::fromString(item->text(2)) );
+ Unit u;
+ u.id = item->text(3).toInt();
+ amountEdit->setUnit( u );
+ } else {
+ amountEdit->setAmount( -1 );
+ Unit u;
+ u.id = -1;
+ amountEdit->setUnit( u );
+ }
+
+ amountEditDialog.setMainWidget(box);
+
+ if ( amountEditDialog.exec() == TQDialog::Accepted ) {
+ MixedNumber amount = amountEdit->amount();
+ Unit unit = amountEdit->unit();
+
+ if ( amount.toDouble() <= 1e-5 ) {
+ amount = -1;
+ unit.id = -1;
+
+ item->setText(1,TQString::null);
+ } else {
+ item->setText(1,amount.toString()+" "+((amount.toDouble()>1)?unit.plural:unit.name));
+ }
+
+ item->setText(2,amount.toString());
+ item->setText(3,TQString::number(unit.id));
+
+ IngredientList::iterator ing_it = m_item_ing_map[item];
+ (*ing_it).amount = amount.toDouble();
+ (*ing_it).units = unit;
+ }
+ }
+}
+
+void IngredientMatcherDialog::addIngredient()
+{
+ TQPtrList<TQListViewItem> items = allIngListView->listView()->selectedItems();
+ if ( items.count() > 0 ) {
+ TQPtrListIterator<TQListViewItem> it(items);
+ TQListViewItem *item;
+ while ( (item = it.current()) != 0 ) {
+ bool dup = false;
+ for ( TQListViewItem *exists_it = ingListView->listView()->firstChild(); exists_it; exists_it = exists_it->nextSibling() ) {
+ if ( exists_it->text( 0 ) == item->text( 0 ) ) {
+ dup = true;
+ break;
+ }
+ }
+
+ if ( !dup ) {
+ TQListViewItem * new_item = new TQCheckListItem( ingListView->listView(), item->text( 0 ), TQCheckListItem::CheckBox );
+
+ ingListView->listView() ->setSelected( new_item, true );
+ ingListView->listView() ->ensureItemVisible( new_item );
+ allIngListView->listView() ->setSelected( item, false );
+
+ m_item_ing_map.insert( new_item, m_ingredientList.append( Ingredient( item->text( 0 ), 0, Unit(), -1, item->text( 1 ).toInt() ) ) );
+ }
+ ++it;
+ }
+ }
+}
+
+void IngredientMatcherDialog::removeIngredient()
+{
+ TQListViewItem * item = ingListView->listView() ->selectedItem();
+ if ( item ) {
+ for ( IngredientList::iterator it = m_ingredientList.begin(); it != m_ingredientList.end(); ++it ) {
+ if ( *m_item_ing_map.find( item ) == it ) {
+ m_ingredientList.remove( it );
+ m_item_ing_map.remove( item );
+ break;
+ }
+ }
+ delete item;
+ }
+}
+
+void IngredientMatcherDialog::unselectIngredients()
+{
+ ingListView->listView()->clear();
+ for ( TQListViewItem *it = allIngListView->listView()->firstChild(); it; it = it->nextSibling() )
+ allIngListView->listView()->setSelected(it,false);
+}
+
+void IngredientMatcherDialog::findRecipes( void )
+{
+ TDEApplication::setOverrideCursor( KCursor::waitCursor() );
+
+ START_TIMER("Ingredient Matcher: loading database data");
+
+ RecipeList rlist;
+ database->loadRecipes( &rlist, RecipeDB::Title | RecipeDB::NamesOnly | RecipeDB::Ingredients | RecipeDB::IngredientAmounts );
+
+ END_TIMER();
+ START_TIMER("Ingredient Matcher: analyzing data for matching recipes");
+
+ // Clear the list
+ recipeListView->listView() ->clear();
+
+ // Now show the recipes with ingredients that are contained in the previous set
+ // of ingredients
+ RecipeList incompleteRecipes;
+ TQValueList <int> missingNumbers;
+ TQValueList <IngredientList> missingIngredients;
+
+ RecipeList::Iterator it;
+ for ( it = rlist.begin();it != rlist.end();++it ) {
+ IngredientList il = ( *it ).ingList;
+ if ( il.isEmpty() )
+ continue;
+
+ IngredientList missing;
+ if ( m_ingredientList.containsSubSet( il, missing, true, database ) ) {
+ new CustomRecipeListItem( recipeListView->listView(), *it );
+ }
+ else {
+ incompleteRecipes.append( *it );
+ missingIngredients.append( missing );
+ missingNumbers.append( missing.count() );
+ }
+ }
+ END_TIMER();
+
+ //Check if the user wants to show missing ingredients
+
+ if ( missingNumberSpinBox->value() == 0 ) {
+ TDEApplication::restoreOverrideCursor();
+ return ;
+ } //"None"
+
+
+
+ START_TIMER("Ingredient Matcher: searching for and displaying partial matches");
+
+ IngredientList requiredIngredients;
+ for ( TQListViewItem *it = ingListView->listView()->firstChild(); it; it = it->nextSibling() ) {
+ if ( ((TQCheckListItem*)it)->isOn() )
+ requiredIngredients << *m_item_ing_map[it];
+ }
+
+ // Classify recipes with missing ingredients in different lists by ammount
+ TQValueList<int>::Iterator nit;
+ TQValueList<IngredientList>::Iterator ilit;
+ int missingNoAllowed = missingNumberSpinBox->value();
+
+ if ( missingNoAllowed == -1 ) // "Any"
+ {
+ for ( nit = missingNumbers.begin();nit != missingNumbers.end();++nit )
+ if ( ( *nit ) > missingNoAllowed )
+ missingNoAllowed = ( *nit );
+ }
+
+
+ for ( int missingNo = 1; missingNo <= missingNoAllowed; missingNo++ ) {
+ nit = missingNumbers.begin();
+ ilit = missingIngredients.begin();
+
+ bool titleShownYet = false;
+
+ for ( it = incompleteRecipes.begin();it != incompleteRecipes.end();++it, ++nit, ++ilit ) {
+ if ( !( *it ).ingList.containsAny( m_ingredientList ) )
+ continue;
+
+ if ( !( *it ).ingList.containsSubSet( requiredIngredients ) )
+ continue;
+
+ if ( ( *nit ) == missingNo ) {
+ if ( !titleShownYet ) {
+ new SectionItem( recipeListView->listView(), i18n( "You are missing 1 ingredient for:", "You are missing %n ingredients for:", missingNo ) );
+ titleShownYet = true;
+ }
+ new CustomRecipeListItem( recipeListView->listView(), *it, *ilit );
+ }
+ }
+ }
+ END_TIMER();
+
+ TDEApplication::restoreOverrideCursor();
+}
+
+void IngredientMatcherDialog::reload( ReloadFlags flag )
+{
+ ( ( StdIngredientListView* ) allIngListView->listView() ) ->reload(flag);
+}
+
+void SectionItem::paintCell ( TQPainter * p, const TQColorGroup & /*cg*/, int column, int width, int /*align*/ )
+{
+ // Draw the section's deco
+ p->setPen( TDEGlobalSettings::activeTitleColor() );
+ p->setBrush( TDEGlobalSettings::activeTitleColor() );
+ p->drawRect( 0, 0, width, height() );
+
+ // Draw the section's text
+ if ( column == 0 ) {
+ TQFont titleFont = TDEGlobalSettings::windowTitleFont ();
+ p->setFont( titleFont );
+
+ p->setPen( TDEGlobalSettings::activeTextColor() );
+ p->drawText( 0, 0, width, height(), TQt::AlignLeft | TQt::AlignVCenter, mText );
+ }
+}
+
+#include "ingredientmatcherdialog.moc"