diff options
Diffstat (limited to 'src/dialogs')
79 files changed, 13287 insertions, 0 deletions
diff --git a/src/dialogs/Makefile.am b/src/dialogs/Makefile.am new file mode 100644 index 0000000..23f80e1 --- /dev/null +++ b/src/dialogs/Makefile.am @@ -0,0 +1,38 @@ +## Makefile.am for krecipes + +# this is the program that gets installed. it's name is used for all +# of the other Makefile.am variables + +# set the include path for X, tqt and TDE +INCLUDES = -I$(srcdir)/.. $(all_includes) + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + +noinst_LTLIBRARIES=libkrecipesdialogs.la +libkrecipesdialogs_la_SOURCES= \ + advancedsearchdialog.cpp recipeimportdialog.cpp \ + dietwizarddialog.cpp recipeinputdialog.cpp \ + recipeviewdialog.cpp selectrecipedialog.cpp \ + ingredientsdialog.cpp selectunitdialog.cpp \ + createelementdialog.cpp propertiesdialog.cpp \ + createpropertydialog.cpp selectpropertydialog.cpp \ + unitsdialog.cpp dependanciesdialog.cpp \ + shoppinglistdialog.cpp shoppinglistviewdialog.cpp \ + selectcategoriesdialog.cpp categorieseditordialog.cpp \ + authorsdialog.cpp selectauthorsdialog.cpp \ + resizerecipedialog.cpp \ + dietviewdialog.cpp ingredientmatcherdialog.cpp \ + usdadatadialog.cpp prepmethodsdialog.cpp \ + createcategorydialog.cpp borderdialog.cpp \ + refineshoppinglistdialog.cpp pagesetupdialog.cpp \ + dbimportdialog.cpp createunitdialog.cpp \ + setupdisplay.cpp \ + ingredientparserdialog.cpp ingredientgroupsdialog.cpp \ + editratingdialog.cpp similarcategoriesdialog.cpp \ + conversiondialog.cpp createingredientweightdialog.cpp \ + recipeprintpreview.cpp + +libkrecipesdialogs_la_METASOURCES=AUTO + +#the library search path. +libkrecipesdialogs_la_LDFLAGS = $(KDE_RPATH) $(all_libraries) diff --git a/src/dialogs/advancedsearchdialog.cpp b/src/dialogs/advancedsearchdialog.cpp new file mode 100644 index 0000000..9f4864d --- /dev/null +++ b/src/dialogs/advancedsearchdialog.cpp @@ -0,0 +1,932 @@ +/*************************************************************************** +* Copyright (C) 2003-2004 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "advancedsearchdialog.h" + +#include <tqvariant.h> +#include <tqpushbutton.h> +#include <tqtabwidget.h> +#include <tqwidget.h> +#include <tqcheckbox.h> +#include <tqframe.h> +#include <tqcombobox.h> +#include <tqheader.h> +#include <tqlistview.h> +#include <tqgroupbox.h> +#include <tqspinbox.h> +#include <tqdatetimeedit.h> +#include <kpushbutton.h> +#include <tqlayout.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> +#include <tqlabel.h> +#include <tqlineedit.h> +#include <tqscrollview.h> +#include <tqhbox.h> +#include <tqradiobutton.h> +#include <tqbuttongroup.h> + +#include <tdeapplication.h> +#include <kcursor.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <tdelistview.h> +#include <tdelocale.h> +#include <tdeconfig.h> +#include <tdeglobal.h> +#include <tdepopupmenu.h> + +#include "backends/recipedb.h" +#include "backends/searchparameters.h" +#include "recipeactionshandler.h" +#include "widgets/recipelistview.h" +#include "widgets/kdateedit.h" +#include "widgets/ratingwidget.h" +#include "widgets/fractioninput.h" +#include "widgets/criteriacombobox.h" + +#include "profiling.h" + +AdvancedSearchDialog::AdvancedSearchDialog( TQWidget *parent, RecipeDB *db ) : TQWidget( parent ), + database( db ) +{ + /// + ///BEGIN OF AUTOMATICALLY GENERATED GUI CODE/// + /// + AdvancedSearchDialogLayout = new TQHBoxLayout( this, 5, 3, "AdvancedSearchDialogLayout"); + + layout7 = new TQVBoxLayout( 0, 0, 3, "layout7"); + + textLabel1_4 = new TQLabel( this, "textLabel1_4" ); + layout7->addWidget( textLabel1_4 ); + + scrollView1 = new TQScrollView( this, "scrollView1" ); + scrollView1->enableClipper(true); + + parametersFrame = new TQFrame( scrollView1, "parametersFrame" ); + parametersFrame->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)3, (TQSizePolicy::SizeType)3, 0, 0, parametersFrame->sizePolicy().hasHeightForWidth() ) ); + parametersFrame->setFrameShape( TQFrame::NoFrame ); + parametersFrame->setFrameShadow( TQFrame::Plain ); + parametersFrame->setLineWidth( 0 ); + parametersFrameLayout = new TQVBoxLayout( parametersFrame, 0, 0, "parametersFrameLayout"); + + titleButton = new TQPushButton( parametersFrame, "titleButton" ); + titleButton->setToggleButton( TRUE ); + parametersFrameLayout->addWidget( titleButton ); + + titleFrame = new TQFrame( parametersFrame, "titleFrame" ); + titleFrame->setFrameShape( TQFrame::StyledPanel ); + titleFrame->setFrameShadow( TQFrame::Raised ); + titleFrameLayout = new TQVBoxLayout( titleFrame, 5, 3, "titleFrameLayout"); + + requireAllTitle = new TQCheckBox( i18n("Require All Words"), titleFrame ); + titleFrameLayout->addWidget( requireAllTitle ); + + TQHBox *titleHBox = new TQHBox( titleFrame ); + /*TQLabel *titleInfoLabel = */new TQLabel(i18n("Keywords:"),titleHBox); + titleEdit = new TQLineEdit( titleHBox, "titleEdit" ); + titleFrameLayout->addWidget( titleHBox ); + + parametersFrameLayout->addWidget( titleFrame ); + titleFrameSpacer = new TQSpacerItem( 0, 0, TQSizePolicy::Minimum, TQSizePolicy::Preferred ); + parametersFrameLayout->addItem( titleFrameSpacer ); + + + ingredientButton = new TQPushButton( parametersFrame, "ingredientButton" ); + ingredientButton->setToggleButton( TRUE ); + parametersFrameLayout->addWidget( ingredientButton ); + + ingredientFrame = new TQFrame( parametersFrame, "ingredientFrame" ); + ingredientFrame->setFrameShape( TQFrame::StyledPanel ); + ingredientFrame->setFrameShadow( TQFrame::Raised ); + ingredientFrameLayout = new TQGridLayout( ingredientFrame, 1, 1, 3, 3, "ingredientFrameLayout"); + + TQLabel *ingredientInfoLabel = new TQLabel(i18n("Enter ingredients: (e.g. chicken pasta \"white wine\")"),ingredientFrame); + ingredientInfoLabel->setTextFormat( TQt::RichText ); + ingredientFrameLayout->addMultiCellWidget( ingredientInfoLabel, 0, 0, 0, 1 ); + + ingredientsAllEdit = new TQLineEdit( ingredientFrame, "ingredientsAllEdit" ); + + ingredientFrameLayout->addWidget( ingredientsAllEdit, 1, 1 ); + + ingredientsAnyEdit = new TQLineEdit( ingredientFrame, "ingredientsAnyEdit" ); + + ingredientFrameLayout->addWidget( ingredientsAnyEdit, 2, 1 ); + + textLabel1_2 = new TQLabel( ingredientFrame, "textLabel1_2" ); + + ingredientFrameLayout->addWidget( textLabel1_2, 2, 0 ); + + textLabel1 = new TQLabel( ingredientFrame, "textLabel1" ); + + ingredientFrameLayout->addWidget( textLabel1, 1, 0 ); + + ingredientsWithoutEdit = new TQLineEdit( ingredientFrame, "ingredientsWithoutEdit" ); + + ingredientFrameLayout->addWidget( ingredientsWithoutEdit, 3, 1 ); + + textLabel1_3 = new TQLabel( ingredientFrame, "textLabel1_3" ); + + ingredientFrameLayout->addWidget( textLabel1_3, 3, 0 ); + parametersFrameLayout->addWidget( ingredientFrame ); + spacer3_2_3_2_2 = new TQSpacerItem( 0, 0, TQSizePolicy::Minimum, TQSizePolicy::Preferred ); + parametersFrameLayout->addItem( spacer3_2_3_2_2 ); + + + categoriesButton = new TQPushButton( parametersFrame, "categoriesButton" ); + categoriesButton->setToggleButton( TRUE ); + parametersFrameLayout->addWidget( categoriesButton ); + + categoryFrame = new TQFrame( parametersFrame, "categoryFrame" ); + categoryFrame->setFrameShape( TQFrame::StyledPanel ); + categoryFrame->setFrameShadow( TQFrame::Raised ); + categoryFrameLayout = new TQGridLayout( categoryFrame, 1, 1, 3, 3, "categoryFrameLayout"); + + TQLabel *categoryInfoLabel = new TQLabel(i18n("Enter categories: (e.g. Desserts Pastas \"Main Dishes\")"),categoryFrame); + categoryInfoLabel->setTextFormat( TQt::RichText ); + categoryFrameLayout->addMultiCellWidget( categoryInfoLabel, 0, 0, 0, 1 ); + + categoriesAllEdit = new TQLineEdit( categoryFrame, "categoriesAllEdit" ); + + categoryFrameLayout->addWidget( categoriesAllEdit, 1, 1 ); + + textLabel1_5 = new TQLabel( categoryFrame, "textLabel1_5" ); + + categoryFrameLayout->addWidget( textLabel1_5, 1, 0 ); + + textLabel1_3_3 = new TQLabel( categoryFrame, "textLabel1_3_3" ); + + categoryFrameLayout->addWidget( textLabel1_3_3, 3, 0 ); + + categoriesAnyEdit = new TQLineEdit( categoryFrame, "categoriesAnyEdit" ); + + categoryFrameLayout->addWidget( categoriesAnyEdit, 2, 1 ); + + textLabel1_2_3 = new TQLabel( categoryFrame, "textLabel1_2_3" ); + + categoryFrameLayout->addWidget( textLabel1_2_3, 2, 0 ); + + categoriesNotEdit = new TQLineEdit( categoryFrame, "categoriesNotEdit" ); + + categoryFrameLayout->addWidget( categoriesNotEdit, 3, 1 ); + parametersFrameLayout->addWidget( categoryFrame ); + spacer3_2_3_2 = new TQSpacerItem( 0, 0, TQSizePolicy::Minimum, TQSizePolicy::Preferred ); + parametersFrameLayout->addItem( spacer3_2_3_2 ); + + + authorsButton = new TQPushButton( parametersFrame, "authorsButton" ); + authorsButton->setToggleButton( TRUE ); + parametersFrameLayout->addWidget( authorsButton ); + + authorsFrame = new TQFrame( parametersFrame, "authorsFrame" ); + authorsFrame->setFrameShape( TQFrame::StyledPanel ); + authorsFrame->setFrameShadow( TQFrame::Raised ); + authorsFrameLayout = new TQGridLayout( authorsFrame, 1, 1, 3, 3, "authorsFrameLayout"); + + TQLabel *authorsInfoLabel = new TQLabel(i18n("Enter author name (e.g. Smith or \"Jane Doe\")"),authorsFrame); + authorsInfoLabel->setTextFormat( TQt::RichText ); + authorsFrameLayout->addMultiCellWidget( authorsInfoLabel, 0, 0, 0, 1 ); + + textLabel1_2_4 = new TQLabel( authorsFrame, "textLabel1_2_4" ); + + authorsFrameLayout->addWidget( textLabel1_2_4, 1, 0 ); + + textLabel1_6 = new TQLabel( authorsFrame, "textLabel1_6" ); + + authorsFrameLayout->addWidget( textLabel1_6, 2, 0 ); + + textLabel1_3_4 = new TQLabel( authorsFrame, "textLabel1_3_4" ); + + authorsFrameLayout->addWidget( textLabel1_3_4, 3, 0 ); + + authorsAnyEdit = new TQLineEdit( authorsFrame, "authorsAnyEdit" ); + + authorsFrameLayout->addWidget( authorsAnyEdit, 1, 1 ); + + authorsAllEdit = new TQLineEdit( authorsFrame, "authorsAllEdit" ); + + authorsFrameLayout->addWidget( authorsAllEdit, 2, 1 ); + + authorsWithoutEdit = new TQLineEdit( authorsFrame, "authorsWithoutEdit" ); + + authorsFrameLayout->addWidget( authorsWithoutEdit, 3, 1 ); + parametersFrameLayout->addWidget( authorsFrame ); + spacer3_2_3 = new TQSpacerItem( 0, 0, TQSizePolicy::Minimum, TQSizePolicy::Preferred ); + parametersFrameLayout->addItem( spacer3_2_3 ); + + + servingsButton = new TQPushButton( parametersFrame, "servingsButton" ); + servingsButton->setToggleButton( TRUE ); + parametersFrameLayout->addWidget( servingsButton ); + + servingsFrame = new TQFrame( parametersFrame, "servingsFrame" ); + servingsFrame->setFrameShape( TQFrame::StyledPanel ); + servingsFrame->setFrameShadow( TQFrame::Raised ); + servingsFrameLayout = new TQVBoxLayout( servingsFrame, 3, 3, "servingsFrameLayout"); + + enableServingsCheckBox = new TQCheckBox( servingsFrame, "enableServingsCheckBox" ); + servingsFrameLayout->addWidget( enableServingsCheckBox ); + + layout5 = new TQHBoxLayout( 0, 0, 3, "layout5"); + + servingsComboBox = new TQComboBox( FALSE, servingsFrame, "servingsComboBox" ); + servingsComboBox->setEnabled( FALSE ); + servingsComboBox->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)1, (TQSizePolicy::SizeType)0, 1, 0, servingsComboBox->sizePolicy().hasHeightForWidth() ) ); + layout5->addWidget( servingsComboBox ); + + servingsSpinBox = new TQSpinBox( servingsFrame, "servingsSpinBox" ); + servingsSpinBox->setEnabled( FALSE ); + servingsSpinBox->setMinValue( 1 ); + servingsSpinBox->setMaxValue( 9999 ); + layout5->addWidget( servingsSpinBox ); + servingsFrameLayout->addLayout( layout5 ); + parametersFrameLayout->addWidget( servingsFrame ); + spacer3_2_2 = new TQSpacerItem( 0, 0, TQSizePolicy::Minimum, TQSizePolicy::Preferred ); + parametersFrameLayout->addItem( spacer3_2_2 ); + + + prepTimeButton = new TQPushButton( parametersFrame, "prepTimeButton" ); + prepTimeButton->setToggleButton( TRUE ); + parametersFrameLayout->addWidget( prepTimeButton ); + + prepTimeFrame = new TQFrame( parametersFrame, "prepTimeFrame" ); + prepTimeFrame->setFrameShape( TQFrame::StyledPanel ); + prepTimeFrame->setFrameShadow( TQFrame::Raised ); + prepTimeFrameLayout = new TQVBoxLayout( prepTimeFrame, 3, 3, "prepTimeFrameLayout"); + + enablePrepTimeCheckBox = new TQCheckBox( prepTimeFrame, "enablePrepTimeCheckBox" ); + prepTimeFrameLayout->addWidget( enablePrepTimeCheckBox ); + + layout6 = new TQHBoxLayout( 0, 0, 3, "layout6"); + + prepTimeComboBox = new TQComboBox( FALSE, prepTimeFrame, "prepTimeComboBox" ); + prepTimeComboBox->setEnabled( FALSE ); + prepTimeComboBox->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)1, (TQSizePolicy::SizeType)0, 1, 0, prepTimeComboBox->sizePolicy().hasHeightForWidth() ) ); + layout6->addWidget( prepTimeComboBox ); + + prepTimeEdit = new TQTimeEdit( prepTimeFrame, "prepTimeEdit" ); + prepTimeEdit->setEnabled( FALSE ); + prepTimeEdit->setDisplay( int( TQTimeEdit::Minutes | TQTimeEdit::Hours ) ); + layout6->addWidget( prepTimeEdit ); + prepTimeFrameLayout->addLayout( layout6 ); + parametersFrameLayout->addWidget( prepTimeFrame ); + spacer15 = new TQSpacerItem( 0, 0, TQSizePolicy::Minimum, TQSizePolicy::Preferred ); + parametersFrameLayout->addItem( spacer15 ); + + + instructionsButton = new TQPushButton( parametersFrame, "instructionsButton" ); + instructionsButton->setToggleButton( TRUE ); + parametersFrameLayout->addWidget( instructionsButton ); + + instructionsFrame = new TQFrame( parametersFrame, "instructionsFrame" ); + instructionsFrame->setFrameShape( TQFrame::StyledPanel ); + instructionsFrame->setFrameShadow( TQFrame::Raised ); + instructionsFrameLayout = new TQVBoxLayout( instructionsFrame, 5, 3, "instructionsFrameLayout"); + + requireAllInstructions = new TQCheckBox( i18n("Require All Words"), instructionsFrame ); + instructionsFrameLayout->addWidget( requireAllInstructions ); + + TQHBox *instructionsHBox = new TQHBox(instructionsFrame); + /*TQLabel *instructionsInfoLabel = */new TQLabel(i18n("Keywords:"),instructionsHBox); + + instructionsEdit = new TQLineEdit( instructionsHBox, "instructionsEdit" ); + instructionsFrameLayout->addWidget( instructionsHBox ); + + parametersFrameLayout->addWidget( instructionsFrame ); + instructionsFrameSpacer = new TQSpacerItem( 0, 0, TQSizePolicy::Minimum, TQSizePolicy::Preferred ); + parametersFrameLayout->addItem( instructionsFrameSpacer ); + + + metaDataButton = new TQPushButton( parametersFrame, "metaDataButton" ); + metaDataButton->setToggleButton( TRUE ); + parametersFrameLayout->addWidget( metaDataButton ); + + metaDataFrame = new TQFrame( parametersFrame, "metaDataFrame" ); + metaDataFrame->setFrameShape( TQFrame::StyledPanel ); + metaDataFrame->setFrameShadow( TQFrame::Raised ); + metaDataFrameLayout = new TQVBoxLayout( metaDataFrame, 5, 3, "metaDataFrameLayout"); + + TQLabel *createdLabel = new TQLabel( i18n("Created:"), metaDataFrame ); + metaDataFrameLayout->addWidget( createdLabel ); + + TQHBox *createdHBox = new TQHBox(metaDataFrame); + createdStartDateEdit = new KDateEdit(createdHBox,"createdStartEdit"); + createdStartDateEdit->setSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::Preferred ); + (void)new TQLabel(" - ",createdHBox); + createdEndDateEdit = new KDateEdit(createdHBox,"createdEndEdit"); + createdEndDateEdit->setSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::Preferred ); + metaDataFrameLayout->addWidget( createdHBox ); + + TQLabel *modifiedLabel = new TQLabel( i18n("Modified:"), metaDataFrame ); + metaDataFrameLayout->addWidget( modifiedLabel ); + + TQHBox *modifiedHBox = new TQHBox(metaDataFrame); + modifiedStartDateEdit = new KDateEdit(modifiedHBox,"modifiedStartEdit"); + modifiedStartDateEdit->setSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::Preferred ); + (void)new TQLabel(" - ",modifiedHBox); + modifiedEndDateEdit = new KDateEdit(modifiedHBox,"modifiedEndEdit"); + modifiedEndDateEdit->setSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::Preferred ); + metaDataFrameLayout->addWidget( modifiedHBox ); + + TQLabel *accessedLabel = new TQLabel( i18n("Last Accessed:"), metaDataFrame ); + metaDataFrameLayout->addWidget( accessedLabel ); + + TQHBox *accessedHBox = new TQHBox(metaDataFrame); + accessedStartDateEdit = new KDateEdit(accessedHBox,"accessedStartEdit"); + accessedStartDateEdit->setSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::Preferred ); + (void)new TQLabel(" - ",accessedHBox); + accessedEndDateEdit = new KDateEdit(accessedHBox,"accessedEndEdit"); + accessedEndDateEdit->setSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::Preferred ); + metaDataFrameLayout->addWidget( accessedHBox ); + + parametersFrameLayout->addWidget( metaDataFrame ); + metaDataFrameSpacer = new TQSpacerItem( 0, 0, TQSizePolicy::Minimum, TQSizePolicy::Preferred ); + parametersFrameLayout->addItem( metaDataFrameSpacer ); + + //=============RATINGS FRAME===========// + ratingsButton = new TQPushButton( parametersFrame, "ratingsButton" ); + ratingsButton->setToggleButton( TRUE ); + parametersFrameLayout->addWidget( ratingsButton ); + + ratingButtonGroup = new TQButtonGroup( parametersFrame, "ratingButtonGroup" ); + ratingButtonGroup->setLineWidth( 0 ); + ratingButtonGroup->setColumnLayout(0, TQt::Vertical ); + ratingButtonGroup->layout()->setSpacing( 5 ); + ratingButtonGroup->layout()->setMargin( 3 ); + ratingButtonGroupLayout = new TQVBoxLayout( ratingButtonGroup->layout() ); + ratingButtonGroupLayout->setAlignment( TQt::AlignTop ); + + ratingAvgRadioButton = new TQRadioButton( ratingButtonGroup, "ratingAvgRadioButton" ); + ratingAvgRadioButton->setChecked( TRUE ); + ratingButtonGroupLayout->addWidget( ratingAvgRadioButton ); + + ratingAvgFrame = new TQFrame( ratingButtonGroup, "ratingAvgFrame" ); + ratingAvgFrame->setLineWidth( 0 ); + ratingAvgFrameLayout = new TQHBoxLayout( ratingAvgFrame, 2, 2, "ratingAvgFrameLayout"); + + avgStarsEdit = new FractionInput( ratingAvgFrame ); + avgStarsEdit->setAllowRange(true); + ratingAvgFrameLayout->addWidget( avgStarsEdit ); + + avgStarsLabel = new TQLabel( ratingAvgFrame, "avgStarsLabel" ); + ratingAvgFrameLayout->addWidget( avgStarsLabel ); + ratingButtonGroupLayout->addWidget( ratingAvgFrame ); + + criterionRadioButton = new TQRadioButton( ratingButtonGroup, "criterionRadioButton" ); + ratingButtonGroupLayout->addWidget( criterionRadioButton ); + + criterionFrame = new TQFrame( ratingButtonGroup, "criterionFrame" ); + criterionFrame->setEnabled( FALSE ); + criterionFrame->setLineWidth( 0 ); + criterionFrameLayout = new TQVBoxLayout( criterionFrame, 2, 2, "criterionFrameLayout"); + + layout12 = new TQHBoxLayout( 0, 0, 6, "layout12"); + + criteriaComboBox = new CriteriaComboBox( FALSE, criterionFrame, database ); + criteriaComboBox->setEditable( false ); + criteriaComboBox->reload(); + layout12->addWidget( criteriaComboBox ); + + starsWidget = new FractionInput( criterionFrame ); + starsWidget->setAllowRange(true); + starsWidget->setSizePolicy( TQSizePolicy::Ignored, TQSizePolicy::Preferred ); + layout12->addWidget( starsWidget ); + + + addCriteriaButton = new TQPushButton( criterionFrame, "addCriteriaButton" ); + addCriteriaButton->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)0, (TQSizePolicy::SizeType)0, 0, 0, addCriteriaButton->sizePolicy().hasHeightForWidth() ) ); + addCriteriaButton->setMaximumSize( TQSize( 30, 30 ) ); + layout12->addWidget( addCriteriaButton ); +#if 0 + removeCriteriaButton = new TQPushButton( criterionFrame, "removeCriteriaButton" ); + removeCriteriaButton->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)0, (TQSizePolicy::SizeType)0, 0, 0, removeCriteriaButton->sizePolicy().hasHeightForWidth() ) ); + removeCriteriaButton->setMaximumSize( TQSize( 30, 30 ) ); + layout12->addWidget( removeCriteriaButton ); +#endif + criterionFrameLayout->addLayout( layout12 ); + + criteriaListView = new TDEListView( criterionFrame, "criteriaListView" ); + criteriaListView->setSizePolicy( TQSizePolicy::Preferred, TQSizePolicy::Minimum ); + criteriaListView->addColumn( i18n( "Criterion" ) ); + criteriaListView->addColumn( i18n( "Stars" ) ); + criterionFrameLayout->addWidget( criteriaListView ); + ratingButtonGroupLayout->addWidget( criterionFrame ); + + parametersFrameLayout->addWidget( ratingButtonGroup ); + ratingsFrameSpacer = new TQSpacerItem( 0, 0, TQSizePolicy::Minimum, TQSizePolicy::Expanding ); + parametersFrameLayout->addItem( ratingsFrameSpacer ); + + + scrollView1->addChild( parametersFrame ); + layout7->addWidget( scrollView1 ); + + layout9 = new TQHBoxLayout( 0, 0, 3, "layout9"); + + clearButton = new KPushButton( this, "clearButton" ); + clearButton->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)1, (TQSizePolicy::SizeType)0, 0, 0, clearButton->sizePolicy().hasHeightForWidth() ) ); + layout9->addWidget( clearButton ); + spacer3 = new TQSpacerItem( 110, 0, TQSizePolicy::Expanding, TQSizePolicy::Minimum ); + layout9->addItem( spacer3 ); + + findButton = new KPushButton( this, "findButton" ); + findButton->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)1, (TQSizePolicy::SizeType)0, 0, 0, findButton->sizePolicy().hasHeightForWidth() ) ); + layout9->addWidget( findButton ); + layout7->addLayout( layout9 ); + AdvancedSearchDialogLayout->addLayout( layout7 ); + + resultsListView = new TDEListView( this, "resultsListView" ); + resultsListView->setSelectionMode( TQListView::Extended ); + resultsListView->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)7, (TQSizePolicy::SizeType)7, 0, 1, resultsListView->sizePolicy().hasHeightForWidth() ) ); + AdvancedSearchDialogLayout->addWidget( resultsListView ); + languageChange(); + clearWState( WState_Polished ); + /// + ///END OF AUTOMATICALLY GENERATED GUI CODE/// + /// + + resultsListView->setSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::Preferred ); + scrollView1->setSizePolicy( TQSizePolicy::Preferred, TQSizePolicy::Ignored ); + + AdvancedSearchDialogLayout->setStretchFactor( resultsListView, 2 ); + + scrollView1->setHScrollBarMode( TQScrollView::AlwaysOff ); + scrollView1->setResizePolicy( TQScrollView::AutoOneFit ); + + TDEConfig *config = TDEGlobal::config(); + config->setGroup( "Advanced" ); + bool show_id = config->readBoolEntry( "ShowID", false ); + resultsListView->addColumn( i18n( "Title" ) ); + resultsListView->addColumn( i18n( "Id" ), show_id ? -1 : 0 ); + + actionHandler = new RecipeActionsHandler( resultsListView, database, RecipeActionsHandler::Open | RecipeActionsHandler::Edit | RecipeActionsHandler::Export | RecipeActionsHandler::CopyToClipboard | RecipeActionsHandler::Remove ); + + connect( titleEdit, TQ_SIGNAL( returnPressed() ), TQ_SLOT( search() ) ); + connect( ingredientsAllEdit, TQ_SIGNAL( returnPressed() ), TQ_SLOT( search() ) ); + connect( ingredientsAnyEdit, TQ_SIGNAL( returnPressed() ), TQ_SLOT( search() ) ); + connect( ingredientsWithoutEdit, TQ_SIGNAL( returnPressed() ), TQ_SLOT( search() ) ); + connect( authorsAnyEdit, TQ_SIGNAL( returnPressed() ), TQ_SLOT( search() ) ); + connect( authorsAllEdit, TQ_SIGNAL( returnPressed() ), TQ_SLOT( search() ) ); + connect( authorsWithoutEdit, TQ_SIGNAL( returnPressed() ), TQ_SLOT( search() ) ); + connect( categoriesNotEdit, TQ_SIGNAL( returnPressed() ), TQ_SLOT( search() ) ); + connect( categoriesAnyEdit, TQ_SIGNAL( returnPressed() ), TQ_SLOT( search() ) ); + connect( categoriesAllEdit, TQ_SIGNAL( returnPressed() ), TQ_SLOT( search() ) ); + connect( ingredientsWithoutEdit, TQ_SIGNAL( returnPressed() ), TQ_SLOT( search() ) ); + connect( instructionsEdit, TQ_SIGNAL( returnPressed() ), TQ_SLOT( search() ) ); + + connect( findButton, TQ_SIGNAL( clicked() ), TQ_SLOT( search() ) ); + connect( clearButton, TQ_SIGNAL( clicked() ), TQ_SLOT( clear() ) ); + + connect( enableServingsCheckBox, TQ_SIGNAL( toggled( bool ) ), servingsSpinBox, TQ_SLOT( setEnabled( bool ) ) ); + connect( enableServingsCheckBox, TQ_SIGNAL( toggled( bool ) ), servingsComboBox, TQ_SLOT( setEnabled( bool ) ) ); + connect( enablePrepTimeCheckBox, TQ_SIGNAL( toggled( bool ) ), prepTimeEdit, TQ_SLOT( setEnabled( bool ) ) ); + connect( enablePrepTimeCheckBox, TQ_SIGNAL( toggled( bool ) ), prepTimeComboBox, TQ_SLOT( setEnabled( bool ) ) ); + + connect( titleButton, TQ_SIGNAL( toggled( bool ) ), titleFrame, TQ_SLOT( setShown( bool ) ) ); + connect( ingredientButton, TQ_SIGNAL( toggled( bool ) ), ingredientFrame, TQ_SLOT( setShown( bool ) ) ); + connect( authorsButton, TQ_SIGNAL( toggled( bool ) ), authorsFrame, TQ_SLOT( setShown( bool ) ) ); + connect( categoriesButton, TQ_SIGNAL( toggled( bool ) ), categoryFrame, TQ_SLOT( setShown( bool ) ) ); + connect( servingsButton, TQ_SIGNAL( toggled( bool ) ), servingsFrame, TQ_SLOT( setShown( bool ) ) ); + connect( prepTimeButton, TQ_SIGNAL( toggled( bool ) ), prepTimeFrame, TQ_SLOT( setShown( bool ) ) ); + connect( instructionsButton, TQ_SIGNAL( toggled( bool ) ), instructionsFrame, TQ_SLOT( setShown( bool ) ) ); + connect( metaDataButton, TQ_SIGNAL( toggled( bool ) ), metaDataFrame, TQ_SLOT( setShown( bool ) ) ); + connect( ratingsButton, TQ_SIGNAL( toggled( bool ) ), ratingButtonGroup, TQ_SLOT( setShown( bool ) ) ); + + connect( titleButton, TQ_SIGNAL( toggled( bool ) ), TQ_SLOT( buttonSwitched() ) ); + connect( ingredientButton, TQ_SIGNAL( toggled( bool ) ), TQ_SLOT( buttonSwitched() ) ); + connect( authorsButton, TQ_SIGNAL( toggled( bool ) ), TQ_SLOT( buttonSwitched() ) ); + connect( categoriesButton, TQ_SIGNAL( toggled( bool ) ), TQ_SLOT( buttonSwitched() ) ); + connect( servingsButton, TQ_SIGNAL( toggled( bool ) ), TQ_SLOT( buttonSwitched() ) ); + connect( prepTimeButton, TQ_SIGNAL( toggled( bool ) ), TQ_SLOT( buttonSwitched() ) ); + connect( instructionsButton, TQ_SIGNAL( toggled( bool ) ), TQ_SLOT( buttonSwitched() ) ); + connect( metaDataButton, TQ_SIGNAL( toggled( bool ) ), TQ_SLOT( buttonSwitched() ) ); + connect( ratingsButton, TQ_SIGNAL( toggled( bool ) ), TQ_SLOT( buttonSwitched() ) ); + + connect( ratingButtonGroup, TQ_SIGNAL( clicked( int ) ), this, TQ_SLOT( activateRatingOption( int ) ) ); + + connect( addCriteriaButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( slotAddRatingCriteria() ) ); + + titleFrame->setShown(false); + ingredientFrame->setShown(false); + authorsFrame->setShown(false); + categoryFrame->setShown(false); + servingsFrame->setShown(false); + prepTimeFrame->setShown(false); + instructionsFrame->setShown(false); + metaDataFrame->setShown(false); + ratingButtonGroup->setShown(false); + + connect( actionHandler, TQ_SIGNAL( recipeSelected( int, int ) ), TQ_SIGNAL( recipeSelected( int, int ) ) ); + connect( actionHandler, TQ_SIGNAL( recipesSelected( const TQValueList<int> &, int ) ), TQ_SIGNAL( recipesSelected( const TQValueList<int> &, int ) ) ); + + connect( database, TQ_SIGNAL( recipeRemoved( int ) ), TQ_SLOT( removeRecipe( int ) ) ); + + clear(); + + TDEPopupMenu *kpop = new TDEPopupMenu( criteriaListView ); + kpop->insertItem( i18n( "&Delete" ), this, TQ_SLOT( slotRemoveRatingCriteria() ), Key_Delete ); +} + +AdvancedSearchDialog::~AdvancedSearchDialog() +{} + +void AdvancedSearchDialog::languageChange() +{ + titleButton->setText( TQString("%1 >>").arg(i18n("Title")) ); + textLabel1_4->setText( i18n( "Search using the following criteria:" ) ); + ingredientButton->setText( TQString("%1 >>").arg(i18n("Ingredients")) ); + textLabel1_2->setText( i18n( "Uses any of:" ) ); + textLabel1->setText( i18n( "Uses all:" ) ); + textLabel1_3->setText( i18n( "Without:" ) ); + categoriesButton->setText( i18n( "Categories >>" ) ); + textLabel1_5->setText( i18n( "In all:" ) ); + textLabel1_3_3->setText( i18n( "Not in:" ) ); + textLabel1_2_3->setText( i18n( "In any of:" ) ); + authorsButton->setText( TQString("%1 >>").arg(i18n("Authors")) ); + textLabel1_2_4->setText( i18n( "By any of:" ) ); + textLabel1_6->setText( i18n( "By all:" ) ); + textLabel1_3_4->setText( i18n( "Not by:" ) ); + servingsButton->setText( TQString("%1 >>").arg(i18n("Yield")) ); + enableServingsCheckBox->setText( i18n( "Enabled" ) ); + servingsComboBox->clear(); + servingsComboBox->insertItem( i18n( "Yields at least:" ) ); + servingsComboBox->insertItem( i18n( "Yields at most:" ) ); + servingsComboBox->insertItem( i18n( "Yields about:" ) ); + prepTimeButton->setText( TQString("%1 >>").arg(i18n("Preparation Time")) ); + enablePrepTimeCheckBox->setText( i18n( "Enabled" ) ); + prepTimeComboBox->clear(); + prepTimeComboBox->insertItem( i18n( "Ready in at most:" ) ); + prepTimeComboBox->insertItem( i18n( "Ready in about:" ) ); + instructionsButton->setText( TQString("%1 >>").arg(i18n("Instructions")) ); + metaDataButton->setText( TQString("%1 >>").arg(i18n("Meta Data")) ); + clearButton->setText( i18n( "C&lear" ) ); + findButton->setText( i18n( "&Search" ) ); + ratingAvgRadioButton->setText( i18n( "By average:" ) ); + avgStarsLabel->setText( i18n( "stars" ) ); + criterionRadioButton->setText( i18n( "By criteria:" ) ); + addCriteriaButton->setText( i18n( "+" ) ); + //removeCriteriaButton->setText( i18n( "-" ) ); + criteriaListView->header()->setLabel( 0, i18n( "Criteria" ) ); + criteriaListView->header()->setLabel( 1, i18n( "Stars" ) ); + ratingsButton->setText( TQString("%1 >>").arg(i18n("Ratings")) ); +} + +void AdvancedSearchDialog::removeRecipe( int id ) +{ + TQListViewItemIterator iterator( resultsListView ); + while ( iterator.current() ) { + if ( iterator.current()->rtti() == 1000 ) { + RecipeListItem * recipe_it = ( RecipeListItem* ) iterator.current(); + if ( recipe_it->recipeID() == id ) + delete recipe_it; + } + ++iterator; + } +} + +void AdvancedSearchDialog::clear() +{ + resultsListView->clear(); + authorsAllEdit->clear(); + authorsWithoutEdit->clear(); + authorsAnyEdit->clear(); + categoriesAllEdit->clear(); + categoriesNotEdit->clear(); + categoriesAnyEdit->clear(); + ingredientsAllEdit->clear(); + ingredientsWithoutEdit->clear(); + ingredientsAnyEdit->clear(); + titleEdit->clear(); + instructionsEdit->clear(); + + createdStartDateEdit->setDate( TQDate() ); + createdEndDateEdit->setDate( TQDate() ); + modifiedStartDateEdit->setDate( TQDate() ); + modifiedEndDateEdit->setDate( TQDate() ); + accessedStartDateEdit->setDate( TQDate() ); + accessedEndDateEdit->setDate( TQDate() ); + + servingsSpinBox->setValue( 1 ); + prepTimeEdit->setTime( TQTime(0,0) ); + + enablePrepTimeCheckBox->setChecked(false); + enableServingsCheckBox->setChecked(false); + + requireAllTitle->setChecked(false); + requireAllInstructions->setChecked(false); + + ratingAvgRadioButton->setChecked(true); + activateRatingOption(0); + avgStarsEdit->clear(); + criteriaListView->clear(); + starsWidget->clear(); +} + +void AdvancedSearchDialog::activateRatingOption( int button_id ) +{ + switch ( button_id ) { + case 0: + criterionFrame->setEnabled( false ); + ratingAvgFrame->setEnabled( true ); + break; + case 1: + criterionFrame->setEnabled( true ); + ratingAvgFrame->setEnabled( false ); + break; + default: + break; + } +} + +void AdvancedSearchDialog::buttonSwitched() +{ + const TQObject *sent = sender(); + + if ( sent->inherits("TQPushButton") ) { + TQPushButton *pushed = (TQPushButton*) sent; + + TQString suffix = ( pushed->state() == TQButton::On ) ? " <<" : " >>"; + pushed->setText( pushed->text().left( pushed->text().length() - 3 ) + suffix ); + } +} + +void AdvancedSearchDialog::search() +{ + TDEApplication::setOverrideCursor( KCursor::waitCursor() ); + + //we need to load more than just the title because we'll be doing further refining of the search + int load_items = RecipeDB::Title | RecipeDB::NamesOnly | RecipeDB::Noatime; + if ( !authorsAllEdit->text().isEmpty() || !authorsWithoutEdit->text().isEmpty() ) + load_items |= RecipeDB::Authors; + if ( !ingredientsAllEdit->text().isEmpty() || !ingredientsWithoutEdit->text().isEmpty() ) + load_items |= RecipeDB::Ingredients; + if ( !categoriesAllEdit->text().isEmpty() || !categoriesNotEdit->text().isEmpty() ) + load_items |= RecipeDB::Categories; + if ( (ratingAvgRadioButton->isChecked() && !avgStarsEdit->isEmpty()) || (criterionRadioButton->isChecked() && criteriaListView->firstChild()) ) + load_items |= RecipeDB::Ratings; + + RecipeSearchParameters parameters; + + parameters.titleKeywords = split(titleEdit->text(),true); + parameters.requireAllTitleWords = requireAllTitle->isChecked(); + + parameters.instructionsKeywords = split(instructionsEdit->text(),true); + parameters.requireAllInstructionsWords = requireAllInstructions->isChecked(); + + parameters.ingsOr = split(ingredientsAnyEdit->text(),true); + parameters.catsOr = split(categoriesAnyEdit->text(),true); + parameters.authorsOr = split(authorsAnyEdit->text(),true); + + if ( enablePrepTimeCheckBox->isChecked() ) + parameters.prep_time = prepTimeEdit->time(); + parameters.prep_param = prepTimeComboBox->currentItem(); + + if ( enableServingsCheckBox->isChecked() ) + parameters.servings = servingsSpinBox->value(); + parameters.servings_param = servingsComboBox->currentItem(); + + parameters.createdDateBegin = createdStartDateEdit->date(); + parameters.createdDateEnd = createdEndDateEdit->date(); + if ( parameters.createdDateEnd.date().isValid() ) + parameters.createdDateEnd = parameters.createdDateEnd.addDays(1); //we want to include the given day in the search + + parameters.modifiedDateBegin = modifiedStartDateEdit->date(); + parameters.modifiedDateEnd = modifiedEndDateEdit->date(); + if ( parameters.modifiedDateEnd.date().isValid() ) + parameters.modifiedDateEnd = parameters.modifiedDateEnd.addDays(1); //we want to include the given day in the search + + parameters.accessedDateBegin = accessedStartDateEdit->date(); + parameters.accessedDateEnd = accessedEndDateEdit->date(); + if ( parameters.accessedDateEnd.date().isValid() ) + parameters.accessedDateEnd = parameters.accessedDateEnd.addDays(1); //we want to include the given day in the search + + START_TIMER("Doing database SQL search"); + RecipeList allRecipes; + database->search( &allRecipes, load_items, parameters ); + END_TIMER(); + + /* + * Ideally, would be done by the above SQL query, but I have no idea how to accomplish this. + */ + + START_TIMER("Further narrowing the search (no SQL)"); + TQStringList items = split(authorsAllEdit->text()); + for ( TQStringList::const_iterator author_it = items.begin(); author_it != items.end(); ++author_it ) { + for ( RecipeList::iterator it = allRecipes.begin(); it != allRecipes.end(); ++it ) { + if ( ( *it ).authorList.findByName( TQRegExp(*author_it,false, true) ).id == -1 ) { + it = allRecipes.remove( it ); + it--; + } + } + } + items = split(authorsWithoutEdit->text()); + for ( TQStringList::const_iterator author_it = items.begin(); author_it != items.end(); ++author_it ) { + for ( RecipeList::iterator it = allRecipes.begin(); it != allRecipes.end(); ++it ) { + if ( ( *it ).authorList.findByName( TQRegExp(*author_it,false,true) ).id != -1 ) { + it = allRecipes.remove( it ); + it--; + } + } + } + + //narrow down by categories + items = split(categoriesAllEdit->text()); + for ( TQStringList::const_iterator cat_it = items.begin(); cat_it != items.end(); ++cat_it ) { + for ( RecipeList::iterator it = allRecipes.begin(); it != allRecipes.end(); ++it ) { + if ( ( *it ).categoryList.findByName( TQRegExp(*cat_it,false,true) ).id == -1 ) { + it = allRecipes.remove( it ); + it--; + } + } + } + items = split(categoriesNotEdit->text()); + for ( TQStringList::const_iterator cat_it = items.begin(); cat_it != items.end(); ++cat_it ) { + for ( RecipeList::iterator it = allRecipes.begin(); it != allRecipes.end(); ++it ) { + if ( ( *it ).categoryList.findByName( TQRegExp(*cat_it,false,true) ).id != -1 ) { + it = allRecipes.remove( it ); + it--; + } + } + } + + //narrow down by ingredients + items = split(ingredientsAllEdit->text()); + for ( TQStringList::const_iterator ing_it = items.begin(); ing_it != items.end(); ++ing_it ) { + for ( RecipeList::iterator it = allRecipes.begin(); it != allRecipes.end(); ++it ) { + if ( ( *it ).ingList.findByName( TQRegExp(*ing_it,false,true) ).ingredientID == -1 ) { + it = allRecipes.remove( it ); + it--; + } + } + } + items = split(ingredientsWithoutEdit->text()); + for ( TQStringList::const_iterator ing_it = items.begin(); ing_it != items.end(); ++ing_it ) { + for ( RecipeList::iterator it = allRecipes.begin(); it != allRecipes.end(); ++it ) { + if ( ( *it ).ingList.findByName( TQRegExp(*ing_it,false,true) ).ingredientID != -1 ) { + it = allRecipes.remove( it ); + it--; + } + } + } + + if ( ratingAvgRadioButton->isChecked() && !avgStarsEdit->isEmpty() ) { + for ( RecipeList::iterator recipe_it = allRecipes.begin(); recipe_it != allRecipes.end(); ++recipe_it ) { + double sum = 0; + int count = 0; + + for ( RatingList::iterator rating_it = (*recipe_it).ratingList.begin(); rating_it != (*recipe_it).ratingList.end(); ++rating_it ) { + sum += (*rating_it).average(); + ++count; + } + + if ( count != 0 ) { + double average = sum/count; + + double stars; + double stars_offset; + avgStarsEdit->value(stars,stars_offset); + if ( stars_offset < 1e-10 ) { //if an exact amount is given, search for an amount within 0.5 of what is given + //we can get negatives here, but it really doesn't matter + stars = stars-0.5; + stars_offset = 1.0; + } + + + kdDebug()<<"average for "<<(*recipe_it).title<<" "<<average<<endl; + if ( average < stars || average > stars + stars_offset ) { + recipe_it = allRecipes.remove( recipe_it ); + recipe_it--; + } + } + else { + recipe_it = allRecipes.remove( recipe_it ); + recipe_it--; + } + } + } + + //TODO: Clean this up and/or do it more efficiently + if ( criterionRadioButton->isChecked() && criteriaListView->firstChild() ) { + for ( RecipeList::iterator recipe_it = allRecipes.begin(); recipe_it != allRecipes.end(); ++recipe_it ) { + TQMap< int, double > idSumMap; + TQMap< int, int > idCountMap; + + for ( RatingList::const_iterator rating_it = (*recipe_it).ratingList.begin(); rating_it != (*recipe_it).ratingList.end(); ++rating_it ) { + for ( RatingCriteriaList::const_iterator rc_it = (*rating_it).ratingCriteriaList.begin(); rc_it != (*rating_it).ratingCriteriaList.end(); ++rc_it ) { + TQMap< int, double >::iterator sum_it = idSumMap.find((*rc_it).id); + if ( sum_it == idSumMap.end() ) + sum_it = idSumMap.insert((*rc_it).id,0); + (*sum_it) += (*rc_it).stars; + + TQMap< int, int >::iterator count_it = idCountMap.find((*rc_it).id); + if ( count_it == idCountMap.end() ) + count_it = idCountMap.insert((*rc_it).id,0); + (*count_it)++; + } + } + + for ( TQListViewItem *item = criteriaListView->firstChild(); item; item = item->nextSibling() ) { + Ingredient i; i.setAmount( item->text(1) ); + double stars = i.amount; + double stars_offset = i.amount_offset; + + if ( stars_offset < 1e-10 ) { //if an exact amount is given, search for an amount within 0.5 of what is given + //we can get negatives here, but it really doesn't matter + stars = stars-0.5; + stars_offset = 1.0; + } + + int id = item->text(2).toInt(); + + TQMap< int, double >::iterator sum_it = idSumMap.find(id); + if ( sum_it != idSumMap.end() ) { + TQMap< int, int >::iterator count_it = idCountMap.find(id); + double average = (*sum_it)/(*count_it); + + if ( average < stars || average > stars + stars_offset ) { + recipe_it = allRecipes.remove( recipe_it ); + recipe_it--; + break; + } + } + else { + recipe_it = allRecipes.remove( recipe_it ); + recipe_it--; + break; + } + } + } + } + END_TIMER(); + + + //now display the recipes left + resultsListView->clear(); + for ( RecipeList::const_iterator it = allRecipes.begin(); it != allRecipes.end(); ++it ) { + ( void ) new RecipeListItem( resultsListView, *it ); + } + + if ( !resultsListView->firstChild() ) { + ( void ) new TQListViewItem( resultsListView, "--- "+i18n("No matching recipes found")+" ---"); + } + + TDEApplication::restoreOverrideCursor(); +} + +TQStringList AdvancedSearchDialog::split( const TQString &text, bool sql_wildcards ) const +{ + TQStringList result; + + // To keep quoted words together, first split on quotes, + // and then split again on the even numbered items + + TQStringList temp = TQStringList::split('"',text,true); + for ( uint i = 0; i < temp.count(); ++i ) { + if ( i & 1 ) //odd + result += temp[i].stripWhiteSpace(); + else //even + result += TQStringList::split(' ',temp[i]); + } + + if ( sql_wildcards ) { + for ( TQStringList::iterator it = result.begin(); it != result.end(); ++it ) { + (*it).replace("%","\\%"); + (*it).replace("_","\\_"); + + (*it).replace("*","%"); + (*it).replace("?","_"); + } + } + + return result; +} + +void AdvancedSearchDialog::slotAddRatingCriteria() +{ + TQListViewItem * it = new TQListViewItem(criteriaListView,criteriaComboBox->currentText()); + + MixedNumber stars; + double stars_offset; + starsWidget->value(stars,stars_offset); + TQString stars_str = stars.toString(); + if ( stars_offset > 0 ) + stars_str += "-"+MixedNumber( stars + stars_offset ).toString(); + else if ( stars.toDouble() <= 1e-10 ) + stars_str = ""; + + it->setText(1,stars_str); + it->setText(2,TQString::number(criteriaComboBox->criteriaID(criteriaComboBox->currentItem()))); +} + +void AdvancedSearchDialog::slotRemoveRatingCriteria() +{ + delete criteriaListView->selectedItem(); +} + +#include "advancedsearchdialog.moc" diff --git a/src/dialogs/advancedsearchdialog.h b/src/dialogs/advancedsearchdialog.h new file mode 100644 index 0000000..65eb171 --- /dev/null +++ b/src/dialogs/advancedsearchdialog.h @@ -0,0 +1,179 @@ +/*************************************************************************** +* Copyright (C) 2003-2004 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef ADVANCEDSEARCHDIALOG_H +#define ADVANCEDSEARCHDIALOG_H + +#include <tqwidget.h> + +class TQVBoxLayout; +class TQHBoxLayout; +class TQGridLayout; +class TQSpacerItem; +class TQScrollView; +class TQPushButton; +class TQFrame; +class TQLineEdit; +class TQLabel; +class TQCheckBox; +class TQComboBox; +class TQSpinBox; +class TQTimeEdit; +class KPushButton; +class TDEListView; +class TQListViewItem; +class TQRadioButton; +class TQButtonGroup; + +class KDateEdit; +class RecipeDB; +class RecipeActionsHandler; +class FractionInput; +class CriteriaComboBox; + + +class AdvancedSearchDialog : public TQWidget +{ + TQ_OBJECT + +public: + AdvancedSearchDialog( TQWidget *parent, RecipeDB * ); + ~AdvancedSearchDialog(); + + virtual void languageChange(); + + RecipeActionsHandler *actionHandler; + +protected: + TQLabel* textLabel1_4; + TQScrollView* scrollView1; + TQFrame* parametersFrame; + TQLineEdit* titleEdit; + TQPushButton* titleButton; + TQFrame* titleFrame; + TQPushButton* ingredientButton; + TQFrame* ingredientFrame; + TQLineEdit* ingredientsAllEdit; + TQLineEdit* ingredientsAnyEdit; + TQLabel* textLabel1_2; + TQLabel* textLabel1; + TQLineEdit* ingredientsWithoutEdit; + TQLabel* textLabel1_3; + TQPushButton* categoriesButton; + TQFrame* categoryFrame; + TQLineEdit* categoriesAllEdit; + TQLabel* textLabel1_5; + TQLabel* textLabel1_3_3; + TQLineEdit* categoriesAnyEdit; + TQLabel* textLabel1_2_3; + TQLineEdit* categoriesNotEdit; + TQPushButton* authorsButton; + TQFrame* authorsFrame; + TQLabel* textLabel1_2_4; + TQLabel* textLabel1_6; + TQLabel* textLabel1_3_4; + TQLineEdit* authorsAnyEdit; + TQLineEdit* authorsAllEdit; + TQLineEdit* authorsWithoutEdit; + TQPushButton* servingsButton; + TQFrame* servingsFrame; + TQCheckBox* enableServingsCheckBox; + TQComboBox* servingsComboBox; + TQSpinBox* servingsSpinBox; + TQPushButton* prepTimeButton; + TQFrame* prepTimeFrame; + TQCheckBox* enablePrepTimeCheckBox; + TQComboBox* prepTimeComboBox; + TQTimeEdit* prepTimeEdit; + TQLineEdit* instructionsEdit; + TQPushButton* instructionsButton; + TQFrame* instructionsFrame; + KPushButton* clearButton; + KPushButton* findButton; + TDEListView* resultsListView; + TQCheckBox *requireAllTitle; + TQCheckBox *requireAllInstructions; + KDateEdit *createdStartDateEdit; + KDateEdit *createdEndDateEdit; + KDateEdit *modifiedStartDateEdit; + KDateEdit *modifiedEndDateEdit; + KDateEdit *accessedStartDateEdit; + KDateEdit *accessedEndDateEdit; + TQPushButton* metaDataButton; + TQFrame* metaDataFrame; + TQRadioButton* ratingAvgRadioButton; + FractionInput* avgStarsEdit; + TQLabel* avgStarsLabel; + TQRadioButton* criterionRadioButton; + CriteriaComboBox* criteriaComboBox; + FractionInput* starsWidget; + TQPushButton* addCriteriaButton; + TQPushButton* removeCriteriaButton; + TDEListView* criteriaListView; + TQPushButton* ratingsButton; + TQButtonGroup *ratingButtonGroup; + TQFrame *ratingAvgFrame; + TQFrame *criterionFrame; + TQVBoxLayout *criterionFrameLayout; + TQHBoxLayout *ratingAvgFrameLayout; + TQVBoxLayout *ratingButtonGroupLayout; + + TQHBoxLayout* AdvancedSearchDialogLayout; + TQVBoxLayout* layout7; + TQHBoxLayout* scrollView1Layout; + TQVBoxLayout* parametersFrameLayout; + TQSpacerItem* spacer3_2_3_2_2; + TQSpacerItem* spacer3_2_3_2; + TQSpacerItem* spacer3_2_3; + TQSpacerItem* spacer3_2_2; + TQSpacerItem* titleFrameSpacer; + TQSpacerItem* instructionsFrameSpacer; + TQSpacerItem* metaDataFrameSpacer; + TQSpacerItem* spacer15; + TQVBoxLayout* titleFrameLayout; + TQGridLayout* ingredientFrameLayout; + TQGridLayout* categoryFrameLayout; + TQGridLayout* authorsFrameLayout; + TQVBoxLayout* servingsFrameLayout; + TQHBoxLayout* layout5; + TQVBoxLayout* prepTimeFrameLayout; + TQVBoxLayout* instructionsFrameLayout; + TQVBoxLayout* metaDataFrameLayout; + TQHBoxLayout* layout6; + TQHBoxLayout* layout9; + TQSpacerItem* spacer3; + TQVBoxLayout* ratingsFrameLayout; + TQHBoxLayout* layout11; + TQHBoxLayout* layout12; + TQSpacerItem* ratingsFrameSpacer; + + RecipeDB *database; + +signals: + void recipeSelected( int, int ); + void recipesSelected( const TQValueList<int> &, int ); + +private slots: + void search(); + void clear(); + void buttonSwitched(); + void activateRatingOption( int button_id ); + void slotAddRatingCriteria(); + void slotRemoveRatingCriteria(); + + //called by a signal from the database when a recipe is removed + void removeRecipe( int id ); + +private: + TQStringList split( const TQString &text, bool sql_wildcards = false ) const; +}; + +#endif //ADVANCEDSEARCHDIALOG_H + diff --git a/src/dialogs/authorsdialog.cpp b/src/dialogs/authorsdialog.cpp new file mode 100644 index 0000000..0a53899 --- /dev/null +++ b/src/dialogs/authorsdialog.cpp @@ -0,0 +1,66 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "authorsdialog.h" +#include "createelementdialog.h" +#include "backends/recipedb.h" +#include "widgets/authorlistview.h" + +#include <kdialog.h> +#include <tdelocale.h> +#include <tdemessagebox.h> + +AuthorsDialog::AuthorsDialog( TQWidget* parent, RecipeDB *db ) : TQWidget( parent ) +{ + + // Store pointer to database + database = db; + + TQHBoxLayout* layout = new TQHBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); + + //Author List + authorListView = new StdAuthorListView( this, database, true ); + layout->addWidget( authorListView ); + + //Buttons + TQVBoxLayout* vboxl = new TQVBoxLayout( KDialog::spacingHint() ); + + newAuthorButton = new TQPushButton( this ); + newAuthorButton->setText( i18n( "Create ..." ) ); + newAuthorButton->setFlat( true ); + vboxl->addWidget( newAuthorButton ); + + removeAuthorButton = new TQPushButton( this ); + removeAuthorButton->setText( i18n( "Delete" ) ); + removeAuthorButton->setFlat( true ); + vboxl->addWidget( removeAuthorButton ); + vboxl->addStretch(); + + layout->addLayout( vboxl ); + + //Connect Signals & Slots + + connect ( newAuthorButton, TQ_SIGNAL( clicked() ), authorListView, TQ_SLOT( createNew() ) ); + connect ( removeAuthorButton, TQ_SIGNAL( clicked() ), authorListView, TQ_SLOT( remove + () ) ); +} + +AuthorsDialog::~AuthorsDialog() +{} + +// (Re)loads the data from the database +void AuthorsDialog::reload( ReloadFlags flag ) +{ + authorListView->reload( flag ); +} + +#include "authorsdialog.moc" diff --git a/src/dialogs/authorsdialog.h b/src/dialogs/authorsdialog.h new file mode 100644 index 0000000..3678ae3 --- /dev/null +++ b/src/dialogs/authorsdialog.h @@ -0,0 +1,51 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef AUTHORSDIALOG_H +#define AUTHORSDIALOG_H + +#include <tqwidget.h> +#include <tqpushbutton.h> +#include <tqhbox.h> +#include <tqlayout.h> +#include <kiconloader.h> +#include <tdelistview.h> + +#include "widgets/dblistviewbase.h" + +class RecipeDB; +class StdAuthorListView; + +/** +@author Unai Garro +*/ + +class AuthorsDialog: public TQWidget +{ + + TQ_OBJECT + +public: + + AuthorsDialog( TQWidget* parent, RecipeDB *db ); + ~AuthorsDialog(); + void reload( ReloadFlags flag = Load ); +private: + // Internal data + RecipeDB *database; + //Widgets + StdAuthorListView *authorListView; + TQPushButton *newAuthorButton; + TQPushButton *removeAuthorButton; + TDEIconLoader *il; +}; +#endif diff --git a/src/dialogs/borderdialog.cpp b/src/dialogs/borderdialog.cpp new file mode 100644 index 0000000..13a8459 --- /dev/null +++ b/src/dialogs/borderdialog.cpp @@ -0,0 +1,261 @@ +/*************************************************************************** +* Copyright (C) 2004 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "borderdialog.h" + +#include <tqpushbutton.h> +#include <tqgroupbox.h> +#include <tqvbox.h> +#include <tqlabel.h> +#include <tqspinbox.h> +#include <tqlayout.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> + +#include <kdebug.h> +#include <tdehtml_part.h> +#include <tdehtmlview.h> +#include <tdelistbox.h> +#include <tdelocale.h> + +#include "datablocks/kreborder.h" + +BorderDialog::BorderDialog( const KreBorder &border, TQWidget* parent, const char* name ) + : KDialogBase( parent, name, true, TQString::null, + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok ) +{ + TQVBox *page = makeVBoxMainWidget(); + + borderGroupBox = new TQGroupBox( page, "borderGroupBox" ); + borderGroupBox->setColumnLayout( 0, TQt::Vertical ); + borderGroupBox->layout() ->setSpacing( 6 ); + borderGroupBox->layout() ->setMargin( 11 ); + borderGroupBoxLayout = new TQVBoxLayout( borderGroupBox->layout() ); + borderGroupBoxLayout->setAlignment( TQt::AlignTop ); + + layout4 = new TQHBoxLayout( 0, 0, 6, "layout4" ); + + layout3 = new TQVBoxLayout( 0, 0, 6, "layout3" ); + + styleLabel = new TQLabel( borderGroupBox, "styleLabel" ); + layout3->addWidget( styleLabel ); + + styleListBox = new TDEListBox( borderGroupBox, "styleListBox" ); + layout3->addWidget( styleListBox ); + layout4->addLayout( layout3 ); + + layout2 = new TQVBoxLayout( 0, 0, 6, "layout2" ); + + colorLabel = new TQLabel( borderGroupBox, "colorLabel" ); + layout2->addWidget( colorLabel ); + + TQHBox *color_hbox = new TQHBox( borderGroupBox ); + color_hbox->setSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding ); + hsSelector = new KHSSelector( color_hbox ); + hsSelector->setMinimumSize( 140, 70 ); + connect( hsSelector, TQ_SIGNAL( valueChanged( int, int ) ), TQ_SLOT( slotHSChanged( int, int ) ) ); + + valuePal = new KValueSelector( color_hbox ); + valuePal->setMinimumSize( 26, 70 ); + connect( valuePal, TQ_SIGNAL( valueChanged( int ) ), TQ_SLOT( slotVChanged( int ) ) ); + + layout2->addWidget( color_hbox ); + layout4->addLayout( layout2 ); + + layout1 = new TQVBoxLayout( 0, 0, 6, "layout1" ); + + widthLabel = new TQLabel( borderGroupBox, "widthLabel" ); + layout1->addWidget( widthLabel ); + + widthSpinBox = new TQSpinBox( borderGroupBox, "widthSpinBox" ); + widthSpinBox->setMinValue( 1 ); + layout1->addWidget( widthSpinBox ); + + widthListBox = new TDEListBox( borderGroupBox, "widthListBox" ); + layout1->addWidget( widthListBox ); + layout4->addLayout( layout1 ); + borderGroupBoxLayout->addLayout( layout4 ); + + borderPreview = new TDEHTMLPart( borderGroupBox ); + borderPreview->view() ->setSizePolicy( TQSizePolicy::Preferred, TQSizePolicy::Fixed ); + borderGroupBoxLayout->addWidget( borderPreview->view() ); + + languageChange(); + + connect( widthSpinBox, TQ_SIGNAL( valueChanged( int ) ), TQ_SLOT( updatePreview() ) ); + connect( widthListBox, TQ_SIGNAL( highlighted( int ) ), TQ_SLOT( updateSpinBox( int ) ) ); + connect( styleListBox, TQ_SIGNAL( highlighted( int ) ), TQ_SLOT( updatePreview() ) ); + + initListBoxs(); + loadBorder( border ); + + clearWState( WState_Polished ); +} + +BorderDialog::~BorderDialog() +{} + +void BorderDialog::languageChange() +{ + borderGroupBox->setTitle( i18n( "Requested Border" ) ); + styleLabel->setText( i18n( "Style:" ) ); + colorLabel->setText( i18n( "Color:" ) ); + widthLabel->setText( i18n( "Width:" ) ); +} + +KreBorder BorderDialog::border() const +{ + int width = widthSpinBox->value(); + + TQString style; + switch ( styleListBox->currentItem() ) { + case 0: + style = "none"; + break; + case 1: + style = "dotted"; + break; + case 2: + style = "dashed"; + break; + case 3: + style = "solid"; + break; + case 4: + style = "double"; + break; + case 5: + style = "groove"; + break; + case 6: + style = "ridge"; + break; + case 7: + style = "inset"; + break; + case 8: + style = "outset"; + break; + } + + return KreBorder( width, style, selColor ); +} + +void BorderDialog::loadBorder( const KreBorder &border ) +{ + widthSpinBox->setValue( border.width ); + widthListBox->setCurrentItem( border.width - 1 ); + + if ( border.style == "none" ) + styleListBox->setCurrentItem( 0 ); + else if ( border.style == "dotted" ) + styleListBox->setCurrentItem( 1 ); + else if ( border.style == "dashed" ) + styleListBox->setCurrentItem( 2 ); + else if ( border.style == "solid" ) + styleListBox->setCurrentItem( 3 ); + else if ( border.style == "double" ) + styleListBox->setCurrentItem( 4 ); + else if ( border.style == "groove" ) + styleListBox->setCurrentItem( 5 ); + else if ( border.style == "ridge" ) + styleListBox->setCurrentItem( 6 ); + else if ( border.style == "inset" ) + styleListBox->setCurrentItem( 7 ); + else if ( border.style == "outset" ) + styleListBox->setCurrentItem( 8 ); + + setColor( border.color ); + + updatePreview(); +} + +void BorderDialog::initListBoxs() +{ + styleListBox->insertItem( i18n( "None" ) ); + styleListBox->insertItem( i18n( "See http://krecipes.sourceforge.net/bordertypes.png for an example", "Dotted" ) ); + styleListBox->insertItem( i18n( "See http://krecipes.sourceforge.net/bordertypes.png for an example", "Dashed" ) ); + styleListBox->insertItem( i18n( "See http://krecipes.sourceforge.net/bordertypes.png for an example", "Solid" ) ); + styleListBox->insertItem( i18n( "See http://krecipes.sourceforge.net/bordertypes.png for an example", "Double" ) ); + styleListBox->insertItem( i18n( "See http://krecipes.sourceforge.net/bordertypes.png for an example", "Groove" ) ); + styleListBox->insertItem( i18n( "See http://krecipes.sourceforge.net/bordertypes.png for an example", "Ridge" ) ); + styleListBox->insertItem( i18n( "See http://krecipes.sourceforge.net/bordertypes.png for an example", "Inset" ) ); + styleListBox->insertItem( i18n( "See http://krecipes.sourceforge.net/bordertypes.png for an example", "Outset" ) ); + + widthListBox->insertItem( "1" ); + widthListBox->insertItem( "2" ); + widthListBox->insertItem( "3" ); + widthListBox->insertItem( "4" ); + widthListBox->insertItem( "5" ); + widthListBox->insertItem( "6" ); + widthListBox->insertItem( "7" ); +} + +void BorderDialog::updatePreview() +{ + KreBorder b( border() ); + + TQString html_str = TQString( "<html><body><div style=\"vertical-align: middle; border: %1px %2 %3;\"><center><h1>%4</h1></center></div></body></html>" ).arg( b.width ).arg( b.style ).arg( b.color.name() ).arg( i18n( "Border Preview" ) ); + + borderPreview->begin(); + borderPreview->write( html_str ); + borderPreview->end(); + borderPreview->show(); +} + +void BorderDialog::updateSpinBox( int index ) +{ + widthSpinBox->setValue( index + 1 ); +} + +void BorderDialog::slotHSChanged( int h, int s ) +{ + int _h, _s, v; + selColor.hsv( &_h, &_s, &v ); + if ( v < 1 ) + v = 1; + + KColor col; + col.setHsv( h, s, v ); + + setColor( col ); + updatePreview(); +} + +void BorderDialog::slotVChanged( int v ) +{ + int h, s, _v; + selColor.hsv( &h, &s, &_v ); + + KColor col; + col.setHsv( h, s, v ); + + setColor( col ); + updatePreview(); +} + +void BorderDialog::setColor( const KColor &color ) +{ + if ( color == selColor ) + return ; + + selColor = color; + + int h, s, v; + color.hsv( &h, &s, &v ); + hsSelector->setValues( h, s ); + valuePal->setHue( h ); + valuePal->setSaturation( s ); + valuePal->setValue( v ); + valuePal->updateContents(); + valuePal->repaint( FALSE ); +} + +#include "borderdialog.moc" diff --git a/src/dialogs/borderdialog.h b/src/dialogs/borderdialog.h new file mode 100644 index 0000000..07905ee --- /dev/null +++ b/src/dialogs/borderdialog.h @@ -0,0 +1,75 @@ +/*************************************************************************** +* Copyright (C) 2004 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef BORDERDIALOG_H +#define BORDERDIALOG_H + +#include <kdialogbase.h> +#include <kcolordialog.h> + +class TQVBoxLayout; +class TQHBoxLayout; +class TQGridLayout; +class TQSpacerItem; +class TQGroupBox; +class TQLabel; +class TDEListBox; +class TQListBoxItem; +class TQSpinBox; +class TDEHTMLPart; + +class KreBorder; + +class BorderDialog : public KDialogBase +{ + TQ_OBJECT + +public: + BorderDialog( const KreBorder &border, TQWidget* parent = 0, const char* name = 0 ); + ~BorderDialog(); + + KreBorder border() const; + + TQGroupBox* borderGroupBox; + TQLabel* styleLabel; + TDEListBox* styleListBox; + TQLabel* colorLabel; + KHSSelector* hsSelector; + KValueSelector* valuePal; + TQLabel* widthLabel; + TQSpinBox* widthSpinBox; + TDEListBox* widthListBox; + TDEHTMLPart* borderPreview; + +protected: + TQVBoxLayout* borderGroupBoxLayout; + TQHBoxLayout* layout4; + TQVBoxLayout* layout3; + TQVBoxLayout* layout2; + TQVBoxLayout* layout1; + +protected slots: + virtual void languageChange(); + void updatePreview(); + void updateSpinBox( int index ); + + void slotHSChanged( int h, int s ); + void slotVChanged( int v ); + void setColor( const KColor &color ); + +private: + void loadBorder( const KreBorder &border ); + void initListBoxs(); + + KColor selColor; + +}; + +#endif // BORDERDIALOG_H diff --git a/src/dialogs/categorieseditordialog.cpp b/src/dialogs/categorieseditordialog.cpp new file mode 100644 index 0000000..d383fde --- /dev/null +++ b/src/dialogs/categorieseditordialog.cpp @@ -0,0 +1,67 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "categorieseditordialog.h" + +#include <kdebug.h> +#include <kdialog.h> +#include <tdelocale.h> +#include <tdemessagebox.h> + +#include "widgets/categorylistview.h" +#include "createcategorydialog.h" +#include "backends/recipedb.h" + +CategoriesEditorDialog::CategoriesEditorDialog( TQWidget* parent, RecipeDB *db ) : TQWidget( parent ) +{ + + // Store pointer to database + database = db; + + TQHBoxLayout* layout = new TQHBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); + + //Category List + categoryListView = new StdCategoryListView( this, database, true ); + layout->addWidget( categoryListView ); + + //Buttons + TQVBoxLayout* vboxl = new TQVBoxLayout( KDialog::spacingHint() ); + + newCategoryButton = new TQPushButton( this ); + newCategoryButton->setText( i18n( "Create ..." ) ); + newCategoryButton->setFlat( true ); + vboxl->addWidget( newCategoryButton ); + + removeCategoryButton = new TQPushButton( this ); + removeCategoryButton->setText( i18n( "Delete" ) ); + removeCategoryButton->setFlat( true ); + vboxl->addWidget( removeCategoryButton ); + vboxl->addStretch(); + + layout->addLayout( vboxl ); + + //Connect Signals & Slots + + connect ( newCategoryButton, TQ_SIGNAL( clicked() ), categoryListView, TQ_SLOT( createNew() ) ); + connect ( removeCategoryButton, TQ_SIGNAL( clicked() ), categoryListView, TQ_SLOT( remove + () ) ); +} + +CategoriesEditorDialog::~CategoriesEditorDialog() +{} + +void CategoriesEditorDialog::reload( ReloadFlags flag ) +{ + categoryListView->reload( flag ); +} + +#include "categorieseditordialog.moc" diff --git a/src/dialogs/categorieseditordialog.h b/src/dialogs/categorieseditordialog.h new file mode 100644 index 0000000..9b2e56d --- /dev/null +++ b/src/dialogs/categorieseditordialog.h @@ -0,0 +1,56 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef CATEGORIESEDITORDIALOG_H +#define CATEGORIESEDITORDIALOG_H + +#include <tqwidget.h> +#include <tqpushbutton.h> +#include <tqhbox.h> +#include <tqlayout.h> +#include <kiconloader.h> +#include <tdelistview.h> + +#include "datablocks/categorytree.h" +#include "widgets/dblistviewbase.h" + +class RecipeDB; +class StdCategoryListView; + +/** +@author Unai Garro +*/ +class CategoriesEditorDialog: public TQWidget +{ + + TQ_OBJECT + +public: + + CategoriesEditorDialog( TQWidget* parent, RecipeDB *db ); + ~CategoriesEditorDialog(); + + void reload( ReloadFlags flag = Load ); + +private: + // Internal data + RecipeDB *database; + //Widgets + TQGridLayout *layout; + StdCategoryListView *categoryListView; + TQHBox *buttonBar; + TQPushButton *newCategoryButton; + TQPushButton *removeCategoryButton; + TDEIconLoader *il; +}; + +#endif diff --git a/src/dialogs/conversiondialog.cpp b/src/dialogs/conversiondialog.cpp new file mode 100644 index 0000000..c9e3f51 --- /dev/null +++ b/src/dialogs/conversiondialog.cpp @@ -0,0 +1,166 @@ +/*************************************************************************** +* Copyright (C) 2006 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "conversiondialog.h" + +#include <tqvariant.h> +#include <tqpushbutton.h> +#include <kcombobox.h> +#include <tqlabel.h> +#include <klineedit.h> +#include <tqlayout.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> +#include <tqvbox.h> + +#include <kcombobox.h> +#include <klineedit.h> +#include <tdelocale.h> + +#include "backends/recipedb.h" +#include "widgets/unitcombobox.h" +#include "widgets/ingredientcombobox.h" +#include "widgets/prepmethodcombobox.h" +#include "widgets/fractioninput.h" + +ConversionDialog::ConversionDialog( TQWidget* parent, RecipeDB *db, const char* name ) + : KDialogBase( parent, name, false, i18n( "Measurement Converter" ), + KDialogBase::Close | KDialogBase::User1 | KDialogBase::Help, KDialogBase::Close ), + m_database(db) +{ + setHelp("measure-converter"); + setButtonText( KDialogBase::User1, i18n("Convert") ); + + setSizeGripEnabled( TRUE ); + + TQVBox *page = makeVBoxMainWidget(); + + TQHBox *vbox = new TQVBox(page); + + TQHBox *fromTopBox = new TQHBox(vbox); + convertLabel = new TQLabel( fromTopBox, "convertLabel" ); + + amountEdit = new FractionInput( fromTopBox ); + + fromUnitBox = new UnitComboBox( fromTopBox, db ); + fromUnitBox->reload(); + fromTopBox->setStretchFactor( fromUnitBox, 2 ); + fromTopBox->setSpacing(3); + + TQHBox *fromBottomBox = new TQHBox(vbox); + + ingredientBox = new IngredientComboBox( FALSE, fromBottomBox, db, i18n( "--Ingredient (optional)--" ) ); + ingredientBox->reload(); + + prepMethodBox = new PrepMethodComboBox( false, fromBottomBox, db, i18n( "-No Preparation-" ) ); + prepMethodBox->reload(); + fromBottomBox->setSpacing(3); + + TQHBox *toBox = new TQHBox(vbox); + + toLabel = new TQLabel( toBox, "toLabel" ); + + toUnitBox = new UnitComboBox( toBox, db ); + toUnitBox->reload(); + toBox->setStretchFactor( toUnitBox, 2 ); + toBox->setSpacing(8); + + TQHBox *resultBox = new TQHBox(vbox); + resultLabel = new TQLabel( resultBox, "resultLabel" ); + resultText = new TQLabel( resultBox, "resultText" ); + resultBox->setStretchFactor( resultText, 2 ); + + languageChange(); + + setInitialSize( TQSize(300, 200).expandedTo(minimumSizeHint()) ); + + // signals and slots connections + connect ( this, TQ_SIGNAL( closeClicked() ), this, TQ_SLOT( accept() ) ); +} + +ConversionDialog::~ConversionDialog() +{ +} + +void ConversionDialog::languageChange() +{ + convertLabel->setText( i18n( "Convert" ) ); + toLabel->setText( i18n( "To" ) ); + resultLabel->setText( i18n( "<b>Result:</b>" ) ); + resultText->setText( TQString::null ); +} + +void ConversionDialog::show() +{ + reset(); + KDialogBase::show(); +} + +void ConversionDialog::reset() +{ + resultText->setText( TQString::null ); + ingredientBox->setCurrentItem( 0 ); + prepMethodBox->setCurrentItem( 0 ); + toUnitBox->setCurrentItem( 0 ); + fromUnitBox->setCurrentItem( 0 ); + amountEdit->clear(); +} + +void ConversionDialog::slotUser1() +{ + convert(); +} + +void ConversionDialog::convert() +{ + Ingredient result, ing; + Unit unit = m_database->unitName(toUnitBox->id(toUnitBox->currentItem())); + + ing.amount = amountEdit->value().toDouble(); + ing.ingredientID = ingredientBox->id(ingredientBox->currentItem()); + ing.units = m_database->unitName(fromUnitBox->id(fromUnitBox->currentItem())); + + int prepID = prepMethodBox->id(prepMethodBox->currentItem()); + if ( prepID != -1 ) + ing.prepMethodList.append(Element(TQString::null,prepID)); + + switch ( m_database->convertIngredientUnits( ing, unit, result ) ) { + case RecipeDB::Success: + resultLabel->setText( i18n( "<b>Result:</b>" ) ); + resultText->setText(TQString::number(result.amount)+" "+((result.amount>1)?result.units.plural:result.units.name)); + break; + case RecipeDB::MismatchedPrepMethodUsingApprox: + resultLabel->setText( i18n( "<b>Approximated result:</b>" ) ); + resultText->setText(TQString::number(result.amount)+" "+((result.amount>1)?result.units.plural:result.units.name)); + break; + case RecipeDB::MissingUnitConversion: + resultLabel->setText( i18n( "<b>Error:</b>" ) ); + resultText->setText( i18n("Missing unit conversion") ); + break; + case RecipeDB::MissingIngredientWeight: + resultLabel->setText( i18n( "<b>Error:</b>" ) ); + resultText->setText( i18n("No ingredient weight available") ); + break; + case RecipeDB::MismatchedPrepMethod: + resultLabel->setText( i18n( "<b>Error:</b>" ) ); + resultText->setText( i18n("No ingredient weight available for this method of preparation") ); + break; + case RecipeDB::MissingIngredient: + resultLabel->setText( i18n( "<b>Error:</b>" ) ); + resultText->setText( i18n("Ingredient required for conversion") ); + break; + case RecipeDB::InvalidTypes: + resultLabel->setText( i18n( "<b>Error:</b>" ) ); + resultText->setText( i18n("Impossible unit conversion based on unit types") ); + break; + } +} + +#include "conversiondialog.moc" diff --git a/src/dialogs/conversiondialog.h b/src/dialogs/conversiondialog.h new file mode 100644 index 0000000..b467ce1 --- /dev/null +++ b/src/dialogs/conversiondialog.h @@ -0,0 +1,62 @@ +/*************************************************************************** +* Copyright (C) 2006 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef CONVERSIONDIALOG_H +#define CONVERSIONDIALOG_H + +#include <kdialogbase.h> + +class TQVBoxLayout; +class TQHBoxLayout; +class TQGridLayout; +class TQSpacerItem; +class KComboBox; +class TQLabel; +class KLineEdit; +class TQPushButton; + +class RecipeDB; +class UnitComboBox; +class IngredientComboBox; +class PrepMethodComboBox; +class FractionInput; + +class ConversionDialog : public KDialogBase +{ +TQ_OBJECT + +public: + ConversionDialog( TQWidget* parent, RecipeDB *, const char* name = 0 ); + ~ConversionDialog(); + + virtual void show(); + void reset(); + +protected: + IngredientComboBox* ingredientBox; + PrepMethodComboBox* prepMethodBox; + TQLabel* convertLabel; + UnitComboBox* toUnitBox; + UnitComboBox* fromUnitBox; + FractionInput* amountEdit; + TQLabel* toLabel; + TQLabel* resultLabel; + TQLabel* resultText; + +protected slots: + virtual void languageChange(); + void slotUser1(); + void convert(); + +private: + RecipeDB *m_database; +}; + +#endif // CONVERSIONDIALOG_H diff --git a/src/dialogs/createcategorydialog.cpp b/src/dialogs/createcategorydialog.cpp new file mode 100644 index 0000000..f0cbc21 --- /dev/null +++ b/src/dialogs/createcategorydialog.cpp @@ -0,0 +1,80 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "createcategorydialog.h" + +#include <tqpushbutton.h> +#include <tqgroupbox.h> +#include <tqlayout.h> +#include <tqlabel.h> +#include <tqvbox.h> + +#include <kcombobox.h> +#include <klineedit.h> +#include <tdelocale.h> + +CreateCategoryDialog::CreateCategoryDialog( TQWidget *parent, const ElementList& categories ) + : KDialogBase( parent, "createCategoryDialog", true, i18n( "New Category" ), + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok ) +{ + TQVBox *page = makeVBoxMainWidget(); + + box = new TQGroupBox( page ); + box->setColumnLayout( 0, TQt::Vertical ); + box->layout() ->setSpacing( 6 ); + box->layout() ->setMargin( 11 ); + TQVBoxLayout *boxLayout = new TQVBoxLayout( box->layout() ); + boxLayout->setAlignment( TQt::AlignTop ); + box->setTitle( i18n( "New Category" ) ); + + elementEdit = new KLineEdit( box ); + boxLayout->addWidget( elementEdit ); + + TQHBox *subcatHBox = new TQHBox( box ); + ( void ) new TQLabel( i18n( "Subcategory of:" ), subcatHBox ); + categoryComboBox = new KComboBox( subcatHBox ); + boxLayout->addWidget( subcatHBox ); + loadCategories( categories ); + + adjustSize(); + setFixedSize( size() ); //we've got all the widgets put in, now let's keep it this size + + elementEdit->setFocus(); +} + + +CreateCategoryDialog::~CreateCategoryDialog() +{} + +void CreateCategoryDialog::loadCategories( const ElementList& categories ) +{ + categoryComboBox->insertItem( i18n( "**NONE**" ) ); + for ( ElementList::const_iterator it = categories.begin(); it != categories.end(); ++it ) { + categoryComboBox->insertItem( ( *it ).name ); + idMap.insert( ( *it ).name, ( *it ).id ); + } +} + +TQString CreateCategoryDialog::newCategoryName( void ) +{ + return ( elementEdit->text() ); +} + +int CreateCategoryDialog::subcategory( void ) +{ + if ( categoryComboBox->currentItem() == 0 ) { + return -1; + } + else { + return idMap[ categoryComboBox->currentText() ]; + } +} diff --git a/src/dialogs/createcategorydialog.h b/src/dialogs/createcategorydialog.h new file mode 100644 index 0000000..2211006 --- /dev/null +++ b/src/dialogs/createcategorydialog.h @@ -0,0 +1,51 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef CREATECATEGORYDIALOG_H +#define CREATECATEGORYDIALOG_H + +#include <tqmap.h> + +#include <kdialogbase.h> + +#include "datablocks/elementlist.h" + +class KLineEdit; +class TQPushButton; +class TQVBoxLayout; +class TQGroupBox; +class TQVBox; +class KComboBox; + +/** +@author Jason Kivlighn +*/ +class CreateCategoryDialog : public KDialogBase +{ +public: + CreateCategoryDialog( TQWidget *parent, const ElementList &categories ); + ~CreateCategoryDialog(); + TQString newCategoryName( void ); + int subcategory( void ); + +private: + void loadCategories( const ElementList &categories ); + + //Widgets + TQGroupBox *box; + KLineEdit *elementEdit; + KComboBox* categoryComboBox; + TQMap<TQString, int> idMap; + +}; + +#endif diff --git a/src/dialogs/createelementdialog.cpp b/src/dialogs/createelementdialog.cpp new file mode 100644 index 0000000..1f5b4a0 --- /dev/null +++ b/src/dialogs/createelementdialog.cpp @@ -0,0 +1,48 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "createelementdialog.h" + +#include <tdelocale.h> + +CreateElementDialog::CreateElementDialog( TQWidget *parent, const TQString &text ) + : KDialogBase( parent, "createElementDialog", true, text, + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok ) +{ + TQVBox *page = makeVBoxMainWidget(); + + box = new TQGroupBox( page ); + box->setColumnLayout( 0, TQt::Vertical ); + box->layout() ->setSpacing( 6 ); + box->layout() ->setMargin( 11 ); + TQVBoxLayout *boxLayout = new TQVBoxLayout( box->layout() ); + boxLayout->setAlignment( TQt::AlignTop ); + box->setTitle( text ); + + elementEdit = new KLineEdit( box ); + boxLayout->addWidget( elementEdit ); + + adjustSize(); + setFixedSize( size() ); //we've got all the widgets put in, now let's keep it this size + + elementEdit->setFocus(); +} + + +CreateElementDialog::~CreateElementDialog() +{} + +TQString CreateElementDialog::newElementName( void ) +{ + return ( elementEdit->text() ); +} + diff --git a/src/dialogs/createelementdialog.h b/src/dialogs/createelementdialog.h new file mode 100644 index 0000000..775647a --- /dev/null +++ b/src/dialogs/createelementdialog.h @@ -0,0 +1,40 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef CREATEELEMENTDIALOG_H +#define CREATEELEMENTDIALOG_H + +#include <tqpushbutton.h> +#include <tqgroupbox.h> +#include <tqlayout.h> +#include <tqvbox.h> + +#include <klineedit.h> +#include <kdialogbase.h> + +/** +@author Unai Garro +*/ +class CreateElementDialog : public KDialogBase +{ +public: + CreateElementDialog( TQWidget *parent, const TQString &text ); + ~CreateElementDialog(); + TQString newElementName( void ); + +private: + //Widgets + TQGroupBox *box; + KLineEdit *elementEdit; +}; + +#endif diff --git a/src/dialogs/createingredientweightdialog.cpp b/src/dialogs/createingredientweightdialog.cpp new file mode 100644 index 0000000..45bf158 --- /dev/null +++ b/src/dialogs/createingredientweightdialog.cpp @@ -0,0 +1,124 @@ +/*************************************************************************** +* Copyright (C) 2006 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "createingredientweightdialog.h" + +#include <tqgroupbox.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqlayout.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> +#include <tqvbox.h> + +#include <tdemessagebox.h> +#include <tdelocale.h> + +#include "widgets/unitcombobox.h" +#include "widgets/prepmethodcombobox.h" +#include "widgets/fractioninput.h" +#include "datablocks/weight.h" +#include "backends/recipedb.h" + +CreateIngredientWeightDialog::CreateIngredientWeightDialog( TQWidget* parent, RecipeDB *db ) + : KDialogBase( parent, "createIngWeightDialog", true, TQString::null, + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok ) +{ + TQVBox *page = makeVBoxMainWidget(); + + groupBox1 = new TQGroupBox( page ); + groupBox1->setColumnLayout(0, TQt::Vertical ); + groupBox1->layout()->setSpacing( 6 ); + groupBox1->layout()->setMargin( 11 ); + groupBox1Layout = new TQGridLayout( groupBox1->layout() ); + groupBox1Layout->setAlignment( TQt::AlignTop ); + + perAmountEdit = new FractionInput( groupBox1 ); + + groupBox1Layout->addWidget( perAmountEdit, 1, 1 ); + + weightEdit = new FractionInput( groupBox1 ); + + groupBox1Layout->addWidget( weightEdit, 0, 1 ); + + weightUnitBox = new UnitComboBox( groupBox1, db, Unit::Mass ); + weightUnitBox->reload(); + + groupBox1Layout->addMultiCellWidget( weightUnitBox, 0, 0, 2, 3 ); + + perAmountLabel = new TQLabel( groupBox1, "perAmountLabel" ); + + groupBox1Layout->addWidget( perAmountLabel, 1, 0 ); + + weightLabel = new TQLabel( groupBox1, "weightLabel" ); + + groupBox1Layout->addWidget( weightLabel, 0, 0 ); + + perAmountUnitBox = new UnitComboBox( groupBox1, db ); + perAmountUnitBox->reload(); + + groupBox1Layout->addWidget( perAmountUnitBox, 1, 2 ); + + prepMethodBox = new PrepMethodComboBox( false, groupBox1, db, i18n("-No Preparation-") ); + prepMethodBox->reload(); + groupBox1Layout->addWidget( prepMethodBox, 1, 3 ); + + languageChange(); + clearWState( WState_Polished ); + + weightEdit->setFocus(); +} + +CreateIngredientWeightDialog::~CreateIngredientWeightDialog() +{ + // no need to delete child widgets, TQt does it all for us +} + +void CreateIngredientWeightDialog::languageChange() +{ + groupBox1->setTitle( i18n( "New Ingredient Weight" ) ); + perAmountLabel->setText( i18n( "Per Amount:" ) ); + weightLabel->setText( i18n( "Weight:" ) ); +} + +void CreateIngredientWeightDialog::slotOk() +{ + if ( !perAmountEdit->isInputValid() ) { + KMessageBox::error( this, i18n( "Amount field contains invalid input." ), + i18n( "Invalid input" ) ); + perAmountEdit->setFocus(); + perAmountEdit->selectAll(); + return; + } + else if ( !weightEdit->isInputValid() ) { + KMessageBox::error( this, i18n( "Amount field contains invalid input." ), + i18n( "Invalid input" ) ); + weightEdit->setFocus(); + weightEdit->selectAll(); + return; + } + + accept(); +} + +Weight CreateIngredientWeightDialog::weight() const +{ + Weight w; + w.perAmount = perAmountEdit->value().toDouble(); + w.perAmountUnitID = perAmountUnitBox->id( perAmountUnitBox->currentItem() ); + w.weight = weightEdit->value().toDouble(); + w.weightUnitID = weightUnitBox->id( weightUnitBox->currentItem() ); + w.prepMethodID = prepMethodBox->id( prepMethodBox->currentItem() ); + w.prepMethod = prepMethodBox->currentText(); + + return w; +} + +#include "createingredientweightdialog.moc" diff --git a/src/dialogs/createingredientweightdialog.h b/src/dialogs/createingredientweightdialog.h new file mode 100644 index 0000000..cbc4d8f --- /dev/null +++ b/src/dialogs/createingredientweightdialog.h @@ -0,0 +1,60 @@ +/*************************************************************************** +* Copyright (C) 2006 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef CREATEINGREDIENTWEIGHTDIALOG_H +#define CREATEINGREDIENTWEIGHTDIALOG_H + +#include <kdialogbase.h> + +class TQVBoxLayout; +class TQHBoxLayout; +class TQGridLayout; +class TQSpacerItem; +class TQGroupBox; +class KLineEdit; +class KComboBox; +class TQLabel; +class TQPushButton; + +class FractionInput; +class UnitComboBox; +class PrepMethodComboBox; +class RecipeDB; +class Weight; + +class CreateIngredientWeightDialog : public KDialogBase +{ +TQ_OBJECT + +public: + CreateIngredientWeightDialog( TQWidget* parent, RecipeDB* ); + ~CreateIngredientWeightDialog(); + + Weight weight() const; + +protected: + TQGridLayout* groupBox1Layout; + +protected slots: + virtual void languageChange(); + void slotOk(); + +private: + TQGroupBox* groupBox1; + FractionInput* perAmountEdit; + FractionInput* weightEdit; + UnitComboBox* weightUnitBox; + TQLabel* perAmountLabel; + TQLabel* weightLabel; + UnitComboBox* perAmountUnitBox; + PrepMethodComboBox* prepMethodBox; +}; + +#endif // CREATEINGREDIENTWEIGHTDIALOG_H diff --git a/src/dialogs/createpropertydialog.cpp b/src/dialogs/createpropertydialog.cpp new file mode 100644 index 0000000..9f8f107 --- /dev/null +++ b/src/dialogs/createpropertydialog.cpp @@ -0,0 +1,69 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "createpropertydialog.h" + +#include <tdelocale.h> + +CreatePropertyDialog::CreatePropertyDialog( TQWidget *parent, UnitList* list ) + : KDialogBase( parent, "createPropertyDialog", true, i18n( "New Property" ), + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok ) +{ + + // Initialize Internal Variables + unitList = list; // Store the pointer to the unitList; + + // Initialize widgets + TQVBox *page = makeVBoxMainWidget(); + + box = new TQGroupBox( page ); + box->setColumnLayout( 0, TQt::Vertical ); + box->layout() ->setSpacing( 6 ); + box->layout() ->setMargin( 11 ); + TQGridLayout *gridLayout = new TQGridLayout( box->layout() ); + gridLayout->setAlignment( TQt::AlignTop ); + box->setTitle( i18n( "New Property" ) ); + + nameEditText = new TQLabel( i18n( "Property name:" ), box ); + propertyNameEdit = new KLineEdit( box ); + propertyNameEdit->setMinimumWidth( 150 ); + gridLayout->addWidget( nameEditText, 0, 0 ); + gridLayout->addWidget( propertyNameEdit, 0, 1 ); + + unitsText = new TQLabel( i18n( "Units:" ), box ); + propertyUnits = new KLineEdit( box ); + propertyUnits->setMinimumWidth( 150 ); + gridLayout->addWidget( unitsText, 1, 0 ); + gridLayout->addWidget( propertyUnits, 1, 1 ); + + adjustSize(); + setFixedSize( size() ); + + propertyNameEdit->setFocus(); +} + + +CreatePropertyDialog::~CreatePropertyDialog() +{} + + +TQString CreatePropertyDialog::newPropertyName( void ) +{ + return ( propertyNameEdit->text() ); +} + +TQString CreatePropertyDialog::newUnitsName( void ) +{ + return ( propertyUnits->text() ); +} + + diff --git a/src/dialogs/createpropertydialog.h b/src/dialogs/createpropertydialog.h new file mode 100644 index 0000000..1714e9e --- /dev/null +++ b/src/dialogs/createpropertydialog.h @@ -0,0 +1,56 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +/** +@author Unai Garro +*/ + +#ifndef CREATEPROPERTYDIALOG_H +#define CREATEPROPERTYDIALOG_H + +#include <tqcombobox.h> +#include <tqlayout.h> +#include <tqpushbutton.h> +#include <tqgroupbox.h> +#include <tqvbox.h> +#include <tqlabel.h> + +#include <klineedit.h> +#include <kdialogbase.h> + +#include "datablocks/unit.h" + +class CreatePropertyDialog : public KDialogBase +{ +public: + CreatePropertyDialog( TQWidget *parent, UnitList *list ); + ~CreatePropertyDialog(); + TQString newPropertyName( void ); + TQString newUnitsName( void ); + + +private: + //Widgets + TQGroupBox *box; + KLineEdit *propertyNameEdit; + KLineEdit *propertyUnits; + TQLabel *nameEditText; + TQLabel *unitsText; + + //Internal variables + UnitList *unitList; + + //Methods + void loadUnits(); +}; + +#endif diff --git a/src/dialogs/createunitdialog.cpp b/src/dialogs/createunitdialog.cpp new file mode 100644 index 0000000..4929bb6 --- /dev/null +++ b/src/dialogs/createunitdialog.cpp @@ -0,0 +1,116 @@ +/*************************************************************************** +* Copyright (C) 2003-2004 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "createunitdialog.h" + +#include <tqlabel.h> + +#include <tdelocale.h> +#include <klineedit.h> +#include <kcombobox.h> + +CreateUnitDialog::CreateUnitDialog( TQWidget *parent, const TQString &name, const TQString &plural, const TQString &name_abbrev, const TQString &plural_abbrev, bool newUnit ) + : KDialogBase( parent, "createElementDialog", true, (newUnit)?i18n( "New Unit" ):i18n("Unit"), + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok ) +{ + TQVBox *page = makeVBoxMainWidget(); + + box = new TQGroupBox( page ); + box->setColumnLayout( 0, TQt::Vertical ); + box->layout() ->setSpacing( 6 ); + box->layout() ->setMargin( 11 ); + TQGridLayout *gridLayout = new TQGridLayout( box->layout() ); + gridLayout->setAlignment( TQt::AlignTop ); + + box->setTitle( (newUnit)?i18n( "New Unit" ):i18n("Unit") ); + + TQLabel *nameLabel = new TQLabel( i18n( "Singular:" ), box ); + nameEdit = new KLineEdit( name, box ); + + gridLayout->addWidget( nameLabel, 0, 0 ); + gridLayout->addWidget( nameEdit, 0, 1 ); + + TQLabel *nameAbbrevLabel = new TQLabel( i18n( "Abbreviation:" ), box ); + nameAbbrevEdit = new KLineEdit( name_abbrev, box ); + + gridLayout->addWidget( nameAbbrevLabel, 0, 2 ); + gridLayout->addWidget( nameAbbrevEdit, 0, 3 ); + + TQLabel *pluralLabel = new TQLabel( i18n( "Plural:" ), box ); + pluralEdit = new KLineEdit( plural, box ); + + gridLayout->addWidget( pluralLabel, 1, 0 ); + gridLayout->addWidget( pluralEdit, 1, 1 ); + + TQLabel *pluralAbbrevLabel = new TQLabel( i18n( "Abbreviation:" ), box ); + pluralAbbrevEdit = new KLineEdit( plural_abbrev, box ); + + gridLayout->addWidget( pluralAbbrevLabel, 1, 2 ); + gridLayout->addWidget( pluralAbbrevEdit, 1, 3 ); + + TQLabel *typeLabel = new TQLabel( i18n( "Type:" ), box ); + typeComboBox = new KComboBox( false, box ); + typeComboBox->insertItem(i18n("Other")); + typeComboBox->insertItem(i18n("Mass")); + typeComboBox->insertItem(i18n("Volume")); + + gridLayout->addWidget( typeLabel, 2, 0 ); + gridLayout->addMultiCellWidget( typeComboBox, 2, 2, 1, 3 ); + + adjustSize(); + setFixedSize( size() ); //we've got all the widgets put in, now let's keep it this size + + connect( nameAbbrevEdit, TQ_SIGNAL(textChanged(const TQString&)), TQ_SLOT(nameAbbrevTextChanged(const TQString &)) ); + + if ( name.isEmpty() ) + nameEdit->setFocus(); + else if ( plural.isEmpty() ) + pluralEdit->setFocus(); +} + + +CreateUnitDialog::~CreateUnitDialog() +{} + +Unit CreateUnitDialog::newUnit( void ) +{ + TQString name = nameEdit->text(); + TQString plural = pluralEdit->text(); + + if ( name.isEmpty() ) + name = plural; + if ( plural.isEmpty() ) + plural = name; + + Unit new_unit = Unit( name, plural ); + new_unit.name_abbrev = nameAbbrevEdit->text(); + new_unit.plural_abbrev = pluralAbbrevEdit->text(); + + new_unit.type = (Unit::Type)typeComboBox->currentItem(); + + return new_unit; +} + +void CreateUnitDialog::nameAbbrevTextChanged(const TQString &newText) +{ + //appending + if ( newText.left( newText.length()-1 ) == pluralAbbrevEdit->text() ) { + pluralAbbrevEdit->setText( newText ); + } + + //truncating + if ( newText.left( newText.length()-1 ) == pluralAbbrevEdit->text().left( newText.length()-1 ) ) { + pluralAbbrevEdit->setText( newText ); + } +} + +#include "createunitdialog.moc" diff --git a/src/dialogs/createunitdialog.h b/src/dialogs/createunitdialog.h new file mode 100644 index 0000000..a2e1777 --- /dev/null +++ b/src/dialogs/createunitdialog.h @@ -0,0 +1,52 @@ +/*************************************************************************** +* Copyright (C) 2003-2004 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef CREATEUNITDIALOG_H +#define CREATEUNITDIALOG_H + +#include <kdialogbase.h> +#include <tqpushbutton.h> +#include <tqgroupbox.h> +#include <tqlayout.h> +#include <tqvbox.h> + +#include "datablocks/unit.h" + +class KComboBox; +class KLineEdit; + +/** +@author Unai Garro +*/ +class CreateUnitDialog : public KDialogBase +{ +TQ_OBJECT + +public: + CreateUnitDialog( TQWidget *parent, const TQString &name = TQString::null, const TQString &plural = TQString::null, const TQString &name_abbrev = TQString::null, const TQString &plural_abbrev = TQString::null, bool newUnit = true ); + ~CreateUnitDialog(); + Unit newUnit( void ); + +protected slots: + void nameAbbrevTextChanged(const TQString &); + +private: + //Widgets + TQGroupBox *box; + KLineEdit *nameEdit; + KLineEdit *pluralEdit; + KLineEdit *nameAbbrevEdit; + KLineEdit *pluralAbbrevEdit; + KComboBox *typeComboBox; +}; + +#endif diff --git a/src/dialogs/dbimportdialog.cpp b/src/dialogs/dbimportdialog.cpp new file mode 100644 index 0000000..7d5d68b --- /dev/null +++ b/src/dialogs/dbimportdialog.cpp @@ -0,0 +1,219 @@ +/*************************************************************************** +* Copyright (C) 2004 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "dbimportdialog.h" + +#include <unistd.h> //for getuid() +#include <pwd.h> //getpwuid() + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <tqpushbutton.h> +#include <tqbuttongroup.h> +#include <tqradiobutton.h> +#include <tqwidgetstack.h> +#include <tqwidget.h> +#include <tqlineedit.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> +#include <tqhbox.h> + +#include <tdeconfig.h> +#include <kdebug.h> +#include <tdelocale.h> +#include <kurlrequester.h> +#include <knuminput.h> + +DBImportDialog::DBImportDialog( TQWidget *parent, const char *name ) + : KDialogBase( parent, name, true, i18n( "Database Import" ), + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok ) +{ + setButtonBoxOrientation( Vertical ); + + TQHBox *page = makeHBoxMainWidget(); + + dbButtonGroup = new TQButtonGroup( page, "dbButtonGroup" ); + dbButtonGroup->setSizePolicy( TQSizePolicy( ( TQSizePolicy::SizeType ) 4, ( TQSizePolicy::SizeType ) 5, 0, 0, dbButtonGroup->sizePolicy().hasHeightForWidth() ) ); + dbButtonGroup->setColumnLayout( 0, TQt::Vertical ); + dbButtonGroup->layout() ->setSpacing( 6 ); + dbButtonGroup->layout() ->setMargin( 11 ); + dbButtonGroupLayout = new TQVBoxLayout( dbButtonGroup->layout() ); + dbButtonGroupLayout->setAlignment( TQt::AlignTop ); + + liteRadioButton = new TQRadioButton( dbButtonGroup, "liteRadioButton" ); + liteRadioButton->setChecked( TRUE ); + dbButtonGroupLayout->addWidget( liteRadioButton ); + + mysqlRadioButton = new TQRadioButton( dbButtonGroup, "mysqlRadioButton" ); + dbButtonGroupLayout->addWidget( mysqlRadioButton ); + + psqlRadioButton = new TQRadioButton( dbButtonGroup, "psqlRadioButton" ); + dbButtonGroupLayout->addWidget( psqlRadioButton ); + + paramStack = new TQWidgetStack( page, "paramStack" ); + paramStack->setSizePolicy( TQSizePolicy( ( TQSizePolicy::SizeType ) 7, ( TQSizePolicy::SizeType ) 5, 0, 0, paramStack->sizePolicy().hasHeightForWidth() ) ); + + sqlitePage = new TQWidget( paramStack, "sqlitePage" ); + serverPageLayout_2 = new TQVBoxLayout( sqlitePage, 11, 6, "serverPageLayout_2" ); + + TQLabel *sqliteLabel = new TQLabel( i18n( "Database file:" ), sqlitePage ); + serverPageLayout_2->addWidget( sqliteLabel ); + sqliteDBRequester = new KURLRequester( sqlitePage, "sqliteDBRequester" ); + sqliteDBRequester->setShowLocalProtocol( false ); + serverPageLayout_2->addWidget( sqliteDBRequester ); + + TQSpacerItem *vSpacer = new TQSpacerItem( 20, 20, TQSizePolicy::Minimum, TQSizePolicy::Expanding ); + serverPageLayout_2->addItem(vSpacer); + + paramStack->addWidget( sqlitePage, 1 ); + + serverPage = new TQWidget( paramStack, "serverPage" ); + serverPageLayout = new TQVBoxLayout( serverPage, 11, 6, "serverPageLayout" ); + + layout5 = new TQGridLayout( 0, 1, 1, 0, 6, "layout5" ); + + hostEdit = new TQLineEdit( serverPage, "hostEdit" ); + layout5->addWidget( hostEdit, 0, 1 ); + hostLabel = new TQLabel( serverPage, "hostLabel" ); + layout5->addWidget( hostLabel, 0, 0 ); + + userEdit = new TQLineEdit( serverPage, "userEdit" ); + layout5->addWidget( userEdit, 1, 1 ); + userLabel = new TQLabel( serverPage, "userLabel" ); + layout5->addWidget( userLabel, 1, 0 ); + + passwordEdit = new TQLineEdit( serverPage, "passwordEdit" ); + passwordEdit->setEchoMode( TQLineEdit::Password ); + layout5->addWidget( passwordEdit, 2, 1 ); + passwordLabel = new TQLabel( serverPage, "passwordLabel" ); + layout5->addWidget( passwordLabel, 2, 0 ); + + portEdit = new KIntNumInput( serverPage, "portEdit" ); + portEdit->setMinValue(0); + portEdit->setValue(0); + layout5->addWidget( portEdit, 3, 1 ); + portLabel = new TQLabel( serverPage, "portLabel" ); + layout5->addWidget( portLabel, 3, 0 ); + + nameEdit = new TQLineEdit( serverPage, "nameEdit" ); + layout5->addWidget( nameEdit, 4, 1 ); + nameLabel = new TQLabel( serverPage, "nameLabel" ); + layout5->addWidget( nameLabel, 4, 0 ); + + serverPageLayout->addLayout( layout5 ); + paramStack->addWidget( serverPage, 0 ); + + languageChange(); + + +#if (!HAVE_MYSQL) + + mysqlRadioButton->setEnabled( false ); +#endif + +#if (!HAVE_POSTGRESQL) + + psqlRadioButton->setEnabled( false ); +#endif + +#if (!(HAVE_SQLITE || HAVE_SQLITE3)) + + liteRadioButton->setEnabled( false ); +#if (HAVE_MYSQL) + + dbButtonGroup->setButton( 1 ); // Otherwise by default liteCheckBox is checked even if it's disabled + switchDBPage(1); +#else + #if (HAVE_POSTGRESQL) + + dbButtonGroup->setButton( 2 ); + switchDBPage(2); +#endif + #endif + #endif + + // signals and slots connections + connect( dbButtonGroup, TQ_SIGNAL( clicked( int ) ), this, TQ_SLOT( switchDBPage( int ) ) ); +} + +void DBImportDialog::languageChange() +{ + dbButtonGroup->setTitle( i18n( "Database" ) ); + liteRadioButton->setText( "SQLite" ); + mysqlRadioButton->setText( "MySQL" ); + psqlRadioButton->setText( "PostgreSQL" ); + hostLabel->setText( i18n( "Server:" ) ); + userLabel->setText( i18n( "Username:" ) ); + passwordLabel->setText( i18n( "Password:" ) ); + nameLabel->setText( i18n( "Database name:" ) ); + portLabel->setText( i18n( "Port:" ) ); + portEdit->setSpecialValueText( i18n("Default") ); + + //set defaults + hostEdit->setText( "localhost" ); + nameEdit->setText( "Krecipes" ); + + // get username + uid_t userID; + struct passwd *user; + userID = getuid(); + user = getpwuid ( userID ); + TQString username(user->pw_name); + + userEdit->setText( username ); +} + +void DBImportDialog::switchDBPage( int id ) +{ + switch ( id ) { + case 0: //SQLite + paramStack->raiseWidget( sqlitePage ); + break; + case 1: //MySQL + case 2: //PostgreSQL + paramStack->raiseWidget( serverPage ); + break; + } +} + +TQString DBImportDialog::dbType() const +{ + int id = dbButtonGroup->id( dbButtonGroup->selected() ); + switch ( id ) { + case 0: + return "SQLite"; + case 1: + return "MySQL"; + case 2: + return "PostgreSQL"; + default: + return TQString::null; + } +} + +void DBImportDialog::serverParams( TQString &host, TQString &user, TQString &pass, int &port, TQString &table ) const +{ + host = hostEdit->text(); + user = userEdit->text(); + pass = passwordEdit->text(); + table = nameEdit->text(); + port = portEdit->value(); +} + +TQString DBImportDialog::dbFile() const +{ + return sqliteDBRequester->url(); +} + +#include "dbimportdialog.moc" diff --git a/src/dialogs/dbimportdialog.h b/src/dialogs/dbimportdialog.h new file mode 100644 index 0000000..eef49c5 --- /dev/null +++ b/src/dialogs/dbimportdialog.h @@ -0,0 +1,76 @@ +/*************************************************************************** +* Copyright (C) 2004 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ +#ifndef DBIMPORTDIALOG_H +#define DBIMPORTDIALOG_H + +#include <kdialogbase.h> + +class TQVBoxLayout; +class TQHBoxLayout; +class TQGridLayout; +class TQSpacerItem; +class TQButtonGroup; +class TQRadioButton; +class TQWidgetStack; +class TQWidget; +class TQLineEdit; +class TQLabel; +class TQPushButton; + +class KURLRequester; +class KIntNumInput; + +/** +@author Jason Kivlighn +*/ + +class DBImportDialog: public KDialogBase +{ + TQ_OBJECT +public: + DBImportDialog( TQWidget *parent = 0, const char *name = 0 ); + + TQString dbType() const; + void serverParams( TQString &host, TQString &user, TQString &pass, int &port, TQString &table ) const; + TQString dbFile() const; + +private: + // Widgets + TQButtonGroup* dbButtonGroup; + TQRadioButton* liteRadioButton; + TQRadioButton* mysqlRadioButton; + TQRadioButton* psqlRadioButton; + TQWidgetStack* paramStack; + TQWidget* serverPage; + TQLineEdit* nameEdit; + TQLabel* passwordLabel; + TQLineEdit* hostEdit; + TQLineEdit* passwordEdit; + TQLineEdit* userEdit; + TQLabel* userLabel; + TQLabel* hostLabel; + TQLabel* nameLabel; + TQLabel* portLabel; + KIntNumInput *portEdit; + TQWidget* sqlitePage; + KURLRequester* sqliteDBRequester; + + TQVBoxLayout* dbButtonGroupLayout; + TQVBoxLayout* serverPageLayout; + TQGridLayout* layout5; + TQVBoxLayout* serverPageLayout_2; + +protected slots: + void languageChange(); + void switchDBPage( int id ); + +}; + +#endif diff --git a/src/dialogs/dependanciesdialog.cpp b/src/dialogs/dependanciesdialog.cpp new file mode 100644 index 0000000..ac7d095 --- /dev/null +++ b/src/dialogs/dependanciesdialog.cpp @@ -0,0 +1,100 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* * +* Copyright (C) 2003-2005 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "dependanciesdialog.h" +#include "datablocks/elementlist.h" + +#include <tqvbox.h> + +#include <tdelocale.h> +#include <tdeglobal.h> +#include <tdeconfig.h> +#include <tdemessagebox.h> + +DependanciesDialog::DependanciesDialog( TQWidget *parent, const TQValueList<ListInfo> &lists, bool deps_are_deleted ) : KDialogBase( parent, "DependanciesDialog", true, TQString::null, + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Cancel ), + m_depsAreDeleted(deps_are_deleted) +{ + init( lists ); +} + +DependanciesDialog::DependanciesDialog( TQWidget *parent, const ListInfo &list, bool deps_are_deleted ) : KDialogBase( parent, "DependanciesDialog", true, TQString::null, + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Cancel ), + m_depsAreDeleted(deps_are_deleted) +{ + TQValueList<ListInfo> lists; + lists << list; + init( lists ); +} + +DependanciesDialog::~DependanciesDialog() +{} + +void DependanciesDialog::init( const TQValueList<ListInfo> &lists ) +{ + TQVBox *page = makeVBoxMainWidget(); + + // Design the dialog + + instructionsLabel = new TQLabel( page ); + instructionsLabel->setMinimumSize( TQSize( 100, 30 ) ); + instructionsLabel->setMaximumSize( TQSize( 10000, 10000 ) ); + instructionsLabel->setAlignment( int( TQLabel::WordBreak | TQLabel::AlignVCenter ) ); + + if ( m_depsAreDeleted ) { + instructionsLabel->setText( i18n( "<b>WARNING:</b> The following will have to be removed also, since currently they use the element you have chosen to be removed." ) ); + } + else { + instructionsLabel->setText( i18n( "<b>WARNING:</b> The following currently use the element you have chosen to be removed." ) ); + } + + for ( TQValueList<ListInfo>::const_iterator list_it = lists.begin(); list_it != lists.end(); ++list_it ) { + if ( !((*list_it).list).isEmpty() ) { + TQGroupBox *groupBox = new TQGroupBox( 1, TQt::Vertical, (*list_it).name, page ); + TDEListBox *listBox = new TDEListBox( groupBox ); + loadList( listBox, (*list_it).list ); + } + } + + setSizeGripEnabled( true ); +} + +void DependanciesDialog::loadList( TDEListBox* listBox, const ElementList &list ) +{ + TDEConfig * config = TDEGlobal::config(); + config->setGroup( "Advanced" ); + bool show_id = config->readBoolEntry( "ShowID", false ); + + for ( ElementList::const_iterator el_it = list.begin(); el_it != list.end(); ++el_it ) { + TQString name = ( *el_it ).name; + if ( show_id ) + name += " (" + TQString::number(( *el_it ).id) + ")"; + listBox->insertItem( name ); + } +} + +void DependanciesDialog::accept() +{ + if ( !m_msg.isEmpty() ) { + switch ( KMessageBox::warningYesNo(this, + TQString("<b>%1</b><br><br>%2").arg(m_msg).arg(i18n("Are you sure you wish to proceed?")), + TQString::null,KStdGuiItem::yes(),KStdGuiItem::no(),"doubleCheckDelete") ) + { + case KMessageBox::Yes: TQDialog::accept(); break; + case KMessageBox::No: TQDialog::reject(); break; + } + } + else + TQDialog::accept(); +} diff --git a/src/dialogs/dependanciesdialog.h b/src/dialogs/dependanciesdialog.h new file mode 100644 index 0000000..076bd04 --- /dev/null +++ b/src/dialogs/dependanciesdialog.h @@ -0,0 +1,60 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* * +* Copyright (C) 2003-2005 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef DEPENDANCIESDIALOG_H +#define DEPENDANCIESDIALOG_H + +#include <tqgroupbox.h> +#include <tqlabel.h> + +#include <tdelistview.h> +#include <kdialogbase.h> + +#include "datablocks/elementlist.h" + +struct ListInfo { + ElementList list; + TQString name; +}; + +/** +@author Unai Garro +*/ +class DependanciesDialog: public KDialogBase +{ +public: + //Methods + DependanciesDialog( TQWidget *parent, const TQValueList<ListInfo> &lists, bool deps_are_deleted = true ); + DependanciesDialog( TQWidget *parent, const ListInfo &list, bool deps_are_deleted = true ); + + ~DependanciesDialog(); + + void setCustomWarning( const TQString &msg ){ m_msg = msg; } + +public slots: + void accept(); + +private: + //Widgets + TQLabel *instructionsLabel; + + bool m_depsAreDeleted; + TQString m_msg; + + // Methods + void init( const TQValueList<ListInfo> &lists ); + void loadList( TDEListBox*, const ElementList &list ); +}; + +#endif diff --git a/src/dialogs/dietviewdialog.cpp b/src/dialogs/dietviewdialog.cpp new file mode 100644 index 0000000..5b51c27 --- /dev/null +++ b/src/dialogs/dietviewdialog.cpp @@ -0,0 +1,137 @@ +/*************************************************************************** +* Copyright (C) 2003-2005 * +* Unai Garro (ugarro@users.sourceforge.net) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "dietviewdialog.h" + +#include <kiconloader.h> +#include <tdelocale.h> +#include <kstandarddirs.h> + +DietViewDialog::DietViewDialog( TQWidget *parent, const RecipeList &recipeList, int dayNumber, int mealNumber, const TQValueList <int> &dishNumbers ) + : KDialogBase( parent, "dietViewDialog", true, TQString::null, + KDialogBase::User2 | KDialogBase::Close | KDialogBase::User1, KDialogBase::User2, + false, KStdGuiItem::print() ) +{ + setButtonText( KDialogBase::User2, i18n( "Create &Shopping List" ) ); + + // Design the dialog + TQVBox *page = makeVBoxMainWidget(); + + // The html part + dietView = new TDEHTMLPart( page ); + + setInitialSize( TQSize(350, 450) ); + + setSizeGripEnabled( true ); + + connect ( this, TQ_SIGNAL( user2Clicked() ), this, TQ_SLOT( slotOk() ) ); + connect ( this, TQ_SIGNAL( closeClicked() ), this, TQ_SLOT( close() ) ); + connect ( this, TQ_SIGNAL( user1Clicked() ), this, TQ_SLOT( print() ) ); + + // Show the diet + showDiet( recipeList, dayNumber, mealNumber, dishNumbers ); +} + +DietViewDialog::~DietViewDialog() +{} + +void DietViewDialog::showDiet( const RecipeList &recipeList, int dayNumber, int mealNumber, const TQValueList <int> &dishNumbers ) +{ + + + // Header + TQString htmlCode = TQString( "<html><head><title>%1</title>" ).arg( i18n( "Diet" ) ); + + // CSS + htmlCode += "<STYLE type=\"text/css\">\n"; + htmlCode += "#calendar{border: thin solid black}"; + htmlCode += ".dayheader{ background-color: #D6D6D6; color: black; border:none;}"; + htmlCode += ".day{ background-color: #E5E5E5; color: black; border:medium solid #D6D6D6;}"; + htmlCode += ".meal{ background-color: #CDD4FF; color: black; border:thin solid #B4BEFF; text-align:center;}"; + htmlCode += ".dish{font-size: smaller; overflow: hidden; height:2.5em;}"; + htmlCode += "</STYLE>"; + + + htmlCode += "</head><body>"; // /Header + + // Calendar border + htmlCode += TQString( "<div id=\"calendar\">" ); + + // Title + htmlCode += TQString( "<center><div STYLE=\"width: 100%\">" ); + htmlCode += TQString( "<h1>%1</h1></div></center>" ).arg( i18n( "Diet" ) ); + + // Diet table + htmlCode += TQString( "<center><div STYLE=\"width: 98%\">" ); + htmlCode += TQString( "<table><tbody>" ); + + + TQValueList <int>::ConstIterator it; + it = dishNumbers.begin(); + RecipeList::ConstIterator rit; + rit = recipeList.begin(); + + for ( int row = 0, day = 0; row <= ( ( dayNumber - 1 ) / 7 ); row++ ) // New row (week) + { + htmlCode += TQString( "<tr>" ); + + for ( int col = 0; ( col < 7 ) && ( day < dayNumber ); col++, day++ ) // New column (day) + { + htmlCode += TQString( "<td><div class=\"day\">" ); + htmlCode += TQString( "<div class=\"dayheader\"><center>" ); + htmlCode += TQString( i18n( "Day %1" ) ).arg( day + 1 ); + htmlCode += TQString( "</center></div>" ); + for ( int meal = 0;meal < mealNumber;meal++ ) // Meals in each cell + { + int dishNumber = *it; + htmlCode += TQString( "<div class=\"meal\">" ); + for ( int dish = 0; dish < dishNumber;dish++ ) // Dishes in each Meal + { + htmlCode += TQString( "<div class=\"dish\">" ); + htmlCode += ( *rit ).title; + htmlCode += "<br>"; + htmlCode += TQString( "</div>" ); + rit++; + } + it++; + htmlCode += TQString( "</div>" ); + } + it = dishNumbers.begin(); // meals have same dish number everyday + htmlCode += TQString( "</div></td>" ); + } + + htmlCode += TQString( "</tr>" ); + } + + htmlCode += TQString( "</tbody></table>" ); + htmlCode += TQString( "</div></center>" ); + htmlCode += TQString( "</div></body></html>" ); + + resize( TQSize( 600, 400 ) ); + + // Display it + dietView->begin( KURL( locateLocal( "tmp", "/" ) ) ); // Initialize to tmp dir, where photos and logos can be stored + dietView->write( htmlCode ); + dietView->end(); +} + +void DietViewDialog::print( void ) +{ + dietView->view()->print(); +} + +void DietViewDialog::slotOk( void ) +{ + emit signalOk(); + close(); +} + +#include "dietviewdialog.moc" diff --git a/src/dialogs/dietviewdialog.h b/src/dialogs/dietviewdialog.h new file mode 100644 index 0000000..aff4992 --- /dev/null +++ b/src/dialogs/dietviewdialog.h @@ -0,0 +1,45 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* * +* 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. * +***************************************************************************/ + +#ifndef DIETVIEWDIALOG_H +#define DIETVIEWDIALOG_H + +#include <tqpushbutton.h> +#include <tqlayout.h> +#include <tqvbox.h> +#include <tqwidget.h> + +#include <tdehtml_part.h> +#include <tdehtmlview.h> +#include <kdialogbase.h> + +#include "datablocks/recipelist.h" + +class DietViewDialog: public KDialogBase +{ + TQ_OBJECT + +public: + DietViewDialog( TQWidget *parent, const RecipeList &recipeList, int dayNumber, int mealNumber, const TQValueList <int> &dishNumbers ); + ~DietViewDialog(); +private: + // Widgets + TDEHTMLPart *dietView; + + // Private methods + void showDiet( const RecipeList &recipeList, int dayNumber, int mealNumber, const TQValueList <int> &dishNumbers ); +private slots: + void print( void ); + void slotOk( void ); +signals: + void signalOk( void ); +}; + +#endif diff --git a/src/dialogs/dietwizarddialog.cpp b/src/dialogs/dietwizarddialog.cpp new file mode 100644 index 0000000..30414cf --- /dev/null +++ b/src/dialogs/dietwizarddialog.cpp @@ -0,0 +1,748 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "dietwizarddialog.h" +#include "backends/recipedb.h" +#include "dietviewdialog.h" + +#include <tqbitmap.h> +#include <tqheader.h> +#include <tqlayout.h> +#include <tqpainter.h> +#include <tqwmatrix.h> + +#include <tdeapplication.h> +#include <kcursor.h> +#include <tdeglobalsettings.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <knuminput.h> +#include <kdebug.h> + +#include "propertycalculator.h" +#include "widgets/propertylistview.h" +#include "widgets/categorylistview.h" + +#include "profiling.h" + +DietWizardDialog::DietWizardDialog( TQWidget *parent, RecipeDB *db ) : TQVBox( parent ) +{ + // Initialize internal variables + database = db; + mealNumber = 1; + dayNumber = 1; + dietRList = new RecipeList(); + + //Design the dialog + setSpacing( 5 ); + // Options Box + optionsBox = new TQHBox( this ); + + daysSliderBox = new TQVGroupBox( i18n( "Number of Days" ), optionsBox ); + dayNumberLabel = new TQLabel( daysSliderBox ); + dayNumberLabel->setText( "- 1 -" ); + dayNumberLabel->setAlignment( TQt::AlignHCenter ); + dayNumberSelector = new TQSlider( daysSliderBox ); + + dayNumberSelector->setOrientation( TQt::Horizontal ); + dayNumberSelector->setRange( 1, 10 ); + dayNumberSelector->setSteps( 1, 1 ); + dayNumberSelector->setTickmarks( TQSlider::Below ); + dayNumberSelector->setFixedWidth( 100 ); + + mealsSliderBox = new TQVGroupBox( i18n( "Meals per Day" ), optionsBox ); + mealNumberLabel = new TQLabel( mealsSliderBox ); + mealNumberLabel->setText( "- 1 -" ); + mealNumberLabel->setAlignment( TQt::AlignHCenter ); + mealNumberSelector = new TQSlider( mealsSliderBox ); + + mealNumberSelector->setOrientation( TQt::Horizontal ); + mealNumberSelector->setRange( 1, 10 ); + mealNumberSelector->setSteps( 1, 1 ); + mealNumberSelector->setTickmarks( TQSlider::Below ); + mealNumberSelector->setFixedWidth( 100 ); + + // Tabs + mealTabs = new TQTabWidget( this ); + mealTabs->setMargin( 5 ); + + // Button bar + TDEIconLoader il; + + TQHBox *bottom_layout = new TQHBox( this ); + //bottom_layout->layout()->addItem( new TQSpacerItem( 10,10, TQSizePolicy::MinimumExpanding, TQSizePolicy::Fixed ) ); + + okButton = new TQPushButton( bottom_layout ); + okButton->setIconSet( il.loadIconSet( "button_ok", TDEIcon::Small ) ); + okButton->setText( i18n( "Create the diet" ) ); + + TQPushButton *clearButton = new TQPushButton( bottom_layout ); + clearButton->setIconSet( il.loadIconSet( "edit-clear", TDEIcon::Small ) ); + clearButton->setText( i18n( "Clear" ) ); + + // Create Tabs + //don't use newTab, it'll load data and we don't want it to do that at startup + mealTab = new MealInput( mealTabs, database ); + mealTabs->addTab( mealTab,i18n( "Meal 1" ) ); + mealTabs->setCurrentPage( mealTabs->indexOf( mealTab ) ); + + // Signals & Slots + connect( mealNumberSelector, TQ_SIGNAL( valueChanged( int ) ), this, TQ_SLOT( changeMealNumber( int ) ) ); + connect( dayNumberSelector, TQ_SIGNAL( valueChanged( int ) ), this, TQ_SLOT( changeDayNumber( int ) ) ); + connect( okButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( createDiet() ) ); + connect( clearButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( clear() ) ); +} + + +DietWizardDialog::~DietWizardDialog() +{ + delete dietRList; +} + +void DietWizardDialog::clear() +{ + mealNumberSelector->setValue( 1 ); + dayNumberSelector->setValue( 1 ); + + MealInput* mealTab = ( MealInput* ) ( mealTabs->page( 0 ) ); // Get the meal + mealTab->setDishNo( 3 ); + mealTab->showDish( 0 ); + + for ( uint i = 0; i < mealTab->dishInputList.count(); ++i ) { + DishInput* dishInput = mealTab->dishInputList[ i ]; // Get the dish input + dishInput->clear(); + } +} + +void DietWizardDialog::reload( ReloadFlags flag ) +{ + for ( int i = 0; i < mealTabs->count(); ++i ) { + MealInput *mealTab = (MealInput*)mealTabs->page(i); + mealTab->reload(flag); + } +} + +void DietWizardDialog::newTab( const TQString &name ) +{ + mealTab = new MealInput( mealTabs, database ); + mealTab->reload(); + mealTabs->addTab( mealTab, name ); + mealTabs->setCurrentPage( mealTabs->indexOf( mealTab ) ); +} + +void DietWizardDialog::changeMealNumber( int mn ) +{ + mealNumberLabel->setText( TQString( i18n( "- %1 -" ) ).arg( mn ) ); + if ( mn > mealNumber ) { + + while ( mealNumber != mn ) { + mealNumber++; + newTab( i18n( "Meal %1" ).arg( mealNumber ) ); + + } + } + else if ( mn < mealNumber ) { + + while ( mealNumber != mn ) { + mealNumber--; + delete mealTabs->page( mealTabs->count() - 1 ); + } + } +} + +void DietWizardDialog::changeDayNumber( int dn ) +{ + + if ( dn < 7 ) { + dayNumber = dn; + dayNumberLabel->setText( TQString( i18n( "- %1 -" ) ).arg( dn ) ); + } + else if ( dn == 7 ) { + dayNumber = 7; + dayNumberLabel->setText( TQString( i18n( "- 1 week -" ) ) ); + } + else { + dayNumber = ( dn - 6 ) * 7; + dayNumberLabel->setText( TQString( i18n( "- %1 weeks -" ) ).arg( dn - 6 ) ); + } +} + +void DietWizardDialog::createDiet( void ) +{ + TDEApplication::setOverrideCursor( KCursor::waitCursor() ); + + START_TIMER("Creating the diet"); + + RecipeList rlist; + dietRList->clear(); + + // Get the whole list of recipes, detailed + int flags = RecipeDB::Title | getNecessaryFlags(); + database->loadRecipes( &rlist, flags ); + + // temporal iterator list so elements can be removed without reloading them again from the DB + // this list prevents the same meal from showing up in the same day twice + TQValueList <RecipeList::Iterator> tempRList; + + bool alert = false; + + for ( int day = 0;day < dayNumber;day++ ) // Create the diet for the number of days defined by the user + { + populateIteratorList( rlist, &tempRList ); // temporal iterator list so elements can be removed without reloading them again from the DB + for ( int meal = 0;meal < mealNumber;meal++ ) + { + int dishNo = ( ( MealInput* ) ( mealTabs->page( meal ) ) ) ->dishNo(); + + for ( int dish = 0;dish < dishNo;dish++ ) { + bool found = false; + TQValueList <RecipeList::Iterator> tempDishRList = tempRList; + while ( ( !found ) && !tempDishRList.empty() ) { + int random_index = ( int ) ( ( float ) ( kapp->random() ) / ( float ) RAND_MAX * tempDishRList.count() ); + TQValueList<RecipeList::Iterator>::Iterator iit = tempDishRList.at( random_index ); // note that at() retrieves an iterator to the iterator list, so we need to use * in order to get the RecipeList::Iterator + + RecipeList::Iterator rit = *iit; + if ( found = ( ( ( !categoryFiltering( meal, dish ) ) || checkCategories( *rit, meal, dish ) ) && checkConstraints( *rit, meal, dish ) ) ) // Check that the recipe is inside the constraint limits and in the categories specified + { + dietRList->append( *rit ); // Add recipe to the diet list + tempRList.remove( tempRList.find(*iit) ); //can't just remove()... the iterator isn't from this list (its an iterator from tempDishRList) + } + else { + tempDishRList.remove( iit ); // Remove this analized recipe from teh list + } + } + if ( !found ) + alert = true; + } + } + } + + if ( alert ) { + TDEApplication::restoreOverrideCursor(); + KMessageBox::sorry( this, i18n( "I could not create a full diet list given the constraints. Either the recipe list is too short or the constraints are too demanding. " ) ); + } + + else // show the resulting diet + { + + // make a list of dishnumbers + TQValueList<int> dishNumbers; + + for ( int meal = 0;meal < mealNumber;meal++ ) { + int dishNo = ( ( MealInput* ) ( mealTabs->page( meal ) ) ) ->dishNo(); + dishNumbers << dishNo; + } + + TDEApplication::restoreOverrideCursor(); + + // display the list + DietViewDialog dietDisplay( this, *dietRList, dayNumber, mealNumber, dishNumbers ); + connect( &dietDisplay, TQ_SIGNAL( signalOk() ), this, TQ_SLOT( createShoppingList() ) ); + dietDisplay.exec(); + } + + END_TIMER(); +} + + +void DietWizardDialog::populateIteratorList( RecipeList &rl, TQValueList <RecipeList::Iterator> *il ) +{ + il->clear(); + RecipeList::Iterator it; + for ( it = rl.begin();it != rl.end(); ++it ) + il->append( it ); + +} + +int DietWizardDialog::getNecessaryFlags() const +{ + bool need_ingredients = false; + bool need_categories = false; + for ( int meal = 0;meal < mealNumber;meal++ ) { + int dishNo = ( ( MealInput* ) ( mealTabs->page( meal ) ) ) ->dishNo(); + for ( int dish = 0;dish < dishNo;dish++ ) { + if ( !need_categories ) { + if ( categoryFiltering( meal, dish ) ) { + need_categories = true; + } + } + + if ( !need_ingredients ) { + ConstraintList constraints; + loadConstraints( meal, dish, &constraints ); + for ( ConstraintList::const_iterator ct_it = constraints.begin(); ct_it != constraints.end(); ++ct_it ) { + if ( (*ct_it).enabled ) { + need_ingredients = true; + break; + } + } + } + + if ( need_ingredients && need_categories ) + break; + } + + if ( need_ingredients && need_categories ) + break; + } + + kdDebug()<<"Do we need to load ingredients: "<<need_ingredients<<endl; + kdDebug()<<"Do we need to load categories: "<<need_categories<<endl; + + int flags = 0; + if ( need_ingredients ) flags |= RecipeDB::Ingredients; + if ( need_categories ) flags |= RecipeDB::Categories; + + return flags; +} + + +MealInput::MealInput( TQWidget *parent, RecipeDB *db ) : TQWidget( parent ), + database( db ) +{ + // Design the dialog + TQVBoxLayout *layout = new TQVBoxLayout( this ); + layout->setSpacing( 10 ); + + // Options box + + mealOptions = new TQHBox( this ); + mealOptions->setSpacing( 10 ); + layout->addWidget( mealOptions ); + + // Number of dishes input + dishNumberBox = new TQHBox( mealOptions ); + dishNumberBox->setSpacing( 10 ); + dishNumberLabel = new TQLabel( i18n( "No. of dishes: " ), dishNumberBox ); + dishNumberInput = new TQSpinBox( dishNumberBox ); + dishNumberInput->setMinValue( 1 ); + dishNumberInput->setMaxValue( 10 ); + dishNumberBox->setSizePolicy( TQSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Minimum ) ); + + // Toolbar + + toolBar = new TQHGroupBox( mealOptions ); + toolBar->setFrameStyle ( TQFrame::Panel | TQFrame::Sunken ); + toolBar->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::Minimum ) ); + + // Next dish/ Previous dish buttons + TDEIconLoader il; + buttonPrev = new TQToolButton( toolBar ); + buttonPrev->setUsesTextLabel( true ); + buttonPrev->setTextLabel( i18n( "Previous Dish" ) ); + buttonPrev->setIconSet( il.loadIconSet( "back", TDEIcon::Small ) ); + buttonPrev->setTextPosition( TQToolButton::Under ); + buttonNext = new TQToolButton( toolBar ); + buttonNext->setUsesTextLabel( true ); + buttonNext->setTextLabel( i18n( "Next Dish" ) ); + buttonNext->setIconSet( il.loadIconSet( "forward", TDEIcon::Small ) ); + buttonNext->setTextPosition( TQToolButton::Under ); + + + // Dish widgets + dishStack = new TQWidgetStack( this ); + layout->addWidget( dishStack ); + dishStack->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding ) ); + // Add default dishes + DishInput *newDish = new DishInput( this, database, i18n( "1st Course" ) ); + dishStack->addWidget( newDish ); + dishInputList.append( newDish ); + newDish = new DishInput( this, database, i18n( "2nd Course" ) ); + dishStack->addWidget( newDish ); + dishInputList.append( newDish ); + newDish = new DishInput( this, database, i18n( "Dessert" ) ); + dishStack->addWidget( newDish ); + dishInputList.append( newDish ); + dishNumber = 3; + dishNumberInput->setValue( dishNumber ); + + // Signals & Slots + connect( dishNumberInput, TQ_SIGNAL( valueChanged( int ) ), this, TQ_SLOT( changeDishNumber( int ) ) ); + connect( buttonPrev, TQ_SIGNAL( clicked() ), this, TQ_SLOT( prevDish() ) ); + connect( buttonNext, TQ_SIGNAL( clicked() ), this, TQ_SLOT( nextDish() ) ); + +} + +MealInput::~MealInput() +{} + +void MealInput::reload( ReloadFlags flag ) +{ + TQValueList<DishInput*>::iterator it; + for ( it = dishInputList.begin(); it != dishInputList.end(); ++it ) { + DishInput *di = ( *it ); + di->reload(flag); + } +} + +void MealInput::setDishNo( int dn ) +{ + dishNumberInput->setValue( dn ); +} + +void MealInput::changeDishNumber( int dn ) +{ + if ( dn > dishNumber ) { + while ( dishNumber != dn ) { + DishInput * newDish = new DishInput( this, database, TQString( i18n( "Dish %1" ) ).arg( dishNumber + 1 ) ); + newDish->reload(); + dishStack->addWidget( newDish ); + dishInputList.append( newDish ); + dishStack->raiseWidget( newDish ); + dishNumber++; + } + } + else if ( dn < dishNumber ) { + TQValueList <DishInput*>::Iterator it; + while ( dishNumber != dn ) { + it = dishInputList.fromLast(); + DishInput *lastDish = ( *it ); + dishInputList.remove( it ); + + if ( ( *it ) == ( DishInput* ) dishStack->visibleWidget() ) { + it--; + dishStack->raiseWidget( *it ); + } + delete lastDish; + dishNumber--; + } + } +} + + +void MealInput::nextDish( void ) +{ + // First get the place of the current dish input in the list + TQValueList <DishInput*>::iterator it = dishInputList.find( ( DishInput* ) ( dishStack->visibleWidget() ) ); + + //Show the next dish if it exists + it++; + if ( it != dishInputList.end() ) { + dishStack->raiseWidget( *it ); + } + +} + +void MealInput::prevDish( void ) +{ + // First get the place of the current dish input in the list + TQValueList <DishInput*>::iterator it = dishInputList.find( ( DishInput* ) ( dishStack->visibleWidget() ) ); + + //Show the previous dish if it exists + it--; + if ( it != dishInputList.end() ) { + dishStack->raiseWidget( *it ); + } +} + +void MealInput::showDish( int dn ) +{ + TQValueList <DishInput*>::iterator it = dishInputList.at( dn ); + if ( it != dishInputList.end() ) + dishStack->raiseWidget( *it ); +} + +DishInput::DishInput( TQWidget* parent, RecipeDB *db, const TQString &title ) : TQWidget( parent ), + database(db) +{ + + // Initialize internal variables + categoryFiltering = false; + + // Design the widget + + TQVBoxLayout *layout = new TQVBoxLayout( this ); + layout->setSpacing( 10 ); + + //Horizontal Box to hold the TDEListView's + listBox = new TQHGroupBox( i18n( "Dish Characteristics" ), this ); + layout->addWidget( listBox ); + + // Dish id + dishTitle = new DishTitle( listBox, title ); + + //Categories list + categoriesBox = new TQVBox( listBox ); + categoriesEnabledBox = new TQCheckBox( categoriesBox ); + categoriesEnabledBox->setText( i18n( "Enable Category Filtering" ) ); + + categoriesView = new CategoryCheckListView( categoriesBox, database, false ); + categoriesView->setSizePolicy( TQSizePolicy::Ignored, TQSizePolicy::Ignored ); + categoriesView->setEnabled( false ); // Disable it by default + + //Constraints list + constraintsView = new PropertyConstraintListView( listBox, database ); + constraintsView->setSizePolicy( TQSizePolicy::Ignored, TQSizePolicy::Ignored ); + constraintsView->reload(); + + // KDoubleInput based edit boxes + constraintsEditBox1 = new KDoubleNumInput( constraintsView->viewport() ); + constraintsView->addChild( constraintsEditBox1 ); + constraintsEditBox1->hide(); + constraintsEditBox2 = new KDoubleNumInput( constraintsView->viewport() ); + constraintsView->addChild( constraintsEditBox2 ); + constraintsEditBox2->hide(); + + + // Connect Signals & Slots + connect( constraintsView, TQ_SIGNAL( executed( TQListViewItem* ) ), this, TQ_SLOT( insertConstraintsEditBoxes( TQListViewItem* ) ) ); + connect( constraintsView, TQ_SIGNAL( selectionChanged() ), this, TQ_SLOT( hideConstraintInputs() ) ); + connect( constraintsEditBox1, TQ_SIGNAL( valueChanged( double ) ), this, TQ_SLOT( setMinValue( double ) ) ); + connect( constraintsEditBox2, TQ_SIGNAL( valueChanged( double ) ), this, TQ_SLOT( setMaxValue( double ) ) ); + connect( categoriesEnabledBox, TQ_SIGNAL( toggled( bool ) ), this, TQ_SLOT( enableCategories( bool ) ) ); +} + +DishInput::~DishInput() +{} + +void DishInput::clear() +{ + TQListViewItemIterator it( categoriesView ); + while ( it.current() ) { + TQCheckListItem * item = ( TQCheckListItem* ) it.current(); + item->setOn( false ); + ++it; + } + + constraintsView->reload(); + categoriesEnabledBox->setChecked( false ); +} + +void DishInput::enableCategories( bool enable ) +{ + categoriesView->setEnabled( enable ); + categoryFiltering = enable; +} + +bool DishInput::isCategoryFilteringEnabled( void ) const +{ + return categoryFiltering; +} + +void DishInput::reload( ReloadFlags flag ) +{ + constraintsView->reload(); + categoriesView->reload(flag); +} + +void DishInput::insertConstraintsEditBoxes( TQListViewItem* it ) +{ + TQRect r; + + // Constraints Box1 + r = constraintsView->header() ->sectionRect( 2 ); //start at the section 2 header + r.moveBy( 0, constraintsView->itemRect( it ).y() ); //Move down to the item, note that its height is same as header's right now. + + r.setHeight( it->height() ); // Set the item's height + r.setWidth( constraintsView->header() ->sectionRect( 2 ).width() ); // and width + constraintsEditBox1->setGeometry( r ); + + + //Constraints Box2 + r = constraintsView->header() ->sectionRect( 3 ); //start at the section 3 header + r.moveBy( 0, constraintsView->itemRect( it ).y() ); //Move down to the item + + r.setHeight( it->height() ); // Set the item's height + r.setWidth( constraintsView->header() ->sectionRect( 3 ).width() ); // and width + constraintsEditBox2->setGeometry( r ); + + // Set the values from the item + constraintsEditBox1->setValue( ( ( ConstraintsListItem* ) it ) ->minVal() ); + constraintsEditBox2->setValue( ( ( ConstraintsListItem* ) it ) ->maxVal() ); + + // Show Boxes + constraintsEditBox1->show(); + constraintsEditBox2->show(); +} + +void DishInput::hideConstraintInputs() +{ + constraintsEditBox1->hide(); + constraintsEditBox2->hide(); +} + +void DishInput::loadConstraints( ConstraintList *constraints ) const +{ + constraints->clear(); + Constraint constraint; + for ( ConstraintsListItem * it = ( ConstraintsListItem* ) ( constraintsView->firstChild() );it;it = ( ConstraintsListItem* ) ( it->nextSibling() ) ) { + constraint.id = it->propertyId(); + constraint.min = it->minVal(); + constraint.max = it->maxVal(); + constraint.enabled = it->isOn(); + constraints->append( constraint ); + } +} + +void DishInput::loadEnabledCategories( ElementList* categories ) +{ + categories->clear(); + + // Only load those that are checked, unless filtering is disabled + if ( !categoriesView->isEnabled() ) { + database->loadCategories(categories); + } + else { + *categories = categoriesView->selections(); + } +} + +void DishInput::setMinValue( double minValue ) +{ + ConstraintsListItem *it = ( ConstraintsListItem* ) ( constraintsView->selectedItem() ); // Find selected property + + if ( it ) + it->setMin( minValue ); +} + +void DishInput::setMaxValue( double maxValue ) +{ + ConstraintsListItem *it = ( ConstraintsListItem* ) ( constraintsView->selectedItem() ); // Find selected property + + if ( it ) + it->setMax( maxValue ); +} + +DishTitle::DishTitle( TQWidget *parent, const TQString &title ) : TQWidget( parent ) +{ + titleText = title; +} + + +DishTitle::~DishTitle() +{} + +void DishTitle::paintEvent( TQPaintEvent * ) +{ + // Now draw the text + TQPainter painter( this ); + + // First draw the decoration + painter.setPen( TDEGlobalSettings::activeTitleColor() ); + painter.setBrush( TQBrush( TDEGlobalSettings::activeTitleColor() ) ); + painter.drawRoundRect( 0, 20, 30, height() - 40, 50, ( int ) ( 50.0 / ( height() - 40 ) * 35.0 ) ); + + // Now draw the text + + TQFont titleFont = TDEGlobalSettings::windowTitleFont (); + titleFont.setPointSize( 15 ); + painter.setFont( titleFont ); + painter.rotate( -90 ); + painter.setPen( TQColor( 0x00, 0x00, 0x00 ) ); + painter.drawText( 0, 0, -height(), 30, AlignCenter, titleText ); + painter.setPen( TQColor( 0xFF, 0xFF, 0xFF ) ); + painter.drawText( -1, -1, -height() - 1, 29, AlignCenter, titleText ); + painter.end(); +} + +TQSize DishTitle::sizeHint () const +{ + return ( TQSize( 40, 200 ) ); +} + +TQSize DishTitle::minimumSizeHint() const +{ + return ( TQSize( 40, 200 ) ); +} + +bool DietWizardDialog::checkCategories( Recipe &rec, int meal, int dish ) +{ + + // Check if the recipe is among the categories chosen + ElementList categoryList; + loadEnabledCategories( meal, dish, &categoryList ); + + + for ( ElementList::const_iterator cat_it = rec.categoryList.begin(); cat_it != rec.categoryList.end(); ++cat_it ) { + if ( categoryList.containsId( ( *cat_it ).id ) ) + return true; + } + + return false; +} + +/* +** Calculate the recipe Properties and check if they're within the constraints +*/ + +bool DietWizardDialog::checkConstraints( Recipe &rec, int meal, int dish ) +{ + // Check if the properties are within the constraints + ConstraintList constraints; + loadConstraints( meal, dish, &constraints ); //load the constraints + + bool any_enabled = false; + for ( ConstraintList::const_iterator ct_it = constraints.begin(); ct_it != constraints.end(); ++ct_it ) { + if ( (*ct_it).enabled ) { + any_enabled = true; + break; + } + } + if ( !any_enabled ) + return true; + + // Calculate properties of the recipe + calculateProperties( rec, database ); + + bool withinLimits = checkLimits( rec.properties, constraints ); + + return ( withinLimits ); +} + +void DietWizardDialog::loadConstraints( int meal, int dish, ConstraintList *constraints ) const +{ + MealInput * mealTab = ( MealInput* ) ( mealTabs->page( meal ) ); // Get the meal + DishInput* dishInput = mealTab->dishInputList[ dish ]; // Get the dish input + dishInput->loadConstraints( constraints ); //Load the constraints form the TDEListView +} + +void DietWizardDialog::loadEnabledCategories( int meal, int dish, ElementList *categories ) +{ + MealInput * mealTab = ( MealInput* ) ( mealTabs->page( meal ) ); // Get the meal + DishInput* dishInput = mealTab->dishInputList[ dish ]; // Get the dish input + dishInput->loadEnabledCategories( categories ); //Load the categories that have been checked in the TDEListView +} + +bool DietWizardDialog::categoryFiltering( int meal, int dish ) const +{ + MealInput * mealTab = ( MealInput* ) ( mealTabs->page( meal ) ); // Get the meal + DishInput* dishInput = mealTab->dishInputList[ dish ]; // Get the dish input + return ( dishInput->isCategoryFilteringEnabled() ); //Load the categories that have been checked in the TDEListView +} + +bool DietWizardDialog::checkLimits( IngredientPropertyList &properties, ConstraintList &constraints ) +{ + for ( ConstraintList::const_iterator ct_it = constraints.begin(); ct_it != constraints.end(); ++ct_it ) { + if ( (*ct_it).enabled ) { + IngredientPropertyList::const_iterator ip_it = properties.find( (*ct_it).id ); + if ( ip_it != properties.end() ) { + if ( ( (*ip_it).amount > (*ct_it).max ) || ( (*ip_it).amount < (*ct_it).min ) ) + return false; + } + else + return false; + } + } + return true; +} + +void DietWizardDialog::createShoppingList( void ) +{ + emit dietReady(); +} + +RecipeList& DietWizardDialog::dietList( void ) +{ + return *dietRList; +} + +#include "dietwizarddialog.moc" diff --git a/src/dialogs/dietwizarddialog.h b/src/dialogs/dietwizarddialog.h new file mode 100644 index 0000000..c848664 --- /dev/null +++ b/src/dialogs/dietwizarddialog.h @@ -0,0 +1,222 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef DIETWIZARDDIALOG_H +#define DIETWIZARDDIALOG_H + +#include <stdlib.h> // For RAND_MAX + +#include <tqcheckbox.h> +#include <tqhbox.h> +#include <tqhgroupbox.h> +#include <tqlabel.h> +#include <tqptrlist.h> +#include <tqpushbutton.h> +#include <tqslider.h> +#include <tqspinbox.h> +#include <tqtabwidget.h> +#include <tqtoolbutton.h> +#include <tqvaluelist.h> +#include <tqvbox.h> +#include <tqvgroupbox.h> +#include <tqwidgetstack.h> + +#include <tdelistview.h> + +#include "datablocks/constraintlist.h" +#include "datablocks/recipelist.h" +#include "datablocks/elementlist.h" +#include "datablocks/ingredientpropertylist.h" +#include "datablocks/recipe.h" +#include "datablocks/unitratiolist.h" + +#include "widgets/dblistviewbase.h" + +class KDoubleNumInput; + +class DishInput; +class DishTitle; +class MealInput; +class RecipeDB; +class RecipeList; +class CategoryCheckListView; +class PropertyConstraintListView; + +/** +@author Unai Garro +*/ + + +class DietWizardDialog: public TQVBox +{ + + TQ_OBJECT + +public: + + DietWizardDialog( TQWidget *parent, RecipeDB* db ); + ~DietWizardDialog(); + +private: + //Private variables + RecipeDB *database; + + int dayNumber; + int mealNumber; + + RecipeList *dietRList; + + //Widgets + TQHBox *optionsBox; + TQVGroupBox *mealsSliderBox; + TQLabel *mealNumberLabel; + TQSlider *mealNumberSelector; + TQVGroupBox *daysSliderBox; + TQLabel *dayNumberLabel; + TQSlider *dayNumberSelector; + TQTabWidget *mealTabs; + MealInput *mealTab; // points to the current tab + TQPushButton *okButton; + + //Methods + bool checkCategories( Recipe &rec, int meal, int dish ); + bool checkConstraints( Recipe &rec, int meal, int dish ); + bool checkLimits( IngredientPropertyList &properties, ConstraintList &constraints ); + void loadConstraints( int meal, int dish, ConstraintList *constraints ) const; + void loadEnabledCategories( int meal, int dish, ElementList *categories ); + void newTab( const TQString &name ); + bool categoryFiltering( int meal, int dish ) const; + int getNecessaryFlags() const; + +public: + //Methods + void reload( ReloadFlags flags = Load ); + RecipeList& dietList( void ); + +private slots: + void changeDayNumber( int dn ); + void changeMealNumber( int mn ); + void createDiet( void ); + void clear(); + void createShoppingList( void ); + void populateIteratorList( RecipeList &rl, TQValueList <RecipeList::Iterator> *il ); +signals: + void dietReady( void ); +}; + +class MealInput: public TQWidget +{ + TQ_OBJECT + +public: + // Methods + + MealInput( TQWidget *parent, RecipeDB *database ); + ~MealInput(); + void reload( ReloadFlags flag = Load ); + int dishNo( void ) + { + return dishNumber; + }; + void setDishNo( int dn ); + void showDish( int dn ); + + // Public widgets and variables + TQValueList <DishInput*> dishInputList; // The list of dishes + +private: + // Widgets + // Private Variables + int dishNumber; + RecipeDB *database; + + // Settings section for the meal + TQHBox *mealOptions; + + // Dish number setting + TQHBox *dishNumberBox; + TQLabel *dishNumberLabel; + TQSpinBox *dishNumberInput; + + // Move <-> buttons + TQHGroupBox *toolBar; + TQToolButton *buttonNext; + TQToolButton *buttonPrev; + + // Settings for the dish + TQWidgetStack *dishStack; + +public slots: + void nextDish( void ); + void prevDish( void ); + +private slots: + void changeDishNumber( int dn ); + +}; + +class DishInput: public TQWidget +{ + TQ_OBJECT + +public: + DishInput( TQWidget *parent, RecipeDB *database, const TQString &title ); + ~DishInput(); + // Methods + bool isCategoryFilteringEnabled( void ) const; + void loadConstraints( ConstraintList *constraints ) const; + void loadEnabledCategories( ElementList* categories ); + void reload( ReloadFlags flag = Load ); + void setDishTitle( const TQString & text ); + void clear(); + + +private: + // Variables + bool categoryFiltering; + // Widgets + TQHGroupBox *listBox; + DishTitle *dishTitle; + TQVBox *categoriesBox; + TQCheckBox *categoriesEnabledBox; + CategoryCheckListView *categoriesView; + PropertyConstraintListView *constraintsView; + KDoubleNumInput *constraintsEditBox1; + KDoubleNumInput *constraintsEditBox2; + RecipeDB *database; + +private slots: + void enableCategories( bool enable ); + void insertConstraintsEditBoxes( TQListViewItem* it ); + void hideConstraintInputs(); + void setMinValue( double minValue ); + void setMaxValue( double maxValue ); +}; + +class DishTitle: public TQWidget +{ + + TQ_OBJECT + +public: + DishTitle( TQWidget *parent, const TQString &title ); + ~DishTitle(); + virtual TQSize sizeHint () const; + virtual TQSize minimumSizeHint() const; +protected: + //Variables + TQString titleText; + //Methods + virtual void paintEvent( TQPaintEvent *p ); +}; + +#endif diff --git a/src/dialogs/editratingdialog.cpp b/src/dialogs/editratingdialog.cpp new file mode 100644 index 0000000..bab6e1b --- /dev/null +++ b/src/dialogs/editratingdialog.cpp @@ -0,0 +1,243 @@ +/*************************************************************************** +* Copyright (C) 2005 by Jason Kivlighn * +* jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "editratingdialog.h" + +#include <tdelocale.h> + +#include <tqvariant.h> +#include <tqpushbutton.h> +#include <tqlabel.h> +#include <tqcombobox.h> +#include <knuminput.h> +#include <tqheader.h> +#include <tdelistview.h> +#include <tqtextedit.h> +#include <tqlineedit.h> +#include <tqlayout.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> +#include <tqpainter.h> +#include <tqvbox.h> + +#include <tdepopupmenu.h> +#include <tdelocale.h> +#include <kiconloader.h> +#include <kdebug.h> + +#include "datablocks/rating.h" +#include "datablocks/elementlist.h" +#include "datablocks/mixednumber.h" + +#include "widgets/ratingwidget.h" + +class RatingCriteriaListView : public TDEListView +{ +public: + RatingCriteriaListView( TQWidget *parent = 0, const char *name = 0 ) : TDEListView(parent,name){} + + void rename( TQListViewItem *it, int c ) + { + if ( c == 1 ) + it->setPixmap(c,TQPixmap()); + + TDEListView::rename(it,c); + } +}; + + +EditRatingDialog::EditRatingDialog( const ElementList &criteriaList, const Rating &rating, TQWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Rating" ), + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok ) +{ + init(criteriaList); + loadRating(rating); +} + +/* + * Constructs a EditRatingDialog as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + */ +EditRatingDialog::EditRatingDialog( const ElementList &criteriaList, TQWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Rating" ), + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok ) +{ + init(criteriaList); +} + +void EditRatingDialog::init( const ElementList &criteriaList ) +{ + TQVBox *page = makeVBoxMainWidget(); + + layout2 = new TQHBox( page ); + + raterLabel = new TQLabel( layout2, "raterLabel" ); + raterEdit = new TQLineEdit( layout2, "raterEdit" ); + + layout8 = new TQHBox( page ); + + criteriaLabel = new TQLabel( layout8, "criteriaLabel" ); + + criteriaComboBox = new TQComboBox( FALSE, layout8, "criteriaComboBox" ); + criteriaComboBox->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, (TQSizePolicy::SizeType)0, 0, 0, criteriaComboBox->sizePolicy().hasHeightForWidth() ) ); + criteriaComboBox->setEditable( TRUE ); + criteriaComboBox->lineEdit()->disconnect( criteriaComboBox ); //so hitting enter doesn't enter the item into the box + + starsLabel = new TQLabel( layout8, "starsLabel" ); + + starsWidget = new RatingWidget( 5, layout8, "starsWidget" ); + + addButton = new TQPushButton( layout8, "addButton" ); + + removeButton = new TQPushButton( layout8, "removeButton" ); + + criteriaListView = new RatingCriteriaListView( page, "criteriaListView" ); + criteriaListView->addColumn( i18n( "Criteria" ) ); + criteriaListView->addColumn( i18n( "Stars" ) ); + criteriaListView->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)7, (TQSizePolicy::SizeType)7, 0, 0, criteriaListView->sizePolicy().hasHeightForWidth() ) ); + criteriaListView->setSorting(-1); + criteriaListView->setItemsRenameable( true ); + criteriaListView->setRenameable( 0, true ); + criteriaListView->setRenameable( 1, true ); + + commentsLabel = new TQLabel( page, "commentsLabel" ); + + commentsEdit = new TQTextEdit( page, "commentsEdit" ); + + languageChange(); + resize( TQSize(358, 331).expandedTo(minimumSizeHint()) ); + clearWState( WState_Polished ); + + connect( criteriaListView, TQ_SIGNAL(itemRenamed(TQListViewItem*,const TQString &,int)), this, TQ_SLOT(itemRenamed(TQListViewItem*,const TQString &,int)) ); + connect( addButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotAddRatingCriteria()) ); + connect( removeButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotRemoveRatingCriteria()) ); + + TDEIconLoader il; + TDEPopupMenu *kpop = new TDEPopupMenu( criteriaListView ); + kpop->insertItem( il.loadIcon( "editshred", TDEIcon::NoGroup, 16 ), i18n( "&Delete" ), this, TQ_SLOT( slotRemoveRatingCriteria() ), Key_Delete ); + + for ( ElementList::const_iterator criteria_it = criteriaList.begin(); criteria_it != criteriaList.end(); ++criteria_it ) { + criteriaComboBox->insertItem( ( *criteria_it ).name ); + //criteriaComboBox->completionObject()->addItem( ( *criteria_it ).name ); + } + + ratingID = -1; +} + +/* + * Destroys the object and frees any allocated resources + */ +EditRatingDialog::~EditRatingDialog() +{ + // no need to delete child widgets, TQt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void EditRatingDialog::languageChange() +{ + criteriaLabel->setText( i18n( "Criteria:" ) ); + starsLabel->setText( i18n( "Stars:" ) ); + addButton->setText( i18n( "Add" ) ); + removeButton->setText( i18n( "&Delete" ) ); + criteriaListView->header()->setLabel( 0, i18n( "Criteria" ) ); + criteriaListView->header()->setLabel( 1, i18n( "Stars" ) ); + commentsLabel->setText( i18n( "Comments:" ) ); + raterLabel->setText( i18n( "Rater:" ) ); +} + +void EditRatingDialog::itemRenamed(TQListViewItem* it, const TQString &, int c) +{ + if ( c == 1 ) { + bool ok = false; + MixedNumber stars_mn = MixedNumber::fromString(it->text(c),&ok); + if ( ok && !it->text(c).isEmpty() ) { + double stars = TQMAX(0,TQMIN(stars_mn.toDouble(),5)); //force to between 0 and 5 + TQPixmap starsPic = Rating::starsPixmap( stars ); + it->setPixmap(c,starsPic); + it->setText(2,TQString::number(stars)); + } + else { + double stars = it->text(2).toDouble(); //col 2 holds the old value, which we'll set it back to + TQPixmap starsPic = Rating::starsPixmap( stars ); + it->setPixmap(c,starsPic); + } + + it->setText(c,TQString::null); + } +} + +Rating EditRatingDialog::rating() const +{ + Rating r; + + for ( TQListViewItem *it = criteriaListView->firstChild(); it; it = it->nextSibling() ) { + RatingCriteria rc; + rc.name = it->text(0); + rc.stars = it->text(2).toDouble(); + r.append( rc ); + } + + r.comment = commentsEdit->text(); + r.rater = raterEdit->text(); + + r.id = ratingID; + + return r; +} + +void EditRatingDialog::loadRating( const Rating &rating ) +{ + for ( RatingCriteriaList::const_iterator rc_it = rating.ratingCriteriaList.begin(); rc_it != rating.ratingCriteriaList.end(); ++rc_it ) { + addRatingCriteria(*rc_it); + } + + raterEdit->setText(rating.rater); + commentsEdit->setText(rating.comment); + + ratingID = rating.id; +} + +void EditRatingDialog::slotAddRatingCriteria() +{ + RatingCriteria r; + r.name = criteriaComboBox->lineEdit()->text().stripWhiteSpace(); + if ( r.name.isEmpty() ) + return; + + r.stars = starsWidget->text().toDouble(); + + addRatingCriteria(r); + + criteriaComboBox->lineEdit()->clear(); + starsWidget->clear(); + + criteriaComboBox->lineEdit()->setFocus(); +} + +void EditRatingDialog::addRatingCriteria( const RatingCriteria &rc ) +{ + TQListViewItem * it = new TQListViewItem(criteriaListView,rc.name); + + TQPixmap stars = Rating::starsPixmap(rc.stars); + if ( !stars.isNull() ) //there aren't zero stars + it->setPixmap(1,stars); + + it->setText(2,TQString::number(rc.stars)); +} + +void EditRatingDialog::slotRemoveRatingCriteria() +{ + delete criteriaListView->selectedItem(); +} + +#include "editratingdialog.moc" diff --git a/src/dialogs/editratingdialog.h b/src/dialogs/editratingdialog.h new file mode 100644 index 0000000..6996fb0 --- /dev/null +++ b/src/dialogs/editratingdialog.h @@ -0,0 +1,77 @@ +/*************************************************************************** +* Copyright (C) 2005 by Jason Kivlighn * +* jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef EDITRATINGDIALOG_H +#define EDITRATINGDIALOG_H + +#include <kdialogbase.h> + +class TQVBoxLayout; +class TQHBoxLayout; +class TQGridLayout; +class TQSpacerItem; +class TQLabel; +class TQComboBox; +class KDoubleSpinBox; +class TQPushButton; +class TDEListView; +class TQListViewItem; +class TQTextEdit; +class TQLineEdit; +class RatingWidget; + +class Rating; +class RatingCriteria; +class ElementList; +class RatingCriteriaListView; + +class EditRatingDialog : public KDialogBase +{ +TQ_OBJECT + +public: + EditRatingDialog( const ElementList &criteriaList, const Rating &, TQWidget* parent = 0, const char* name = 0 ); + EditRatingDialog( const ElementList &criteriaList, TQWidget* parent = 0, const char* name = 0 ); + ~EditRatingDialog(); + + TQLabel* criteriaLabel; + TQComboBox* criteriaComboBox; + TQLabel* starsLabel; + RatingWidget *starsWidget; + TQPushButton* addButton; + TQPushButton* removeButton; + RatingCriteriaListView* criteriaListView; + TQLabel* commentsLabel; + TQTextEdit* commentsEdit; + TQLabel* raterLabel; + TQLineEdit* raterEdit; + + Rating rating() const; + +protected: + TQHBox* layout8; + TQHBox* layout2; + +protected slots: + virtual void languageChange(); + void slotAddRatingCriteria(); + void slotRemoveRatingCriteria(); + void itemRenamed(TQListViewItem* it, const TQString &, int c); + +private: + void init(const ElementList &criteriaList); + + void loadRating( const Rating & ); + void addRatingCriteria( const RatingCriteria &rc ); + + int ratingID; +}; + +#endif // EDITRATINGDIALOG_H diff --git a/src/dialogs/ingredientgroupsdialog.cpp b/src/dialogs/ingredientgroupsdialog.cpp new file mode 100644 index 0000000..dcfae3d --- /dev/null +++ b/src/dialogs/ingredientgroupsdialog.cpp @@ -0,0 +1,65 @@ +/*************************************************************************** +* Copyright (C) 2005 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "ingredientgroupsdialog.h" + +#include <tqpushbutton.h> +#include <tqlayout.h> +#include <tqvbox.h> + +#include <tdelocale.h> +#include <kdialog.h> + +#include "widgets/krelistview.h" +#include "widgets/headerlistview.h" + +IngredientGroupsDialog::IngredientGroupsDialog( RecipeDB *db, TQWidget *parent, const char *name ) : TQWidget(parent,name), database(db) +{ + TQHBoxLayout* layout = new TQHBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); + + headerListView = new KreListView ( this, i18n( "Header list" ), true, 0 ); + StdHeaderListView *list_view = new StdHeaderListView( headerListView, database, true ); + headerListView->setListView( list_view ); + headerListView->setSizePolicy( TQSizePolicy( TQSizePolicy::Ignored, TQSizePolicy::MinimumExpanding ) ); + layout->addWidget(headerListView); + + TQVBoxLayout *buttonLayout = new TQVBoxLayout(NULL, 0, KDialog::spacingHint()); + TQPushButton *addHeaderButton = new TQPushButton( this ); + addHeaderButton->setText( "+" ); + addHeaderButton->setMinimumSize( TQSize( 30, 30 ) ); + addHeaderButton->setMaximumSize( TQSize( 30, 30 ) ); + addHeaderButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) ); + addHeaderButton->setFlat( true ); + buttonLayout->addWidget(addHeaderButton); + + TQSpacerItem* spacer_buttons = new TQSpacerItem( 10, 10, TQSizePolicy::Fixed, TQSizePolicy::Fixed ); + buttonLayout->addItem( spacer_buttons ); + + TQPushButton *removeHeaderButton = new TQPushButton( this ); + removeHeaderButton->setText( "-" ); + removeHeaderButton->setMinimumSize( TQSize( 30, 30 ) ); + removeHeaderButton->setMaximumSize( TQSize( 30, 30 ) ); + removeHeaderButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) ); + removeHeaderButton->setFlat( true ); + buttonLayout->addWidget(removeHeaderButton); + + TQSpacerItem* spacer_below_buttons = new TQSpacerItem( 10, 10, TQSizePolicy::Fixed, TQSizePolicy::MinimumExpanding ); + buttonLayout->addItem( spacer_below_buttons ); + + layout->addLayout(buttonLayout); + + connect( addHeaderButton, TQ_SIGNAL( clicked() ), list_view, TQ_SLOT( createNew() ) ); + connect( removeHeaderButton, TQ_SIGNAL( clicked() ), list_view, TQ_SLOT( remove() ) ); +} + +void IngredientGroupsDialog::reload( ReloadFlags flag ) +{ + ( ( StdHeaderListView* ) headerListView->listView() ) ->reload(flag); +} diff --git a/src/dialogs/ingredientgroupsdialog.h b/src/dialogs/ingredientgroupsdialog.h new file mode 100644 index 0000000..2b8f585 --- /dev/null +++ b/src/dialogs/ingredientgroupsdialog.h @@ -0,0 +1,33 @@ +/*************************************************************************** +* Copyright (C) 2005 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef INGREDIENTGROUPSDIALOG_H +#define INGREDIENTGROUPSDIALOG_H + +#include <tqwidget.h> + +#include "widgets/dblistviewbase.h" + +class KreListView; +class RecipeDB; + +class IngredientGroupsDialog : public TQWidget +{ +public: + IngredientGroupsDialog( RecipeDB *db, TQWidget *parent, const char *name ); + + void reload( ReloadFlags flag = Load ); + +private: + KreListView *headerListView; + RecipeDB *database; +}; + +#endif 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 (ugarro@users.sourceforge.net) * +* * +* 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" diff --git a/src/dialogs/ingredientmatcherdialog.h b/src/dialogs/ingredientmatcherdialog.h new file mode 100644 index 0000000..2bd54b3 --- /dev/null +++ b/src/dialogs/ingredientmatcherdialog.h @@ -0,0 +1,156 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* * +* Copyright (C) 2006 Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef INGREDIENTMATCHERDIALOG_H +#define INGREDIENTMATCHERDIALOG_H + +#include "datablocks/element.h" +#include "datablocks/ingredientlist.h" +#include "datablocks/recipe.h" +#include "widgets/recipelistview.h" +#include "widgets/dblistviewbase.h" + +#include <tqfontmetrics.h> +#include <tqlabel.h> +#include <tqlistview.h> +#include <tqpushbutton.h> +#include <tqhbox.h> +#include <tqvbox.h> + +#include <kstringhandler.h> +#include <tdelocale.h> + +class KreListView; +class KIntSpinBox; +class RecipeDB; +class MixedNumber; + +/** +@author Unai Garro +*/ + +class CustomRecipeListItem : public RecipeListItem +{ +public: + CustomRecipeListItem( TQListView* qlv, const Recipe &r, const IngredientList &il ) : RecipeListItem( qlv, r ) + { + ingredientListStored = new TQStringList(); + IngredientList::ConstIterator ili; + for ( ili = il.begin();ili != il.end();++ili ) { + if ( (*ili).substitutes.count() > 0 ) { + TQStringList subs; + subs << ( *ili ).name; + for ( TQValueList<IngredientData>::const_iterator it = (*ili).substitutes.begin(); it != (*ili).substitutes.end(); ++it ) { + subs << (*it).name; + } + ingredientListStored->append( subs.join(TQString(" %1 ").arg(i18n("OR"))) ); + } + else + ingredientListStored->append( ( *ili ).name ); + } + + moveItem( qlv->lastItem() ); + } + CustomRecipeListItem( TQListView* qlv, const Recipe &r ) : RecipeListItem( qlv, r ) + { + ingredientListStored = 0; + + moveItem( qlv->lastItem() ); + } + + ~CustomRecipeListItem( void ) + { + delete ingredientListStored; + } + +private: + TQStringList *ingredientListStored; + +public: + virtual TQString text( int column ) const + { + if ( column == 2 && ingredientListStored ) + return ingredientListStored->join ( "," ); + else + return ( RecipeListItem::text( column ) ); + } +}; + +class SectionItem: public TQListViewItem +{ +public: + SectionItem( TQListView* qlv, TQString sectionText ) : TQListViewItem( qlv, qlv->lastItem() ) + { + mText = sectionText; + } + + ~SectionItem( void ) + {} + virtual void paintCell ( TQPainter * p, const TQColorGroup & cg, int column, int width, int align ); + +private: + TQString mText; + +public: + virtual TQString text( int column ) const + { + if ( column == 0 ) + return ( mText ); + else + return ( TQString::null ); + } +}; +class IngredientMatcherDialog: public TQWidget +{ + + TQ_OBJECT + +public: + + IngredientMatcherDialog( TQWidget *parent, RecipeDB* db ); + ~IngredientMatcherDialog(); + void reload( ReloadFlags flag = Load ); + +signals: + void recipeSelected( int, int ); + +private: + //Private variables + RecipeDB *database; + + //Widgets + + KreListView *allIngListView; + KreListView *ingListView; + + KreListView *recipeListView; + TQHBox *missingBox; + TQLabel *missingNumberLabel; + KIntSpinBox *missingNumberSpinBox; + + TQPushButton *okButton; + TQPushButton *clearButton; + TQPushButton *addButton; + TQPushButton *removeButton; + + IngredientList m_ingredientList; + TQMap<TQListViewItem*, IngredientList::iterator> m_item_ing_map; + +private slots: + void findRecipes( void ); + void unselectIngredients(); + void addIngredient(); + void removeIngredient(); + void itemRenamed( TQListViewItem*, const TQPoint &, int col ); +}; + +#endif diff --git a/src/dialogs/ingredientparserdialog.cpp b/src/dialogs/ingredientparserdialog.cpp new file mode 100644 index 0000000..0081bcf --- /dev/null +++ b/src/dialogs/ingredientparserdialog.cpp @@ -0,0 +1,299 @@ +/*************************************************************************** +* Copyright (C) 2005 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "ingredientparserdialog.h" + +#include <tqpushbutton.h> +#include <tqtextedit.h> +#include <tqlabel.h> +#include <tqlineedit.h> +#include <tqlayout.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> +#include <tqheader.h> +#include <tqapplication.h> +#include <tqclipboard.h> +#include <tqvbox.h> + +#include <tdelocale.h> +#include <kdebug.h> +#include <tdelistview.h> +#include <kpushbutton.h> +#include <tdemessagebox.h> +#include <tdeaction.h> +#include <tdepopupmenu.h> + +#include "datablocks/mixednumber.h" +#include "widgets/inglistviewitem.h" + +IngredientParserDialog::IngredientParserDialog( const UnitList &units, TQWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Ingredient Parser" ), + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok ), + m_unitList(units) +{ + setButtonBoxOrientation( Vertical ); + + TQVBox *page = makeVBoxMainWidget(); + + textLabel1 = new TQLabel( page, "textLabel1" ); + textLabel1->setTextFormat( TQLabel::RichText ); + + ingredientTextEdit = new TQTextEdit( page, "ingredientTextEdit" ); + ingredientTextEdit->setTextFormat( TQTextEdit::PlainText ); + + parseButton = new KPushButton( page, "parseButton" ); + + previewLabel = new TQLabel( page, "previewLabel" ); + previewLabel->setTextFormat( TQLabel::RichText ); + + previewIngView = new TDEListView( page, "previewIngView" ); + previewIngView->setSorting(-1); + previewIngView->addColumn( i18n( "Ingredient" ) ); + previewIngView->addColumn( i18n( "Amount" ) ); + previewIngView->addColumn( i18n( "Unit" ) ); + previewIngView->addColumn( i18n( "Preparation Method" ) ); + + languageChange(); + setInitialSize( TQSize(577, 371).expandedTo(minimumSizeHint()) ); + + previewIngView->setItemsRenameable( true ); + previewIngView->setRenameable( 0, true ); + previewIngView->setRenameable( 1, true ); + previewIngView->setRenameable( 2, true ); + previewIngView->setRenameable( 3, true ); + + previewIngView->setSelectionMode( TQListView::Extended ); + + ingredientTextEdit->setText( TQApplication::clipboard()->text() ); + ingredientTextEdit->selectAll(); + + TQWidget *buttonWidget = new TQWidget( page ); + TQHBoxLayout *buttonBox = new TQHBoxLayout(buttonWidget); + TQSpacerItem *horizontalSpacing = new TQSpacerItem( 20, 20, TQSizePolicy::Expanding, TQSizePolicy::Minimum ); + buttonGroup = new TQPushButton( i18n("Set &Header"), buttonWidget ); + TQWhatsThis::add( buttonGroup, i18n("If an ingredient header is detected as an ingredient, select it and click this button so that Krecipes will recognize it as a header. All the ingredients below the header will be included within that group.\n\nAlternatively, if you select multiple ingredients and click this button, those ingredients will be grouped together.") ); + buttonBox->addWidget( buttonGroup ); + buttonBox->addItem( horizontalSpacing ); + + TDEPopupMenu *kpop = new TDEPopupMenu( previewIngView ); + kpop->insertItem( i18n( "&Delete" ), this, TQ_SLOT( removeIngredient() ), Key_Delete ); + kpop->insertItem( i18n("Set &Header") , this, TQ_SLOT( convertToHeader() ) ); + + connect( parseButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(parseText()) ); + connect( buttonGroup, TQ_SIGNAL(clicked()), this, TQ_SLOT(convertToHeader()) ); +} + +IngredientParserDialog::~IngredientParserDialog() +{ + // no need to delete child widgets, TQt does it all for us +} + +void IngredientParserDialog::languageChange() +{ + textLabel1->setText( i18n( "To use: Paste a list of ingredient below, click \"Parse Text\", and then you may correct any incorrectly parsed ingredients.<br><b>Caution: Fields will be truncated if longer than the database allows</b>" ) ); + previewLabel->setText( i18n("Ingredients as understood by Krecipes:") ); + parseButton->setText( i18n( "Parse Text" ) ); + previewIngView->header()->setLabel( 0, i18n( "Ingredient" ) ); + previewIngView->header()->setLabel( 1, i18n( "Amount" ) ); + previewIngView->header()->setLabel( 2, i18n( "Unit" ) ); + previewIngView->header()->setLabel( 3, i18n( "Preparation Method" ) ); +} + +void IngredientParserDialog::accept() +{ + for ( TQListViewItem *it = previewIngView->firstChild(); it; it = it->nextSibling() ) { + if ( it->rtti() == INGGRPLISTVIEWITEM_RTTI ) { + TQString group = ((IngGrpListViewItem*)it)->group(); + for ( IngListViewItem *sub_it = (IngListViewItem*)it->firstChild(); sub_it; sub_it = (IngListViewItem*)sub_it->nextSibling() ) { + Ingredient ing = sub_it->ingredient(); + ing.group = group; + m_ingList.append(ing); + } + } + else + m_ingList.append(((IngListViewItem*)it)->ingredient()); + } + + TQDialog::accept(); +} + +void IngredientParserDialog::removeIngredient() +{ + delete previewIngView->selectedItem(); + if ( !previewIngView->firstChild() ) + enableButtonOK( false ); +} + +void IngredientParserDialog::convertToHeader() +{ + TQPtrList<TQListViewItem> items = previewIngView->selectedItems(); + if ( items.count() == 0 ) + return; + else if ( items.count() > 1 ) + convertToHeader(items); + else { //items.count = 1 + TQListViewItem *item = items.first(); + if ( item->rtti() == INGLISTVIEWITEM_RTTI ) { + TQListViewItem *new_item = new IngGrpListViewItem(previewIngView, + (item->parent())?item->parent():item, + ((IngListViewItem*)item)->ingredient().name, -1); + + TQListViewItem *next_sibling; + TQListViewItem *last_item = 0; + for ( TQListViewItem * it = (item->parent())?item->nextSibling():new_item->nextSibling(); it; it = next_sibling ) { + if ( it->rtti() == INGGRPLISTVIEWITEM_RTTI ) + break; + + next_sibling = it->nextSibling(); //get the next sibling of this item before we move it + + if ( it->parent() ) + it->parent()->takeItem(it); + else + previewIngView->takeItem( it ); + + new_item->insertItem( it ); + + if ( last_item ) + it->moveItem( last_item ); + last_item = it; + } + + new_item->setOpen(true); + + delete item; + } + } +} + +void IngredientParserDialog::convertToHeader( const TQPtrList<TQListViewItem> &items ) +{ + if ( items.count() > 0 ) { + TQPtrListIterator<TQListViewItem> it(items); + TQListViewItem *item = it.current(); + + if ( item->rtti() != INGLISTVIEWITEM_RTTI ) + return; + + TQString group = ((IngListViewItem*)item)->ingredient().name; + TQListViewItem *ingGroupItem = new IngGrpListViewItem(previewIngView, + (item->parent())?item->parent():item, group, -1); + delete item; //delete the ingredient header which was detected as an ingredient + ++it; + + TQListViewItem *last_item = 0; + while ( (item = it.current()) != 0 ) { + //ignore anything that isn't an ingredient (e.g. headers) + if ( item->rtti() == INGLISTVIEWITEM_RTTI ) { + if ( item->parent() ) + item->parent()->takeItem(item); + else + previewIngView->takeItem( item ); + + ingGroupItem->insertItem( item ); + + if ( last_item ) + item->moveItem( last_item ); + last_item = item; + } + + ++it; + } + + ingGroupItem->setOpen(true); + previewIngView->clearSelection(); + } +} + +void IngredientParserDialog::parseText() +{ + previewIngView->clear(); + + TQListViewItem *last_item = 0; + + int line_num = 0; + TQStringList ingredients = TQStringList::split("\n",ingredientTextEdit->text()); + for ( TQStringList::const_iterator it = ingredients.begin(); it != ingredients.end(); ++it ) { + TQString line = (*it).simplifyWhiteSpace(); + + ++line_num; + int format_at = 0; + Ingredient ing; + + + //======amount======// + int first_space = line.find( " ", format_at+1 ); + if ( first_space == -1 ) + first_space = line.length(); + + int second_space = line.find( " ", first_space+1 ); + if ( second_space == -1 ) + second_space = line.length(); + + Ingredient i; + bool ok; + i.setAmount(line.mid(format_at,second_space-format_at),&ok); + if ( !ok ) { + i.setAmount(line.mid(format_at,first_space-format_at),&ok); + if ( ok ) format_at = first_space+1; + } + else + format_at = second_space+1; + + if ( ok ) { + ing.amount = i.amount; + ing.amount_offset = i.amount_offset; + } + else + kdDebug()<<"no amount on line "<<line_num<<endl; + + + //======unit======// + first_space = line.find( " ", format_at+1 ); + if ( first_space == -1 ) + first_space = line.length(); + + bool isUnit = false; + TQString unitCheck = line.mid(format_at,first_space-format_at); + + for ( UnitList::const_iterator unit_it = m_unitList.begin(); unit_it != m_unitList.end(); ++unit_it ) { + if ( (*unit_it).name == unitCheck || (*unit_it).plural == unitCheck || (*unit_it).name_abbrev == unitCheck || (*unit_it).plural_abbrev == unitCheck ) { + isUnit = true; + format_at = first_space+1; + break; + } + } + + if ( isUnit ) { + ing.units.name = unitCheck; + ing.units.plural = unitCheck; + } + else + kdDebug()<<"no unit on line "<<line_num<<endl; + + + //======ingredient======// + int ing_end = line.find( TQRegExp("(,|;)"), format_at+1 ); + if ( ing_end == -1 ) + ing_end = line.length(); + + ing.name = line.mid(format_at,ing_end-format_at); + format_at = ing_end+2; + + + //======prep method======// + int end = line.length(); + ing.prepMethodList = ElementList::split(",",line.mid(format_at,end-format_at)); + + last_item = new IngListViewItem(previewIngView,last_item,ing); + enableButtonOK( true ); + } +} + +#include "ingredientparserdialog.moc" diff --git a/src/dialogs/ingredientparserdialog.h b/src/dialogs/ingredientparserdialog.h new file mode 100644 index 0000000..f9a6dbb --- /dev/null +++ b/src/dialogs/ingredientparserdialog.h @@ -0,0 +1,65 @@ +/*************************************************************************** +* Copyright (C) 2005 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef INGREDIENTPARSERDIALOG_H +#define INGREDIENTPARSERDIALOG_H + +#include <kdialogbase.h> + +#include "datablocks/ingredientlist.h" +#include "datablocks/unit.h" + +class TQVBoxLayout; +class TQHBoxLayout; +class TQGridLayout; +class TQSpacerItem; +class TQLabel; +class TQTextEdit; +class TQLineEdit; +class KPushButton; +class TDEListView; +class TQListViewItem; +class TQPushButton; + +class IngredientParserDialog : public KDialogBase +{ + TQ_OBJECT + +public: + IngredientParserDialog( const UnitList &units, TQWidget* parent = 0, const char* name = 0 ); + ~IngredientParserDialog(); + + IngredientList ingredients() const { return m_ingList; } + +protected: + TQLabel* textLabel1; + TQLabel *previewLabel; + TQTextEdit* ingredientTextEdit; + KPushButton* parseButton; + TDEListView* previewIngView; + TQPushButton* buttonGroup; + +protected slots: + virtual void accept(); + void parseText(); + void removeIngredient(); + + //Set Header button slot + virtual void convertToHeader(); + virtual void languageChange(); + +private: + void convertToHeader( const TQPtrList<TQListViewItem> &items ); + + UnitList m_unitList; + IngredientList m_ingList; +}; + +#endif // INGREDIENTPARSERDIALOG_H diff --git a/src/dialogs/ingredientsdialog.cpp b/src/dialogs/ingredientsdialog.cpp new file mode 100644 index 0000000..358e01f --- /dev/null +++ b/src/dialogs/ingredientsdialog.cpp @@ -0,0 +1,702 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "ingredientsdialog.h" +#include "backends/recipedb.h" +#include "createelementdialog.h" +#include "datablocks/ingredientpropertylist.h" +#include "datablocks/mixednumber.h" +#include "datablocks/weight.h" +#include "unitsdialog.h" +#include "usdadatadialog.h" +#include "selectpropertydialog.h" +#include "selectunitdialog.h" +#include "dependanciesdialog.h" +#include "widgets/ingredientlistview.h" +#include "widgets/weightinput.h" +#include "dialogs/ingredientgroupsdialog.h" +#include "dialogs/createingredientweightdialog.h" + +#include <tdeapplication.h> +#include <kcursor.h> +#include <kdebug.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <tdeglobal.h> +#include <tdeconfig.h> + +#include <tqheader.h> +#include <tqmessagebox.h> +#include <tqtabwidget.h> + +class WeightListItem : public TQListViewItem +{ +public: + WeightListItem( TQListView *listview, TQListViewItem *item, const Weight &w ) : TQListViewItem(listview,item), m_weight(w){} + + void setWeight( const Weight &w ) { m_weight = w; } + Weight weight() const { return m_weight; } + + void setAmountUnit( double amount, const Unit &unit, const Element &prepMethod ) + { + m_weight.perAmount = amount; + m_weight.perAmountUnitID = unit.id; + m_weight.perAmountUnit = (m_weight.perAmount>1)?unit.plural:unit.name; + m_weight.prepMethodID = prepMethod.id; + m_weight.prepMethod = prepMethod.name; + } + + void setWeightUnit( double weight, const Unit &unit ) + { + m_weight.weight = weight; + m_weight.weightUnitID = unit.id; + m_weight.weightUnit = (m_weight.weight>1)?unit.plural:unit.name; + } + + virtual TQString text( int c ) const + { + if ( c == 0 ) + return TQString::number(m_weight.weight)+" "+m_weight.weightUnit; + else if ( c == 1 ) + return TQString::number(m_weight.perAmount)+" " + +m_weight.perAmountUnit + +((m_weight.prepMethodID!=-1)?", "+m_weight.prepMethod:TQString::null); + else + return TQString::null; + } + +private: + Weight m_weight; +}; + +IngredientsDialog::IngredientsDialog( TQWidget* parent, RecipeDB *db ) : TQWidget( parent ) +{ + + // Store pointer to database + database = db; + + // Initialize internal variables + propertiesList = new IngredientPropertyList; + perUnitListBack = new ElementList; + + // Design dialog + + TQHBoxLayout* page_layout = new TQHBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); + + TQTabWidget *tabWidget = new TQTabWidget( this ); + + TQWidget *ingredientTab = new TQWidget( tabWidget ); + + layout = new TQGridLayout( ingredientTab, 1, 1, 0, 0 ); + TQSpacerItem* spacer_left = new TQSpacerItem( 10, 10, TQSizePolicy::Fixed, TQSizePolicy::Minimum ); + layout->addItem( spacer_left, 1, 0 ); + TQSpacerItem* spacer_top = new TQSpacerItem( 10, 10, TQSizePolicy::Minimum, TQSizePolicy::Fixed ); + layout->addItem( spacer_top, 0, 1 ); + + ingredientListView = new KreListView ( ingredientTab, i18n( "Ingredient list" ), true, 0 ); + StdIngredientListView *list_view = new StdIngredientListView( ingredientListView, database, true ); + ingredientListView->setListView( list_view ); + layout->addMultiCellWidget ( ingredientListView, 1, 5, 1, 1 ); + ingredientListView->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding ) ); + + TQSpacerItem* spacer_rightIngredients = new TQSpacerItem( 10, 10, TQSizePolicy::Fixed, TQSizePolicy::Minimum ); + layout->addItem( spacer_rightIngredients, 1, 2 ); + + + addIngredientButton = new TQPushButton( ingredientTab ); + addIngredientButton->setText( "+" ); + layout->addWidget( addIngredientButton, 1, 3 ); + addIngredientButton->setMinimumSize( TQSize( 30, 30 ) ); + addIngredientButton->setMaximumSize( TQSize( 30, 30 ) ); + addIngredientButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) ); + addIngredientButton->setFlat( true ); + + removeIngredientButton = new TQPushButton( ingredientTab ); + removeIngredientButton->setText( "-" ); + layout->addWidget( removeIngredientButton, 3, 3 ); + removeIngredientButton->setMinimumSize( TQSize( 30, 30 ) ); + removeIngredientButton->setMaximumSize( TQSize( 30, 30 ) ); + removeIngredientButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) ); + removeIngredientButton->setFlat( true ); + + TQSpacerItem* spacer_Ing_Buttons = new TQSpacerItem( 10, 10, TQSizePolicy::Minimum, TQSizePolicy::Fixed ); + layout->addItem( spacer_Ing_Buttons, 2, 3 ); + + + TQSpacerItem* spacer_Ing_Units = new TQSpacerItem( 30, 5, TQSizePolicy::Fixed, TQSizePolicy::Minimum ); + layout->addItem( spacer_Ing_Units, 1, 4 ); + + + TDEConfig *config = TDEGlobal::config(); + config->setGroup( "Advanced" ); + bool show_id = config->readBoolEntry( "ShowID", false ); + + TQScrollView *scrollView1 = new TQScrollView( ingredientTab, "scrollView1" ); + scrollView1->enableClipper(true); + TQWidget *rightWidget = new TQWidget(scrollView1); + TQGridLayout *rightLayout = new TQGridLayout( rightWidget, 1, 1, 0, 0 ); + + unitsListView = new KreListView ( rightWidget, i18n( "Unit list" ) ); + unitsListView->listView() ->addColumn( i18n( "Units" ) ); + unitsListView->listView() ->addColumn( i18n( "Id" ), show_id ? -1 : 0 ); + unitsListView->listView() ->setSorting( 0 ); + unitsListView->listView() ->setAllColumnsShowFocus( true ); + rightLayout->addMultiCellWidget ( unitsListView, 1, 4, 0, 0 ); + unitsListView->listView() ->setMinimumWidth( 150 ); + unitsListView->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding ) ); + + TQSpacerItem* spacer_rightUnits = new TQSpacerItem( 5, 5, TQSizePolicy::Fixed, TQSizePolicy::Minimum ); + rightLayout->addItem( spacer_rightUnits, 1, 1 ); + + addUnitButton = new TQPushButton( rightWidget ); + addUnitButton->setText( "+" ); + rightLayout->addWidget( addUnitButton, 1, 2 ); + addUnitButton->resize( TQSize( 30, 30 ) ); + addUnitButton->setMinimumSize( TQSize( 30, 30 ) ); + addUnitButton->setMaximumSize( TQSize( 30, 30 ) ); + addUnitButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) ); + addUnitButton->setFlat( true ); + + removeUnitButton = new TQPushButton( rightWidget ); + removeUnitButton->setText( "-" ); + rightLayout->addWidget( removeUnitButton, 3, 2 ); + removeUnitButton->resize( TQSize( 30, 30 ) ); + removeUnitButton->setMinimumSize( TQSize( 30, 30 ) ); + removeUnitButton->setMaximumSize( TQSize( 30, 30 ) ); + removeUnitButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) ); + removeUnitButton->setFlat( true ); + TQSpacerItem* spacer_Units_Properties = new TQSpacerItem( 10, 10, TQSizePolicy::Minimum, TQSizePolicy::Fixed ); + rightLayout->addItem( spacer_Units_Properties, 2, 2 ); + + + propertiesListView = new KreListView ( rightWidget, i18n( "Ingredient Properties" ) ); + rightLayout->addMultiCellWidget ( propertiesListView, 6, 9, 0, 0 ); + + propertiesListView->listView() ->addColumn( i18n( "Property" ) ); + propertiesListView->listView() ->addColumn( i18n( "Amount" ) ); + propertiesListView->listView() ->addColumn( i18n( "Units" ) ); + propertiesListView->listView() ->addColumn( i18n( "Id" ), show_id ? -1 : 0 ); + propertiesListView->listView() ->setAllColumnsShowFocus( true ); + propertiesListView->listView() ->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding ) ); + propertiesListView->listView() ->setSorting( -1 ); // Disable sorting. For the moment, the order is important to identify the per_units ID corresponding to this row. So the user shouldn't change this order. + + addPropertyButton = new TQPushButton( rightWidget ); + addPropertyButton->setText( "+" ); + rightLayout->addWidget( addPropertyButton, 6, 2 ); + addPropertyButton->resize( TQSize( 30, 30 ) ); + addPropertyButton->setMinimumSize( TQSize( 30, 30 ) ); + addPropertyButton->setMaximumSize( TQSize( 30, 30 ) ); + addPropertyButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) ); + addPropertyButton->setFlat( true ); + + removePropertyButton = new TQPushButton( rightWidget ); + removePropertyButton->setText( "-" ); + rightLayout->addWidget( removePropertyButton, 8, 2 ); + removePropertyButton->resize( TQSize( 30, 30 ) ); + removePropertyButton->setMinimumSize( TQSize( 30, 30 ) ); + removePropertyButton->setMaximumSize( TQSize( 30, 30 ) ); + removePropertyButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) ); + removePropertyButton->setFlat( true ); + + TQSpacerItem* spacer_Prop_Buttons = new TQSpacerItem( 9, 10, TQSizePolicy::Minimum, TQSizePolicy::Fixed ); + rightLayout->addItem( spacer_Prop_Buttons, 7, 2 ); + + weightsListView = new KreListView ( rightWidget, i18n( "Ingredient Weights" ) ); + weightsListView->listView() ->addColumn( i18n( "Weight" ) ); + weightsListView->listView() ->addColumn( i18n( "Per Amount" ) ); + weightsListView->listView() ->setAllColumnsShowFocus( true ); + rightLayout->addMultiCellWidget ( weightsListView, 10, 14, 0, 0 ); + weightsListView->listView() ->setMinimumWidth( 150 ); + weightsListView->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding ) ); + + //TQSpacerItem* spacer_rightWeights = new TQSpacerItem( 5, 5, TQSizePolicy::Fixed, TQSizePolicy::Minimum ); + //layout->addItem( spacer_rightWeights, 1, 6 ); + + addWeightButton = new TQPushButton( rightWidget ); + addWeightButton->setText( "+" ); + rightLayout->addWidget( addWeightButton, 10, 2 ); + addWeightButton->resize( TQSize( 30, 30 ) ); + addWeightButton->setMinimumSize( TQSize( 30, 30 ) ); + addWeightButton->setMaximumSize( TQSize( 30, 30 ) ); + addWeightButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) ); + addWeightButton->setFlat( true ); + + removeWeightButton = new TQPushButton( rightWidget ); + removeWeightButton->setText( "-" ); + rightLayout->addWidget( removeWeightButton, 12, 2 ); + removeWeightButton->resize( TQSize( 30, 30 ) ); + removeWeightButton->setMinimumSize( TQSize( 30, 30 ) ); + removeWeightButton->setMaximumSize( TQSize( 30, 30 ) ); + removeWeightButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) ); + removeWeightButton->setFlat( true ); + + TQSpacerItem* spacer_Weight_Properties = new TQSpacerItem( 10, 10, TQSizePolicy::Minimum, TQSizePolicy::Fixed ); + rightLayout->addItem( spacer_Weight_Properties, 11, 2 ); + + TQSpacerItem* spacerBottom = new TQSpacerItem( 10, 10, TQSizePolicy::Fixed, TQSizePolicy::Expanding ); + rightLayout->addItem( spacerBottom, 13, 2 ); + + scrollView1->setResizePolicy( TQScrollView::AutoOneFit ); + layout->addMultiCellWidget(scrollView1,1,4,5,5); + + TQPushButton *loadUsdaButton = new TQPushButton( ingredientTab ); + loadUsdaButton->setText( i18n( "Load USDA data" ) ); + loadUsdaButton->setFlat( true ); + layout->addWidget(loadUsdaButton,5,5); + + scrollView1->addChild(rightWidget); + scrollView1->setSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::Ignored ); + + + inputBox = new KDoubleNumInput( propertiesListView->listView() ->viewport() ); + propertiesListView->listView() ->addChild( inputBox ); + inputBox->hide(); + + tabWidget->insertTab( ingredientTab, i18n( "Ingredients" ) ); + + groupsDialog = new IngredientGroupsDialog(database,tabWidget,"groupsDialog"); + tabWidget->insertTab( groupsDialog, i18n( "Headers" ) ); + + page_layout->addWidget( tabWidget ); + + // Initialize + unitList = new UnitList; + + // Signals & Slots + connect( ingredientListView->listView(), TQ_SIGNAL( selectionChanged() ), this, TQ_SLOT( updateLists() ) ); + connect( addIngredientButton, TQ_SIGNAL( clicked() ), list_view, TQ_SLOT( createNew() ) ); + connect( addUnitButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( addUnitToIngredient() ) ); + connect( removeUnitButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( removeUnitFromIngredient() ) ); + connect( addWeightButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( addWeight() ) ); + connect( removeWeightButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( removeWeight() ) ); + connect( removeIngredientButton, TQ_SIGNAL( clicked() ), list_view, TQ_SLOT( remove + () ) ); + connect( addPropertyButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( addPropertyToIngredient() ) ); + connect( removePropertyButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( removePropertyFromIngredient() ) ); + connect( propertiesListView->listView(), TQ_SIGNAL( executed( TQListViewItem* ) ), this, TQ_SLOT( insertPropertyEditBox( TQListViewItem* ) ) ); + connect( propertiesListView->listView(), TQ_SIGNAL( selectionChanged() ), inputBox, TQ_SLOT( hide() ) ); + connect( inputBox, TQ_SIGNAL( valueChanged( double ) ), this, TQ_SLOT( setPropertyAmount( double ) ) ); + + connect( weightsListView->listView(), TQ_SIGNAL( doubleClicked( TQListViewItem*, const TQPoint &, int ) ), TQ_SLOT( itemRenamed( TQListViewItem*, const TQPoint &, int ) ) ); + + connect( loadUsdaButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( openUSDADialog() ) ); +} + + +IngredientsDialog::~IngredientsDialog() +{ + delete unitList; + delete perUnitListBack; + delete propertiesList; +} + +void IngredientsDialog::reloadIngredientList( ReloadFlags flag ) +{ + ( ( StdIngredientListView* ) ingredientListView->listView() ) ->reload(flag); + + // Reload Unit List + updateLists(); + +} + +void IngredientsDialog::reloadUnitList() +{ + + int ingredientID = -1; + // Find selected ingredient + TQListViewItem *it; + it = ingredientListView->listView() ->selectedItem(); + + if ( it ) { // Check if an ingredient is selected first + ingredientID = it->text( 1 ).toInt(); + } + + + unitList->clear(); + unitsListView->listView() ->clear(); + + if ( ingredientID >= 0 ) { + database->loadPossibleUnits( ingredientID, unitList ); + + //Populate this data into the TDEListView + + for ( UnitList::const_iterator unit_it = unitList->begin(); unit_it != unitList->end(); ++unit_it ) { + if ( !( *unit_it ).name.isEmpty() ) { + ( void ) new TQListViewItem( unitsListView->listView(), ( *unit_it ).name, TQString::number( ( *unit_it ).id ) ); + } + } + + // Select the first unit + unitsListView->listView() ->setSelected( unitsListView->listView() ->firstChild(), true ); + + } +} + +void IngredientsDialog::addWeight() +{ + TQListViewItem *it = ingredientListView->listView()->selectedItem(); + if ( it ) { + CreateIngredientWeightDialog weightDialog( this, database ); + if ( weightDialog.exec() == TQDialog::Accepted ) { + Weight w = weightDialog.weight(); + w.ingredientID = it->text( 1 ).toInt(); + database->addIngredientWeight( w ); + + TQListViewItem * lastElement = weightsListView->listView()->lastItem(); + + WeightListItem *weight_it = new WeightListItem( weightsListView->listView(), lastElement, w ); + weight_it->setAmountUnit( w.perAmount, database->unitName(w.perAmountUnitID), + Element(w.prepMethod,w.prepMethodID) + ); + weight_it->setWeightUnit( w.weight, database->unitName(w.weightUnitID) ); + } + } +} + +void IngredientsDialog::removeWeight() +{ + TQListViewItem *it = weightsListView->listView() ->selectedItem(); + if ( it ) { + switch ( KMessageBox::warningContinueCancel(this, i18n("Recipes may require this information for nutrient analysis. Are you sure you want to delete this entry?"), TQString::null, KStdGuiItem::cont(), "DeleteIngredientWeight") ) { + case KMessageBox::Continue: + database->removeIngredientWeight( ((WeightListItem*)it)->weight().id ); + delete it; + break; + default: break; + } + } +} + +void IngredientsDialog::itemRenamed( TQListViewItem* item, const TQPoint &, int col ) +{ + WeightListItem *weight_it = (WeightListItem*)item; + Weight w = weight_it->weight(); + + if ( col == 0 ) { + KDialogBase amountEditDialog(this,"WeightAmountEdit", + 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, Unit::Mass, MixedNumber::DecimalFormat ); + + WeightListItem *it = (WeightListItem*)item; + Weight w = it->weight(); + + amountEdit->setAmount( w.weight ); + amountEdit->setUnit( Unit(w.weightUnit,w.weightUnit,w.weightUnitID) ); + + amountEditDialog.setMainWidget(box); + + if ( amountEditDialog.exec() == TQDialog::Accepted ) { + MixedNumber amount = amountEdit->amount(); + Unit unit = amountEdit->unit(); + + it->setWeightUnit( amount.toDouble(), unit ); + database->addIngredientWeight( it->weight() ); + } + } + else if ( col == 1 ) { + KDialogBase amountEditDialog(this,"PerAmountEdit", + false, i18n("Enter amount"), KDialogBase::Cancel | KDialogBase::Ok, KDialogBase::Ok); + + TQGroupBox *box = new TQGroupBox( 1, Horizontal, i18n("Amount"), &amountEditDialog ); + WeightInput *amountEdit = new WeightInput( box, database, Unit::All, MixedNumber::DecimalFormat ); + + WeightListItem *it = (WeightListItem*)item; + Weight w = it->weight(); + + amountEdit->setAmount( w.perAmount ); + amountEdit->setUnit( Unit(w.perAmountUnit,w.perAmountUnit,w.perAmountUnitID) ); + amountEdit->setPrepMethod( Element(w.prepMethod,w.prepMethodID) ); + + amountEditDialog.setMainWidget(box); + + if ( amountEditDialog.exec() == TQDialog::Accepted ) { + MixedNumber amount = amountEdit->amount(); + Unit unit = amountEdit->unit(); + + it->setAmountUnit( amount.toDouble(), unit, amountEdit->prepMethod() ); + database->addIngredientWeight( it->weight() ); + } + } +} + +void IngredientsDialog::addUnitToIngredient( void ) +{ + + // Find selected ingredient item + TQListViewItem * it; + int ingredientID = -1; + if ( ( it = ingredientListView->listView() ->selectedItem() ) ) { + ingredientID = it->text( 1 ).toInt(); + } + if ( ingredientID >= 0 ) // an ingredient was selected previously + { + UnitList allUnits; + database->loadUnits( &allUnits ); + + SelectUnitDialog unitsDialog( this, allUnits, SelectUnitDialog::HideEmptyUnit ); + + if ( unitsDialog.exec() == TQDialog::Accepted ) + { + int unitID = unitsDialog.unitID(); + + if ( !( database->ingredientContainsUnit( ingredientID, unitID ) ) ) + database->addUnitToIngredient( ingredientID, unitID ); // Add chosen unit to ingredient in database + else { + TQMessageBox::information( this, i18n( "Unit Exists" ), i18n( "The ingredient contains already the unit that you have chosen." ) ); + } + reloadUnitList(); // Reload the list from database + } + } +} + +void IngredientsDialog::removeUnitFromIngredient( void ) +{ + + // Find selected ingredient/unit item combination + TQListViewItem * it; + int ingredientID = -1, unitID = -1; + if ( ( it = ingredientListView->listView() ->selectedItem() ) ) + ingredientID = it->text( 1 ).toInt(); + if ( ( it = unitsListView->listView() ->selectedItem() ) ) + unitID = it->text( 1 ).toInt(); + + if ( ( ingredientID >= 0 ) && ( unitID >= 0 ) ) // an ingredient/unit combination was selected previously + { + ElementList dependingRecipes, dependingPropertiesInfo; + + database->findIngredientUnitDependancies( ingredientID, unitID, &dependingRecipes, &dependingPropertiesInfo ); + + TQValueList<ListInfo> lists; + if ( !dependingRecipes.isEmpty() ) { + ListInfo info; + info.list = dependingRecipes; + info.name = i18n("Recipes"); + lists << info; + } + if ( !dependingPropertiesInfo.isEmpty() ) { + ListInfo info; + info.list = dependingPropertiesInfo; + info.name = i18n("Properties"); + lists << info; + } + + if ( lists.isEmpty() ) + database->removeUnitFromIngredient( ingredientID, unitID ); + else + { // must warn! + DependanciesDialog warnDialog( this, lists ); + if ( !dependingRecipes.isEmpty() ) + warnDialog.setCustomWarning( i18n("You are about to permanantly delete recipes from your database.") ); + if ( warnDialog.exec() == TQDialog::Accepted ) + database->removeUnitFromIngredient( ingredientID, unitID ); + } + reloadUnitList(); // Reload the list from database + reloadPropertyList(); // Properties could have been removed if a unit is removed, so we need to reload. + } +} + +void IngredientsDialog:: reloadPropertyList( void ) +{ + propertiesList->clear(); + propertiesListView->listView() ->clear(); + perUnitListBack->clear(); + + inputBox->hide(); + + + //If none is selected, select first item + TQListViewItem *it; + it = ingredientListView->listView() ->selectedItem(); + + //Populate this data into the TDEListView + if ( it ) { // make sure that the ingredient list is not empty + + database->loadProperties( propertiesList, it->text( 1 ).toInt() ); // load the list for this ingredient + for ( IngredientPropertyList::const_iterator prop_it = propertiesList->begin(); prop_it != propertiesList->end(); ++prop_it ) { + TQListViewItem * lastElement = propertiesListView->listView() ->lastItem(); + //Insert property after the last one (it's important to keep the order in the case of the properties to be able to identify the per_units ID later on). + ( void ) new TQListViewItem( propertiesListView->listView(), lastElement, (*prop_it).name, TQString::number( (*prop_it).amount ), (*prop_it).units + TQString( "/" ) + (*prop_it).perUnit.name, TQString::number( (*prop_it).id ) ); + // Store the perUnits with the ID for using later + Element perUnitEl; + perUnitEl.id = (*prop_it).perUnit.id; + perUnitEl.name = (*prop_it).perUnit.name; + perUnitListBack->append( perUnitEl ); + + } + } +} + +void IngredientsDialog::reloadWeightList( void ) +{ + weightsListView->listView() ->clear(); + + //If none is selected, select first item + TQListViewItem *it = ingredientListView->listView() ->selectedItem(); + + //Populate this data into the TDEListView + if ( it ) { // make sure that the ingredient list is not empty + WeightList list = database->ingredientWeightUnits( it->text( 1 ).toInt() ); // load the list for this ingredient + for ( WeightList::const_iterator weight_it = list.begin(); weight_it != list.end(); ++weight_it ) { + TQListViewItem * lastElement = weightsListView->listView() ->lastItem(); + + Weight w = *weight_it; + WeightListItem *weight_it1 = new WeightListItem( weightsListView->listView(), lastElement, w ); + weight_it1->setAmountUnit( w.perAmount, + database->unitName(w.perAmountUnitID), + Element((w.prepMethodID==-1)?TQString::null:database->prepMethodName(w.prepMethodID),w.prepMethodID) + ); + weight_it1->setWeightUnit( w.weight, database->unitName(w.weightUnitID) ); + } + } +} + +void IngredientsDialog:: updateLists( void ) +{ + reloadUnitList(); + reloadPropertyList(); + reloadWeightList(); +} + +void IngredientsDialog::addPropertyToIngredient( void ) +{ + + // Find selected ingredient item + TQListViewItem * it; + int ingredientID = -1; + if ( ( it = ingredientListView->listView() ->selectedItem() ) ) { + ingredientID = it->text( 1 ).toInt(); + } + if ( ingredientID >= 0 ) // an ingredient was selected previously + { + IngredientPropertyList allProperties; + database->loadProperties( &allProperties ); + UnitList unitList; + database->loadPossibleUnits( ingredientID, &unitList ); + SelectPropertyDialog propertyDialog( this, &allProperties, &unitList, SelectPropertyDialog::HideEmptyUnit ); + + if ( propertyDialog.exec() == TQDialog::Accepted ) + { + + int propertyID = propertyDialog.propertyID(); + int perUnitsID = propertyDialog.perUnitsID(); + if ( !( database->ingredientContainsProperty( ingredientID, propertyID, perUnitsID ) ) ) { + if ( ( propertyID >= 0 ) && ( perUnitsID >= 0 ) ) // check if the property is not -1 ... (not selected) + database->addPropertyToIngredient( ingredientID, propertyID, 0, perUnitsID ); // Add result chosen property to ingredient in database, with amount 0 by default + } + else { + TQMessageBox::information( this, i18n( "Property Exists" ), i18n( "The property you tried to add already exists in the ingredient with the same per units." ) ); + } + reloadPropertyList(); // Reload the list from database + } + } +} + +void IngredientsDialog::removePropertyFromIngredient( void ) +{ + + // Find selected ingredient/property item combination + TQListViewItem * it; + int ingredientID = -1, propertyID = -1; + int perUnitsID = -1; + if ( ( it = ingredientListView->listView() ->selectedItem() ) ) + ingredientID = it->text( 1 ).toInt(); + if ( ( it = propertiesListView->listView() ->selectedItem() ) ) + propertyID = it->text( 3 ).toInt(); + if ( propertyID >= 0 ) + perUnitsID = perUnitListBack->getElement( findPropertyNo( it ) ).id ; + + if ( ( ingredientID >= 0 ) && ( propertyID >= 0 ) && ( perUnitsID >= 0 ) ) // an ingredient/property combination was selected previously + { + ElementList results; + database->removePropertyFromIngredient( ingredientID, propertyID, perUnitsID ); + + reloadPropertyList(); // Reload the list from database + + } +} + +void IngredientsDialog::insertPropertyEditBox( TQListViewItem* it ) +{ + TQRect r = propertiesListView->listView() ->header() ->sectionRect( 1 ); + + r.moveBy( 0, propertiesListView->listView() ->itemRect( it ).y() ); //Move down to the item, note that its height is same as header's right now. + + r.setHeight( it->height() ); // Set the item's height + + inputBox->setGeometry( r ); + + inputBox->setValue( it->text( 1 ).toDouble() ); + inputBox->show(); +} + +void IngredientsDialog::setPropertyAmount( double amount ) +{ + TQListViewItem *ing_it = ingredientListView->listView() ->selectedItem(); // Find selected ingredient + TQListViewItem *prop_it = propertiesListView->listView() ->selectedItem(); + + if ( ing_it && prop_it ) // Appart from property, Check if an ingredient is selected first, just in case + { + prop_it->setText( 1, TQString::number( amount ) ); + int propertyID = prop_it->text( 3 ).toInt(); + int ingredientID = ing_it->text( 1 ).toInt(); + int per_units = perUnitListBack->getElement( findPropertyNo( prop_it ) ).id ; + database->changePropertyAmountToIngredient( ingredientID, propertyID, amount, per_units ); + } +} + +int IngredientsDialog::findPropertyNo( TQListViewItem * /*it*/ ) +{ + bool found = false; + int i = 0; + TQListViewItem* item = propertiesListView->listView() ->firstChild(); + while ( i < propertiesListView->listView() ->childCount() && !found ) { + if ( item == propertiesListView->listView() ->currentItem() ) + found = true; + else { + item = item->nextSibling(); + ++i; + } + } + if ( found ) { + return ( i ); + } + else { + return ( -1 ); + } +} + +void IngredientsDialog::reload( ReloadFlags flag ) +{ + reloadIngredientList( flag ); + groupsDialog->reload( flag ); +} + +void IngredientsDialog::openUSDADialog( void ) +{ + TQListViewItem * ing_it = ingredientListView->listView() ->selectedItem(); // Find selected ingredient + if ( ing_it ) { + TDEApplication::setOverrideCursor( KCursor::waitCursor() ); + USDADataDialog usda_dialog( Element( ing_it->text( 0 ), ing_it->text( 1 ).toInt() ), database, this ); + TDEApplication::restoreOverrideCursor(); + + if ( usda_dialog.exec() == TQDialog::Accepted ) { + reloadPropertyList(); //update property list upon success + reloadWeightList(); + } + } + else + TQMessageBox::information( this, TQString::null, i18n( "No ingredient selected." ) ); +} + +#include "ingredientsdialog.moc" diff --git a/src/dialogs/ingredientsdialog.h b/src/dialogs/ingredientsdialog.h new file mode 100644 index 0000000..32af993 --- /dev/null +++ b/src/dialogs/ingredientsdialog.h @@ -0,0 +1,93 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef INGREDIENTSDIALOG_H +#define INGREDIENTSDIALOG_H + +#include <tqpushbutton.h> +#include <tqvbox.h> +#include <tqlayout.h> +#include <tqwidget.h> +#include <knuminput.h> + +#include "widgets/krelistview.h" +#include "widgets/dblistviewbase.h" +#include "datablocks/unit.h" + +class KDoubleNumInput; + +class RecipeDB; +class ElementList; +class SelectUnitDialog; +class CreateElementDialog; +class IngredientPropertyList; +class SelectPropertyDialog; +class UnitsDialog; +class IngredientGroupsDialog; +class MixedNumber; + +class IngredientsDialog: public TQWidget +{ +TQ_OBJECT + +public: + IngredientsDialog( TQWidget* parent, RecipeDB *db ); + ~IngredientsDialog(); + void reload( ReloadFlags flag = Load ); + +private: + // Widgets + TQGridLayout* layout; + TQPushButton* addIngredientButton; + TQPushButton* removeIngredientButton; + TQPushButton* addUnitButton; + TQPushButton* removeUnitButton; + TQPushButton* addPropertyButton; + TQPushButton* removePropertyButton; + TQPushButton* addWeightButton; + TQPushButton* removeWeightButton; + KreListView* ingredientListView; + KreListView* unitsListView; + KreListView* propertiesListView; + KreListView* weightsListView; + TQPushButton* pushButton5; + KDoubleNumInput* inputBox; + IngredientGroupsDialog *groupsDialog; + + // Internal Methods + void reloadIngredientList( ReloadFlags flag = Load ); + void reloadUnitList( void ); + void reloadPropertyList( void ); + void reloadWeightList( void ); + int findPropertyNo( TQListViewItem *it ); + + // Internal Variables + RecipeDB *database; + UnitList *unitList; + IngredientPropertyList *propertiesList; + ElementList *perUnitListBack; + +private slots: + void addUnitToIngredient( void ); + void removeUnitFromIngredient( void ); + void addWeight(); + void removeWeight(); + void updateLists( void ); + void addPropertyToIngredient( void ); + void removePropertyFromIngredient( void ); + void insertPropertyEditBox( TQListViewItem* it ); + void setPropertyAmount( double amount ); + void openUSDADialog( void ); + void itemRenamed( TQListViewItem*, const TQPoint &, int col ); +}; + +#endif diff --git a/src/dialogs/pagesetupdialog.cpp b/src/dialogs/pagesetupdialog.cpp new file mode 100644 index 0000000..08e3fda --- /dev/null +++ b/src/dialogs/pagesetupdialog.cpp @@ -0,0 +1,310 @@ +/*************************************************************************** +* Copyright (C) 2003-2005 by Jason Kivlighn * +* (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "pagesetupdialog.h" + +#include <tqdir.h> +#include <tqlayout.h> +#include <tqhbox.h> +#include <tqfileinfo.h> +#include <tqpushbutton.h> +#include <tqpopupmenu.h> +#include <tqtooltip.h> +#include <tqtabwidget.h> +#include <tqlabel.h> + +#include <tdehtmlview.h> +#include <tdeapplication.h> +#include <kdebug.h> +#include <tdefiledialog.h> +#include <tdelocale.h> +#include <kiconloader.h> +#include <tdemessagebox.h> +#include <kstandarddirs.h> +#include <tdeaction.h> +#include <tdeconfig.h> +#include <kstdaction.h> +#include <tdetoolbar.h> +#include <tdepopupmenu.h> + +#include "setupdisplay.h" + +PageSetupDialog::PageSetupDialog( TQWidget *parent, const Recipe &sample, const TQString &configEntry ) : KDialog( parent, 0, true ), m_configEntry(configEntry) +{ + TDEIconLoader il; + + TQVBoxLayout * layout = new TQVBoxLayout( this ); + + TDEToolBar *toolbar = new TDEToolBar( this ); + TDEActionCollection *actionCollection = new TDEActionCollection( this ); + + TDEAction *std_open = KStdAction::open( 0, 0, 0 ); //use this to create a custom open action + TDEToolBarPopupAction *custom_open = new TDEToolBarPopupAction( std_open->text(), std_open->icon(), std_open->shortcut(), this, TQ_SLOT( loadFile() ), actionCollection, "open_popup" ); + + TDEPopupMenu *open_popup = custom_open->popupMenu(); + + open_popup->insertTitle( i18n( "Styles" ) ); + TQDir included_layouts( getIncludedLayoutDir(), "*.klo", TQDir::Name | TQDir::IgnoreCase, TQDir::Files ); + for ( unsigned int i = 0; i < included_layouts.count(); i++ ) { + int id = open_popup->insertItem( included_layouts[ i ].left(included_layouts[ i ].find(".")), this, TQ_SLOT( loadLayout( int ) ) ); + included_layouts_map.insert( id, included_layouts[ i ] ); + } + + open_popup->insertTitle( i18n( "Templates" ) ); + TQDir included_templates( getIncludedLayoutDir(), "*.template", TQDir::Name | TQDir::IgnoreCase, TQDir::Files ); + for ( unsigned int i = 0; i < included_templates.count(); i++ ) { + int id = open_popup->insertItem( included_templates[ i ].left(included_templates[ i ].find(".")).replace("_"," "), this, TQ_SLOT( loadTemplate( int ) ) ); + included_layouts_map.insert( id, included_templates[ i ] ); + } + + custom_open->plug( toolbar ); + + KStdAction::save( this, TQ_SLOT( saveLayout() ), actionCollection ) ->plug( toolbar ); + KStdAction::saveAs( this, TQ_SLOT( saveAsLayout() ), actionCollection ) ->plug( toolbar ); + KStdAction::redisplay( this, TQ_SLOT( reloadLayout() ), actionCollection ) ->plug( toolbar ); + + TDEToolBarPopupAction *shown_items = new TDEToolBarPopupAction( i18n( "Items Shown" ), "frame_edit" ); + shown_items->setDelayed( false ); + shown_items_popup = shown_items->popupMenu(); + shown_items_popup->insertTitle( i18n( "Show Items" ) ); + shown_items->plug( toolbar ); + layout->addWidget( toolbar ); + + TQLabel *help = new TQLabel(i18n("<i>Usage: Right-click any element to edit the look of that element.</i>"),this); + layout->addWidget( help ); + + m_htmlPart = new SetupDisplay(sample, this); + layout->addWidget( m_htmlPart->view() ); + + TQHBox *buttonsBox = new TQHBox( this ); + TQPushButton *okButton = new TQPushButton( il.loadIconSet( "ok", TDEIcon::Small ), i18n( "Save and Close" ), buttonsBox ); + TQPushButton *cancelButton = new TQPushButton( il.loadIconSet( "cancel", TDEIcon::Small ), i18n( "&Cancel" ), buttonsBox ); + layout->addWidget( buttonsBox ); + + connect( m_htmlPart, TQ_SIGNAL(itemVisibilityChanged(KreDisplayItem*,bool)), this, TQ_SLOT(updateItemVisibility(KreDisplayItem*,bool)) ); + connect( okButton, TQ_SIGNAL( clicked() ), TQ_SLOT( accept() ) ); + connect( cancelButton, TQ_SIGNAL( clicked() ), TQ_SLOT( reject() ) ); + + TDEConfig *config = TDEGlobal::config(); + config->setGroup( "Page Setup" ); + TQSize defaultSize(300,400); + resize(config->readSizeEntry( "WindowSize", &defaultSize )); + + //let's do everything we can to be sure at least some layout is loaded + TQString layoutFile = config->readEntry( m_configEntry+"Layout", locate( "appdata", "layouts/Default.klo" ) ); + if ( layoutFile.isEmpty() || !TQFile::exists( layoutFile ) ) + layoutFile = locate( "appdata", "layouts/Default.klo" ); + + TQString tmpl = config->readEntry( m_configEntry+"Template", locate( "appdata", "layouts/Default.template" ) ); + if ( tmpl.isEmpty() || !TQFile::exists( tmpl ) ) + tmpl = locate( "appdata", "layouts/Default.template" ); + kdDebug()<<"tmpl: "<<tmpl<<endl; + active_template = tmpl; + loadLayout( layoutFile ); + + initShownItems(); +} + +void PageSetupDialog::accept() +{ + if ( m_htmlPart->hasChanges() ) + saveLayout(); + + if ( !active_filename.isEmpty() ) { + TDEConfig * config = kapp->config(); + config->setGroup( "Page Setup" ); + config->writeEntry( m_configEntry+"Layout", active_filename ); + } + + if ( !active_template.isEmpty() ) { + TDEConfig * config = kapp->config(); + config->setGroup( "Page Setup" ); + config->writeEntry( m_configEntry+"Template", active_template ); + } + + TDEConfig *config = kapp->config(); + config->setGroup( "Page Setup" ); + config->writeEntry( "WindowSize", size() ); + + TQDialog::accept(); +} + +void PageSetupDialog::reject() +{ + if ( m_htmlPart->hasChanges() ) { + switch ( KMessageBox::questionYesNoCancel( this, i18n( "The recipe view layout has been modified.\nDo you want to save it?" ), i18n( "Save Layout?" ) ) ) { + case KMessageBox::Yes: + saveLayout(); + break; + case KMessageBox::No: + break; + default: + return ; + } + } + + TQDialog::reject(); +} + +void PageSetupDialog::updateItemVisibility( KreDisplayItem *item, bool visible ) +{ + shown_items_popup->setItemChecked( widget_popup_map[ item ], visible ); +} + +void PageSetupDialog::initShownItems() +{ + shown_items_popup->clear(); + + PropertiesMap properties = m_htmlPart->properties(); + + TQValueList<TQString> nameList; + TQMap<TQString,KreDisplayItem*> nameMap; + + for ( PropertiesMap::const_iterator it = properties.begin(); it != properties.end(); ++it ) { + nameList << it.key()->name; + nameMap.insert( it.key()->name, it.key() ); + } + qHeapSort( nameList ); + + for ( TQValueList<TQString>::const_iterator it = nameList.begin(); it != nameList.end(); ++it ) { + KreDisplayItem *item = nameMap[*it]; + if ( properties[item] & SetupDisplay::Visibility ) { + int new_id = shown_items_popup->insertItem ( *it ); + shown_items_popup->setItemChecked( new_id, item->show ); + shown_items_popup->connectItem( new_id, this, TQ_SLOT( setItemShown( int ) ) ); + + popup_widget_map.insert( new_id, item ); + widget_popup_map.insert( item, new_id ); + } + } +} + +void PageSetupDialog::setItemShown( int id ) +{ + shown_items_popup->setItemChecked( id, !shown_items_popup->isItemChecked( id ) ); + m_htmlPart->setItemShown( popup_widget_map[ id ], shown_items_popup->isItemChecked( id ) ); +} + +void PageSetupDialog::loadFile() +{ + TQString file = KFileDialog::getOpenFileName( locateLocal( "appdata", "layouts/" ), TQString("*.klo *.template|%1").arg(i18n("Krecipes style or template file")), this, i18n( "Select Layout" ) ); + + if ( file.endsWith(".klo") ) + loadLayout( file ); + else { + active_template = file; + m_htmlPart->loadTemplate( file ); + } +} + +void PageSetupDialog::loadTemplate( int popup_param ) +{ + active_template = getIncludedLayoutDir() + "/" + included_layouts_map[ popup_param ]; + m_htmlPart->loadTemplate( active_template ); +} + +void PageSetupDialog::loadLayout( int popup_param ) +{ + loadLayout( getIncludedLayoutDir() + "/" + included_layouts_map[ popup_param ] ); +} + +void PageSetupDialog::loadLayout( const TQString &filename ) +{ + if ( m_htmlPart->hasChanges() ) { + switch ( KMessageBox::questionYesNoCancel( this, i18n( "This layout has been modified.\nDo you want to save it?" ), i18n( "Save Layout?" ) ) ) { + case KMessageBox::Yes: + saveLayout(); + break; + case KMessageBox::No: + break; + default: + return ; + } + } + + if ( !filename.isEmpty() ) { + m_htmlPart->loadLayout( filename ); + setActiveFile( filename ); + } +} + +void PageSetupDialog::reloadLayout() +{ + m_htmlPart->reload(); +} + +void PageSetupDialog::saveLayout() +{ + if ( m_htmlPart->hasChanges() ) { + if ( have_write_perm ) + m_htmlPart->saveLayout( active_filename ); + else { + switch ( KMessageBox::warningYesNo( this, i18n( "Unable to save the layout because you do not have sufficient permissions to modify this file.\nWould you like to instead save the current layout to a new file?" ) ) ) { + case KMessageBox::Yes: + saveAsLayout(); + break; + default: + break; + } + } + } +} + +void PageSetupDialog::saveAsLayout() +{ + TQString filename = KFileDialog::getSaveFileName( TDEGlobal::instance() ->dirs() ->saveLocation( "appdata", "layouts/" ), "*.klo|Krecipes Layout (*.klo)", this, TQString::null ); + + if ( !filename.isEmpty() ) { + if ( haveWritePerm( filename ) ) { + m_htmlPart->saveLayout( filename ); + setActiveFile(filename); + } + else { + switch ( KMessageBox::warningYesNo( this, i18n( "You have selected a file that you do not have the permissions to write to.\nWould you like to select another file?" ) ) ) { + case KMessageBox::Yes: + saveAsLayout(); + break; + default: + break; + } + } + } +} + +TQString PageSetupDialog::getIncludedLayoutDir() const +{ + TQFileInfo file_info( locate( "appdata", "layouts/Default.klo" ) ); + return file_info.dirPath( true ); +} + +void PageSetupDialog::setActiveFile( const TQString &filename ) +{ + active_filename = filename; + have_write_perm = haveWritePerm( filename ); +} + +bool PageSetupDialog::haveWritePerm( const TQString &filename ) +{ + TQFileInfo info( filename ); + + if ( info.exists() ) //check that we can write to this particular file + { + TQFileInfo info( filename ); + return info.isWritable(); + } + else //check that we can write to the directory since the file doesn't exist + { + TQFileInfo dir_info( info.dirPath( true ) ); + return dir_info.isWritable(); + } +} + + +#include "pagesetupdialog.moc" diff --git a/src/dialogs/pagesetupdialog.h b/src/dialogs/pagesetupdialog.h new file mode 100644 index 0000000..70c2b4d --- /dev/null +++ b/src/dialogs/pagesetupdialog.h @@ -0,0 +1,72 @@ +/*************************************************************************** +* Copyright (C) 2003-2005 by Jason Kivlighn * +* (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef PAGESETUPDIALOG_H +#define PAGESETUPDIALOG_H + +#include <tqmap.h> + +#include <kdialog.h> + +#include "datablocks/recipe.h" + +class TDEPopupMenu; + +class SetupDisplay; +class KreDisplayItem; + +/** + * @author Jason Kivlighn + */ +class PageSetupDialog : public KDialog +{ + TQ_OBJECT + +public: + PageSetupDialog( TQWidget *parent, const Recipe &sample, const TQString &configEntry = TQString::null ); + ~PageSetupDialog() + {} + +protected: + virtual void accept(); + virtual void reject(); + void save(); + +private slots: + void loadFile(); + void loadLayout( int ); + void loadLayout( const TQString &filename ); + void loadTemplate( int ); + void reloadLayout(); + void saveLayout(); + void saveAsLayout(); + void updateItemVisibility( KreDisplayItem*, bool ); + void setItemShown( int id ); + +private: + TQString getIncludedLayoutDir() const; + void setActiveFile( const TQString &filename ); + bool haveWritePerm( const TQString &filename ); + void initShownItems(); + + SetupDisplay *m_htmlPart; + + TQString active_filename; + TQString active_template; + bool have_write_perm; + TQString m_configEntry; + + TQMap<int, KreDisplayItem*> popup_widget_map; + TQMap<KreDisplayItem*, int> widget_popup_map; + TQMap<int, TQString> included_layouts_map; + TDEPopupMenu *shown_items_popup; +}; + +#endif //PAGESETUPDIALOG_H diff --git a/src/dialogs/prepmethodsdialog.cpp b/src/dialogs/prepmethodsdialog.cpp new file mode 100644 index 0000000..066c09f --- /dev/null +++ b/src/dialogs/prepmethodsdialog.cpp @@ -0,0 +1,67 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "prepmethodsdialog.h" +#include "createelementdialog.h" +#include "dependanciesdialog.h" +#include "backends/recipedb.h" +#include "widgets/prepmethodlistview.h" + +#include <kdialog.h> +#include <tdelocale.h> +#include <tdemessagebox.h> + +PrepMethodsDialog::PrepMethodsDialog( TQWidget* parent, RecipeDB *db ) : TQWidget( parent ) +{ + + // Store pointer to database + database = db; + + TQHBoxLayout* layout = new TQHBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); + + //PrepMethod List + prepMethodListView = new StdPrepMethodListView( this, database, true ); + layout->addWidget( prepMethodListView ); + + //Buttons + TQVBoxLayout* vboxl = new TQVBoxLayout( KDialog::spacingHint() ); + + newPrepMethodButton = new TQPushButton( this ); + newPrepMethodButton->setText( i18n( "Create ..." ) ); + newPrepMethodButton->setFlat( true ); + vboxl->addWidget( newPrepMethodButton ); + + removePrepMethodButton = new TQPushButton( this ); + removePrepMethodButton->setText( i18n( "Delete" ) ); + removePrepMethodButton->setFlat( true ); + vboxl->addWidget( removePrepMethodButton ); + vboxl->addStretch(); + + layout->addLayout( vboxl ); + + //Connect Signals & Slots + + connect ( newPrepMethodButton, TQ_SIGNAL( clicked() ), prepMethodListView, TQ_SLOT( createNew() ) ); + connect ( removePrepMethodButton, TQ_SIGNAL( clicked() ), prepMethodListView, TQ_SLOT( remove + () ) ); +} + +PrepMethodsDialog::~PrepMethodsDialog() +{} + +// (Re)loads the data from the database +void PrepMethodsDialog::reload( ReloadFlags flag ) +{ + prepMethodListView->reload( flag ); +} + +#include "prepmethodsdialog.moc" diff --git a/src/dialogs/prepmethodsdialog.h b/src/dialogs/prepmethodsdialog.h new file mode 100644 index 0000000..5dbb01c --- /dev/null +++ b/src/dialogs/prepmethodsdialog.h @@ -0,0 +1,53 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef PREPMETHODSDIALOG_H +#define PREPMETHODSDIALOG_H + +#include <tqwidget.h> +#include <tqpushbutton.h> +#include <tqhbox.h> +#include <tqlayout.h> +#include <kiconloader.h> +#include <tdelistview.h> + +#include "widgets/dblistviewbase.h" + +class RecipeDB; +class StdPrepMethodListView; + +/** +@author Unai Garro +*/ + +class PrepMethodsDialog: public TQWidget +{ + + TQ_OBJECT + +public: + + PrepMethodsDialog( TQWidget* parent, RecipeDB *db ); + ~PrepMethodsDialog(); + void reload( ReloadFlags flag = Load ); +private: + // Internal data + RecipeDB *database; + //Widgets + TQGridLayout *layout; + StdPrepMethodListView *prepMethodListView; + TQHBox *buttonBar; + TQPushButton *newPrepMethodButton; + TQPushButton *removePrepMethodButton; + TDEIconLoader *il; +}; +#endif diff --git a/src/dialogs/propertiesdialog.cpp b/src/dialogs/propertiesdialog.cpp new file mode 100644 index 0000000..366eb63 --- /dev/null +++ b/src/dialogs/propertiesdialog.cpp @@ -0,0 +1,77 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "propertiesdialog.h" +#include <tdelocale.h> +#include <kdialog.h> +#include <tdemessagebox.h> +#include <tdeconfig.h> + +#include "backends/recipedb.h" +#include "createpropertydialog.h" +#include "widgets/propertylistview.h" + +PropertiesDialog::PropertiesDialog( TQWidget *parent, RecipeDB *db ) : TQWidget( parent ) +{ + + // Store pointer to database + database = db; + + // Design dialog + + TQHBoxLayout* layout = new TQHBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); + + propertyListView = new CheckPropertyListView( this, database, true ); + propertyListView->reload(); + + TDEConfig *config = TDEGlobal::config(); + config->setGroup("Formatting"); + TQStringList hiddenList = config->readListEntry("HiddenProperties"); + for ( TQCheckListItem *item = (TQCheckListItem*)propertyListView->firstChild(); item; item = (TQCheckListItem*)item->nextSibling() ) { + if ( !hiddenList.contains(item->text(0)) ) + item->setOn(true); + } + + layout->addWidget ( propertyListView ); + + TQVBoxLayout* vboxl = new TQVBoxLayout( KDialog::spacingHint() ); + addPropertyButton = new TQPushButton( this ); + addPropertyButton->setText( i18n( "Create ..." ) ); + addPropertyButton->setFlat( true ); + vboxl->addWidget( addPropertyButton ); + removePropertyButton = new TQPushButton( this ); + removePropertyButton->setText( i18n( "Delete" ) ); + removePropertyButton->setFlat( true ); + vboxl->addWidget( removePropertyButton ); + vboxl->addStretch(); + layout->addLayout( vboxl ); + + // Connect signals & slots + connect( addPropertyButton, TQ_SIGNAL( clicked() ), propertyListView, TQ_SLOT( createNew() ) ); + connect( removePropertyButton, TQ_SIGNAL( clicked() ), propertyListView, TQ_SLOT( remove + () ) ); + + //FIXME: We've got some sort of build issue... we get undefined references to CreatePropertyDialog without this dummy code here + UnitList list; + CreatePropertyDialog d( this, &list ); +} + + +PropertiesDialog::~PropertiesDialog() +{} + +void PropertiesDialog::reload( void ) +{ + propertyListView->reload(); +} + +#include "propertiesdialog.moc" diff --git a/src/dialogs/propertiesdialog.h b/src/dialogs/propertiesdialog.h new file mode 100644 index 0000000..d6ae406 --- /dev/null +++ b/src/dialogs/propertiesdialog.h @@ -0,0 +1,47 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef PROPERTIESDIALOG_H +#define PROPERTIESDIALOG_H + +#include <tqlayout.h> +#include <tqpushbutton.h> +#include <tqvbox.h> +#include <tdelistview.h> + +class RecipeDB; +class StdPropertyListView; + +/** +@author Unai Garro +*/ +class PropertiesDialog: public TQWidget +{ + TQ_OBJECT +public: + PropertiesDialog( TQWidget *parent, RecipeDB *db ); + ~PropertiesDialog(); + void reload( void ); + +private: + // Variables + RecipeDB *database; + + // Widgets + TQGridLayout* layout; + TQPushButton* addPropertyButton; + TQPushButton* removePropertyButton; + StdPropertyListView* propertyListView; + +}; + +#endif diff --git a/src/dialogs/recipeimportdialog.cpp b/src/dialogs/recipeimportdialog.cpp new file mode 100644 index 0000000..cbc3dcf --- /dev/null +++ b/src/dialogs/recipeimportdialog.cpp @@ -0,0 +1,185 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "recipeimportdialog.h" + +#include <tdelocale.h> +#include <kpushbutton.h> +#include <tdelistview.h> +#include <kdebug.h> + +#include <tqvbox.h> +#include <tqlayout.h> +#include <tqheader.h> +#include <tqvariant.h> +#include <tqdict.h> + +#include "datablocks/recipe.h" + +RecipeImportDialog::RecipeImportDialog( const RecipeList &list, TQWidget *parent ) + : KDialogBase( parent, "RecipeImportDialog", true, i18n( "Import Recipes" ), + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok ), + list_copy( list ) +{ + setButtonBoxOrientation( Vertical ); + + TQVBox *page = makeVBoxMainWidget(); + + kListView = new TDEListView( page ); + kListView->addColumn( i18n( "Recipes" ) ); + kListView->setProperty( "selectionMode", "NoSelection" ); + kListView->setRootIsDecorated( true ); + kListView->setAllColumnsShowFocus( true ); + + languageChange(); + + setInitialSize( TQSize( 600, 480 ).expandedTo( minimumSizeHint() ) ); + + loadListView(); +} + +RecipeImportDialog::~RecipeImportDialog() +{ + delete recipe_items; +} + +void RecipeImportDialog::languageChange() +{ +} + +void RecipeImportDialog::loadListView() +{ + CustomCheckListItem * head_item = new CustomCheckListItem( kListView, TQString( i18n( "All (%1)" ) ).arg( list_copy.count() ), TQCheckListItem::CheckBox ); + head_item->setOpen( true ); + + //get all categories + TQStringList categoryList; + + RecipeList::const_iterator recipe_it; + for ( recipe_it = list_copy.begin(); recipe_it != list_copy.end(); ++recipe_it ) { + for ( ElementList::const_iterator cat_it = ( *recipe_it ).categoryList.begin(); cat_it != ( *recipe_it ).categoryList.end(); ++cat_it ) { + if ( categoryList.contains( ( *cat_it ).name ) < 1 ) + categoryList << ( *cat_it ).name; + } + } + + //create all category check list items + TQDict<CustomCheckListItem> all_categories; + + TQStringList::iterator it; + for ( it = categoryList.begin(); it != categoryList.end(); ++it ) { + CustomCheckListItem *category_item = new CustomCheckListItem( head_item, *it, TQCheckListItem::CheckBox ); + //category_item->setOpen(true); + + all_categories.insert( *it, category_item ); + } + + //add recipes to category check list items + recipe_items = new TQMap<CustomCheckListItem*, RecipeList::const_iterator>; //we won't be able to identify a recipe later if we just put a value in here. The iterator will be unique so we'll use it. This is safe since the list is constant (iterators won't become invlalid). + + CustomCheckListItem *item = 0; + CustomCheckListItem *category_item = 0; + + for ( recipe_it = list_copy.begin(); recipe_it != list_copy.end(); ++recipe_it ) { + if ( ( *recipe_it ).categoryList.count() == 0 ) { + if ( !category_item ) //don't create this until there are recipes to put in it + { + category_item = new CustomCheckListItem( head_item, i18n( "Uncategorized" ), TQCheckListItem::CheckBox ); + all_categories.insert( i18n( "Uncategorized" ), category_item ); + } + CustomCheckListItem *item = new CustomCheckListItem( category_item, ( *recipe_it ).title, TQCheckListItem::CheckBox ); + recipe_items->insert( item, recipe_it ); + } + else { + for ( ElementList::const_iterator cat_it = ( *recipe_it ).categoryList.begin(); cat_it != ( *recipe_it ).categoryList.end(); ++cat_it ) { + + CustomCheckListItem *category_item = all_categories[ ( *cat_it ).name ]; + + item = new CustomCheckListItem( category_item, item, ( *recipe_it ).title, TQCheckListItem::CheckBox ); + recipe_items->insert( item, recipe_it ); + } + } + } + + //append the number of recipes in each category to the check list item text + TQDictIterator<CustomCheckListItem> categories_it( all_categories ); + for ( ; categories_it.current(); ++categories_it ) { + int count = 0; + for ( TQCheckListItem * it = static_cast<TQCheckListItem*>( categories_it.current() ->firstChild() ); it; it = static_cast<TQCheckListItem*>( it->nextSibling() ) ) { + count++; + } + categories_it.current() ->setText( 0, categories_it.current() ->text( 0 ) + TQString( " (%1)" ).arg( count ) ); + } + + head_item->setOn( true ); //this will check all recipes +} + +RecipeList RecipeImportDialog::getSelectedRecipes() +{ + RecipeList selected_recipes; + + TQValueList<RecipeList::const_iterator> already_included_recipes; + + TQMap<CustomCheckListItem*, RecipeList::const_iterator>::const_iterator it; + for ( it = recipe_items->begin(); it != recipe_items->end(); ++it ) { + if ( static_cast<CustomCheckListItem*>( it.key() ) ->isOn() && + ( already_included_recipes.contains( it.data() ) == 0 ) ) //make sure it isn't already in the list + { + already_included_recipes.prepend( it.data() ); + selected_recipes.prepend( *it.data() ); + } + } + + return selected_recipes; +} + +CustomCheckListItem::CustomCheckListItem( TQListView *parent, const TQString & s, Type t ) + : TQCheckListItem( parent, s, t ), m_locked( false ) +{} + +CustomCheckListItem::CustomCheckListItem( CustomCheckListItem *parent, const TQString & s, Type t ) + : TQCheckListItem( parent, s, t ), m_locked( false ) +{} + +CustomCheckListItem::CustomCheckListItem( TQCheckListItem *parent, TQCheckListItem *after, const TQString & s, Type t ) + : TQCheckListItem( parent, after, s, t ), m_locked( false ) +{} + +void CustomCheckListItem::stateChange( bool on ) +{ + if ( !m_locked ) { + for ( TQCheckListItem * it = static_cast<TQCheckListItem*>( firstChild() ); it; it = static_cast<TQCheckListItem*>( it->nextSibling() ) ) { + it->setOn( on ); + } + } + + if ( !on ) { + TQListViewItem * parent = this->parent(); + if ( parent && ( parent->rtti() == 1 ) ) { + CustomCheckListItem * item = static_cast<CustomCheckListItem*>( parent ); + item->setLocked( true ); + item->setOn( on ); + item->setLocked( false ); + } + } + + TQString thisText = text(0); + TQListViewItemIterator it( listView() ); + while ( it.current() ) { + if ( it.current()->rtti() == 1 && it.current()->text(0) == thisText ) { + CustomCheckListItem * item = static_cast<CustomCheckListItem*>( it.current() ); + item->setOn( on ); + } + ++it; + } +} + diff --git a/src/dialogs/recipeimportdialog.h b/src/dialogs/recipeimportdialog.h new file mode 100644 index 0000000..5dfdf2c --- /dev/null +++ b/src/dialogs/recipeimportdialog.h @@ -0,0 +1,80 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef RECIPEIMPORTDIALOG_H +#define RECIPEIMPORTDIALOG_H + +#include <tqvaluelist.h> +#include <tqmap.h> +#include <tqlistview.h> + +#include <kdialogbase.h> + +#include "datablocks/recipelist.h" + +class TDEListView; + +class TQListViewItem; + +class Recipe; +class CustomCheckListItem; + +/** + * @author Jason Kivlighn + */ +class RecipeImportDialog : public KDialogBase +{ +public: + RecipeImportDialog( const RecipeList &all_recipes, TQWidget *parent = 0 ); + ~RecipeImportDialog(); + + RecipeList getSelectedRecipes(); + +protected slots: + virtual void languageChange(); + +private: + void loadListView(); + + TDEListView* kListView; + + TQMap<CustomCheckListItem*, RecipeList::const_iterator> *recipe_items; + const RecipeList list_copy; +}; + +/** A specialized TQCheckListItem that sets the state of its children to its + * current state. + * @author Jason Kivlighn + */ +class CustomCheckListItem : public TQCheckListItem +{ +public: + CustomCheckListItem( TQListView *parent, const TQString &, Type ); + CustomCheckListItem( CustomCheckListItem *parent, const TQString &, Type ); + CustomCheckListItem( TQCheckListItem *parent, TQCheckListItem *after, const TQString &, Type ); + +protected: + virtual void stateChange( bool ); + bool locked() const + { + return m_locked; + } + void setLocked( bool b ) + { + m_locked = b; + } + +private: + bool m_locked; +}; + +#endif //RECIPEIMPORTDIALOG_H diff --git a/src/dialogs/recipeinputdialog.cpp b/src/dialogs/recipeinputdialog.cpp new file mode 100644 index 0000000..31ee38e --- /dev/null +++ b/src/dialogs/recipeinputdialog.cpp @@ -0,0 +1,1641 @@ +/*************************************************************************** +* Copyright (C) 2003-2005 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.com) * +* * +* Copyright (C) 2006 Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "recipeinputdialog.h" + +#include <tqstring.h> +#include <tqlayout.h> +#include <tqhbox.h> +#include <tqvbox.h> +#include <tqimage.h> +#include <tqmessagebox.h> +#include <tqtooltip.h> +#include <tqdatetimeedit.h> +#include <tqdragobject.h> +#include <tqbuttongroup.h> +#include <tqradiobutton.h> +#include <tqwidgetstack.h> +#include <tqpainter.h> + +#include <tdeapplication.h> +#include <tdecompletionbox.h> +#include <tdespell.h> +#include <kurl.h> +#include <tdefiledialog.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <kdebug.h> +#include <kled.h> +#include <kdialogbase.h> + +#include "selectauthorsdialog.h" +#include "resizerecipedialog.h" +#include "ingredientparserdialog.h" +#include "editratingdialog.h" +#include "createunitdialog.h" +#include "datablocks/recipe.h" +#include "datablocks/categorytree.h" +#include "datablocks/unit.h" +#include "datablocks/weight.h" +#include "backends/recipedb.h" +#include "selectcategoriesdialog.h" +#include "widgets/fractioninput.h" +#include "widgets/kretextedit.h" +#include "widgets/inglistviewitem.h" +#include "../widgets/ratingdisplaywidget.h" +#include "widgets/kwidgetlistbox.h" +#include "widgets/ingredientinputwidget.h" +#include "image.h" //Initializes default photo + +#include "profiling.h" + +enum ColorStatus { GreenStatus, RedStatus, YellowStatus }; + +ClickableLed::ClickableLed( TQWidget *parent ) : KLed(parent) +{ +} + +void ClickableLed::mouseReleaseEvent( TQMouseEvent* ) +{ + emit clicked(); +} + +ImageDropLabel::ImageDropLabel( TQWidget *parent, TQPixmap &_sourcePhoto ) : TQLabel( parent ), + sourcePhoto( _sourcePhoto ) +{ + setAcceptDrops( TRUE ); +} + +void ImageDropLabel::dragEnterEvent( TQDragEnterEvent* event ) +{ + event->accept( TQImageDrag::canDecode( event ) ); +} + +void ImageDropLabel::dropEvent( TQDropEvent* event ) +{ + TQImage image; + + if ( TQImageDrag::decode( event, image ) ) { + if ( ( image.width() > width() || image.height() > height() ) || ( image.width() < width() && image.height() < height() ) ) { + TQPixmap pm_scaled; + pm_scaled.convertFromImage( image.smoothScale( width(), height(), TQImage::ScaleMin ) ); + setPixmap( pm_scaled ); + + sourcePhoto = pm_scaled; // to save scaled later on + } + else { + setPixmap( image ); + sourcePhoto = image; + } + + emit changed(); + } +} + + +RecipeInputDialog::RecipeInputDialog( TQWidget* parent, RecipeDB *db ) : TQVBox( parent ) +{ + + // Adjust internal parameters + loadedRecipe = new Recipe(); + loadedRecipe->recipeID = -1; // No loaded recipe initially + loadedRecipe->title = TQString::null; + loadedRecipe->instructions = TQString::null; + database = db; + + TDEIconLoader *il = new TDEIconLoader; + + // Tabs + tabWidget = new TQTabWidget( this, "tabWidget" ); + tabWidget->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding ) ); + + + //------- Recipe Tab ----------------- + // Recipe Photo + + recipeTab = new TQGroupBox( tabWidget ); + recipeTab->setFrameStyle( TQFrame::NoFrame ); + recipeTab->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding ) ); + + + // Design the Dialog + TQGridLayout* recipeLayout = new TQGridLayout( recipeTab, 1, 1, 0, 0 ); + + // Border + TQSpacerItem* spacer_left = new TQSpacerItem( 10, 10, TQSizePolicy::Fixed, TQSizePolicy::Minimum ); + recipeLayout->addItem( spacer_left, 1, 0 ); + TQSpacerItem* spacer_right = new TQSpacerItem( 10, 10, TQSizePolicy::Fixed, TQSizePolicy::Minimum ); + recipeLayout->addItem( spacer_right, 1, 8 ); + TQSpacerItem* spacer_top = new TQSpacerItem( 10, 10, TQSizePolicy::Minimum , TQSizePolicy::Fixed ); + recipeLayout->addItem( spacer_top, 0, 1 ); + TQSpacerItem* spacer_bottom = new TQSpacerItem( 10, 10, TQSizePolicy::Minimum , TQSizePolicy::MinimumExpanding ); + recipeLayout->addItem( spacer_bottom, 8, 1 ); + + + TQPixmap image1( defaultPhoto ); + + photoLabel = new ImageDropLabel( recipeTab, sourcePhoto ); + photoLabel->setPixmap( image1 ); + photoLabel->setFixedSize( TQSize( 221, 166 ) ); + photoLabel->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) ); + photoLabel->setAlignment( TQt::AlignHCenter | TQt::AlignVCenter ); + recipeLayout->addMultiCellWidget( photoLabel, 3, 7, 1, 1 ); + + TQVBox *photoButtonsBox = new TQVBox( recipeTab ); + + changePhotoButton = new TQPushButton( photoButtonsBox ); + changePhotoButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Preferred, TQSizePolicy::Ignored ) ); + changePhotoButton->setText( "..." ); + TQToolTip::add + ( changePhotoButton, i18n( "Select photo" ) ); + + TQPushButton *clearPhotoButton = new TQPushButton( photoButtonsBox ); + clearPhotoButton->setPixmap( il->loadIcon( "clear_left", TDEIcon::NoGroup, 16 ) ); + TQToolTip::add + ( clearPhotoButton, i18n( "Clear photo" ) ); + + recipeLayout->addMultiCellWidget( photoButtonsBox, 3, 7, 2, 2 ); + + + //Title->photo spacer + TQSpacerItem* title_photo = new TQSpacerItem( 10, 10, TQSizePolicy::Minimum, TQSizePolicy::Fixed ); + recipeLayout->addItem( title_photo, 2, 3 ); + + + // Title + TQVBox *titleBox = new TQVBox( recipeTab ); + titleBox->setSpacing( 5 ); + titleLabel = new TQLabel( i18n( "Recipe Name" ), titleBox ); + titleEdit = new KLineEdit( titleBox ); + titleEdit->setMinimumSize( TQSize( 360, 30 ) ); + titleEdit->setMaximumSize( TQSize( 10000, 30 ) ); + titleEdit->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::Fixed ) ); + recipeLayout->addMultiCellWidget( titleBox, 1, 1, 1, 7 ); + + + // Photo ->author spacer + TQSpacerItem* title_spacer = new TQSpacerItem( 10, 10, TQSizePolicy::Fixed, TQSizePolicy::Minimum ); + recipeLayout->addItem( title_spacer, 2, 1 ); + + // Author(s) & Categories + TQVBox *authorBox = new TQVBox( recipeTab ); // contains label and authorInput (input widgets) + authorBox->setSpacing( 5 ); + recipeLayout->addWidget( authorBox, 3, 4 ); + authorLabel = new TQLabel( i18n( "Authors" ), authorBox ); + TQHBox *authorInput = new TQHBox( authorBox ); // Contains input + button + + + authorShow = new KLineEdit( authorInput ); + authorShow->setReadOnly( true ); + authorShow->setMinimumSize( TQSize( 100, 20 ) ); + authorShow->setMaximumSize( TQSize( 10000, 20 ) ); + authorShow->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::Fixed ) ); + + + addAuthorButton = new TQPushButton( authorInput ); + addAuthorButton->setText( "+" ); + addAuthorButton->setFixedSize( TQSize( 20, 20 ) ); + addAuthorButton->setFlat( true ); + + + TQSpacerItem* author_category = new TQSpacerItem( 10, 10, TQSizePolicy::Fixed, TQSizePolicy::Minimum ); + recipeLayout->addItem( author_category, 3, 5 ); + + TQVBox *categoryBox = new TQVBox( recipeTab ); // Contains the label and categoryInput (input widgets) + categoryBox->setSpacing( 5 ); + categoryLabel = new TQLabel( i18n( "Categories" ), categoryBox ); + TQHBox *categoryInput = new TQHBox( categoryBox ); // Contains the input widgets + + categoryShow = new KLineEdit( categoryInput ); + categoryShow->setReadOnly( true ); + categoryShow->setMinimumSize( TQSize( 100, 20 ) ); + categoryShow->setMaximumSize( TQSize( 10000, 20 ) ); + categoryShow->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::Fixed ) ); + recipeLayout->addWidget( categoryBox, 4, 4 ); + + addCategoryButton = new TQPushButton( categoryInput ); + addCategoryButton->setText( "+" ); + addCategoryButton->setFixedSize( TQSize( 20, 20 ) ); + addCategoryButton->setFlat( true ); + + //Category ->Servings spacer + TQSpacerItem* category_yield = new TQSpacerItem( 10, 10, TQSizePolicy::Minimum, TQSizePolicy::Fixed ); + recipeLayout->addItem( category_yield, 5, 4 ); + + TQHBox *serv_prep_box = new TQHBox( recipeTab ); + serv_prep_box->setSpacing( 5 ); + + // Backup options + TQGroupBox *yieldGBox = new TQGroupBox( serv_prep_box, "yieldGBox" ); + yieldGBox->setTitle( i18n( "Yield" ) ); + yieldGBox->setColumns( 2 ); + + yieldLabel = new TQLabel( i18n( "Amount" ), yieldGBox ); + /*TQLabel *yieldTypeLabel = */new TQLabel( i18n( "Type" ), yieldGBox ); + yieldNumInput = new FractionInput( yieldGBox ); + yieldNumInput->setAllowRange(true); + yieldTypeEdit = new KLineEdit( yieldGBox ); + + TQVBox *prepTimeBox = new TQVBox( serv_prep_box ); + prepTimeBox->setSizePolicy( TQSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Fixed ) ); + prepTimeBox->setSpacing( 5 ); + + ( void ) new TQLabel( i18n( "Preparation Time" ), prepTimeBox ); + prepTimeEdit = new TQTimeEdit( prepTimeBox ); + prepTimeEdit->setMinValue( TQTime( 0, 0 ) ); + prepTimeEdit->setDisplay( TQTimeEdit::Hours | TQTimeEdit::Minutes ); + + recipeLayout->addWidget( serv_prep_box, 6, 4 ); + + //------- END OF Recipe Tab --------------- + + //------- Ingredients Tab ----------------- + + ingredientGBox = new TQGroupBox( recipeTab ); + ingredientGBox->setFrameStyle( TQFrame::NoFrame ); + ingredientGBox->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding ) ); + TQGridLayout* ingredientsLayout = new TQGridLayout( ingredientGBox ); + + // Border + TQSpacerItem* spacerBoxLeft = new TQSpacerItem( 10, 10, TQSizePolicy::Fixed, TQSizePolicy::Minimum ); + ingredientsLayout->addItem( spacerBoxLeft, 1, 0 ); + TQSpacerItem* spacerBoxTop = new TQSpacerItem( 10, 20, TQSizePolicy::Minimum, TQSizePolicy::Fixed ); + ingredientsLayout->addItem( spacerBoxTop, 0, 1 ); + + //Input Widgets + ingInput = new IngredientInputWidget( database, ingredientGBox ); + ingredientsLayout->addMultiCellWidget( ingInput, 1, 1, 1, 5 ); + + // Spacers to list and buttons + TQSpacerItem* spacerToList = new TQSpacerItem( 10, 10, TQSizePolicy::Minimum, TQSizePolicy::Fixed ); + ingredientsLayout->addItem( spacerToList, 2, 1 ); + TQSpacerItem* spacerToButtons = new TQSpacerItem( 10, 10, TQSizePolicy::Fixed, TQSizePolicy::Minimum ); + ingredientsLayout->addItem( spacerToButtons, 3, 4 ); + + // Add, Up,down,... buttons + + addButton = new KPushButton( ingredientGBox ); + addButton->setFixedSize( TQSize( 31, 31 ) ); + addButton->setFlat( true ); + TQPixmap pm = il->loadIcon( "new", TDEIcon::NoGroup, 16 ); + addButton->setPixmap( pm ); + addButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) ); + ingredientsLayout->addWidget( addButton, 3, 5 ); + + // Spacer to the rest of buttons + TQSpacerItem* spacerToOtherButtons = new TQSpacerItem( 10, 10, TQSizePolicy::Minimum, TQSizePolicy::Fixed ); + ingredientsLayout->addItem( spacerToOtherButtons, 4, 5 ); + + upButton = new KPushButton( ingredientGBox ); + upButton->setFixedSize( TQSize( 31, 31 ) ); + upButton->setFlat( true ); + pm = il->loadIcon( "go-up", TDEIcon::NoGroup, 16 ); + upButton->setPixmap( pm ); + upButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) ); + ingredientsLayout->addWidget( upButton, 5, 5 ); + + downButton = new KPushButton( ingredientGBox ); + downButton->setFixedSize( TQSize( 31, 31 ) ); + downButton->setFlat( true ); + pm = il->loadIcon( "go-down", TDEIcon::NoGroup, 16 ); + downButton->setPixmap( pm ); + downButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) ); + ingredientsLayout->addWidget( downButton, 6, 5 ); + + removeButton = new KPushButton( ingredientGBox ); + removeButton->setFixedSize( TQSize( 31, 31 ) ); + removeButton->setFlat( true ); + pm = il->loadIcon( "remove", TDEIcon::NoGroup, 16 ); + removeButton->setPixmap( pm ); + removeButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) ); + ingredientsLayout->addWidget( removeButton, 7, 5 ); + + ingParserButton = new KPushButton( ingredientGBox ); + ingParserButton->setFixedSize( TQSize( 31, 31 ) ); + ingParserButton->setFlat( true ); + pm = il->loadIcon( "edit-paste", TDEIcon::NoGroup, 16 ); + ingParserButton->setPixmap( pm ); + ingParserButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) ); + ingredientsLayout->addWidget( ingParserButton, 8, 5 ); + + TQToolTip::add + ( addButton, i18n( "Add ingredient" ) ); + TQToolTip::add + ( upButton, i18n( "Move ingredient up" ) ); + TQToolTip::add + ( downButton, i18n( "Move ingredient down" ) ); + TQToolTip::add + ( removeButton, i18n( "Remove ingredient" ) ); + TQToolTip::add + ( ingParserButton, i18n( "Paste Ingredients" ) ); + + // Ingredient List + ingredientList = new TDEListView( ingredientGBox, "ingredientList" ); + ingredientList->addColumn( i18n( "Ingredient" ) ); + ingredientList->addColumn( i18n( "Amount" ) ); + ingredientList->setColumnAlignment( 1, TQt::AlignHCenter ); + ingredientList->addColumn( i18n( "Units" ) ); + ingredientList->addColumn( i18n( "Preparation Method" ) ); + ingredientList->setSorting( -1 ); // Do not sort + ingredientList->setSizePolicy( TQSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::MinimumExpanding ) ); + ingredientList->setItemsRenameable( true ); + ingredientList->setRenameable( 0, false ); //name + ingredientList->setRenameable( 1, true ); //amount + ingredientList->setRenameable( 2, true ); //units + ingredientList->setRenameable( 3, true ); //prep method + ingredientList->setDefaultRenameAction( TQListView::Reject ); + ingredientsLayout->addMultiCellWidget( ingredientList, 3, 9, 1, 3 ); + + TQHBoxLayout *propertyStatusLayout = new TQHBoxLayout( NULL, 0, 5 ); + TQLabel *propertyLabel = new TQLabel( i18n("Property Status:"), ingredientGBox ); + propertyStatusLabel = new TQLabel( ingredientGBox ); + propertyStatusLed = new ClickableLed( ingredientGBox ); + propertyStatusLed->setFixedSize( TQSize(16,16) ); + propertyStatusButton = new TQPushButton( i18n("Details..."), ingredientGBox ); + //TQPushButton *propertyUpdateButton = new TQPushButton( i18n("Update"), ingredientGBox ); + propertyStatusLayout->addWidget( propertyLabel ); + propertyStatusLayout->addWidget( propertyStatusLabel ); + propertyStatusLayout->addWidget( propertyStatusLed ); + propertyStatusLayout->addWidget( propertyStatusButton ); + //propertyStatusLayout->addWidget( propertyUpdateButton ); + TQSpacerItem* propertySpacerRight = new TQSpacerItem( 10, 10, TQSizePolicy::MinimumExpanding, TQSizePolicy::Minimum ); + propertyStatusLayout->addItem( propertySpacerRight ); + + KGuiItem updateGuiItem; + updateGuiItem.setText( i18n("Update") ); + updateGuiItem.setIconSet( il->loadIconSet( "reload", TDEIcon::NoGroup ) ); + propertyStatusDialog = new KDialogBase( KDialogBase::Swallow, i18n("Property details"), + KDialogBase::Close | KDialogBase::User1 | KDialogBase::Help, + KDialogBase::Close, this, "propertyStatusDialog", false, false, + updateGuiItem + ); + propertyStatusDialog->setHelp("property-status"); + statusTextView = new TQTextEdit(0); + statusTextView->setTextFormat( TQt::RichText ); + statusTextView->setReadOnly(true); + propertyStatusDialog->setMainWidget( statusTextView ); + propertyStatusDialog->resize( 400, 300 ); + + ingredientsLayout->addMultiCellLayout( propertyStatusLayout, 10, 10, 1, 4 ); + + // ------- Recipe Instructions Tab ----------- + + instructionsTab = new TQGroupBox( recipeTab ); + instructionsTab->setFrameStyle( TQFrame::NoFrame ); + instructionsTab->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding ) ); + + TQVBoxLayout *instructionsLayout = new TQVBoxLayout( instructionsTab ); + + instructionsEdit = new KreTextEdit( instructionsTab ); + instructionsEdit->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding ) ); + instructionsEdit->setTabChangesFocus ( true ); + instructionsLayout->addWidget( instructionsEdit ); + + spellCheckButton = new TQToolButton( instructionsTab ); + spellCheckButton->setIconSet( il->loadIconSet( "tools-check-spelling", TDEIcon::Small ) ); + TQToolTip::add + ( spellCheckButton, i18n( "Check spelling" ) ); + instructionsLayout->addWidget( spellCheckButton ); + + // ------- END OF Recipe Instructions Tab ----------- + + + // ------- Recipe Ratings Tab ----------- + + TQVBox *ratingsTab = new TQVBox(recipeTab); + ratingListDisplayWidget = new KWidgetListbox(ratingsTab); + TQPushButton *addRatingButton = new TQPushButton(i18n("Add Rating..."),ratingsTab); + + connect( addRatingButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotAddRating()) ); + + // ------- END OF Recipe Ratings Tab ----------- + + + tabWidget->insertTab( recipeTab, i18n( "Recipe" ) ); + tabWidget->insertTab( ingredientGBox, i18n( "Ingredients" ) ); + tabWidget->insertTab( instructionsTab, i18n( "Instructions" ) ); + tabWidget->insertTab( ratingsTab, i18n( "Ratings" ) ); + + + // Functions Box + TQHBox* functionsLayout = new TQHBox( this ); + + functionsBox = new TQGroupBox( 1, TQt::Vertical, functionsLayout ); + functionsBox->setFrameStyle( TQFrame::NoFrame ); + + saveButton = new TQToolButton( functionsBox ); + saveButton->setIconSet( il->loadIconSet( "document-save", TDEIcon::Small ) ); + saveButton->setEnabled( false ); + showButton = new TQToolButton( functionsBox ); + showButton->setIconSet( il->loadIconSet( "viewmag", TDEIcon::Small ) ); + closeButton = new TQToolButton( functionsBox ); + closeButton->setIconSet( il->loadIconSet( "window-close", TDEIcon::Small ) ); + resizeButton = new TQToolButton( functionsBox ); + resizeButton->setIconSet( il->loadIconSet( "2uparrow", TDEIcon::Small ) ); //TODO: give me an icon :) + + saveButton->setTextLabel( i18n( "Save recipe" ), true ); + saveButton->setUsesTextLabel( true ); + showButton->setTextLabel( i18n( "Show recipe" ), true ); + showButton->setUsesTextLabel( true ); + closeButton->setTextLabel( i18n( "Close" ), true ); + closeButton->setUsesTextLabel( true ); + resizeButton->setTextLabel( i18n( "Resize recipe" ), true ); + resizeButton->setUsesTextLabel( true ); + + functionsLayout->layout() ->addItem( new TQSpacerItem( 10, 10, TQSizePolicy::MinimumExpanding, TQSizePolicy::Fixed ) ); + + // Dialog design + tabWidget->resize( size().expandedTo( minimumSizeHint() ) ); + clearWState( WState_Polished ); + + // Initialize internal data + unsavedChanges = false; // Indicates if there's something not saved yet. + enableChangedSignal(); // Enables the signal "changed()" + + // Connect signals & Slots + connect( changePhotoButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( changePhoto() ) ); + connect( clearPhotoButton, TQ_SIGNAL( clicked() ), TQ_SLOT( clearPhoto() ) ); + connect( upButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( moveIngredientUp() ) ); + connect( downButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( moveIngredientDown() ) ); + connect( removeButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( removeIngredient() ) ); + connect( addButton, TQ_SIGNAL( clicked() ), ingInput, TQ_SLOT( addIngredient() ) ); + connect( ingParserButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( slotIngredientParser() ) ); + connect( photoLabel, TQ_SIGNAL( changed() ), this, TQ_SIGNAL( changed() ) ); + connect( this, TQ_SIGNAL( changed() ), this, TQ_SLOT( recipeChanged() ) ); + connect( yieldNumInput, TQ_SIGNAL( textChanged( const TQString & ) ), this, TQ_SLOT( recipeChanged() ) ); + connect( yieldTypeEdit, TQ_SIGNAL( textChanged( const TQString & ) ), this, TQ_SLOT( recipeChanged() ) ); + connect( prepTimeEdit, TQ_SIGNAL( valueChanged( const TQTime & ) ), TQ_SLOT( recipeChanged() ) ); + connect( titleEdit, TQ_SIGNAL( textChanged( const TQString& ) ), this, TQ_SLOT( recipeChanged( const TQString& ) ) ); + connect( instructionsEdit, TQ_SIGNAL( textChanged() ), this, TQ_SLOT( recipeChanged() ) ); + connect( addCategoryButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( addCategory() ) ); + connect( addAuthorButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( addAuthor() ) ); + connect( titleEdit, TQ_SIGNAL( textChanged( const TQString& ) ), this, TQ_SLOT( prepTitleChanged( const TQString& ) ) ); + connect( ingredientList, TQ_SIGNAL( itemRenamed( TQListViewItem*, const TQString &, int ) ), TQ_SLOT( syncListView( TQListViewItem*, const TQString &, int ) ) ); + + connect ( ingInput, TQ_SIGNAL( ingredientEntered(const Ingredient&) ), this, TQ_SLOT( addIngredient(const Ingredient&) ) ); + connect ( ingInput, TQ_SIGNAL( headerEntered(const Element&) ), this, TQ_SLOT( addIngredientHeader(const Element&) ) ); + + connect( propertyStatusLed, TQ_SIGNAL(clicked()), TQ_SLOT(updatePropertyStatus()) ); + connect( propertyStatusDialog, TQ_SIGNAL(user1Clicked()), TQ_SLOT(updatePropertyStatus()) ); + connect( propertyStatusButton, TQ_SIGNAL(clicked()), propertyStatusDialog, TQ_SLOT(show()) ); + + // Function buttons + connect ( saveButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( save() ) ); + connect ( closeButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( closeOptions() ) ); + connect ( showButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( showRecipe() ) ); + connect ( resizeButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( resizeRecipe() ) ); + connect ( spellCheckButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( spellCheck() ) ); + connect ( this, TQ_SIGNAL( enableSaveOption( bool ) ), this, TQ_SLOT( enableSaveButton( bool ) ) ); + + connect ( database, TQ_SIGNAL( recipeRemoved(int) ), this, TQ_SLOT( recipeRemoved(int) ) ); + + delete il; + + //FIXME: We've got some sort of build issue... we get undefined references to CreateUnitDialog without this dummy code here + CreateUnitDialog d( this, "" ); +} + + +RecipeInputDialog::~RecipeInputDialog() +{ + delete loadedRecipe; +} + +void RecipeInputDialog::recipeRemoved( int id ) +{ + if ( loadedRecipe->recipeID == id ) { + loadedRecipe->recipeID = -1; + recipeChanged(); + } +} + +void RecipeInputDialog::prepTitleChanged( const TQString &title ) +{ + //we don't want the menu to grow due to a long title + //### KStringHandler::rsqueeze does this but I can't remember when it was added (compatibility issue...) + TQString short_title = title.left( 20 ); + if ( title.length() > 20 ) + short_title.append( "..." ); + + emit titleChanged( short_title ); +} + +int RecipeInputDialog::loadedRecipeID() const +{ + return loadedRecipe->recipeID; +} + +void RecipeInputDialog::loadRecipe( int recipeID ) +{ + emit enableSaveOption( false ); + unsavedChanges = false; + + //Disable changed() signals + enableChangedSignal( false ); + + //Empty current recipe + loadedRecipe->empty(); + + //Set back to the first page + tabWidget->setCurrentPage( 0 ); + + // Load specified Recipe ID + database->loadRecipe( loadedRecipe, RecipeDB::All ^ RecipeDB::Meta ^ RecipeDB::Properties, recipeID ); + + reload(); + + propertyStatusDialog->hide(); + updatePropertyStatus(); + + //Enable changed() signals + enableChangedSignal(); + +} + +void RecipeInputDialog::reload( void ) +{ + yieldNumInput->setValue( 1, 0 ); + yieldTypeEdit->setText(""); + ingredientList->clear(); + ratingListDisplayWidget->clear(); + ingInput->clear(); + + //Load Values in Interface + titleEdit->setText( loadedRecipe->title ); + instructionsEdit->setText( loadedRecipe->instructions ); + yieldNumInput->setValue( loadedRecipe->yield.amount, loadedRecipe->yield.amount_offset ); + yieldTypeEdit->setText( loadedRecipe->yield.type ); + prepTimeEdit->setTime( loadedRecipe->prepTime ); + + //show ingredient list + IngredientList list_copy = loadedRecipe->ingList; + for ( IngredientList group_list = list_copy.firstGroup(); group_list.count() != 0; group_list = list_copy.nextGroup() ) { + TQListViewItem * lastElement = ingredientList->lastItem(); + TQListViewItem *ing_header = 0; + + TQString group = group_list[ 0 ].group; + if ( !group.isEmpty() ) { + if ( lastElement && lastElement->parent() ) + lastElement = lastElement->parent(); + + ing_header = new IngGrpListViewItem( ingredientList, lastElement, group_list[ 0 ].group, group_list[ 0 ].groupID ); + ing_header->setOpen( true ); + lastElement = ing_header; + } + + for ( IngredientList::const_iterator ing_it = group_list.begin(); ing_it != group_list.end(); ++ing_it ) { + //Insert ingredient after last one + if ( ing_header ) { + lastElement = new IngListViewItem ( ing_header, lastElement, *ing_it ); + } + else { + if ( lastElement && lastElement->parent() ) + lastElement = lastElement->parent(); + lastElement = new IngListViewItem ( ingredientList, lastElement, *ing_it ); + } + + for ( TQValueList<IngredientData>::const_iterator sub_it = (*ing_it).substitutes.begin(); sub_it != (*ing_it).substitutes.end(); ++sub_it ) { + new IngSubListViewItem ( lastElement, *sub_it ); + lastElement->setOpen(true); + } + + //update completion + instructionsEdit->addCompletionItem( ( *ing_it ).name ); + } + } + // + //show photo + if ( !loadedRecipe->photo.isNull() ) { + + // //get the photo + sourcePhoto = loadedRecipe->photo; + + if ( ( sourcePhoto.width() > photoLabel->width() || sourcePhoto.height() > photoLabel->height() ) || ( sourcePhoto.width() < photoLabel->width() && sourcePhoto.height() < photoLabel->height() ) ) { + TQImage pm = sourcePhoto.convertToImage(); + TQPixmap pm_scaled; + pm_scaled.convertFromImage( pm.smoothScale( photoLabel->width(), photoLabel->height(), TQImage::ScaleMin ) ); + photoLabel->setPixmap( pm_scaled ); + + sourcePhoto = pm_scaled; // to save scaled later on + } + else { + photoLabel->setPixmap( sourcePhoto ); + } + } + else { + TQPixmap photo = TQPixmap( defaultPhoto ); + photoLabel->setPixmap( photo ); + sourcePhoto = TQPixmap(); + } + + + // Show categories + showCategories(); + + // Show authors + showAuthors(); + + // Show ratings + for ( RatingList::iterator rating_it = loadedRecipe->ratingList.begin(); rating_it != loadedRecipe->ratingList.end(); ++rating_it ) { + RatingDisplayWidget *item = new RatingDisplayWidget; + item->rating_it = rating_it; + addRating(*rating_it,item); + ratingListDisplayWidget->insertItem(item); + } + ratingListDisplayWidget->ensureCellVisible(0,0); + + // Update yield type auto completion + TDECompletion *completion = yieldTypeEdit->completionObject(); + completion->clear(); + ElementList yieldList; + database->loadYieldTypes( &yieldList ); + for ( ElementList::const_iterator it = yieldList.begin(); it != yieldList.end(); ++it ) { + completion->addItem( (*it).name ); + } +} + +void RecipeInputDialog::changePhoto( void ) +{ + // standard filedialog + KURL filename = KFileDialog::getOpenURL( TQString::null, TQString( "*.png *.jpg *.jpeg *.xpm *.gif|%1 (*.png *.jpg *.jpeg *.xpm *.gif)" ).arg( i18n( "Images" ) ), this ); + TQPixmap pixmap ( filename.path() ); + if ( !( pixmap.isNull() ) ) { + // If photo is bigger than the label, or smaller in width, than photoLabel, scale it + sourcePhoto = pixmap; + if ( ( sourcePhoto.width() > photoLabel->width() || sourcePhoto.height() > photoLabel->height() ) || ( sourcePhoto.width() < photoLabel->width() && sourcePhoto.height() < photoLabel->height() ) ) { + TQImage pm = sourcePhoto.convertToImage(); + TQPixmap pm_scaled; + pm_scaled.convertFromImage( pm.smoothScale( photoLabel->width(), photoLabel->height(), TQImage::ScaleMin ) ); + photoLabel->setPixmap( pm_scaled ); + + sourcePhoto = pm_scaled; // to save scaled later on + photoLabel->setPixmap( pm_scaled ); + } + else { + photoLabel->setPixmap( sourcePhoto ); + } + emit changed(); + } +} + +void RecipeInputDialog::clearPhoto( void ) +{ + sourcePhoto = TQPixmap(); + photoLabel->setPixmap( TQPixmap( defaultPhoto ) ); + + emit changed(); +} + +void RecipeInputDialog::moveIngredientUp( void ) +{ + TQListViewItem * it = ingredientList->selectedItem(); + if ( !it || it->rtti() == INGSUBLISTVIEWITEM_RTTI ) + return ; + + TQListViewItem *iabove = it->itemAbove(); + while ( iabove && iabove->rtti() == INGSUBLISTVIEWITEM_RTTI ) + iabove = iabove->itemAbove(); + + if ( iabove ) { + if ( it->rtti() == INGGRPLISTVIEWITEM_RTTI ) { + if ( iabove->parent() ) + iabove = iabove->parent(); + + int it_index = ingItemIndex( ingredientList, it ); + int iabove_index = ingItemIndex( ingredientList, iabove ); + + iabove->moveItem( it ); //Move the Item + + loadedRecipe->ingList.move( iabove_index, ( iabove->rtti() == INGGRPLISTVIEWITEM_RTTI ) ? iabove->childCount() : 1, it_index + it->childCount() - 1 ); + } + else { + int it_index = ingItemIndex( ingredientList, it ); + int iabove_index = ingItemIndex( ingredientList, iabove ); + IngredientList::iterator ing = loadedRecipe->ingList.at( it_index ); + + if ( iabove->parent() != it->parent() ) { + if ( iabove->rtti() == INGGRPLISTVIEWITEM_RTTI && it->parent() ) { //move the item out of the group + it->parent() ->takeItem( it ); + ingredientList->insertItem( it ); + it->moveItem( ( iabove->itemAbove() ->parent() ) ? iabove->itemAbove() ->parent() : iabove->itemAbove() ); //Move the Item + } + else { //move the item into the group + ingredientList->takeItem( it ); + iabove->parent() ->insertItem( it ); + it->moveItem( iabove ); //Move the Item + } + + ingredientList->setCurrentItem( it ); //Keep selected + } + else { + iabove->moveItem( it ); //Move the Item + loadedRecipe->ingList.move( it_index, iabove_index ); + } + + if ( it->parent() ) + ( *ing ).groupID = ( ( IngGrpListViewItem* ) it->parent() ) ->id(); + else + ( *ing ).groupID = -1; + } + + emit changed(); + } +} + +void RecipeInputDialog::moveIngredientDown( void ) +{ + TQListViewItem * it = ingredientList->selectedItem(); + if ( !it || it->rtti() == INGSUBLISTVIEWITEM_RTTI ) + return ; + + TQListViewItem *ibelow = it->itemBelow(); + while ( ibelow && ibelow->rtti() == INGSUBLISTVIEWITEM_RTTI ) + ibelow = ibelow->itemBelow(); + + if ( ibelow ) { + if ( it->rtti() == INGGRPLISTVIEWITEM_RTTI ) { + TQListViewItem * next_sibling = it->nextSibling(); + + if ( next_sibling ) { + int it_index = ingItemIndex( ingredientList, it ); + int ibelow_index = ingItemIndex( ingredientList, next_sibling ); + + it->moveItem( next_sibling ); //Move the Item + + int skip = 0; + if ( next_sibling->childCount() > 0 ) + skip = next_sibling->childCount() - 1; + + loadedRecipe->ingList.move( it_index, it->childCount(), ibelow_index + skip ); + } + } + else { + int it_index = ingItemIndex( ingredientList, it ); + int ibelow_index = ingItemIndex( ingredientList, ibelow ); + IngredientList::iterator ing = loadedRecipe->ingList.at( it_index ); + + if ( ibelow->rtti() == INGGRPLISTVIEWITEM_RTTI || ( ibelow->parent() != it->parent() ) ) { + if ( ibelow->rtti() == INGGRPLISTVIEWITEM_RTTI && !it->parent() ) { //move the item into the group + if ( !it->parent() ) + ingredientList->takeItem( it ); + else + it->parent() ->takeItem( it ); + + ibelow->insertItem( it ); + } + else { //move the item out of the group + TQListViewItem *parent = it->parent(); //store this because we can't get it after we do it->takeItem() + parent->takeItem( it ); + ingredientList->insertItem( it ); + it->moveItem( parent ); //Move the Item + } + + ingredientList->setCurrentItem( it ); //Keep selected + } + else { + it->moveItem( ibelow ); //Move the Item + loadedRecipe->ingList.move( it_index, ibelow_index ); + } + + if ( it->parent() ) + ( *ing ).groupID = ( ( IngGrpListViewItem* ) it->parent() ) ->id(); + else + ( *ing ).groupID = -1; + } + + emit changed(); + } + else if ( it->parent() ) { + it->parent() ->takeItem( it ); + ingredientList->insertItem( it ); + it->moveItem( ( ingredientList->lastItem() ->parent() ) ? ingredientList->lastItem() ->parent() : ingredientList->lastItem() ); //Move the Item + ingredientList->setCurrentItem( it ); //Keep selected + + int it_index = ingItemIndex( ingredientList, it ); + IngredientList::iterator ing = loadedRecipe->ingList.at( it_index ); + ( *ing ).groupID = -1; + + emit changed(); + } +} + +void RecipeInputDialog::removeIngredient( void ) +{ + TQListViewItem * it = ingredientList->selectedItem(); + if ( it && (it->rtti() == INGLISTVIEWITEM_RTTI || it->rtti() == INGSUBLISTVIEWITEM_RTTI) ) { + TQListViewItem *iselect = it->itemBelow(); + while ( iselect && iselect->rtti() == INGSUBLISTVIEWITEM_RTTI ) + iselect = iselect->itemBelow(); + + if ( !iselect ) { + iselect = it->itemAbove(); + while ( iselect && iselect->rtti() == INGSUBLISTVIEWITEM_RTTI ) + iselect = iselect->itemAbove(); + } + + IngListViewItem *ing_item = (IngListViewItem*)it; //we can cast IngSubListViewItem to this too, it's a subclass + + IngredientData &ing = loadedRecipe->ingList.findSubstitute( ing_item->ingredient() ); + + //Remove it from the instruction's completion + instructionsEdit->removeCompletionItem( ing.name ); + + loadedRecipe->ingList.removeSubstitute( ing ); + + int ingID = ing_item->ingredient().ingredientID; + TQMap<int,TQString>::iterator map_it; + if ( (map_it = propertyStatusMapRed.find(ingID)) != propertyStatusMapRed.end() ) + propertyStatusMapRed.remove( map_it ); + else if ( (map_it = propertyStatusMapYellow.find(ingID)) != propertyStatusMapYellow.end() ) + propertyStatusMapYellow.remove( map_it ); + showStatusIndicator(); + + //Now remove the ingredient + it->setSelected( false ); + delete it; + if ( iselect ) + ingredientList->setSelected( iselect, true ); // be careful iselect->setSelected doesn't work this way. + + emit changed(); + } + else if ( it && it->rtti() == INGGRPLISTVIEWITEM_RTTI ) { + IngGrpListViewItem * header = ( IngGrpListViewItem* ) it; + + for ( IngListViewItem * sub_item = (IngListViewItem*)header->firstChild(); sub_item; sub_item = (IngListViewItem*)sub_item->nextSibling() ) { + IngredientData &ing = loadedRecipe->ingList.findSubstitute( sub_item->ingredient() ); + + //Remove it from the instruction's completion + instructionsEdit->removeCompletionItem( ing.name ); + + loadedRecipe->ingList.removeSubstitute( ing ); + + int ingID = sub_item->ingredient().ingredientID; + TQMap<int,TQString>::iterator map_it; + if ( (map_it = propertyStatusMapRed.find(ingID)) != propertyStatusMapRed.end() ) + propertyStatusMapRed.remove( map_it ); + else if ( (map_it = propertyStatusMapYellow.find(ingID)) != propertyStatusMapYellow.end() ) + propertyStatusMapYellow.remove( map_it ); + showStatusIndicator(); + } + + delete header; + + emit changed(); + } + +} + +int RecipeInputDialog::createNewYieldIfNecessary( const TQString &yield ) +{ + if ( yield.stripWhiteSpace().isEmpty() ) //no yield + return -1; + else + { + int id = database->findExistingYieldTypeByName( yield ); + if ( id == -1 ) //creating new + { + database->createNewYieldType( yield ); + id = database->lastInsertID(); + } + + return id; + } +} + +void RecipeInputDialog::syncListView( TQListViewItem* it, const TQString &new_text, int col ) +{ + if ( it->rtti() != INGLISTVIEWITEM_RTTI ) + return ; + + IngListViewItem *ing_item = ( IngListViewItem* ) it; + + IngredientData &new_ing = loadedRecipe->ingList.findSubstitute( ing_item->ingredient() ); + + switch ( col ) { + case 1: //amount + { + bool ok; + + Ingredient new_ing_amount; + new_ing_amount.setAmount(new_text,&ok); + + if ( ok ) + { + if ( new_ing.amount != new_ing_amount.amount || + new_ing.amount_offset != new_ing_amount.amount_offset ) { + new_ing.amount = new_ing_amount.amount; + new_ing.amount_offset = new_ing_amount.amount_offset; + if ( !new_text.isEmpty() ) + ing_item->setAmount( new_ing_amount.amount, new_ing_amount.amount_offset ); + + new_ing.amount = new_ing_amount.amount; + new_ing.amount_offset = new_ing_amount.amount_offset; + emit changed(); + } + } + else + { + if ( !new_text.isEmpty() ) + ing_item->setAmount( new_ing.amount, new_ing.amount_offset ); + } + + break; + } + case 2: //unit + { + Unit old_unit = new_ing.units; + + if ( new_text.length() > uint(database->maxUnitNameLength()) ) + { + KMessageBox::error( this, TQString( i18n( "Unit name cannot be longer than %1 characters." ) ).arg( database->maxUnitNameLength() ) ); + ing_item->setUnit( old_unit ); + break; + } + + TQString approp_unit = new_ing.amount > 1 ? new_ing.units.plural : new_ing.units.name; + if ( approp_unit != new_text.stripWhiteSpace() ) + { + Unit new_unit; + int new_id = IngredientInputWidget::createNewUnitIfNecessary( new_text.stripWhiteSpace(), new_ing.amount > 1, ing_item->ingredient().ingredientID, new_unit, database ); + + if ( new_id != -1 ) { + new_ing.units = new_unit; + new_ing.units.id = new_id; + + ing_item->setUnit( new_ing.units ); + + updatePropertyStatus(); + emit changed(); + } + else { + ing_item->setUnit( old_unit ); + } + } + break; + } + case 3: //prep method + { + TQString old_text = new_ing.prepMethodList.join(","); + + TQStringList prepMethodList = TQStringList::split(",",new_text.stripWhiteSpace()); + + for ( TQStringList::const_iterator it = prepMethodList.begin(); it != prepMethodList.end(); ++it ) { + if ( (*it).stripWhiteSpace().length() > uint(database->maxPrepMethodNameLength()) ) + { + KMessageBox::error( this, TQString( i18n( "Preparation method cannot be longer than %1 characters." ) ).arg( database->maxPrepMethodNameLength() ) ); + ing_item->setPrepMethod( old_text ); + break; + } + } + + if ( old_text != new_text.stripWhiteSpace() ) + { + new_ing.prepMethodList = ElementList::split(",",new_text.stripWhiteSpace()); + TQValueList<int> new_ids = IngredientInputWidget::createNewPrepIfNecessary( new_ing.prepMethodList, database ); + + TQValueList<int>::const_iterator id_it = new_ids.begin(); + for ( ElementList::iterator it = new_ing.prepMethodList.begin(); it != new_ing.prepMethodList.end(); ++it, ++id_it ) { + (*it).id = *id_it; + } + + updatePropertyStatus(); + emit changed(); + } + break; + } + } +} + +void RecipeInputDialog::recipeChanged( void ) +{ + if ( changedSignalEnabled ) { + // Enable Save Button + emit enableSaveOption( true ); + emit createButton( this, titleEdit->text() ); + unsavedChanges = true; + + } + +} + +void RecipeInputDialog::recipeChanged( const TQString & /*t*/ ) +{ + recipeChanged(); // jumps to the real slot function +} + +void RecipeInputDialog::enableChangedSignal( bool en ) +{ + changedSignalEnabled = en; +} + +bool RecipeInputDialog::save ( void ) +{ + //check bounds first + if ( titleEdit->text().length() > uint(database->maxRecipeTitleLength()) ) { + KMessageBox::error( this, TQString( i18n( "Recipe title cannot be longer than %1 characters." ) ).arg( database->maxRecipeTitleLength() ), i18n( "Unable to save recipe" ) ); + return false; + } + + emit enableSaveOption( false ); + saveRecipe(); + unsavedChanges = false; + + return true; +} + +void RecipeInputDialog::saveRecipe( void ) +{ + // Nothing except for the ingredient list (loadedRecipe->ingList) + // was stored before for performance. (recipeID is already there) + + loadedRecipe->photo = sourcePhoto; + loadedRecipe->instructions = instructionsEdit->text(); + loadedRecipe->title = titleEdit->text(); + yieldNumInput->value(loadedRecipe->yield.amount,loadedRecipe->yield.amount_offset); + loadedRecipe->yield.type_id = createNewYieldIfNecessary(yieldTypeEdit->text()); + loadedRecipe->prepTime = prepTimeEdit->time(); + + // Now save() + kdDebug() << "Saving..." << endl; + database->saveRecipe( loadedRecipe ); + + +} + +void RecipeInputDialog::newRecipe( void ) +{ + loadedRecipe->empty(); + TQPixmap image( defaultPhoto ); + photoLabel->setPixmap( image ); + sourcePhoto = TQPixmap(); + + instructionsEdit->setText( i18n( "Write the recipe instructions here" ) ); + instructionsEdit->clearCompletionItems(); + titleEdit->setText( i18n( "Write the recipe title here" ) ); + ingredientList->clear(); + authorShow->clear(); + categoryShow->clear(); + yieldNumInput->setValue( 1, 0 ); + yieldTypeEdit->setText(""); + prepTimeEdit->setTime( TQTime( 0, 0 ) ); + + instructionsEdit->selectAll(); + + //Set back to the first page + tabWidget->setCurrentPage( 0 ); + + ingInput->clear(); + + //Set focus to the title + titleEdit->setFocus(); + titleEdit->selectAll(); + + //clear status info + propertyStatusMapRed.clear(); + propertyStatusMapYellow.clear(); + showStatusIndicator(); +} + +bool RecipeInputDialog::everythingSaved() +{ + return ( !( unsavedChanges ) ); +} + +void RecipeInputDialog::addCategory( void ) +{ + SelectCategoriesDialog *editCategoriesDialog = new SelectCategoriesDialog( this, loadedRecipe->categoryList, database ); + + if ( editCategoriesDialog->exec() == TQDialog::Accepted ) { // user presses Ok + loadedRecipe->categoryList.clear(); + editCategoriesDialog->getSelectedCategories( &( loadedRecipe->categoryList ) ); // get the category list chosen + emit( recipeChanged() ); //Indicate that the recipe changed + + } + + delete editCategoriesDialog; + + // show category list + showCategories(); + + +} + +void RecipeInputDialog::showCategories( void ) +{ + TQString categories; + for ( ElementList::const_iterator cat_it = loadedRecipe->categoryList.begin(); cat_it != loadedRecipe->categoryList.end(); ++cat_it ) { + if ( !categories.isEmpty() ) + categories += ","; + categories += ( *cat_it ).name; + } + categoryShow->setText( categories ); +} + +void RecipeInputDialog::addAuthor( void ) +{ + SelectAuthorsDialog * editAuthorsDialog = new SelectAuthorsDialog( this, loadedRecipe->authorList, database ); + + + if ( editAuthorsDialog->exec() == TQDialog::Accepted ) { // user presses Ok + loadedRecipe->authorList.clear(); + editAuthorsDialog->getSelectedAuthors( &( loadedRecipe->authorList ) ); // get the category list chosen + emit( recipeChanged() ); //Indicate that the recipe changed + } + + delete editAuthorsDialog; + + // show authors list + showAuthors(); +} + +void RecipeInputDialog::showAuthors( void ) +{ + TQString authors; + for ( ElementList::const_iterator author_it = loadedRecipe->authorList.begin(); author_it != loadedRecipe->authorList.end(); ++author_it ) { + if ( !authors.isEmpty() ) + authors += ","; + authors += ( *author_it ).name; + } + authorShow->setText( authors ); +} + +void RecipeInputDialog::enableSaveButton( bool enabled ) +{ + saveButton->setEnabled( enabled ); +} + +void RecipeInputDialog::closeOptions( void ) +{ + + // First check if there's anything unsaved in the recipe + if ( unsavedChanges ) { + + switch ( KMessageBox::questionYesNoCancel( this, i18n( "This recipe contains unsaved changes.\n" "Would you like to save it before closing?" ), i18n( "Unsaved changes" ) ) ) { + case KMessageBox::Yes: + save(); + break; + case KMessageBox::No: + break; + case KMessageBox::Cancel: + return ; + } + + } + + emit enableSaveOption( false ); + unsavedChanges = false; + + // Now close really + emit closeRecipe(); + + +} + +void RecipeInputDialog::showRecipe( void ) +{ + // First check if there's anything unsaved in the recipe + + if ( loadedRecipe->recipeID == -1 ) { + switch ( KMessageBox::questionYesNo( this, i18n( "You need to save the recipe before displaying it. Would you like to save it now?" ), i18n( "Unsaved changes" ) ) ) { + case KMessageBox::Yes: + save(); + break; + case KMessageBox::No: + return ; + } + } + else if ( unsavedChanges ) { + + switch ( KMessageBox::questionYesNoCancel( this, i18n( "This recipe has changes that will not be displayed unless the recipe is saved. Would you like to save it now?" ), i18n( "Unsaved changes" ) ) ) { + case KMessageBox::Yes: + save(); + break; + case KMessageBox::No: + break; + case KMessageBox::Cancel: + return ; + } + + } + + // Now open it really + emit showRecipe( loadedRecipe->recipeID ); +} + +void RecipeInputDialog::spellCheck( void ) +{ + TQString text = instructionsEdit->text(); + KSpellConfig default_cfg( this ); + KSpell::modalCheck( text, &default_cfg ); + KMessageBox::information( this, i18n( "Spell check complete." ) ); + + if ( text != instructionsEdit->text() ) //check if there were changes + instructionsEdit->setText( text ); +} + +void RecipeInputDialog::resizeRecipe( void ) +{ + yieldNumInput->value( loadedRecipe->yield.amount, loadedRecipe->yield.amount_offset ); + ResizeRecipeDialog dlg( this, loadedRecipe ); + + if ( dlg.exec() == TQDialog::Accepted ) + reload(); +} + +int RecipeInputDialog::ingItemIndex( TQListView *listview, const TQListViewItem *item ) const +{ + if ( !item ) + return -1; + + if ( item == listview->firstChild() ) + return 0; + else { + TQListViewItemIterator it( listview->firstChild() ); + uint j = 0; + for ( ; it.current() && it.current() != item; ++it ) { + if ( it.current() ->rtti() == INGLISTVIEWITEM_RTTI ) { + if ( !it.current()->parent() || it.current()->parent()->rtti() == INGGRPLISTVIEWITEM_RTTI ) + j++; + } + } + + if ( !it.current() ) + return -1; + + return j; + } +} + +void RecipeInputDialog::slotIngredientParser() +{ + UnitList units; + database->loadUnits(&units); + IngredientParserDialog dlg(units,this); + if ( dlg.exec() == TQDialog::Accepted ) { + IngredientList ings = dlg.ingredients(); + TQStringList usedGroups; + bool haveHeader = false; + for ( IngredientList::iterator it = ings.begin(); it != ings.end(); ++it ) { + if ( !(*it).group.isEmpty() && usedGroups.find((*it).group) == usedGroups.end() ) { + int id = IngredientInputWidget::createNewGroupIfNecessary((*it).group,database); + addIngredientHeader( Element((*it).group, id) ); + haveHeader = true; + usedGroups << (*it).group; + } + (*it).ingredientID = IngredientInputWidget::createNewIngredientIfNecessary((*it).name,database); + (*it).units.id = IngredientInputWidget::createNewUnitIfNecessary((*it).units.name,false,(*it).ingredientID,(*it).units,database); + + TQValueList<int> prepIDs = IngredientInputWidget::createNewPrepIfNecessary((*it).prepMethodList,database); + TQValueList<int>::const_iterator prep_id_it = prepIDs.begin(); + for ( ElementList::iterator prep_it = (*it).prepMethodList.begin(); prep_it != (*it).prepMethodList.end(); ++prep_it, ++prep_id_it ) { + (*prep_it).id = *prep_id_it; + } + + addIngredient( *it, !haveHeader ); + + if ( usedGroups.count() > 0 && (*it).group.isEmpty() ) { + TQListViewItem *last_item = ingredientList->lastItem(); + if ( last_item->parent() ) { + last_item->parent()->takeItem( last_item ); + ingredientList->insertItem( last_item ); + last_item->moveItem( ingredientList->lastItem()->parent() ); + } + } + } + } +} + +void RecipeInputDialog::slotAddRating() +{ + ElementList criteriaList; + database->loadRatingCriterion(&criteriaList); + + EditRatingDialog ratingDlg(criteriaList,this); + if ( ratingDlg.exec() == TQDialog::Accepted ) { + Rating r = ratingDlg.rating(); + + for ( RatingCriteriaList::iterator rc_it = r.ratingCriteriaList.begin(); rc_it != r.ratingCriteriaList.end(); ++rc_it ) { + int criteria_id = database->findExistingRatingByName((*rc_it).name); + if ( criteria_id == -1 ) { + database->createNewRating((*rc_it).name); + criteria_id = database->lastInsertID(); + } + (*rc_it).id = criteria_id; + } + + RatingDisplayWidget *item = new RatingDisplayWidget; + item->rating_it = loadedRecipe->ratingList.append(r); + addRating(r,item); + ratingListDisplayWidget->insertItem(item,0); + emit( recipeChanged() ); //Indicate that the recipe changed + } +} + +void RecipeInputDialog::addRating( const Rating &rating, RatingDisplayWidget *item ) +{ + int average = tqRound(rating.average()); + if ( average >= 0 ) + item->icon->setPixmap( UserIcon(TQString("rating%1").arg(average) ) ); + else //no rating criteria, therefore no average (we don't want to automatically assume a zero average) + item->icon->clear(); + + item->raterName->setText(rating.rater); + item->comment->setText(rating.comment); + + item->criteriaListView->clear(); + for ( RatingCriteriaList::const_iterator rc_it = rating.ratingCriteriaList.begin(); rc_it != rating.ratingCriteriaList.end(); ++rc_it ) { + TQListViewItem * it = new TQListViewItem(item->criteriaListView,(*rc_it).name); + + int stars = int((*rc_it).stars * 2); //multiply by two to make it easier to work with half-stars + + TQPixmap star = UserIcon(TQString::fromLatin1("star_on")); + int pixmapWidth = 18*(stars/2)+((stars%2==1)?9:0); + TQPixmap generatedPixmap(pixmapWidth,18); + + if ( !generatedPixmap.isNull() ) { //there aren't zero stars + generatedPixmap.fill(); + TQPainter painter( &generatedPixmap ); + painter.drawTiledPixmap(0,0,pixmapWidth,18,star); + it->setPixmap(1,generatedPixmap); + } + } + + item->buttonEdit->disconnect(); + item->buttonRemove->disconnect(); + connect(item->buttonEdit, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotEditRating())); + connect(item->buttonRemove, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotRemoveRating())); +} + +void RecipeInputDialog::slotEditRating() +{ + RatingDisplayWidget *sender = (RatingDisplayWidget*)(TQObject::sender()->parent()); + + ElementList criteriaList; + database->loadRatingCriterion(&criteriaList); + + EditRatingDialog ratingDlg(criteriaList,*sender->rating_it,this); + if ( ratingDlg.exec() == TQDialog::Accepted ) { + Rating r = ratingDlg.rating(); + + for ( RatingCriteriaList::iterator rc_it = r.ratingCriteriaList.begin(); rc_it != r.ratingCriteriaList.end(); ++rc_it ) { + int criteria_id = database->findExistingRatingByName((*rc_it).name); + if ( criteria_id == -1 ) { + database->createNewRating((*rc_it).name); + criteria_id = database->lastInsertID(); + } + (*rc_it).id = criteria_id; + } + + (*sender->rating_it) = r; + addRating(r,sender); + emit recipeChanged(); //Indicate that the recipe changed + } +} + +void RecipeInputDialog::slotRemoveRating() +{ + RatingDisplayWidget *sender = (RatingDisplayWidget*)(TQObject::sender()->parent()); + loadedRecipe->ratingList.remove(sender->rating_it); + + //FIXME: sender is removed but never deleted (sender->deleteLater() doesn't work) + ratingListDisplayWidget->removeItem(sender); + + emit recipeChanged(); //Indicate that the recipe changed +} + +void RecipeInputDialog::addIngredient( const Ingredient &ing, bool noHeader ) +{ + Ingredient ingCopy = ing; + + //Append to the ListView + TQListViewItem* lastElement = ingredientList->lastItem(); + while ( lastElement && lastElement->rtti() == INGSUBLISTVIEWITEM_RTTI ) + lastElement = lastElement->itemAbove(); + + if ( noHeader && lastElement ) + lastElement = (lastElement->parent())?lastElement->parent():lastElement; + + if ( !noHeader && lastElement && + ( lastElement->rtti() == INGGRPLISTVIEWITEM_RTTI || ( lastElement->parent() && lastElement->parent() ->rtti() == INGGRPLISTVIEWITEM_RTTI ) ) ) + { + IngGrpListViewItem * header = ( lastElement->parent() ) ? ( IngGrpListViewItem* ) lastElement->parent() : ( IngGrpListViewItem* ) lastElement; + + ingCopy.groupID = header->id(); + + lastElement = new IngListViewItem( header, lastElement, ingCopy ); + for ( TQValueList<IngredientData>::const_iterator it = ingCopy.substitutes.begin(); it != ingCopy.substitutes.end(); ++it ) { + new IngSubListViewItem( lastElement, *it ); + } + lastElement->setOpen(true); + } + else { + lastElement = new IngListViewItem( ingredientList, lastElement, ingCopy ); + for ( TQValueList<IngredientData>::const_iterator it = ing.substitutes.begin(); it != ing.substitutes.end(); ++it ) { + new IngSubListViewItem( lastElement, *it ); + } + lastElement->setOpen(true); + } + + //append to recipe + loadedRecipe->ingList.append( ingCopy ); + + //update the completion in the instructions edit + instructionsEdit->addCompletionItem( ingCopy.name ); + + updatePropertyStatus( ingCopy, true ); + + emit changed(); +} + +void RecipeInputDialog::addIngredientHeader( const Element &header ) +{ + TQListViewItem *last_item = ingredientList->lastItem(); + if ( last_item && last_item->parent() ) + last_item = last_item->parent(); + + IngGrpListViewItem *ing_header = new IngGrpListViewItem( ingredientList, last_item, header.name, header.id ); + ing_header->setOpen( true ); +} + +void RecipeInputDialog::updatePropertyStatus() +{ + propertyStatusMapRed.clear(); + propertyStatusMapYellow.clear(); + + for ( IngredientList::const_iterator ing_it = loadedRecipe->ingList.begin(); ing_it != loadedRecipe->ingList.end(); ++ing_it ) { + updatePropertyStatus( *ing_it, false ); + } + + showStatusIndicator(); +} + +void RecipeInputDialog::updatePropertyStatus( const Ingredient &ing, bool updateIndicator ) +{ + IngredientPropertyList ingPropertyList; + database->loadProperties( &ingPropertyList, ing.ingredientID ); + + if ( ingPropertyList.count() == 0 ) { + propertyStatusMapRed.insert(ing.ingredientID,TQString(i18n("<b>%1:</b> No nutrient information available")).arg(ing.name)); + } + + TQMap<int,bool> ratioCache; //unit->conversion possible + IngredientPropertyList::const_iterator prop_it; + for ( prop_it = ingPropertyList.begin(); prop_it != ingPropertyList.end(); ++prop_it ) { + Ingredient result; + + TQMap<int,bool>::const_iterator cache_it = ratioCache.find((*prop_it).perUnit.id); + if ( cache_it == ratioCache.end() ) { + RecipeDB::ConversionStatus status = database->convertIngredientUnits( ing, (*prop_it).perUnit, result ); + ratioCache.insert((*prop_it).perUnit.id,status==RecipeDB::Success||status==RecipeDB::MismatchedPrepMethod); + + switch ( status ) { + case RecipeDB::Success: break; + case RecipeDB::MissingUnitConversion: { + if ( ing.units.type != Unit::Other && ing.units.type == (*prop_it).perUnit.type ) { + propertyStatusMapRed.insert(ing.ingredientID,TQString(i18n("<b>%3:</b> Unit conversion missing for conversion from '%1' to '%2'")) + .arg(ing.units.name.isEmpty()?i18n("-No unit-"):ing.units.name) + .arg((*prop_it).perUnit.name) + .arg(ing.name)); + } else { + WeightList weights = database->ingredientWeightUnits( ing.ingredientID ); + TQValueList< TQPair<int,int> > usedIds; + TQStringList missingConversions; + for ( WeightList::const_iterator weight_it = weights.begin(); weight_it != weights.end(); ++weight_it ) { + //skip entries that only differ in how it's prepared + TQPair<int,int> usedPair((*weight_it).perAmountUnitID,(*weight_it).weightUnitID); + if ( usedIds.find(usedPair) != usedIds.end() ) + continue; + + TQString toUnit = database->unitName((*weight_it).perAmountUnitID).name; + if ( toUnit.isEmpty() ) toUnit = i18n("-No unit-"); + + TQString fromUnit = database->unitName((*weight_it).weightUnitID).name; + if ( fromUnit.isEmpty() ) fromUnit = i18n("-No unit-"); + + TQString ingUnit = ing.units.name; + if ( ingUnit.isEmpty() ) ingUnit = i18n("-No unit-"); + + TQString propUnit = (*prop_it).perUnit.name; + if ( propUnit.isEmpty() ) propUnit = i18n("-No unit-"); + + missingConversions << conversionPath( ingUnit, toUnit, fromUnit, propUnit); + + usedIds << usedPair; + } + propertyStatusMapRed.insert(ing.ingredientID,TQString(i18n("<b>%1:</b> Either an appropriate ingredient weight entry is needed, or Krecipes needs conversion information to perform one of the following conversions: %2")) + .arg(ing.name) + .arg("<ul><li>"+missingConversions.join("</li><li>")+"</li></ul>") + ); + } + break; + } + case RecipeDB::MissingIngredientWeight: + propertyStatusMapRed.insert(ing.ingredientID,TQString(i18n("<b>%1:</b> No ingredient weight entries")).arg(ing.name)); + break; + case RecipeDB::MismatchedPrepMethod: + if ( ing.prepMethodList.count() == 0 ) + propertyStatusMapRed.insert(ing.ingredientID,TQString(i18n("<b>%1:</b> There is no ingredient weight entry for when no preparation method is specified")).arg(ing.name)); + else + propertyStatusMapRed.insert(ing.ingredientID,TQString(i18n("<b>%1:</b> There is no ingredient weight entry for when prepared in any of the following manners: %2")).arg(ing.name).arg("<ul><li>"+ing.prepMethodList.join("</li><li>")+"</li></ul>")); + break; + case RecipeDB::MismatchedPrepMethodUsingApprox: + propertyStatusMapYellow.insert(ing.ingredientID,TQString(i18n("<b>%1:</b> There is no ingredient weight entry for when prepared in any of the following manners (defaulting to a weight entry without a preparation method specified): %2")).arg(ing.name).arg("<ul><li>"+ing.prepMethodList.join("</li><li>")+"</li></ul>")); + break; + default: kdDebug()<<"Code error: Unhandled conversion status code "<<status<<endl; break; + } + } + } + + if ( updateIndicator ) + showStatusIndicator(); +} + +void RecipeInputDialog::showStatusIndicator() +{ + if ( propertyStatusMapRed.count() == 0 ) { + if ( propertyStatusMapYellow.count() == 0 ) { + propertyStatusLed->setColor( TQt::green ); + propertyStatusLabel->setText( i18n("Complete") ); + propertyStatusButton->setEnabled(false); + } + else { + propertyStatusLed->setColor( TQt::yellow ); + propertyStatusLabel->setText( i18n("Complete, but approximations made") ); + propertyStatusButton->setEnabled(true); + } + } + else { + propertyStatusLed->setColor( TQt::red ); + propertyStatusLabel->setText( i18n("Incomplete") ); + propertyStatusButton->setEnabled(true); + } + + if ( propertyStatusMapRed.count() == 0 && propertyStatusMapYellow.count() == 0 ) + propertyStatusDialog->hide(); + else + statusTextView->setText(statusMessage()); +} + +TQString RecipeInputDialog::statusMessage() const +{ + TQString statusMessage; + + if ( propertyStatusMapRed.count() > 0 ) { + statusMessage.append( i18n("The nutrient information for this recipe is incomplete because the following information is missing:") ); + statusMessage.append("<ul>"); + for ( TQMap<int,TQString>::const_iterator it = propertyStatusMapRed.begin(); it != propertyStatusMapRed.end(); ++it ) { + statusMessage.append("<li>"); + statusMessage.append(it.data()); + statusMessage.append("</li>"); + } + statusMessage.append("</ul>"); + } + + if ( propertyStatusMapYellow.count() > 0 ) { + statusMessage.append( i18n("The following approximations will be made when determining nutrient information:") ); + statusMessage.append("<ul>"); + for ( TQMap<int,TQString>::const_iterator it = propertyStatusMapYellow.begin(); it != propertyStatusMapYellow.end(); ++it ) { + statusMessage.append("<li>"); + statusMessage.append(it.data()); + statusMessage.append("</li>"); + } + statusMessage.append("</ul>"); + } + + return statusMessage; +} + +TQString RecipeInputDialog::conversionPath( const TQString &ingUnit, const TQString &toUnit, const TQString &fromUnit, const TQString &propUnit ) const +{ + TQString path = "'"+ingUnit+"'"; + + TQString lastUnit = ingUnit; + if ( lastUnit != toUnit ) { + path.append(" => '"+toUnit+"'"); + lastUnit = toUnit; + } + if ( lastUnit != fromUnit ) { + path.append(" => '"+fromUnit+"'"); + lastUnit = fromUnit; + } + if ( lastUnit != propUnit ) { + path.append(" => '"+propUnit+"'"); + lastUnit = propUnit; + } + return path; +} + +#include "recipeinputdialog.moc" diff --git a/src/dialogs/recipeinputdialog.h b/src/dialogs/recipeinputdialog.h new file mode 100644 index 0000000..dd9a623 --- /dev/null +++ b/src/dialogs/recipeinputdialog.h @@ -0,0 +1,228 @@ +/*************************************************************************** +* Copyright (C) 2003-2005 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef RECIPEINPUTDIALOG_H +#define RECIPEINPUTDIALOG_H + +#include <kdialog.h> +#include <ktextedit.h> +#include <klineedit.h> +#include <kcombobox.h> +#include <tdelistview.h> +#include <knuminput.h> +#include <kpushbutton.h> +#include <kiconloader.h> +#include <kled.h> + +#include <tqlabel.h> +#include <tqgroupbox.h> +#include <tqmap.h> +#include <tqobject.h> +#include <tqtabwidget.h> +#include <tqtoolbutton.h> +#include <tqvbox.h> + +#include "datablocks/elementlist.h" + +class TQTabWidget; +class TQTimeEdit; +class TQDragEvent; +class TQButtonGroup; +class TQWidgetStack; +class TQTextEdit; + +class KreTextEdit; +class KWidgetListbox; +class KDialogBase; + +class ImageDropLabel; +class Recipe; +class ElementList; +class RecipeDB; +class FractionInput; +class Ingredient; +class Rating; +class RatingDisplayWidget; +class IngredientInputWidget; +class ClickableLed; + +/** +@author Unai Garro +*/ +class RecipeInputDialog: public TQVBox +{ + TQ_OBJECT + +public: + + RecipeInputDialog( TQWidget* parent, RecipeDB* db ); + void loadRecipe( int recipeID ); + ~RecipeInputDialog(); + void newRecipe( void ); + bool everythingSaved(); + void reload( void ); + int loadedRecipeID() const; + +private: + + // Internal Data + Recipe *loadedRecipe; //Loaded Recipe + RecipeDB *database; + bool changedSignalEnabled; + bool unsavedChanges; + + // Widgets + TQTabWidget* tabWidget; + TQGroupBox* recipeTab; + TQGroupBox* instructionsTab; + + //Recipe Photo + ImageDropLabel *photoLabel; + TQPixmap sourcePhoto; + TQPushButton *changePhotoButton; + + //Recipe Body + KreTextEdit* instructionsEdit; + TQLabel* titleLabel; + KLineEdit* titleEdit; + + //Additional recipe data + TQLabel* yieldLabel; + FractionInput* yieldNumInput; + KLineEdit* yieldTypeEdit; + TQTimeEdit *prepTimeEdit; + TQLabel* authorLabel; + KLineEdit* authorShow; + TQPushButton* addAuthorButton; + TQLabel* categoryLabel; + KLineEdit* categoryShow; + TQPushButton* addCategoryButton; + + //Ingredient inputs + TDEListView* ingredientList; + TQGroupBox *ingredientGBox; + IngredientInputWidget *ingInput; + ClickableLed *propertyStatusLed; + TQLabel *propertyStatusLabel; + TQPushButton *propertyStatusButton; + TQTextEdit *statusTextView; + KDialogBase *propertyStatusDialog; + + // Buttons to move ingredients up & down... + KPushButton* upButton; + KPushButton* downButton; + KPushButton* removeButton; + KPushButton* addButton; + KPushButton* ingParserButton; + + //Function buttons + TQGroupBox* functionsBox; + TQToolButton* saveButton; + TQToolButton* closeButton; + TQToolButton* showButton; + TQToolButton* resizeButton; + + TQToolButton* spellCheckButton; + + KWidgetListbox *ratingListDisplayWidget; + + TQMap<int,TQString> propertyStatusMapRed; + TQMap<int,TQString> propertyStatusMapYellow; + + // Internal functions + int createNewYieldIfNecessary( const TQString &yield ); + void saveRecipe( void ); + void showCategories( void ); + void showAuthors( void ); + int ingItemIndex( TQListView *listview, const TQListViewItem *item ) const; + void addRating( const Rating &rating, RatingDisplayWidget *item ); + TQString statusMessage() const; + TQString conversionPath( const TQString &ingUnit, const TQString &toUnit, const TQString &fromUnit, const TQString &propUnit ) const; + + // Signals & Slots + +private slots: + void changePhoto( void ); + void clearPhoto( void ); + void moveIngredientUp( void ); + void moveIngredientDown( void ); + void removeIngredient( void ); + void syncListView( TQListViewItem* it, const TQString &new_text, int col ); + void recipeChanged( void ); + void recipeChanged( const TQString &t ); + void enableChangedSignal( bool en = true ); + void addCategory( void ); + void addAuthor( void ); + void enableSaveButton( bool enabled ); + void closeOptions( void ); + void showRecipe( void ); + void prepTitleChanged( const TQString &title ); + void recipeRemoved( int id ); + void slotIngredientParser(); + void slotAddRating(); + void slotEditRating(); + void slotRemoveRating(); + void addIngredient( const Ingredient &ing, bool noHeader = false ); + void addIngredientHeader( const Element &header ); + void updatePropertyStatus(); + void updatePropertyStatus( const Ingredient &ing, bool updateIndicator ); + void showStatusIndicator(); + +public slots: + bool save ( void ); // Activated when krecipes.cpp sends signal save() + void spellCheck( void ); + void resizeRecipe( void ); + +signals: + void changed( void ); + void closeRecipe( void ); + void createButton( TQWidget* w, const TQString &title ); + void enableSaveOption( bool en = true ); + void showRecipe( int recipeID ); //Indicates krecipesview to show it + void titleChanged( const TQString &title ); + + +}; + +class ClickableLed : public KLed +{ +TQ_OBJECT + +public: + ClickableLed( TQWidget *parent ); + +protected: + virtual void mouseReleaseEvent( TQMouseEvent* ); + +signals: + void clicked(); +}; + +class ImageDropLabel : public TQLabel +{ + TQ_OBJECT + +public: + ImageDropLabel( TQWidget *parent, TQPixmap &_sourcePhoto ); + +signals: + void changed(); + +protected: + void dragEnterEvent( TQDragEnterEvent* event ); + void dropEvent( TQDropEvent* event ); + +private: + TQPixmap &sourcePhoto; +}; + +#endif diff --git a/src/dialogs/recipeprintpreview.cpp b/src/dialogs/recipeprintpreview.cpp new file mode 100644 index 0000000..7350d11 --- /dev/null +++ b/src/dialogs/recipeprintpreview.cpp @@ -0,0 +1,62 @@ +/*************************************************************************** +* Copyright (C) 2006 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "recipeprintpreview.h" + +#include <tqvbox.h> + +#include <kdebug.h> +#include <tdelocale.h> + +#include "recipeviewdialog.h" +#include "pagesetupdialog.h" + +RecipePrintPreview::RecipePrintPreview( TQWidget *parent, RecipeDB *db, const TQValueList<int> &ids ) + : KDialogBase( parent, "RecipePrintPreview", true, i18n("Print Preview"), + KDialogBase::Ok | KDialogBase::Cancel | KDialogBase::User1 | KDialogBase::Help, KDialogBase::Ok ) +{ + setHelp("print-recipe"); + setButtonText( KDialogBase::User1, i18n("&Edit") ); + setButtonText( KDialogBase::Ok, i18n("&Print") ); + + setSizeGripEnabled( true ); + + // Initialize UI Elements + TQVBox *page = makeVBoxMainWidget(); + + recipeView = new RecipeViewDialog( page, db ); + recipeView->loadRecipes( ids, "Print" ); + + setInitialSize( TQSize(450,500), false ); +} + +RecipePrintPreview::~RecipePrintPreview() +{ +} + +void RecipePrintPreview::slotOk() +{ + recipeView->printNoPreview(); + accept(); +} + +void RecipePrintPreview::slotUser1( void ) +{ + PageSetupDialog pageSetup( this, Recipe(), "Print" ); + if ( pageSetup.exec() == TQDialog::Accepted ) + reload(); +} + +void RecipePrintPreview::reload() +{ + recipeView->reload( "Print" ); +} + +#include "recipeprintpreview.moc" diff --git a/src/dialogs/recipeprintpreview.h b/src/dialogs/recipeprintpreview.h new file mode 100644 index 0000000..f4c7b65 --- /dev/null +++ b/src/dialogs/recipeprintpreview.h @@ -0,0 +1,41 @@ +/*************************************************************************** +* Copyright (C) 2006 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef RECIPEPRINTPREVIEW_H +#define RECIPEPRINTPREVIEW_H + +#include <tqstring.h> +#include <tqvaluelist.h> + +#include <kdialogbase.h> + +class RecipeDB; +class RecipeViewDialog; + +class RecipePrintPreview : public KDialogBase +{ +TQ_OBJECT + +public: + RecipePrintPreview( TQWidget *parent, RecipeDB *db, const TQValueList<int> &ids ); + ~RecipePrintPreview(); + + void reload(); + +public slots: + void slotOk(); + void slotUser1( void ); + +private: + // Internal Variables + RecipeViewDialog *recipeView; +}; + +#endif diff --git a/src/dialogs/recipeviewdialog.cpp b/src/dialogs/recipeviewdialog.cpp new file mode 100644 index 0000000..133aece --- /dev/null +++ b/src/dialogs/recipeviewdialog.cpp @@ -0,0 +1,167 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "recipeviewdialog.h" + +#include <tqlayout.h> +#include <tqstyle.h> +#include <tqfile.h> + +#include <tdeapplication.h> +#include <kcursor.h> +#include <kdebug.h> +#include <tdehtmlview.h> +#include <tdehtml_part.h> +#include <tdelocale.h> +#include <tdemainwindow.h> +#include <kprogress.h> +#include <kstandarddirs.h> +#include <kstatusbar.h> +#include <tdeconfig.h> +#include <tdeglobal.h> + +#include "datablocks/mixednumber.h" +#include "backends/recipedb.h" +#include "exporters/htmlexporter.h" +#include "recipeprintpreview.h" + +RecipeViewDialog::RecipeViewDialog( TQWidget *parent, RecipeDB *db, int recipeID ) : TQVBox( parent ), + database(db) +{ + // Initialize UI Elements + recipeView = new TDEHTMLPart( this ); + + connect( database, TQ_SIGNAL(recipeRemoved(int)), TQ_SLOT(recipeRemoved(int)) ); + + tmp_filename = locateLocal( "tmp", "krecipes_recipe_view" ); + + //----------Load the recipe -------- + if ( recipeID != -1 ) + loadRecipe( recipeID ); +} + +RecipeViewDialog::~RecipeViewDialog() +{ + if ( recipe_loaded ) + removeOldFiles(); +} + +bool RecipeViewDialog::loadRecipe( int recipeID ) +{ + TQValueList<int> ids; + ids.append( recipeID ); + return loadRecipes( ids ); +} + +bool RecipeViewDialog::loadRecipes( const TQValueList<int> &ids, const TQString &layoutConfig ) +{ + TDEApplication::setOverrideCursor( KCursor::waitCursor() ); + + // Remove any files created by the last recipe loaded + removeOldFiles(); + + ids_loaded = ids; //need to save these ids in order to delete the html files later...make sure this comes after the call to removeOldFiles() + recipe_loaded = ( ids.count() > 0 && ids[ 0 ] >= 0 ); + + bool success = showRecipes( ids, layoutConfig ); + + TDEApplication::restoreOverrideCursor(); + return success; +} + +bool RecipeViewDialog::showRecipes( const TQValueList<int> &ids, const TQString &layoutConfig ) +{ + KProgressDialog * progress_dialog = 0; + + if ( ids.count() > 1 ) //we don't want a progress bar coming up when there is only one recipe... it may show up during the splash screen + { + progress_dialog = new KProgressDialog( this, "open_progress_dialog", TQString::null, i18n( "Opening recipes, please wait..." ), true ); + progress_dialog->resize( 240, 80 ); + } + + HTMLExporter html_generator( tmp_filename + ".html", "html" ); + if ( layoutConfig != TQString::null ) { + TDEConfig *config = TDEGlobal::config(); + config->setGroup( "Page Setup" ); + TQString styleFile = config->readEntry( layoutConfig+"Layout", locate( "appdata", "layouts/Default.klo" ) ); + if ( !styleFile.isEmpty() && TQFile::exists( styleFile ) ) + html_generator.setStyle( styleFile ); + + TQString templateFile = config->readEntry( layoutConfig+"Template", locate( "appdata", "layouts/Default.template" ) ); + if ( !templateFile.isEmpty() && TQFile::exists( templateFile ) ) + html_generator.setTemplate( templateFile ); + } + + html_generator.exporter( ids, database, progress_dialog ); //writes the generated HTML to 'tmp_filename+".html"' + if ( progress_dialog && progress_dialog->wasCancelled() ) { + delete progress_dialog; + return false; + } + + delete recipeView; // Temporary workaround + recipeView = new TDEHTMLPart( this ); // to avoid the problem of caching images of TDEHTMLPart + + KURL url; + url.setPath( tmp_filename + ".html" ); + recipeView->openURL( url ); + recipeView->show(); + kdDebug() << "Opening URL: " << url.htmlURL() << endl; + + delete progress_dialog; + return true; +} + +void RecipeViewDialog::print() +{ + if ( recipe_loaded ) { + RecipePrintPreview preview( this, database, ids_loaded ); + preview.exec(); + } +} + +void RecipeViewDialog::printNoPreview( void ) +{ + if ( recipe_loaded ) { + recipeView->view() ->print(); + } +} + +void RecipeViewDialog::reload( const TQString &layoutConfig ) +{ + loadRecipes( ids_loaded, layoutConfig ); +} + +void RecipeViewDialog::removeOldFiles() +{ + if ( ids_loaded.count() > 0 ) { + RecipeList recipe_list; + database->loadRecipes( &recipe_list, RecipeDB::Title, ids_loaded ); + + TQValueList<int> recipe_ids; + for ( RecipeList::const_iterator it = recipe_list.begin(); it != recipe_list.end(); ++it ) + recipe_ids << ( *it ).recipeID; + + HTMLExporter::removeHTMLFiles( tmp_filename, recipe_ids ); + } +} + +void RecipeViewDialog::recipeRemoved( int id ) +{ + //if the deleted recipe is loaded, clean the view up + if ( ids_loaded.find(id) != ids_loaded.end() ) { + Recipe recipe; database->loadRecipe( &recipe, RecipeDB::Title, id ); + HTMLExporter::removeHTMLFiles( tmp_filename, recipe.recipeID ); + ids_loaded.remove(id); + } +} + +#include "recipeviewdialog.moc" diff --git a/src/dialogs/recipeviewdialog.h b/src/dialogs/recipeviewdialog.h new file mode 100644 index 0000000..2b7c884 --- /dev/null +++ b/src/dialogs/recipeviewdialog.h @@ -0,0 +1,77 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef RECIPEVIEWDIALOG_H +#define RECIPEVIEWDIALOG_H + +#include <tqvbox.h> +#include <tqstring.h> + +class RecipeDB; +class Recipe; +class TDEHTMLPart; +class TQPushButton; + +/** +@author Unai Garro +*/ + +class RecipeViewDialog : public TQVBox +{ + TQ_OBJECT + +public: + RecipeViewDialog( TQWidget *parent, RecipeDB *db, int recipeID = -1 ); + + ~RecipeViewDialog(); + + /** @return Boolean indicating whether or not the recipe was successfully loaded */ + bool loadRecipe( int recipeID ); + + /** @return Boolean indicating whether or not the recipes were successfully loaded */ + bool loadRecipes( const TQValueList<int> &ids, const TQString &layoutConfig = TQString::null ); + + int recipesLoaded() const + { + return ids_loaded.count(); + } + const TQValueList<int> currentRecipes() const + { + return ids_loaded; + } + + void reload( const TQString &layoutConfig = TQString::null ); + +public slots: + void printNoPreview( void ); + void print( void ); + +private: + + // Internal Variables + TDEHTMLPart *recipeView; + RecipeDB *database; + bool recipe_loaded; + TQValueList<int> ids_loaded; + TQString tmp_filename; + + // Internal Methods + bool showRecipes( const TQValueList<int> &ids, const TQString &layoutConfig ); + void removeOldFiles(); + +private slots: + void recipeRemoved(int); + +}; + + +#endif diff --git a/src/dialogs/refineshoppinglistdialog.cpp b/src/dialogs/refineshoppinglistdialog.cpp new file mode 100644 index 0000000..adbe5bb --- /dev/null +++ b/src/dialogs/refineshoppinglistdialog.cpp @@ -0,0 +1,206 @@ +/*************************************************************************** +* Copyright (C) 2004 by Jason Kivlighn * +* (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "refineshoppinglistdialog.h" + +#include <tqvariant.h> +#include <tqpushbutton.h> +#include <tqlabel.h> +#include <tqheader.h> +#include <tqlayout.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> + +#include <tdelocale.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kcursor.h> +#include <tdeconfig.h> + +#include "backends/recipedb.h" +#include "widgets/krelistview.h" +#include "widgets/ingredientlistview.h" +#include "shoppinglistviewdialog.h" +#include "shoppingcalculator.h" +#include "datablocks/mixednumber.h" + +RefineShoppingListDialog::RefineShoppingListDialog( TQWidget* parent, RecipeDB *db, const ElementList &recipeList ) + : KDialogBase( parent, "refinedialog", true, TQString::null, + KDialogBase::Ok, KDialogBase::Ok ), + database( db ) +{ + setButtonText( KDialogBase::Ok, i18n( "&Done" ) ); + + TQVBox *page = makeVBoxMainWidget(); + + helpLabel = new TQLabel( page, "helpLabel" ); + helpLabel->setTextFormat( TQLabel::RichText ); + + TQWidget *layout2Widget = new TQWidget(page); + + TQHBoxLayout *layout2 = new TQHBoxLayout( layout2Widget, 0, 6, "layout2" ); + + allIngListView = new KreListView( layout2Widget, TQString::null, true, 0 ); + StdIngredientListView *list_view = new StdIngredientListView(allIngListView,database); + list_view->reload(); + allIngListView->setListView(list_view); + layout2->addWidget( allIngListView ); + + layout1 = new TQVBoxLayout( 0, 0, 6, "layout1" ); + + TDEIconLoader il; + + addButton = new TQPushButton( layout2Widget, "addButton" ); + addButton->setIconSet( il.loadIconSet( "forward", TDEIcon::Small ) ); + addButton->setFixedSize( TQSize( 32, 32 ) ); + layout1->addWidget( addButton ); + + removeButton = new TQPushButton( layout2Widget, "removeButton" ); + removeButton->setIconSet( il.loadIconSet( "back", TDEIcon::Small ) ); + removeButton->setFixedSize( TQSize( 32, 32 ) ); + layout1->addWidget( removeButton ); + spacer1 = new TQSpacerItem( 51, 191, TQSizePolicy::Minimum, TQSizePolicy::Expanding ); + layout1->addItem( spacer1 ); + layout2->addLayout( layout1 ); + + ingListView = new KreListView( layout2Widget, TQString::null, true ); + ingListView->listView() ->addColumn( i18n( "Ingredients in Shopping List" ) ); + ingListView->listView() ->addColumn( i18n( "Amount" ) ); + ingListView->listView() ->addColumn( i18n( "Unit" ) ); + ingListView->listView() ->setItemsRenameable( true ); + ingListView->listView() ->setRenameable( 0, false ); + ingListView->listView() ->setRenameable( 1, true ); + ingListView->listView() ->setRenameable( 2, true ); + layout2->addWidget( ingListView ); + + languageChange(); + + clearWState( WState_Polished ); + + connect( addButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( addIngredient() ) ); + connect( removeButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( removeIngredient() ) ); + connect( ingListView->listView(), TQ_SIGNAL( itemRenamed( TQListViewItem*, const TQString &, int ) ), TQ_SLOT( itemRenamed( TQListViewItem*, const TQString &, int ) ) ); + + TDEApplication::setOverrideCursor( KCursor::waitCursor() ); + calculateShopping( recipeList, &ingredientList, database ); + TDEApplication::restoreOverrideCursor(); + + loadData(); +} + +RefineShoppingListDialog::~RefineShoppingListDialog() +{} + +void RefineShoppingListDialog::languageChange() +{ + helpLabel->setText( i18n( "On the right are the ingredients needed for the recipes you selected. You may now add additional ingredients, remove ingredients you do not need, or modify the amounts of existing ingredients." ) ); + allIngListView->listView() ->header() ->setLabel( 0, i18n( "Ingredients" ) ); + ingListView->listView() ->header() ->setLabel( 0, i18n( "Ingredients in Shopping List" ) ); + ingListView->listView() ->header() ->setLabel( 1, i18n( "Amount" ) ); + ingListView->listView() ->header() ->setLabel( 2, i18n( "Unit" ) ); +} + +void RefineShoppingListDialog::accept() +{ + hide(); + + ShoppingListViewDialog view( this, ingredientList ); + view.exec(); + + TQDialog::accept(); +} + +void RefineShoppingListDialog::loadData() +{ + for ( IngredientList::iterator it = ingredientList.begin(); it != ingredientList.end(); ++it ) { + //from here on, the shopping list will work with the upper value of the range (if exists) + (*it).amount = (*it).amount+(*it).amount_offset; + (*it).amount_offset = 0; + + TQString amount_str; + if ( ( *it ).amount > 0 ) { + TDEConfig * config = kapp->config(); + config->setGroup( "Formatting" ); + + if ( config->readBoolEntry( "Fraction" ) ) + amount_str = MixedNumber( ( *it ).amount ).toString(); + else + amount_str = beautify( TDEGlobal::locale() ->formatNumber( ( *it ).amount, 5 ) ); + } + + TQListViewItem *new_item = new TQListViewItem( ingListView->listView(), ( *it ).name, amount_str, ( *it ).amount > 1 ? ( *it ).units.plural : ( *it ).units.name ); + item_ing_map.insert( new_item, it ); + } +} + +void RefineShoppingListDialog::addIngredient() +{ + TQListViewItem * item = allIngListView->listView() ->selectedItem(); + if ( item ) { + TQListViewItem * new_item = new TQListViewItem( ingListView->listView(), item->text( 0 ) ); + ingListView->listView() ->setSelected( new_item, true ); + ingListView->listView() ->ensureItemVisible( new_item ); + allIngListView->listView() ->setSelected( item, false ); + + item_ing_map.insert( new_item, ingredientList.append( Ingredient( item->text( 0 ), 0, Unit() ) ) ); + } +} + +void RefineShoppingListDialog::removeIngredient() +{ + TQListViewItem * item = ingListView->listView() ->selectedItem(); + if ( item ) { + for ( IngredientList::iterator it = ingredientList.begin(); it != ingredientList.end(); ++it ) { + if ( *item_ing_map.find( item ) == it ) { + ingredientList.remove( it ); + item_ing_map.remove( item ); + break; + } + } + delete item; + } +} + +void RefineShoppingListDialog::itemRenamed( TQListViewItem* item, const TQString &new_text, int col ) +{ + if ( col == 1 ) { + IngredientList::iterator found_it = *item_ing_map.find( item ); + + bool ok; + MixedNumber amount = MixedNumber::fromString( new_text, &ok ); + if ( ok ) { + ( *found_it ).amount = amount.toDouble(); + } + else { //revert back to the valid amount string + TQString amount_str; + if ( ( *found_it ).amount > 0 ) { + TDEConfig * config = kapp->config(); + config->setGroup( "Formatting" ); + + if ( config->readBoolEntry( "Fraction" ) ) + amount_str = MixedNumber( ( *found_it ).amount ).toString(); + else + amount_str = beautify( TDEGlobal::locale() ->formatNumber( ( *found_it ).amount, 5 ) ); + } + + item->setText( 1, amount_str ); + } + } + else if ( col == 2 ) { + IngredientList::iterator found_it = *item_ing_map.find( item ); + + if ( ( *found_it ).amount > 1 ) + ( *found_it ).units.plural = new_text; + else + ( *found_it ).units.name = new_text; + } +} + +#include "refineshoppinglistdialog.moc" diff --git a/src/dialogs/refineshoppinglistdialog.h b/src/dialogs/refineshoppinglistdialog.h new file mode 100644 index 0000000..5952a9b --- /dev/null +++ b/src/dialogs/refineshoppinglistdialog.h @@ -0,0 +1,66 @@ +/*************************************************************************** +* Copyright (C) 2004 by Jason Kivlighn * +* (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef REFINESHOPPINGLISTDIALOG_H +#define REFINESHOPPINGLISTDIALOG_H + +#include <tqvariant.h> +#include <tqmap.h> + +#include <kdialogbase.h> + +#include "datablocks/ingredientlist.h" + +class TQVBoxLayout; +class TQHBoxLayout; +class TQGridLayout; +class TQSpacerItem; +class TQLabel; +class TQListViewItem; +class TQPushButton; + +class RecipeDB; +class ElementList; +class KreListView; + +class RefineShoppingListDialog : public KDialogBase +{ + TQ_OBJECT + +public: + RefineShoppingListDialog( TQWidget* parent, RecipeDB *db, const ElementList &recipeList ); + ~RefineShoppingListDialog(); + + TQLabel* helpLabel; + KreListView* allIngListView; + TQPushButton* addButton; + TQPushButton* removeButton; + KreListView* ingListView; + +protected: + TQVBoxLayout* layout1; + TQSpacerItem* spacer1; + +protected slots: + virtual void languageChange(); + virtual void accept(); + void addIngredient(); + void removeIngredient(); + void itemRenamed( TQListViewItem*, const TQString &, int ); + +private: + void loadData(); + + RecipeDB *database; + IngredientList ingredientList; + TQMap<TQListViewItem*, IngredientList::iterator> item_ing_map; +}; + +#endif // REFINESHOPPINGLISTDIALOG_H diff --git a/src/dialogs/resizerecipedialog.cpp b/src/dialogs/resizerecipedialog.cpp new file mode 100644 index 0000000..958fadb --- /dev/null +++ b/src/dialogs/resizerecipedialog.cpp @@ -0,0 +1,191 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "resizerecipedialog.h" + +#include <cmath> + +#include <tqvbox.h> +#include <tqvariant.h> +#include <tqbuttongroup.h> +#include <tqframe.h> +#include <tqlabel.h> +#include <knuminput.h> +#include <klineedit.h> +#include <tqradiobutton.h> +#include <tqlayout.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> +#include <tqimage.h> +#include <tqpixmap.h> + +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <kdebug.h> + +#include "datablocks/recipe.h" +#include "widgets/fractioninput.h" + +#define FACTOR_RADIO_BUTTON 0 +#define SERVINGS_RADIO_BUTTON 1 + +ResizeRecipeDialog::ResizeRecipeDialog( TQWidget *parent, Recipe *recipe ) + : KDialogBase( parent, "ResizeRecipeDialog", true, i18n( "Resize Recipe" ), + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok ), + m_recipe( recipe ) +{ + TQVBox *page = makeVBoxMainWidget(); + + buttonGroup = new TQButtonGroup( page ); + buttonGroup->setSizePolicy( TQSizePolicy( ( TQSizePolicy::SizeType ) 5, ( TQSizePolicy::SizeType ) 7, 0, 1, buttonGroup->sizePolicy().hasHeightForWidth() ) ); + buttonGroup->setLineWidth( 0 ); + buttonGroup->setColumnLayout( 0, TQt::Vertical ); + buttonGroup->layout() ->setSpacing( 6 ); + buttonGroup->layout() ->setMargin( 11 ); + buttonGroupLayout = new TQVBoxLayout( buttonGroup->layout() ); + buttonGroupLayout->setAlignment( TQt::AlignTop ); + + yieldRadioButton = new TQRadioButton( buttonGroup ); + buttonGroup->insert( yieldRadioButton, SERVINGS_RADIO_BUTTON ); + buttonGroupLayout->addWidget( yieldRadioButton ); + + yieldFrame = new TQFrame( buttonGroup ); + yieldFrame->setFrameShape( TQFrame::Box ); + yieldFrame->setFrameShadow( TQFrame::Sunken ); + yieldFrame->setLineWidth( 1 ); + yieldFrameLayout = new TQGridLayout( yieldFrame, 1, 1, 11, 6 ); + + currentYieldLabel = new TQLabel( yieldFrame ); + + yieldFrameLayout->addWidget( currentYieldLabel, 0, 0 ); + + newYieldLabel = new TQLabel( yieldFrame ); + + yieldFrameLayout->addMultiCellWidget( newYieldLabel, 1, 1, 0, 1 ); + + currentYieldInput = new KLineEdit( yieldFrame ); + currentYieldInput->setReadOnly( TRUE ); + currentYieldInput->setAlignment( TQt::AlignRight ); + yieldFrameLayout->addMultiCellWidget( currentYieldInput, 0, 0, 1, 2 ); + + newYieldInput = new FractionInput( yieldFrame ); + yieldFrameLayout->addWidget( newYieldInput, 1, 2 ); + + buttonGroupLayout->addWidget( yieldFrame ); + + factorRadioButton = new TQRadioButton( buttonGroup ); + buttonGroup->insert( factorRadioButton, FACTOR_RADIO_BUTTON ); + buttonGroupLayout->addWidget( factorRadioButton ); + + factorFrame = new TQFrame( buttonGroup ); + factorFrame->setSizePolicy( TQSizePolicy( ( TQSizePolicy::SizeType ) 7, ( TQSizePolicy::SizeType ) 5, 1, 0, factorFrame->sizePolicy().hasHeightForWidth() ) ); + factorFrame->setFrameShape( TQFrame::Box ); + factorFrame->setFrameShadow( TQFrame::Sunken ); + factorFrame->setLineWidth( 1 ); + factorFrameLayout = new TQHBoxLayout( factorFrame, 11, 6 ); + + factorLabel = new TQLabel( factorFrame ); + factorFrameLayout->addWidget( factorLabel ); + + factorInput = new FractionInput( factorFrame ); + factorInput->setSizePolicy( TQSizePolicy( ( TQSizePolicy::SizeType ) 7, ( TQSizePolicy::SizeType ) 5, 0, 0, factorInput->sizePolicy().hasHeightForWidth() ) ); + factorFrameLayout->addWidget( factorInput ); + buttonGroupLayout->addWidget( factorFrame ); + + languageChange(); + + + newYieldInput->setValue( m_recipe->yield.amount, 0 ); //Ignore the range info, it doesn't work in this context + currentYieldInput->setText( m_recipe->yield.toString() ); + + if ( recipe->yield.amount_offset > 0 ) { + yieldRadioButton->setEnabled(false); + buttonGroup->setButton( FACTOR_RADIO_BUTTON ); + activateCurrentOption( FACTOR_RADIO_BUTTON ); + } + else { + buttonGroup->setButton( SERVINGS_RADIO_BUTTON ); + activateCurrentOption( SERVINGS_RADIO_BUTTON ); + } + + // signals and slots connections + connect( buttonGroup, TQ_SIGNAL( clicked( int ) ), this, TQ_SLOT( activateCurrentOption( int ) ) ); +} + +void ResizeRecipeDialog::languageChange() +{ + buttonGroup->setTitle( TQString::null ); + yieldRadioButton->setText( i18n( "Scale by yield" ) ); + newYieldLabel->setText( i18n( "New yield:" ) ); + currentYieldLabel->setText( i18n( "Current yield:" ) ); + factorRadioButton->setText( i18n( "Scale by factor" ) ); + factorLabel->setText( i18n( "Factor (i.e. 1/2 to half, 3 to triple):" ) ); +} + +void ResizeRecipeDialog::activateCurrentOption( int button_id ) +{ + switch ( button_id ) { + case SERVINGS_RADIO_BUTTON: + factorFrame->setEnabled( false ); + yieldFrame->setEnabled( true ); + break; + case FACTOR_RADIO_BUTTON: + factorFrame->setEnabled( true ); + yieldFrame->setEnabled( false ); + break; + default: + break; + } +} + +void ResizeRecipeDialog::accept() +{ + if ( currentYieldInput->text().toInt() == 0 ) + KMessageBox::error( this, i18n( "Unable to scale a recipe with zero yield" ) ); + else if ( buttonGroup->selected() == yieldRadioButton ) { + if ( newYieldInput->isInputValid() ) { + double new_yield = newYieldInput->value().toDouble(); + double current_yield = MixedNumber::fromString(currentYieldInput->text()).toDouble(); + + resizeRecipe( new_yield / current_yield ); + } + else { + KMessageBox::error( this, i18n( "Invalid input" ) ); + newYieldInput->selectAll(); + return; + } + } + else { + if ( factorInput->isInputValid() && factorInput->value() > 0 ) + resizeRecipe( factorInput->value().toDouble() ); + else { + KMessageBox::error( this, i18n( "Invalid input" ) ); + factorInput->selectAll(); + return ; + } + } + + TQDialog::accept(); +} + +//TODO YIELD: handle ranges +void ResizeRecipeDialog::resizeRecipe( double factor ) +{ + m_recipe->yield.amount = MixedNumber::fromString(currentYieldInput->text()).toDouble() * factor; + + for ( IngredientList::iterator ing_it = m_recipe->ingList.begin(); ing_it != m_recipe->ingList.end(); ++ing_it ) { + ( *ing_it ).amount = ( *ing_it ).amount * factor; + ( *ing_it ).amount_offset = ( *ing_it ).amount_offset * factor; + } +} + +#include "resizerecipedialog.moc" diff --git a/src/dialogs/resizerecipedialog.h b/src/dialogs/resizerecipedialog.h new file mode 100644 index 0000000..725ecdb --- /dev/null +++ b/src/dialogs/resizerecipedialog.h @@ -0,0 +1,69 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef RESIZERECIPEDIALOG_H +#define RESIZERECIPEDIALOG_H + +#include <kdialogbase.h> + +class Recipe; + +class TQVBoxLayout; +class TQHBoxLayout; +class TQGridLayout; +class FractionInput; +class TQButtonGroup; +class TQFrame; +class TQLabel; +class KIntNumInput; +class KLineEdit; +class TQRadioButton; +class TQPushButton; + +/** + *@author Jason Kivlighn + */ +class ResizeRecipeDialog : public KDialogBase +{ + TQ_OBJECT + +public: + ResizeRecipeDialog( TQWidget *parent, Recipe* ); + +protected slots: + void accept(); + void activateCurrentOption( int ); + virtual void languageChange(); + +private: + void resizeRecipe( double factor ); + + Recipe *m_recipe; + + TQButtonGroup* buttonGroup; + TQRadioButton* yieldRadioButton; + TQFrame* yieldFrame; + TQLabel* currentYieldLabel; + TQLabel* newYieldLabel; + KLineEdit* currentYieldInput; + FractionInput* newYieldInput; + TQRadioButton* factorRadioButton; + TQFrame* factorFrame; + TQLabel* factorLabel; + FractionInput* factorInput; + + TQVBoxLayout* buttonGroupLayout; + TQGridLayout* yieldFrameLayout; + TQHBoxLayout* factorFrameLayout; +}; + +#endif //RESIZERECIPEDIALOG_H diff --git a/src/dialogs/selectauthorsdialog.cpp b/src/dialogs/selectauthorsdialog.cpp new file mode 100644 index 0000000..d7583d3 --- /dev/null +++ b/src/dialogs/selectauthorsdialog.cpp @@ -0,0 +1,181 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "selectauthorsdialog.h" + +#include <tqmessagebox.h> +#include <tqvbox.h> + +#include <tdeconfig.h> +#include <kdialog.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <tdeglobal.h> + +#include "backends/recipedb.h" + +SelectAuthorsDialog::SelectAuthorsDialog( TQWidget *parent, const ElementList ¤tAuthors, RecipeDB *db ) + : KDialogBase( parent, "SelectAuthorsDialog", true, i18n("Authors"), + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok ), + database(db) +{ + TQVBox *page = makeVBoxMainWidget(); + + //Design UI + + // Combo to Pick authors + TQHBox *topBox = new TQHBox(page); + topBox->setSpacing(6); + + authorsCombo = new KComboBox( true, topBox ); + authorsCombo->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding ) ); + authorsCombo->completionObject() ->setCompletionMode( TDEGlobalSettings::CompletionPopupAuto ); + authorsCombo->lineEdit() ->disconnect( authorsCombo ); //so hitting enter doesn't enter the item into the box + + // Add/Remove buttons + + il = new TDEIconLoader; + addAuthorButton = new TQPushButton( topBox ); + TQPixmap pm = il->loadIcon( "go-down", TDEIcon::NoGroup, 16 ); + addAuthorButton->setIconSet( pm ); + + removeAuthorButton = new TQPushButton( topBox ); + pm = il->loadIcon( "go-up", TDEIcon::NoGroup, 16 ); + removeAuthorButton->setIconSet( pm ); + + // Author List + + authorListView = new TDEListView( page ); + authorListView->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding ) ); + + TDEConfig * config = TDEGlobal::config(); + config->setGroup( "Advanced" ); + bool show_id = config->readBoolEntry( "ShowID", false ); + authorListView->addColumn( i18n( "Id" ), show_id ? -1 : 0 ); + authorListView->addColumn( i18n( "Author" ) ); + authorListView->setAllColumnsShowFocus( true ); + + // Load the list + loadAuthors( currentAuthors ); + + adjustSize(); + resize(450, height()); + + // Connect signals & Slots + connect ( addAuthorButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( addAuthor() ) ); + connect ( removeAuthorButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( removeAuthor() ) ); + + authorsCombo->setEditText(TQString::null); + authorsCombo->lineEdit()->setFocus(); +} + +SelectAuthorsDialog::~SelectAuthorsDialog() +{} + +void SelectAuthorsDialog::getSelectedAuthors( ElementList *newAuthors ) +{ + + for ( TQListViewItem * it = authorListView->firstChild();it; it = it->nextSibling() ) { + Element author; + author.id = it->text( 0 ).toInt(); + author.name = it->text( 1 ); + newAuthors->append( author ); + } + +} + +void SelectAuthorsDialog::loadAuthors( const ElementList ¤tAuthors ) +{ + + // Load the combo + reloadAuthorsCombo(); + + // Load the ListView with the authors of this recipe + authorListView->clear(); + for ( ElementList::const_iterator author_it = currentAuthors.begin(); author_it != currentAuthors.end(); ++author_it ) { + ( void ) new TQListViewItem( authorListView, TQString::number( ( *author_it ).id ), ( *author_it ).name ); + } + +} + +void SelectAuthorsDialog::addAuthor( void ) +{ + //check bounds first + if ( authorsCombo->currentText().length() > uint(database->maxAuthorNameLength()) ) { + KMessageBox::error( this, TQString( i18n( "Author name cannot be longer than %1 characters." ) ).arg( database->maxAuthorNameLength() ) ); + authorsCombo->lineEdit() ->selectAll(); + return ; + } + + if ( authorsCombo->lineEdit()->text().isEmpty() ) + return; + + if ( authorsCombo->contains( authorsCombo->currentText() ) ) + authorsCombo->setCurrentItem( authorsCombo->currentText() ); + + createNewAuthorIfNecessary(); + + int currentItem = authorsCombo->currentItem(); + Element currentElement = authorList.getElement( currentItem ); + + ( void ) new TQListViewItem( authorListView, TQString::number( currentElement.id ), currentElement.name ); + +} + +void SelectAuthorsDialog::removeAuthor( void ) +{ + // Find the selected item first + TQListViewItem * it; + it = authorListView->selectedItem(); + + if ( it ) { // Check if an author is selected first + delete it; + } + +} + +void SelectAuthorsDialog::createNewAuthorIfNecessary( void ) +{ + + if ( !authorsCombo->contains( authorsCombo->currentText() ) && + !( authorsCombo->currentText().stripWhiteSpace() ).isEmpty() ) // author is not in the list and is not empty + { // Create new author + TQString newAuthorName = authorsCombo->currentText(); + database->createNewAuthor( newAuthorName ); + //List again the authors + reloadAuthorsCombo(); + + // Select the newly created author + authorsCombo->setCurrentItem( newAuthorName ); + } +} + + +void SelectAuthorsDialog::reloadAuthorsCombo( void ) +{ + + //Load the author list + database->loadAuthors( &authorList ); + + // Load combo with all the authors + authorsCombo->clear(); + authorsCombo->completionObject() ->clear(); + + for ( ElementList::const_iterator author_it = authorList.begin(); author_it != authorList.end(); ++author_it ) { + authorsCombo->insertItem( ( *author_it ).name ); + authorsCombo->completionObject() ->addItem( ( *author_it ).name ); + } + +} + + +#include "selectauthorsdialog.moc" diff --git a/src/dialogs/selectauthorsdialog.h b/src/dialogs/selectauthorsdialog.h new file mode 100644 index 0000000..6304e08 --- /dev/null +++ b/src/dialogs/selectauthorsdialog.h @@ -0,0 +1,66 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef SELECTAUTHORSDIALOG_H +#define SELECTAUTHORSDIALOG_H + +#include <tqlayout.h> +#include <tqpushbutton.h> + +#include <kdialogbase.h> +#include <kiconloader.h> +#include <tdelistview.h> +#include <kcombobox.h> + +#include "datablocks/elementlist.h" + +class RecipeDB; + +/** +@author Unai Garro +*/ +class SelectAuthorsDialog: public KDialogBase +{ + + TQ_OBJECT + +public: + + SelectAuthorsDialog( TQWidget *parent, const ElementList ¤tAuthors, RecipeDB *db ); + ~SelectAuthorsDialog(); + void getSelectedAuthors( ElementList *newAuthors ); + +private: + + //Widgets + KComboBox *authorsCombo; + TDEListView *authorListView; + TQPushButton *okButton; + TQPushButton *cancelButton; + TQPushButton *addAuthorButton; + TQPushButton *removeAuthorButton; + TDEIconLoader *il; + + //Variables + ElementList authorList; + RecipeDB *database; + + //Private methods + void loadAuthors( const ElementList &authorList ); + void createNewAuthorIfNecessary( void ); + void reloadAuthorsCombo( void ); +private slots: + void addAuthor( void ); + void removeAuthor( void ); +}; + +#endif diff --git a/src/dialogs/selectcategoriesdialog.cpp b/src/dialogs/selectcategoriesdialog.cpp new file mode 100644 index 0000000..fe75bd3 --- /dev/null +++ b/src/dialogs/selectcategoriesdialog.cpp @@ -0,0 +1,104 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "selectcategoriesdialog.h" +#include "createcategorydialog.h" + +#include <tqvbox.h> + +#include <tdelocale.h> +#include <kdebug.h> +#include <kdialog.h> +#include <tdemessagebox.h> + +#include "datablocks/categorytree.h" +#include "backends/recipedb.h" +#include "widgets/categorylistview.h" + +SelectCategoriesDialog::SelectCategoriesDialog( TQWidget *parent, const ElementList &items_on, RecipeDB *db ) + : KDialogBase( parent, "SelectCategoriesDialog", true, i18n("Categories"), + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok ), + database(db) +{ + TQVBox *page = makeVBoxMainWidget(); + + //Design UI + + //Category List + categoryListView = new CategoryCheckListView( page, db, true, items_on ); + categoryListView->reload(); + + //New category button + TQPushButton *newCatButton = new TQPushButton( page ); + newCatButton->setText( i18n( "&New Category..." ) ); + newCatButton->setFlat( true ); + + // Load the list + loadCategories( items_on ); + + setSizeGripEnabled( true ); + + // Connect signals & Slots + connect ( newCatButton, TQ_SIGNAL( clicked() ), TQ_SLOT( createNewCategory() ) ); +} + +SelectCategoriesDialog::~SelectCategoriesDialog() +{} + +void SelectCategoriesDialog::getSelectedCategories( ElementList *newSelected ) +{ + *newSelected = categoryListView->selections(); +} + +void SelectCategoriesDialog::loadCategories( const ElementList &items_on ) +{ + categoryListView->populateAll(); + + ElementList::const_iterator it; + for ( it = items_on.begin(); it != items_on.end(); ++it ) { + CategoryCheckListItem *new_item = (CategoryCheckListItem*)categoryListView->findItem(TQString::number((*it).id),1); + if ( new_item ) { + new_item->setOn(true); + } + } +} + +void SelectCategoriesDialog::createNewCategory( void ) +{ + ElementList categories; + database->loadCategories( &categories ); + CreateCategoryDialog* categoryDialog = new CreateCategoryDialog( this, categories ); + + if ( categoryDialog->exec() == TQDialog::Accepted ) { + TQString result = categoryDialog->newCategoryName(); + int subcategory = categoryDialog->subcategory(); + + //check bounds first + if ( result.length() > uint(database->maxCategoryNameLength()) ) { + KMessageBox::error( this, TQString( i18n( "Category name cannot be longer than %1 characters." ) ).arg( database->maxCategoryNameLength() ) ); + return ; + } + + database->createNewCategory( result, subcategory ); // Create the new category in the database + + //a listview item will automatically be created, but we need to turn it on + Element new_cat( result, database->lastInsertID() ); + TQCheckListItem *new_item = ((TQCheckListItem*)categoryListView->findItem( TQString::number(new_cat.id), 1 )); + if ( new_item ) + new_item->setOn(true); + } + + delete categoryDialog; +} + + +#include "selectcategoriesdialog.moc" diff --git a/src/dialogs/selectcategoriesdialog.h b/src/dialogs/selectcategoriesdialog.h new file mode 100644 index 0000000..d73bb2b --- /dev/null +++ b/src/dialogs/selectcategoriesdialog.h @@ -0,0 +1,57 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef SELECTCATEGORIESDIALOG_H +#define SELECTCATEGORIESDIALOG_H + +#include <tqlayout.h> +#include <tqpushbutton.h> + +#include <tdelistview.h> +#include <kdialogbase.h> + +#include "datablocks/elementlist.h" + +class CategoryTree; +class CategoryCheckListItem; +class CategoryCheckListView; +class RecipeDB; + +/** +@author Unai Garro +*/ +class SelectCategoriesDialog: public KDialogBase +{ + + TQ_OBJECT + +public: + + SelectCategoriesDialog( TQWidget *parent, const ElementList &items_on, RecipeDB* db ); + ~SelectCategoriesDialog(); + void getSelectedCategories( ElementList *selected ); +private: + + //Widgets + CategoryCheckListView *categoryListView; + + //Variables + RecipeDB *database; + + //Private methods + void loadCategories( const ElementList &items_on ); + +private slots: + void createNewCategory( void ); +}; + +#endif diff --git a/src/dialogs/selectpropertydialog.cpp b/src/dialogs/selectpropertydialog.cpp new file mode 100644 index 0000000..1ce1887 --- /dev/null +++ b/src/dialogs/selectpropertydialog.cpp @@ -0,0 +1,123 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "selectpropertydialog.h" + +#include <tdeconfig.h> +#include <tdeglobal.h> +#include <tdelocale.h> + +#include "datablocks/ingredientpropertylist.h" + +SelectPropertyDialog::SelectPropertyDialog( TQWidget* parent, IngredientPropertyList *propertyList, UnitList *unitList, OptionFlag showEmpty ) + : KDialogBase( parent, "SelectPropertyDialog", true, i18n( "Choose Property" ), + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok ), m_showEmpty(showEmpty) +{ + + // Initialize internal variables + unitListBack = new UnitList; + + // Initialize Widgets + TQVBox *page = makeVBoxMainWidget(); + + box = new TQGroupBox( page ); + box->setTitle( i18n( "Choose Property" ) ); + box->setColumnLayout( 0, TQt::Vertical ); + box->layout() ->setSpacing( 6 ); + box->layout() ->setMargin( 11 ); + TQVBoxLayout *boxLayout = new TQVBoxLayout( box->layout() ); + boxLayout->setAlignment( TQt::AlignTop ); + + propertyChooseView = new TDEListView( box, "propertyChooseView" ); + + TDEConfig *config = TDEGlobal::config(); + config->setGroup( "Advanced" ); + bool show_id = config->readBoolEntry( "ShowID", false ); + propertyChooseView->addColumn( i18n( "Id" ), show_id ? -1 : 0 ); + + propertyChooseView->addColumn( i18n( "Property" ) ); + propertyChooseView->setAllColumnsShowFocus( true ); + boxLayout->addWidget( propertyChooseView ); + + TQHBoxLayout *layout2 = new TQHBoxLayout; + + perUnitsLabel = new TQLabel( box ); + perUnitsLabel->setGeometry( TQRect( 5, 285, 100, 30 ) ); + perUnitsLabel->setText( i18n( "Per units:" ) ); + layout2->addWidget( perUnitsLabel ); + + perUnitsBox = new KComboBox( FALSE, box ); + layout2->addWidget( perUnitsBox ); + boxLayout->addLayout( layout2 ); + + resize( TQSize( 200, 380 ).expandedTo( minimumSizeHint() ) ); + clearWState( WState_Polished ); + + // Load data + loadProperties( propertyList ); + loadUnits( unitList ); +} + + +SelectPropertyDialog::~SelectPropertyDialog() +{} + + +int SelectPropertyDialog::propertyID( void ) +{ + + TQListViewItem * it; + if ( ( it = propertyChooseView->selectedItem() ) ) { + return ( it->text( 0 ).toInt() ); + } + else + return ( -1 ); +} + +int SelectPropertyDialog::perUnitsID() +{ + + int comboCount = perUnitsBox->count(); + if ( comboCount > 0 ) { // If not, the list may be empty (no list defined) and crashes while reading as seen before. So check just in case. + int comboID = perUnitsBox->currentItem(); + return ( *unitListBack->at( comboID ) ).id; + } + else + return ( -1 ); +} + +void SelectPropertyDialog::loadProperties( IngredientPropertyList *propertyList ) +{ + for ( IngredientPropertyList::const_iterator prop_it = propertyList->begin(); prop_it != propertyList->end(); ++prop_it ) { + ( void ) new TQListViewItem( propertyChooseView, TQString::number( (*prop_it).id ), (*prop_it).name ); + } +} +void SelectPropertyDialog::loadUnits( UnitList *unitList ) +{ + for ( UnitList::const_iterator unit_it = unitList->begin(); unit_it != unitList->end(); ++unit_it ) { + TQString unitName = ( *unit_it ).name; + if ( unitName.isEmpty() ) { + if ( m_showEmpty == ShowEmptyUnit ) + unitName = " "+i18n("-No unit-"); + else + continue; + } + + // Insert in the combobox + perUnitsBox->insertItem( unitName ); + + // Store with index for using later + Unit newUnit( *unit_it ); + newUnit.name = unitName; + unitListBack->append( newUnit ); + } +} diff --git a/src/dialogs/selectpropertydialog.h b/src/dialogs/selectpropertydialog.h new file mode 100644 index 0000000..94d7c3b --- /dev/null +++ b/src/dialogs/selectpropertydialog.h @@ -0,0 +1,60 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef SELECTPROPERTYDIALOG_H +#define SELECTPROPERTYDIALOG_H + +#include <tqwidget.h> +#include <tqlayout.h> +#include <tqgroupbox.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqvbox.h> + +#include <tdelistview.h> +#include <kcombobox.h> +#include <kdialogbase.h> + +#include "datablocks/unit.h" + +class IngredientPropertyList; + +/** +@author Unai Garro +*/ +class SelectPropertyDialog: public KDialogBase +{ +public: + enum OptionFlag { ShowEmptyUnit, HideEmptyUnit } ; + + // Methods + SelectPropertyDialog( TQWidget* parent, IngredientPropertyList *propertyList, UnitList *unitList, OptionFlag showEmpty = ShowEmptyUnit ); + ~SelectPropertyDialog(); + int propertyID( void ); + int perUnitsID( void ); +private: + //Widgets + TQGroupBox *box; + TDEListView *propertyChooseView; + TQLabel *perUnitsLabel; + KComboBox *perUnitsBox; + OptionFlag m_showEmpty; + + void loadProperties( IngredientPropertyList *propertyList ); + void loadUnits( UnitList *unitList ); + + //Internal variables + UnitList *unitListBack; // To store unit list with ID's for later use + +}; + +#endif diff --git a/src/dialogs/selectrecipedialog.cpp b/src/dialogs/selectrecipedialog.cpp new file mode 100644 index 0000000..a8a6ca6 --- /dev/null +++ b/src/dialogs/selectrecipedialog.cpp @@ -0,0 +1,257 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "selectrecipedialog.h" + +#include <tqsignalmapper.h> +#include <tqtabwidget.h> +#include <tqtooltip.h> + +#include <tdelocale.h> +#include <kdebug.h> +#include <tdeapplication.h> +#include <kprogress.h> +#include <tdemessagebox.h> +#include <tdeglobal.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <kiconloader.h> + +#include "advancedsearchdialog.h" +#include "datablocks/categorytree.h" +#include "backends/recipedb.h" +#include "datablocks/recipe.h" +#include "selectunitdialog.h" +#include "createelementdialog.h" +#include "recipefilter.h" +#include "widgets/recipelistview.h" +#include "widgets/categorylistview.h" +#include "widgets/categorycombobox.h" + +SelectRecipeDialog::SelectRecipeDialog( TQWidget *parent, RecipeDB* db ) + : TQWidget( parent ) +{ + //Store pointer to Recipe Database + database = db; + + TQVBoxLayout *tabLayout = new TQVBoxLayout( this ); + tabWidget = new TQTabWidget( this ); + tabWidget->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding ) ); + tabLayout->addWidget( tabWidget ); + + basicSearchTab = new TQGroupBox( this ); + basicSearchTab->setFrameStyle( TQFrame::NoFrame ); + basicSearchTab->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding ) ); + + //Design dialog + + layout = new TQGridLayout( basicSearchTab, 1, 1, 0, 0 ); + + // Border Spacers + TQSpacerItem* spacer_left = new TQSpacerItem( 10, 10, TQSizePolicy::Fixed, TQSizePolicy::Minimum ); + layout->addMultiCell( spacer_left, 1, 4, 0, 0 ); + TQSpacerItem* spacer_top = new TQSpacerItem( 10, 10, TQSizePolicy::Minimum, TQSizePolicy::Fixed ); + layout->addMultiCell( spacer_top, 0, 0, 1, 4 ); + + searchBar = new TQHBox( basicSearchTab ); + searchBar->setSpacing( 7 ); + layout->addWidget( searchBar, 1, 1 ); + + TDEIconLoader *il = new TDEIconLoader; + TQPushButton *clearSearchButton = new TQPushButton( searchBar ); + clearSearchButton->setPixmap( il->loadIcon( "locationbar_erase", TDEIcon::NoGroup, 16 ) ); + + searchLabel = new TQLabel( searchBar ); + searchLabel->setText( i18n( "Search:" ) ); + searchLabel->setFixedWidth( searchLabel->fontMetrics().width( i18n( "Search:" ) ) + 5 ); + searchBox = new KLineEdit( searchBar ); + + TQSpacerItem* searchSpacer = new TQSpacerItem( 10, 10, TQSizePolicy::Fixed, TQSizePolicy::Minimum ); + layout->addItem( searchSpacer, 1, 2 ); + + #ifdef ENABLE_SLOW + categoryBox = new CategoryComboBox( basicSearchTab, database ); + layout->addWidget( categoryBox, 1, 3 ); + #endif + + TQSpacerItem* spacerFromSearchBar = new TQSpacerItem( 10, 10, TQSizePolicy::Minimum, TQSizePolicy::Fixed ); + layout->addItem( spacerFromSearchBar, 2, 1 ); + + recipeListView = new RecipeListView( basicSearchTab, database ); + recipeListView->reload(); + recipeListView->setSizePolicy( TQSizePolicy::Ignored, TQSizePolicy::Expanding ); + layout->addMultiCellWidget( recipeListView, 3, 3, 1, 3 ); + + buttonBar = new TQHBox( basicSearchTab ); + layout->addMultiCellWidget( buttonBar, 4, 4, 1, 3 ); + + openButton = new TQPushButton( buttonBar ); + openButton->setText( i18n( "Open Recipe(s)" ) ); + openButton->setDisabled( true ); + TQPixmap pm = il->loadIcon( "ok", TDEIcon::NoGroup, 16 ); + openButton->setIconSet( pm ); + editButton = new TQPushButton( buttonBar ); + editButton->setText( i18n( "Edit Recipe" ) ); + editButton->setDisabled( true ); + pm = il->loadIcon( "edit", TDEIcon::NoGroup, 16 ); + editButton->setIconSet( pm ); + removeButton = new TQPushButton( buttonBar ); + removeButton->setText( i18n( "Delete" ) ); + removeButton->setDisabled( true ); + removeButton->setMaximumWidth( 100 ); + pm = il->loadIcon( "editshred", TDEIcon::NoGroup, 16 ); + removeButton->setIconSet( pm ); + + tabWidget->insertTab( basicSearchTab, i18n( "Basic" ) ); + + advancedSearch = new AdvancedSearchDialog( this, database ); + tabWidget->insertTab( advancedSearch, i18n( "Advanced" ) ); + + TQToolTip::add( clearSearchButton, i18n( "Clear search" ) ); + + //Takes care of all recipe actions and provides a popup menu to 'recipeListView' + actionHandler = new RecipeActionsHandler( recipeListView, database ); + + recipeFilter = new RecipeFilter( recipeListView ); + + // Signals & Slots + + connect( openButton, TQ_SIGNAL( clicked() ), actionHandler, TQ_SLOT( open() ) ); + connect( this, TQ_SIGNAL( recipeSelected( bool ) ), openButton, TQ_SLOT( setEnabled( bool ) ) ); + connect( editButton, TQ_SIGNAL( clicked() ), actionHandler, TQ_SLOT( edit() ) ); + connect( this, TQ_SIGNAL( recipeSelected( bool ) ), editButton, TQ_SLOT( setEnabled( bool ) ) ); + connect( removeButton, TQ_SIGNAL( clicked() ), actionHandler, TQ_SLOT( remove() ) ); + connect( this, TQ_SIGNAL( recipeSelected( bool ) ), removeButton, TQ_SLOT( setEnabled( bool ) ) ); + + connect( clearSearchButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( clearSearch() ) ); + + TDEConfig * config = kapp->config(); + config->setGroup( "Performance" ); + if ( config->readBoolEntry("SearchAsYouType",true) ) { + connect( searchBox, TQ_SIGNAL( returnPressed( const TQString& ) ), recipeFilter, TQ_SLOT( filter( const TQString& ) ) ); + connect( searchBox, TQ_SIGNAL( textChanged( const TQString& ) ), this, TQ_SLOT( ensurePopulated() ) ); + connect( searchBox, TQ_SIGNAL( textChanged( const TQString& ) ), recipeFilter, TQ_SLOT( filter( const TQString& ) ) ); + } + else { + connect( searchBox, TQ_SIGNAL( returnPressed( const TQString& ) ), this, TQ_SLOT( ensurePopulated() ) ); + connect( searchBox, TQ_SIGNAL( returnPressed( const TQString& ) ), recipeFilter, TQ_SLOT( filter( const TQString& ) ) ); + } + + connect( recipeListView, TQ_SIGNAL( selectionChanged() ), this, TQ_SLOT( haveSelectedItems() ) ); + #ifdef ENABLE_SLOW + connect( recipeListView, TQ_SIGNAL( nextGroupLoaded() ), categoryBox, TQ_SLOT( loadNextGroup() ) ); + connect( recipeListView, TQ_SIGNAL( prevGroupLoaded() ), categoryBox, TQ_SLOT( loadPrevGroup() ) ); + connect( categoryBox, TQ_SIGNAL( activated( int ) ), this, TQ_SLOT( filterComboCategory( int ) ) ); + #endif + connect( recipeListView, TQ_SIGNAL( nextGroupLoaded() ), TQ_SLOT( refilter() ) ); + connect( recipeListView, TQ_SIGNAL( prevGroupLoaded() ), TQ_SLOT( refilter() ) ); + + connect( advancedSearch, TQ_SIGNAL( recipeSelected( int, int ) ), TQ_SIGNAL( recipeSelected( int, int ) ) ); + connect( advancedSearch, TQ_SIGNAL( recipesSelected( const TQValueList<int> &, int ) ), TQ_SIGNAL( recipesSelected( const TQValueList<int> &, int ) ) ); + + connect( actionHandler, TQ_SIGNAL( recipeSelected( int, int ) ), TQ_SIGNAL( recipeSelected( int, int ) ) ); + connect( actionHandler, TQ_SIGNAL( recipesSelected( const TQValueList<int> &, int ) ), TQ_SIGNAL( recipesSelected( const TQValueList<int> &, int ) ) ); + + delete il; +} + +SelectRecipeDialog::~SelectRecipeDialog() +{ + delete recipeFilter; +} + +void SelectRecipeDialog::clearSearch() +{ + searchBox->setText( TQString::null ); + recipeFilter->filter( TQString::null ); +} + +void SelectRecipeDialog::reload( ReloadFlags flag ) +{ + recipeListView->reload(flag); + + #ifdef ENABLE_SLOW + categoryBox->reload(); + filterComboCategory( categoryBox->currentItem() ); + #endif +} + +void SelectRecipeDialog::refilter() +{ + if ( !searchBox->text().isEmpty() ) { + ensurePopulated(); + recipeFilter->filter(searchBox->text()); + } +} + +void SelectRecipeDialog::ensurePopulated() +{ + recipeListView->populateAll(); +} + +void SelectRecipeDialog::haveSelectedItems() +{ + if ( recipeListView->selectedItems().count() > 0 ) + emit recipeSelected( true ); + else + emit recipeSelected( false ); +} + +void SelectRecipeDialog::getCurrentRecipe( Recipe *recipe ) +{ + TQPtrList<TQListViewItem> items = recipeListView->selectedItems(); + if ( items.count() == 1 && items.at(0)->rtti() == 1000 ) { + RecipeListItem * recipe_it = ( RecipeListItem* )items.at(0); + database->loadRecipe( recipe, RecipeDB::All, recipe_it->recipeID() ); + } +} + +void SelectRecipeDialog::filterComboCategory( int row ) +{ + recipeListView->populateAll(); //TODO: this would be faster if we didn't need to load everything first + + kdDebug() << "I got row " << row << "\n"; + + //First get the category ID corresponding to this combo row + int categoryID = categoryBox->id( row ); + + //Now filter + recipeFilter->filterCategory( categoryID ); // if categoryID==-1 doesn't filter + recipeFilter->filter( searchBox->text() ); + + if ( categoryID != -1 ) { + TQListViewItemIterator it( recipeListView ); + while ( it.current() ) { + TQListViewItem *item = it.current(); + if ( item->isVisible() ) { + item->setOpen( true ); //will only open if already populated + //(could be the selected category's parent + if ( !item->firstChild() ) { + recipeListView->open( item ); //populates and opens the selected category + break; + } + } + ++it; + } + + } +} + +RecipeActionsHandler* SelectRecipeDialog::getActionsHandler() const +{ + if ( tabWidget->currentPage() == basicSearchTab ) + return actionHandler; + else + return advancedSearch->actionHandler; +} + +#include "selectrecipedialog.moc" diff --git a/src/dialogs/selectrecipedialog.h b/src/dialogs/selectrecipedialog.h new file mode 100644 index 0000000..d296259 --- /dev/null +++ b/src/dialogs/selectrecipedialog.h @@ -0,0 +1,99 @@ +/************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn(jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef SELECTRECIPEDIALOG_H +#define SELECTRECIPEDIALOG_H + + +#include <tqwidget.h> +#include <tqpushbutton.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqcursor.h> +#include <tqintdict.h> + +#include <kcombobox.h> +#include <klineedit.h> +#include <tdelistview.h> +#include <kdialog.h> +#include <tdefiledialog.h> +#include <tdepopupmenu.h> + +#include "recipeactionshandler.h" +#include "widgets/dblistviewbase.h" + +class TQHBox; +class TQGroupBox; + +class RecipeDB; +class ElementList; +class Recipe; +class AdvancedSearchDialog; +class CategoryTree; +class RecipeFilter; +class RecipeListView; +class CategoryComboBox; + +/** +@author Unai Garro +*/ +class SelectRecipeDialog : public TQWidget +{ + TQ_OBJECT +public: + SelectRecipeDialog( TQWidget *parent, RecipeDB *db ); + ~SelectRecipeDialog(); + + + //Public Methods + void getCurrentRecipe( Recipe *recipe ); + + RecipeActionsHandler * getActionsHandler() const; + +private: + + // Widgets + TQGridLayout *layout; + TQTabWidget *tabWidget; + TQGroupBox *basicSearchTab; + TQHBox *searchBar; + RecipeListView* recipeListView; + TQHBox *buttonBar; + TQPushButton *openButton; + TQPushButton *removeButton; + TQPushButton *editButton; + TQLabel *searchLabel; + KLineEdit *searchBox; + CategoryComboBox *categoryBox; + AdvancedSearchDialog *advancedSearch; + // Internal Data + RecipeDB *database; + RecipeActionsHandler *actionHandler; + RecipeFilter *recipeFilter; + +signals: + void recipeSelected( int id, int action ); + void recipesSelected( const TQValueList<int> &ids, int action ); + void recipeSelected( bool ); + +private slots: + void filterComboCategory( int row ); + void refilter(); + void ensurePopulated(); + +public slots: + void haveSelectedItems(); + void reload( ReloadFlags flag = Load ); + void clearSearch(); +}; + +#endif diff --git a/src/dialogs/selectunitdialog.cpp b/src/dialogs/selectunitdialog.cpp new file mode 100644 index 0000000..d9500a6 --- /dev/null +++ b/src/dialogs/selectunitdialog.cpp @@ -0,0 +1,77 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "selectunitdialog.h" + +#include <tdeconfig.h> +#include <tdeglobal.h> +#include <tdelocale.h> + +SelectUnitDialog::SelectUnitDialog( TQWidget* parent, const UnitList &unitList, OptionFlag showEmpty ) + : KDialogBase( parent, "SelectUnitDialog", true, i18n( "Choose Unit" ), + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok ), m_showEmpty(showEmpty) +{ + TQVBox *page = makeVBoxMainWidget(); + + box = new TQGroupBox( page ); + box->setTitle( i18n( "Choose Unit" ) ); + box->setColumnLayout( 0, TQt::Vertical ); + TQVBoxLayout *boxLayout = new TQVBoxLayout( box->layout() ); + + unitChooseView = new TDEListView( box ); + + TDEConfig *config = TDEGlobal::config(); + config->setGroup( "Advanced" ); + bool show_id = config->readBoolEntry( "ShowID", false ); + unitChooseView->addColumn( i18n( "Id" ), show_id ? -1 : 0 ); + + unitChooseView->addColumn( i18n( "Unit" ) ); + unitChooseView->setSorting(1); + unitChooseView->setGeometry( TQRect( 5, 30, 180, 250 ) ); + unitChooseView->setAllColumnsShowFocus( true ); + boxLayout->addWidget( unitChooseView ); + + resize( TQSize( 200, 350 ) ); + + loadUnits( unitList ); +} + + +SelectUnitDialog::~SelectUnitDialog() +{} + +int SelectUnitDialog::unitID( void ) +{ + + TQListViewItem * it; + if ( ( it = unitChooseView->selectedItem() ) ) { + return ( it->text( 0 ).toInt() ); + } + else + return ( -1 ); +} + +void SelectUnitDialog::loadUnits( const UnitList &unitList ) +{ + for ( UnitList::const_iterator unit_it = unitList.begin(); unit_it != unitList.end(); ++unit_it ) { + TQString unitName = ( *unit_it ).name; + if ( unitName.isEmpty() ) { + if ( m_showEmpty == ShowEmptyUnit ) + unitName = " "+i18n("-No unit-"); + else + continue; + } + + ( void ) new TQListViewItem( unitChooseView, TQString::number( ( *unit_it ).id ), unitName ); + } +} + diff --git a/src/dialogs/selectunitdialog.h b/src/dialogs/selectunitdialog.h new file mode 100644 index 0000000..f2d8af0 --- /dev/null +++ b/src/dialogs/selectunitdialog.h @@ -0,0 +1,51 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef SELECTUNITDIALOG_H +#define SELECTUNITDIALOG_H + +#include <tqwidget.h> +#include <tqlayout.h> +#include <tqpushbutton.h> +#include <tqgroupbox.h> +#include <tqvbox.h> + +#include <tdelistview.h> +#include <kdialogbase.h> + +#include "datablocks/unit.h" + +/** +@author Unai Garro +*/ +class SelectUnitDialog : public KDialogBase +{ +public: + enum OptionFlag { ShowEmptyUnit, HideEmptyUnit } ; + + SelectUnitDialog( TQWidget* parent, const UnitList &unitList, OptionFlag = ShowEmptyUnit ); + + ~SelectUnitDialog(); + + int unitID( void ); + +private: + //Widgets + TQGroupBox *box; + TDEListView *unitChooseView; + OptionFlag m_showEmpty; + + void loadUnits( const UnitList &unitList ); + +}; + +#endif diff --git a/src/dialogs/setupdisplay.cpp b/src/dialogs/setupdisplay.cpp new file mode 100644 index 0000000..6efa42f --- /dev/null +++ b/src/dialogs/setupdisplay.cpp @@ -0,0 +1,602 @@ +/*************************************************************************** +* Copyright (C) 2003-2005 * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "setupdisplay.h" + +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kdebug.h> +#include <tdefontdialog.h> +#include <kcolordialog.h> +#include <tdelocale.h> +#include <tdepopupmenu.h> +#include <kiconloader.h> +#include <kstandarddirs.h> +#include <tdetempfile.h> + +#include <tdehtmlview.h> +#include <dom/dom_doc.h> +#include <dom/css_rule.h> + +#include <tqinputdialog.h> +#include <tqaction.h> +#include <tqlabel.h> +#include <tqfile.h> +#include <tqregexp.h> +#include <tqtextedit.h> +#include <tqtooltip.h> +#include <tqobjectlist.h> +#include <tqvaluelist.h> +#include <tqlayout.h> + +#include "datablocks/mixednumber.h" +#include "dialogs/borderdialog.h" +#include "exporters/htmlexporter.h" + +#include <cmath> + +KreDisplayItem::KreDisplayItem( const TQString &n, const TQString &_name ) : nodeId(n), name(_name) +{ + clear(); +} + +void KreDisplayItem::clear() +{ + alignment = TQt::AlignHCenter; + show = true; + backgroundColor = TQColor(255,255,255); + textColor = TQColor(0,0,0); + columns = 1; +} + +SetupDisplay::SetupDisplay( const Recipe &sample, TQWidget *parent ) : TDEHTMLPart(parent), + box_properties( new PropertiesMap ), + node_item_map( new TQMap<TQString, KreDisplayItem*> ), + has_changes( false ), + popup(0) +{ + connect( this, TQ_SIGNAL( popupMenu(const TQString &,const TQPoint &) ), TQ_SLOT( nodeClicked(const TQString &,const TQPoint &) ) ); + + if ( sample.recipeID != -1 ) + m_sample = sample; + else { + m_sample.title = i18n("Recipe Title"); + m_sample.yield.amount = 0; + m_sample.categoryList.append( Element(i18n( "Category 1, Category 2, ..." ) ) ); + m_sample.instructions = i18n("Instructions"); + m_sample.prepTime = TQTime(0,0); + + m_sample.authorList.append( Element(i18n( "Author 1, Author 2, ..." )) ); + + Ingredient ing; + ing.name = i18n("Ingredient 1"); + m_sample.ingList.append( ing ); + + ing.name = i18n("Ingredient 2"); + m_sample.ingList.append( ing ); + + ing.name = "..."; + m_sample.ingList.append( ing ); + + RatingCriteria rc; + Rating rating1; + rating1.rater = i18n("Rater"); + rating1.comment = i18n("Comment"); + + rc.name = i18n("Criteria 1"); + rc.stars = 5.0; + rating1.append(rc); + + rc.name = i18n("Criteria 2"); + rc.stars = 2.5; + rating1.append(rc); + + IngredientProperty prop; + prop.name = i18n("Property 1"); + m_sample.properties.append(prop); + prop.name = i18n("Property 2"); + m_sample.properties.append(prop); + prop.name = "..."; + m_sample.properties.append(prop); + + m_sample.ratingList.append(rating1); + } + + kdDebug()<<"first load"<<endl; + loadHTMLView(); + show(); + + createItem( "background", i18n("Background"), BackgroundColor ); + createItem( "title", i18n("Title"), Font | BackgroundColor | TextColor | Visibility | Alignment | Border ); + createItem( "instructions", i18n("Instructions"), Font | BackgroundColor | TextColor | Visibility | Alignment | Border ); + createItem( "prep_time", i18n("Preparation Time"), Font | BackgroundColor | TextColor | Visibility | Alignment | Border ); + createItem( "photo", i18n("Photo"), Visibility | Border ); + createItem( "authors", i18n("Authors"), Font | BackgroundColor | TextColor | Visibility | Alignment | Border ); + createItem( "categories", i18n("Categories"), Font | BackgroundColor | TextColor | Visibility | Alignment | Border ); + createItem( "ingredients", i18n("Ingredients"), Font | BackgroundColor | TextColor | Visibility | Alignment | Border | Columns ); + createItem( "properties", i18n("Properties"), Font | BackgroundColor | TextColor | Visibility | Alignment | Border | Columns ); + createItem( "ratings", i18n("Ratings"), Font | BackgroundColor | TextColor | Visibility | Alignment | Border ); + createItem( "yield", i18n("Yield"), Font | BackgroundColor | TextColor | Visibility | Alignment | Border ); +} + +SetupDisplay::~SetupDisplay() +{ + delete box_properties; + delete node_item_map; +} + +void SetupDisplay::loadHTMLView( const TQString &templateFile, const TQString &styleFile ) +{ + kdDebug()<<"loading template: "<<templateFile<<" style: "<<styleFile<<endl; + TQString tmp_filename = locateLocal( "tmp", "krecipes_recipe_view" ); + HTMLExporter exporter( tmp_filename + ".html", "html" ); + if ( templateFile != TQString::null ) + exporter.setTemplate( templateFile ); + if ( styleFile != TQString::null ) + exporter.setStyle( styleFile ); + + RecipeList recipeList; + recipeList.append(m_sample); + + TQFile file(tmp_filename + ".html"); + if ( file.open( IO_WriteOnly ) ) { + TQTextStream stream(&file); + exporter.writeStream(stream,recipeList); + } + else { + kdDebug()<<"Unable to open file for writing"<<endl; + } + file.close(); + + KURL url; + url.setPath( tmp_filename + ".html" ); + openURL( url ); + kdDebug() << "Opening URL: " << url.htmlURL() << endl; +} + +void SetupDisplay::reload() +{ + loadHTMLView( m_activeTemplate, m_activeStyle ); +} + +void SetupDisplay::loadTemplate( const TQString &filename ) +{ + bool storeChangedState = has_changes; + KTempFile tmpFile; + saveLayout(tmpFile.name()); + has_changes = storeChangedState; //saveLayout() sets changes to false + + loadHTMLView( filename, tmpFile.name() ); + + m_activeTemplate = filename; +} + +void SetupDisplay::createItem( const TQString &node, const TQString &name, unsigned int properties ) +{ + KreDisplayItem * item = new KreDisplayItem( node, name ); + box_properties->insert( item, properties ); + node_item_map->insert( node, item ); +} + +void SetupDisplay::loadLayout( const TQString &filename ) +{ + TQFile input( filename ); + if ( input.open( IO_ReadOnly ) ) { + TQDomDocument doc; + TQString error; + int line; + int column; + if ( !doc.setContent( &input, &error, &line, &column ) ) { + kdDebug() << TQString( i18n( "\"%1\" at line %2, column %3. This may not be a Krecipes layout file." ) ).arg( error ).arg( line ).arg( column ) << endl; + return ; + } + + m_styleSheet = DOM::CSSStyleSheet(); + + TQMap<TQString,KreDisplayItem*>::iterator it; + for ( it = node_item_map->begin(); it != node_item_map->end(); ++it ) { + it.data()->clear(); + } + processDocument( doc ); + + loadHTMLView(m_activeTemplate, filename); + m_activeStyle = filename; + + has_changes = false; + } + else + kdDebug() << "Unable to open file: " << filename << endl; +} + +void SetupDisplay::beginObject( const TQString &object ) +{ + TQMap<TQString, KreDisplayItem*>::iterator map_it = node_item_map->find( object ); + if ( map_it != node_item_map->end() ) + m_currentItem = map_it.data(); + else + m_currentItem = 0; +} + +void SetupDisplay::endObject() +{ + m_currentItem = 0; +} + +void SetupDisplay::loadBackgroundColor( const TQString &object, const TQColor &color ) +{ + if ( m_currentItem ) { + m_currentItem->backgroundColor = color; + m_styleSheet.insertRule("."+object+" { "+bgColorAsCSS(color)+" }",m_styleSheet.cssRules().length()); + } +} + +void SetupDisplay::loadFont( const TQString &object, const TQFont &font ) +{ + if ( m_currentItem ) { + m_currentItem->font = font; + m_styleSheet.insertRule("."+object+" { "+fontAsCSS(font)+" }",m_styleSheet.cssRules().length()); + } +} + +void SetupDisplay::loadTextColor( const TQString &object, const TQColor &color ) +{ + if ( m_currentItem ) { + m_currentItem->textColor = color; + m_styleSheet.insertRule("."+object+" { "+textColorAsCSS(color)+" }",m_styleSheet.cssRules().length()); + } +} + +void SetupDisplay::loadVisibility( const TQString &object, bool visible ) +{ + if ( m_currentItem ) { + m_currentItem->show = visible; + emit itemVisibilityChanged( m_currentItem, visible ); + + m_styleSheet.insertRule("."+object+" { "+visibilityAsCSS(visible)+" }",m_styleSheet.cssRules().length()); + } +} + +void SetupDisplay::loadAlignment( const TQString &object, int alignment ) +{ + if ( m_currentItem ) { + m_currentItem->alignment = alignment; + m_styleSheet.insertRule("."+object+" { "+alignmentAsCSS(alignment)+" }",m_styleSheet.cssRules().length()); + } +} + +void SetupDisplay::loadBorder( const TQString &object, const KreBorder& border ) +{ + if ( m_currentItem ) { + m_currentItem->border = border; + m_styleSheet.insertRule("."+object+" { "+borderAsCSS(border)+" }",m_styleSheet.cssRules().length()); + } +} + +void SetupDisplay::loadColumns( const TQString &/*object*/, int cols ) +{ + if ( m_currentItem ) { + m_currentItem->columns = cols; + } +} + +void SetupDisplay::saveLayout( const TQString &filename ) +{ + TQDomImplementation dom_imp; + TQDomDocument doc = dom_imp.createDocument( TQString::null, "krecipes-layout", dom_imp.createDocumentType( "krecipes-layout", TQString::null, TQString::null ) ); + + TQDomElement layout_tag = doc.documentElement(); + layout_tag.setAttribute( "version", 0.4 ); + //layout_tag.setAttribute( "generator", TQString("Krecipes v%1").arg(krecipes_version()) ); + doc.appendChild( layout_tag ); + + for ( TQMap<TQString, KreDisplayItem*>::const_iterator it = node_item_map->begin(); it != node_item_map->end(); ++it ) { + TQDomElement base_tag = doc.createElement( it.key() ); + layout_tag.appendChild( base_tag ); + + int properties = (*box_properties)[it.data()]; + if ( properties & BackgroundColor ) { + TQDomElement backgroundcolor_tag = doc.createElement( "background-color" ); + backgroundcolor_tag.appendChild( doc.createTextNode( it.data()->backgroundColor.name() ) ); + base_tag.appendChild( backgroundcolor_tag ); + } + + if ( properties & TextColor ) { + TQDomElement textcolor_tag = doc.createElement( "text-color" ); + textcolor_tag.appendChild( doc.createTextNode( it.data()->textColor.name() ) ); + base_tag.appendChild( textcolor_tag ); + } + + if ( properties & Font ) { + TQDomElement font_tag = doc.createElement( "font" ); + font_tag.appendChild( doc.createTextNode( it.data()->font.toString() ) ); + base_tag.appendChild( font_tag ); + } + + if ( properties & Visibility ) { + TQDomElement visibility_tag = doc.createElement( "visible" ); + visibility_tag.appendChild( doc.createTextNode( (it.data()->show) ? "true" : "false" ) ); + base_tag.appendChild( visibility_tag ); + } + + if ( properties & Alignment ) { + TQDomElement alignment_tag = doc.createElement( "alignment" ); + alignment_tag.appendChild( doc.createTextNode( TQString::number( it.data()->alignment ) ) ); + base_tag.appendChild( alignment_tag ); + } + + if ( properties & Border ) { + TQDomElement border_tag = doc.createElement( "border" ); + border_tag.setAttribute( "width", it.data()->border.width ); + border_tag.setAttribute( "style", it.data()->border.style ); + border_tag.setAttribute( "color", it.data()->border.color.name() ); + base_tag.appendChild( border_tag ); + } + + if ( properties & Columns ) { + TQDomElement columns_tag = doc.createElement( "columns" ); + columns_tag.appendChild( doc.createTextNode( TQString::number( it.data()->columns ) ) ); + base_tag.appendChild( columns_tag ); + } + } + + TQFile out_file( filename ); + if ( out_file.open( IO_WriteOnly ) ) { + has_changes = false; + + TQTextStream stream( &out_file ); + stream << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" << doc.toString(); + } + else + kdDebug() << "Error: Unable to write to file " << filename << endl; +} + +void SetupDisplay::begin(const KURL &url, int xOffset, int yOffset) +{ + kdDebug()<<"begin"<<endl; + TDEHTMLPart::begin(url,xOffset,yOffset); + kdDebug()<<"end"<<endl; + + DOM::Document doc = document(); + DOM::DOMImplementation impl = doc.implementation(); + kdDebug() << "(1) document: " << document().handle() << endl; + #if 0 + if ( !impl.isNull() ) { + //m_styleSheet = impl.createCSSStyleSheet("-krecipes","screen"); + //m_styleSheet = DOM::CSSStyleSheet(); + //doc.addStyleSheet(m_styleSheet); + //applyStylesheet(); + } + #endif +} + +void SetupDisplay::nodeClicked(const TQString &/*url*/,const TQPoint &point) +{ + DOM::Node node = nodeUnderMouse(); + DOM::Element element; + if ( node.nodeType() != DOM::Node::ELEMENT_NODE ) { + kdDebug()<<"not an element"<<endl; + element = (DOM::Element)node.parentNode(); + } + else + element = (DOM::Element)node; + + while ( !element.parentNode().isNull() ) { + if ( element.hasAttribute("class") ) { + TQString id = element.getAttribute("class").string(); + if ( node_item_map->keys().contains(id) ) + break; + } + + element = (DOM::Element)element.parentNode(); + } + + m_currNodeId = element.getAttribute("class").string(); + if ( m_currNodeId.isEmpty() ) { + kdDebug()<<"Code error: unable to determine class of selected element"<<endl; + return; + } + + KreDisplayItem *item = *node_item_map->find( m_currNodeId ); + + delete popup; + popup = new TDEPopupMenu( view() ); + popup->insertTitle( item->name ); + + unsigned int properties = 0; + for ( PropertiesMap::const_iterator it = box_properties->begin(); it != box_properties->end(); ++it ) { + if ( it.key()->nodeId == m_currNodeId ) { + properties = it.data(); + break; + } + } + + TDEIconLoader il; + + if ( properties & BackgroundColor ) + popup->insertItem( i18n( "Background Color..." ), this, TQ_SLOT( setBackgroundColor() ) ); + + if ( properties & TextColor ) + popup->insertItem( i18n( "Text Color..." ), this, TQ_SLOT( setTextColor() ) ); + + if ( properties & Font ) + popup->insertItem( il.loadIconSet( "text", TDEIcon::Small, 16 ), i18n( "Font..." ), this, TQ_SLOT( setFont() ) ); + + if ( properties & Visibility ) { + int id = popup->insertItem( i18n( "Show" ), this, TQ_SLOT( setShown( int ) ) ); + popup->setItemChecked( id, item->show ); + } + + if ( properties & Alignment ) { + TQPopupMenu * sub_popup = new TQPopupMenu( popup ); + + TQActionGroup *alignment_actions = new TQActionGroup( this ); + alignment_actions->setExclusive( true ); + + TQAction *c_action = new TQAction( i18n( "Center" ), i18n( "Center" ), 0, alignment_actions, 0, true ); + TQAction *l_action = new TQAction( i18n( "Left" ), i18n( "Left" ), 0, alignment_actions, 0, true ); + TQAction *r_action = new TQAction( i18n( "Right" ), i18n( "Right" ), 0, alignment_actions, 0, true ); + + int align = item->alignment; + if ( align & TQt::AlignHCenter ) + c_action->setOn(true); + if ( align & TQt::AlignLeft ) + l_action->setOn(true); + if ( align & TQt::AlignRight ) + r_action->setOn(true); + + connect( alignment_actions, TQ_SIGNAL( selected( TQAction* ) ), TQ_SLOT( setAlignment( TQAction* ) ) ); + + popup->insertItem( i18n( "Alignment" ), sub_popup ); + + alignment_actions->addTo( sub_popup ); + } + + if ( properties & Border ) + popup->insertItem( i18n( "Border..." ), this, TQ_SLOT( setBorder() ) ); + + if ( properties & Columns ) + popup->insertItem( i18n( "Columns..." ), this, TQ_SLOT( setColumns() ) ); + + popup->popup( point ); +} + +void SetupDisplay::applyStylesheet() +{ + loadTemplate( m_activeTemplate ); + if ( !document().isNull() && !m_styleSheet.isNull() ) { + //document().removeStyleSheet(m_styleSheet); + //document().addStyleSheet(m_styleSheet); + } +} + +void SetupDisplay::setBackgroundColor() +{ + KreDisplayItem *item = *node_item_map->find( m_currNodeId ); + if ( KColorDialog::getColor( item->backgroundColor, view() ) == TQDialog::Accepted ) { + m_currentItem = item; + loadBackgroundColor(m_currNodeId,item->backgroundColor); + m_currentItem = 0; + + applyStylesheet(); + has_changes = true; + } +} + +void SetupDisplay::setBorder() +{ + KreDisplayItem *item = *node_item_map->find( m_currNodeId ); + BorderDialog borderDialog( item->border, view() ); + if ( borderDialog.exec() == TQDialog::Accepted ) { + m_currentItem = item; + loadBorder( m_currNodeId, borderDialog.border() ); + m_currentItem = 0; + + applyStylesheet(); + has_changes = true; + } +} + +void SetupDisplay::setColumns() +{ + KreDisplayItem *item = *node_item_map->find( m_currNodeId ); + int cols = TQInputDialog::getInteger( TQString::null, i18n("Select the number of columns to use:"), item->columns, 1, 100, 1, 0, view() ); + if ( cols > 0 ) { + m_currentItem = item; + loadColumns( m_currNodeId, cols ); + m_currentItem = 0; + + loadTemplate( m_activeTemplate ); + has_changes = true; + } +} + +void SetupDisplay::setTextColor() +{ + KreDisplayItem *item = *node_item_map->find( m_currNodeId ); + if ( KColorDialog::getColor( item->textColor, view() ) == TQDialog::Accepted ) { + m_currentItem = item; + loadTextColor(m_currNodeId,item->textColor); + m_currentItem = 0; + + applyStylesheet(); + has_changes = true; + } +} + +void SetupDisplay::setShown( int id ) +{ + KreDisplayItem *item = *node_item_map->find( m_currNodeId ); + emit itemVisibilityChanged( item, !popup->isItemChecked( id ) ); + + m_currentItem = item; + loadVisibility(m_currNodeId,!popup->isItemChecked( id )); + m_currentItem = 0; + + applyStylesheet(); + has_changes = true; +} + +void SetupDisplay::setFont() +{ + KreDisplayItem *item = *node_item_map->find( m_currNodeId ); + if ( TDEFontDialog::getFont( item->font, false, view() ) == TQDialog::Accepted ) { + m_currentItem = item; + loadFont(m_currNodeId,item->font); + m_currentItem = 0; + + applyStylesheet(); + has_changes = true; + } +} + +void SetupDisplay::setAlignment( TQAction *action ) +{ + KreDisplayItem *item = *node_item_map->find( m_currNodeId ); + + //TODO: isn't there a simpler way to do this... + //preserve non-horizontal alignment flags + if ( item->alignment & TQt::AlignRight ) + item->alignment ^= TQt::AlignRight; + if ( item->alignment & TQt::AlignHCenter ) + item->alignment ^= TQt::AlignHCenter; + if ( item->alignment & TQt::AlignLeft ) + item->alignment ^= TQt::AlignLeft; + + if ( action->text() == i18n( "Center" ) ) + item->alignment |= TQt::AlignHCenter; + else if ( action->text() == i18n( "Left" ) ) + item->alignment |= TQt::AlignLeft; + else if ( action->text() == i18n( "Right" ) ) + item->alignment |= TQt::AlignRight; + + m_currentItem = item; + loadAlignment(m_currNodeId,item->alignment); + m_currentItem = 0; + + applyStylesheet(); + has_changes = true; +} + +void SetupDisplay::setItemShown( KreDisplayItem *item, bool visible ) +{ + item->show = visible; + + m_styleSheet.insertRule("."+item->nodeId+" { visibility:"+(item->show?"visible":"hidden")+" }",m_styleSheet.cssRules().length()); + applyStylesheet(); + + has_changes = true; +} + +void SetupDisplay::changeMade( void ) +{ + has_changes = true; +} + +#include "setupdisplay.moc" diff --git a/src/dialogs/setupdisplay.h b/src/dialogs/setupdisplay.h new file mode 100644 index 0000000..3edd092 --- /dev/null +++ b/src/dialogs/setupdisplay.h @@ -0,0 +1,148 @@ +/*************************************************************************** +* Copyright (C) 2003 by Jason Kivlighn * +* (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef SETUPDISPLAY_H +#define SETUPDISPLAY_H + +#include <tdehtml_part.h> +#include <dom/html_element.h> +#include <dom/css_stylesheet.h> + +#include <tqdom.h> +#include <tqwidget.h> +#include <tqmap.h> + +#include "datablocks/recipe.h" +#include "datablocks/kreborder.h" +#include "klomanager.h" + +#include <math.h> + +class TDEPopupMenu; + +class TQAction; +class TQLabel; +class TQWidget; + +class StyleSheet; + +class KreDisplayItem +{ +public: + KreDisplayItem( const TQString &id, const TQString &name ); + + void clear(); + + TQString nodeId; + TQString name; + KreBorder border; + int alignment; + int columns; + bool show; + TQColor backgroundColor; + TQColor textColor; + TQFont font; +}; + +typedef TQMap< KreDisplayItem*, unsigned int > PropertiesMap; + +/** @brief A TDEHTMLPart for editing specific CSS properties + * + * Set up the items of a recipe for display. + * + * @author Jason Kivlighn + */ +class SetupDisplay : public TDEHTMLPart, protected KLOManager +{ + TQ_OBJECT + +public: + SetupDisplay( const Recipe &, TQWidget *parent ); + ~SetupDisplay(); + + enum Properties { None = 0, BackgroundColor = 1, TextColor = 2, Font = 4, Visibility = 8, Alignment = 32, Columns = 64, Border = 128 }; + + void saveLayout( const TQString & ); + void loadLayout( const TQString & ); + void loadTemplate( const TQString &filename ); + + bool hasChanges() const + { + return has_changes; + } + + void setItemShown( KreDisplayItem *item, bool visible ); + + const PropertiesMap properties() const + { + return * box_properties; + } + + void reload(); + +signals: + void itemVisibilityChanged( KreDisplayItem *, bool ); + +protected: + virtual void begin (const KURL &url=KURL(), int xOffset=0, int yOffset=0); + + virtual void loadBackgroundColor( const TQString &obj, const TQColor& ); + virtual void loadFont( const TQString &obj, const TQFont& ); + virtual void loadTextColor( const TQString &obj, const TQColor& ); + virtual void loadVisibility( const TQString &obj, bool ); + virtual void loadAlignment( const TQString &obj, int ); + virtual void loadBorder( const TQString &obj, const KreBorder& ); + virtual void loadColumns( const TQString &obj, int ); + + virtual void beginObject( const TQString &obj ); + virtual void endObject(); + +protected slots: + void nodeClicked(const TQString &url,const TQPoint &point); + void changeMade(); + + //slots to set properties of item boxes + void setBackgroundColor(); + void setBorder(); + void setColumns(); + void setTextColor(); + void setFont(); + void setShown( int id ); + void setAlignment( TQAction * ); + +private: + PropertiesMap *box_properties; + TQMap<TQString, KreDisplayItem*> *node_item_map; + + bool has_changes; + + // Methods + void applyStylesheet(); + void loadPageLayout( const TQDomElement &tag ); + void loadHTMLView( const TQString &templateFile = TQString::null, const TQString &styleFile = TQString::null ); + + void createItem( const TQString &id, const TQString &name, unsigned int properties ); + + //the name of the element under the mouse on a right-click + TQString m_currNodeId; + + //the item corresponding to the current point of processing the KLO + KreDisplayItem *m_currentItem; + + TDEPopupMenu *popup; + DOM::CSSStyleSheet m_styleSheet; + Recipe m_sample; + + TQString m_activeTemplate; + TQString m_activeStyle; +}; + +#endif //SETUPDISPLAY_H + diff --git a/src/dialogs/shoppinglistdialog.cpp b/src/dialogs/shoppinglistdialog.cpp new file mode 100644 index 0000000..a0ac00f --- /dev/null +++ b/src/dialogs/shoppinglistdialog.cpp @@ -0,0 +1,267 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "shoppinglistdialog.h" + +#include <tdelocale.h> +#include <tdeconfig.h> +#include <kcursor.h> +#include <kdialog.h> +#include <tdeglobal.h> +#include <tdeapplication.h> + +#include "backends/recipedb.h" +#include "refineshoppinglistdialog.h" +#include "datablocks/recipelist.h" +#include "widgets/recipelistview.h" +#include "recipefilter.h" +#include "recipeactionshandler.h" + +/** A simple listview to accept dropping a RecipeItemDrag */ +class ShoppingListView : public TDEListView +{ +public: + ShoppingListView( TQWidget *parent ) : TDEListView( parent ) + {} + +protected: + bool acceptDrag( TQDropEvent *event ) const + { + return RecipeItemDrag::canDecode( event ); + } + + TQDragObject *dragObject() + { + RecipeListItem * item = dynamic_cast<RecipeListItem*>( selectedItem() ); + if ( item != 0 ) { + + RecipeItemDrag * obj = new RecipeItemDrag( item, this, "Recipe drag item" ); + /*const TQPixmap *pm = item->pixmap(0); + if( pm ) + obj->setPixmap( *pm );*/ + return obj; + } + return 0; + } +}; + + +ShoppingListDialog::ShoppingListDialog( TQWidget *parent, RecipeDB *db ) : TQWidget( parent ) +{ + // Store pointer to database + database = db; + + // Design dialog + layout = new TQGridLayout( this, 2, 2, KDialog::marginHint(), KDialog::spacingHint() ); + + recipeListView = new KreListView ( this, i18n( "Full recipe list" ), true, 1 ); + layout->addWidget( recipeListView, 0, 0 ); + listview = new RecipeListView( recipeListView, database ); + listview->setSizePolicy( TQSizePolicy::Ignored, TQSizePolicy::MinimumExpanding ); + listview->setDragEnabled( true ); + listview->setAcceptDrops( true ); + listview->setDropVisualizer( false ); + connect( recipeListView, TQ_SIGNAL( textChanged(const TQString&) ), TQ_SLOT( ensurePopulated() ) ); + connect( listview, TQ_SIGNAL( dropped( TDEListView*, TQDropEvent*, TQListViewItem* ) ), + this, TQ_SLOT( slotDropped( TDEListView*, TQDropEvent*, TQListViewItem* ) ) ); + recipeListView->setListView( listview ); + recipeListView->setCustomFilter( new RecipeFilter( recipeListView->listView() ), TQ_SLOT( filter( const TQString & ) ) ); + recipeListView->setSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::MinimumExpanding ); + + TQBoxLayout* vboxl = new TQVBoxLayout( KDialog::spacingHint() ); + TDEIconLoader il; + addRecipeButton = new TQPushButton( this ); + addRecipeButton->setIconSet( il.loadIconSet( "forward", TDEIcon::Small ) ); + addRecipeButton->setFixedSize( TQSize( 32, 32 ) ); + addRecipeButton->setFlat( true ); + vboxl->addWidget( addRecipeButton ); + + removeRecipeButton = new TQPushButton( this ); + removeRecipeButton->setIconSet( il.loadIconSet( "back", TDEIcon::Small ) ); + removeRecipeButton->setFixedSize( TQSize( 32, 32 ) ); + removeRecipeButton->setFlat( true ); + vboxl->addWidget( removeRecipeButton ); + vboxl->addStretch(); + + layout->addItem( vboxl, 0, 1 ); + + shopRecipeListView = new KreListView ( this, i18n("Shopping List") ); + ShoppingListView *slistview = new ShoppingListView( shopRecipeListView ); + slistview->setSizePolicy( TQSizePolicy::Ignored, TQSizePolicy::MinimumExpanding ); + slistview->setDragEnabled( true ); + slistview->setAcceptDrops( true ); + slistview->setDropVisualizer( false ); + connect( slistview, TQ_SIGNAL( dropped( TDEListView*, TQDropEvent*, TQListViewItem* ) ), + this, TQ_SLOT( slotDropped( TDEListView*, TQDropEvent*, TQListViewItem* ) ) ); + shopRecipeListView->setListView( slistview ); + layout->addWidget( shopRecipeListView, 0, 2 ); + + shopRecipeListView->listView() ->addColumn( i18n( "Recipe Title" ) ); + + TDEConfig *config = TDEGlobal::config(); + config->setGroup( "Advanced" ); + bool show_id = config->readBoolEntry( "ShowID", false ); + shopRecipeListView->listView() ->addColumn( i18n( "Id" ), show_id ? -1 : 0 ); + + shopRecipeListView->listView() ->setSorting( -1 ); + shopRecipeListView->setSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::MinimumExpanding ); + shopRecipeListView->listView() ->setAllColumnsShowFocus( true ); + + buttonBar = new TQHBox( this, "buttonBar" ); + layout->addMultiCellWidget( buttonBar, 1, 1, 0, 2 ); + + layout->setColStretch( 0, 1 ); + layout->setColStretch( 1, 0 ); + layout->setColStretch( 2, 1 ); + + okButton = new TQPushButton( buttonBar, "okButton" ); + okButton->setText( i18n( "&OK" ) ); + TQPixmap pm = il.loadIcon( "ok", TDEIcon::NoGroup, 16 ); + okButton->setIconSet( pm ); + + //buttonBar->layout()->addItem( new TQSpacerItem( 10,10, TQSizePolicy::MinimumExpanding, TQSizePolicy::Fixed ) ); + + clearButton = new TQPushButton( buttonBar, "clearButton" ); + clearButton->setText( i18n( "Clear" ) ); + pm = il.loadIcon( "edit-clear", TDEIcon::NoGroup, 16 ); + clearButton->setIconSet( pm ); + + //Takes care of all recipe actions and provides a popup menu to 'recipeListView' + actionHandler = new RecipeActionsHandler( recipeListView->listView(), database, RecipeActionsHandler::ExpandAll | RecipeActionsHandler::CollapseAll ); + + // Connect signals & slots + connect( addRecipeButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( addRecipe() ) ); + connect( removeRecipeButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( removeRecipe() ) ); + connect( okButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( showShoppingList() ) ); + connect( clearButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( clear() ) ); +} + +ShoppingListDialog::~ShoppingListDialog() +{} + +void ShoppingListDialog::ensurePopulated() +{ + listview->populateAll(); +} + +void ShoppingListDialog::createShopping( const RecipeList &rlist ) +{ + clear(); + RecipeList::const_iterator it; + for ( it = rlist.begin(); it != rlist.end(); ++it ) { + new RecipeListItem( shopRecipeListView->listView(), shopRecipeListView->listView() ->lastItem(), *it ); + } +} + +void ShoppingListDialog::reloadRecipeList( ReloadFlags flag ) +{ + ( ( RecipeListView* ) recipeListView->listView() ) ->reload( flag ); +} + +void ShoppingListDialog::reload( ReloadFlags flag ) +{ + reloadRecipeList ( flag ); // Missing: check if there's non-existing recipes in the list now, and if so, delete. +} + +void ShoppingListDialog::addRecipe( void ) +{ + TQPtrList<TQListViewItem> items = recipeListView->listView()->selectedItems(); + + TQPtrListIterator<TQListViewItem> it(items); + TQListViewItem *item; + while ( (item = it.current()) != 0 ) { + addRecipe( item ); + ++it; + } +} + +void ShoppingListDialog::addRecipe( TQListViewItem *item ) +{ + if ( item ) { + if ( item->rtti() == 1000 ) { + RecipeListItem * recipe_it = ( RecipeListItem* ) item; + + Recipe r; + r.title = recipe_it->title(); + r.recipeID = recipe_it->recipeID(); + ( void ) new RecipeListItem( shopRecipeListView->listView(), r ); + } + } +} + +void ShoppingListDialog::removeRecipe( void ) +{ + TQListViewItem * it; + it = shopRecipeListView->listView() ->selectedItem(); + if ( it ) + delete it; +} + +void ShoppingListDialog::showShoppingList( void ) +{ + // Store the recipe list in ElementList object first + ElementList recipeList; + RecipeListItem *it; + for ( it = ( RecipeListItem* ) shopRecipeListView->listView() ->firstChild();it;it = ( RecipeListItem* ) it->nextSibling() ) { + Element newEl; + newEl.id = it->recipeID(); + newEl.name = it->title(); // Storing the title is not necessary, but do it just in case it's used later on + recipeList.append( newEl ); + } + + RefineShoppingListDialog refineDialog( this, database, recipeList ); + refineDialog.exec(); +} + +void ShoppingListDialog::addRecipeToShoppingList( int recipeID ) +{ + Recipe r; + r.title = database->recipeTitle( recipeID ); + r.recipeID = recipeID; + + new RecipeListItem( shopRecipeListView->listView(), r ); +} + +void ShoppingListDialog::clear() +{ + shopRecipeListView->listView() ->clear(); +} + +void ShoppingListDialog::slotDropped( TDEListView *list, TQDropEvent *e, TQListViewItem * /*after*/ ) +{ + Recipe r; + RecipeListItem *item = new RecipeListItem( recipeListView->listView(), r ); // needs parent, use this temporarily + if ( !RecipeItemDrag::decode( e, *item ) ) { + delete item; + return ; + } + + if ( list == shopRecipeListView->listView() ) { + addRecipe( item ); + } + //find and delete the item if we just dropped onto the recipe list from the shopping list + else if ( list == recipeListView->listView() && e->source() == shopRecipeListView->listView() ) { + TQListViewItemIterator list_it = TQListViewItemIterator( shopRecipeListView->listView() ); + while ( list_it.current() ) { + if ( ( ( RecipeListItem* ) list_it.current() ) ->recipeID() == item->recipeID() ) { + delete list_it.current(); + break; + } + list_it++; + } + } + + delete item; + item = 0; // not needed anymore +} + +#include "shoppinglistdialog.moc" diff --git a/src/dialogs/shoppinglistdialog.h b/src/dialogs/shoppinglistdialog.h new file mode 100644 index 0000000..cc8dc43 --- /dev/null +++ b/src/dialogs/shoppinglistdialog.h @@ -0,0 +1,76 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef SHOPPINGLISTDIALOG_H +#define SHOPPINGLISTDIALOG_H + +#include <tqhbox.h> +#include <tqlayout.h> +#include <kpushbutton.h> +#include <kiconloader.h> + +#include "widgets/krelistview.h" +#include "widgets/dblistviewbase.h" + +class RecipeDB; +class RecipeList; +class ShoppingListViewDialog; +class RecipeActionsHandler; +class RecipeListView; + +/** +@author Unai Garro +*/ + +class ShoppingListDialog: public TQWidget +{ + TQ_OBJECT +public: + + ShoppingListDialog( TQWidget *parent, RecipeDB *db ); + ~ShoppingListDialog(); + void reload( ReloadFlags flag = Load ); + void createShopping( const RecipeList &rlist ); + +private: + + // Internal variables + RecipeDB *database; + // Internal Methods + void reloadRecipeList( ReloadFlags flag = Load ); + void addRecipe( TQListViewItem *item ); + // Widgets + TQGridLayout* layout; + TQPushButton* addRecipeButton; + TQPushButton* removeRecipeButton; + KreListView* recipeListView; + KreListView* shopRecipeListView; + TQHBox *buttonBar; + TQPushButton* okButton; + TQPushButton* clearButton; + ShoppingListViewDialog *shoppingListDisplay; + RecipeActionsHandler *actionHandler; + RecipeListView *listview; + +public slots: + void addRecipeToShoppingList( int recipeID ); // Called from inputdialog-> through krecipesview + +private slots: + void addRecipe( void ); + void removeRecipe( void ); + void showShoppingList( void ); + void clear( void ); + void slotDropped( TDEListView *list, TQDropEvent *e, TQListViewItem *after ); + void ensurePopulated(); +}; + +#endif diff --git a/src/dialogs/shoppinglistviewdialog.cpp b/src/dialogs/shoppinglistviewdialog.cpp new file mode 100644 index 0000000..9099aa1 --- /dev/null +++ b/src/dialogs/shoppinglistviewdialog.cpp @@ -0,0 +1,102 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "shoppinglistviewdialog.h" +#include "datablocks/ingredientlist.h" +#include "datablocks/mixednumber.h" + +#include <tqpushbutton.h> + +#include <tdelocale.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kiconloader.h> + +ShoppingListViewDialog::ShoppingListViewDialog( TQWidget *parent, const IngredientList &ingredientList ) + : KDialogBase( parent, "shoppingviewdialog", true, TQString::null, + KDialogBase::Close | KDialogBase::User1, KDialogBase::Close, + false, KStdGuiItem::print() ) +{ + // Design dialog + TQVBox *page = makeVBoxMainWidget(); + + shoppingListView = new TDEHTMLPart( page ); + + setInitialSize( TQSize(350, 450) ); + + connect ( this, TQ_SIGNAL( user1Clicked() ), this, TQ_SLOT( print() ) ); + connect ( this, TQ_SIGNAL( closeClicked() ), this, TQ_SLOT( accept() ) ); + + //---------- Sort the list -------- + IngredientList list_copy = ingredientList; + qHeapSort( list_copy ); + + //---------- Load the list -------- + display( list_copy ); +} + + +ShoppingListViewDialog::~ShoppingListViewDialog() +{} + +void ShoppingListViewDialog::display( const IngredientList &ingredientList ) +{ + TQString recipeHTML; + + // Create HTML Code + + // Headers + recipeHTML = TQString( "<html><head><title>%1</title></head><body>" ).arg( i18n( "Shopping List" ) ); + recipeHTML += "<center><div STYLE=\"width: 95%\">"; + recipeHTML += TQString( "<center><h1>%1</h1></center>" ).arg( i18n( "Shopping List" ) ); + + // Ingredient List + + recipeHTML += "<div STYLE=\"border:medium solid blue; width:95%\"><table cellspacing=0px width=100%><tbody>"; + bool counter = true; + + TDEConfig *config = TDEGlobal::config(); + config->setGroup( "Formatting" ); + + bool useAbbreviations = config->readBoolEntry("AbbreviateUnits"); + bool useFraction = config->readBoolEntry( "Fraction" ); + + for ( IngredientList::const_iterator ing_it = ingredientList.begin(); ing_it != ingredientList.end(); ++ing_it ) { + TQString color = ( counter ) ? "#CBCEFF" : "#BFC2F0"; + counter = !counter; + + MixedNumber::Format number_format = ( useFraction ) ? MixedNumber::MixedNumberFormat : MixedNumber::DecimalFormat; + TQString amount_str = MixedNumber( ( *ing_it ).amount ).toString( number_format ); + + TQString unit = ( *ing_it ).units.determineName( ( *ing_it ).amount + ( *ing_it ).amount_offset, useAbbreviations ); + + recipeHTML += TQString( "<tr bgcolor=\"%1\"><td>- %2:</td><td>%3 %4</td></tr>" ).arg( color ).arg( ( *ing_it ).name ).arg( amount_str ).arg( unit ); + } + recipeHTML += "</tbody></table></div>"; + // Close + recipeHTML += "</div></center></body></html>"; + + + // Display + shoppingListView->begin( KURL( "file:/tmp/" ) ); // Initialize to /tmp, where photos and logos are stored + shoppingListView->write( recipeHTML ); + shoppingListView->end(); + + +} + +void ShoppingListViewDialog::print() +{ + shoppingListView->view() ->print(); +} + +#include "shoppinglistviewdialog.moc" diff --git a/src/dialogs/shoppinglistviewdialog.h b/src/dialogs/shoppinglistviewdialog.h new file mode 100644 index 0000000..e080808 --- /dev/null +++ b/src/dialogs/shoppinglistviewdialog.h @@ -0,0 +1,46 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef SHOPPINGLISTVIEWDIALOG_H +#define SHOPPINGLISTVIEWDIALOG_H + +#include <tqlayout.h> +#include <tqvbox.h> +#include <tqwidget.h> + +#include <tdehtml_part.h> +#include <tdehtmlview.h> +#include <kdialogbase.h> + +class IngredientList; + +class ShoppingListViewDialog: public KDialogBase +{ + TQ_OBJECT + +public: + ShoppingListViewDialog( TQWidget *parent, const IngredientList &ingredientList ); + ~ShoppingListViewDialog(); + +public slots: + void print(); + +private: + + // Widgets + TDEHTMLPart *shoppingListView; + + // Internal Methods + void display( const IngredientList &ingredientList ); +}; + +#endif diff --git a/src/dialogs/similarcategoriesdialog.cpp b/src/dialogs/similarcategoriesdialog.cpp new file mode 100644 index 0000000..75d9721 --- /dev/null +++ b/src/dialogs/similarcategoriesdialog.cpp @@ -0,0 +1,383 @@ +/*************************************************************************** +* Copyright (C) 2003-2006 Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "similarcategoriesdialog.h" + +#include <tqvariant.h> +#include <tqpushbutton.h> +#include <tqcombobox.h> +#include <tqslider.h> +#include <tqlabel.h> +#include <tqheader.h> +#include <tqlayout.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> + +#include <tdelistview.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <klineedit.h> + +#include "widgets/categorycombobox.h" +#include "backends/recipedb.h" + +SimilarCategoriesDialog::SimilarCategoriesDialog( ElementList &list, TQWidget* parent ) + : TQDialog( parent, "SimilarCategoriesDialog", true ), + m_elementList(list) +{ + SimilarCategoriesDialogLayout = new TQVBoxLayout( this, 11, 6, "SimilarCategoriesDialogLayout"); + + layout6 = new TQHBoxLayout( 0, 0, 6, "layout6"); + + layout4 = new TQGridLayout( 0, 1, 1, 0, 6, "layout4"); + + categoriesBox = new KLineEdit( this ); + + layout4->addWidget( categoriesBox, 0, 1 ); + + thresholdSlider = new TQSlider( this, "thresholdSlider" ); + thresholdSlider->setValue( 40 ); + thresholdSlider->setOrientation( TQSlider::Horizontal ); + + layout4->addWidget( thresholdSlider, 1, 1 ); + + thresholdLabel = new TQLabel( this, "thresholdLabel" ); + + layout4->addWidget( thresholdLabel, 1, 0 ); + + categoryLabel = new TQLabel( this, "categoryLabel" ); + + layout4->addWidget( categoryLabel, 0, 0 ); + layout6->addLayout( layout4 ); + + layout5 = new TQVBoxLayout( 0, 0, 6, "layout5"); + + searchButton = new TQPushButton( this, "searchButton" ); + layout5->addWidget( searchButton ); + spacer4 = new TQSpacerItem( 20, 51, TQSizePolicy::Minimum, TQSizePolicy::Expanding ); + layout5->addItem( spacer4 ); + layout6->addLayout( layout5 ); + SimilarCategoriesDialogLayout->addLayout( layout6 ); + + layout9 = new TQHBoxLayout( 0, 0, 6, "layout9"); + + layout8 = new TQVBoxLayout( 0, 0, 6, "layout8"); + + allLabel = new TQLabel( this, "allLabel" ); + layout8->addWidget( allLabel ); + + allListView = new TDEListView( this, "allListView" ); + allListView->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)7, (TQSizePolicy::SizeType)7, 0, 1, allListView->sizePolicy().hasHeightForWidth() ) ); + layout8->addWidget( allListView ); + layout9->addLayout( layout8 ); + + layout1 = new TQVBoxLayout( 0, 0, 6, "layout1"); + + removeButton = new TQPushButton( this, "removeButton" ); + layout1->addWidget( removeButton ); + + addButton = new TQPushButton( this, "addButton" ); + layout1->addWidget( addButton ); + spacer1 = new TQSpacerItem( 20, 61, TQSizePolicy::Minimum, TQSizePolicy::Expanding ); + layout1->addItem( spacer1 ); + layout9->addLayout( layout1 ); + + layout7 = new TQVBoxLayout( 0, 0, 6, "layout7"); + + toMergeLabel = new TQLabel( this, "toMergeLabel" ); + layout7->addWidget( toMergeLabel ); + + toMergeListView = new TDEListView( this, "toMergeListView" ); + toMergeListView->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)7, (TQSizePolicy::SizeType)7, 0, 1, toMergeListView->sizePolicy().hasHeightForWidth() ) ); + layout7->addWidget( toMergeListView ); + layout9->addLayout( layout7 ); + SimilarCategoriesDialogLayout->addLayout( layout9 ); + + layout10 = new TQHBoxLayout( 0, 0, 6, "layout10"); + spacer2 = new TQSpacerItem( 310, 20, TQSizePolicy::Expanding, TQSizePolicy::Minimum ); + layout10->addItem( spacer2 ); + + mergeButton = new TQPushButton( this, "mergeButton" ); + layout10->addWidget( mergeButton ); + + cancelButton = new TQPushButton( this, "cancelButton" ); + layout10->addWidget( cancelButton ); + SimilarCategoriesDialogLayout->addLayout( layout10 ); + languageChange(); + resize( TQSize(573, 429).expandedTo(minimumSizeHint()) ); + clearWState( WState_Polished ); + + connect( searchButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(findMatches()) ); + connect( mergeButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(mergeMatches()) ); + connect( cancelButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(reject()) ); + connect( addButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(addCategory()) ); + connect( removeButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(removeCategory()) ); +} + +/* + * Destroys the object and frees any allocated resources + */ +SimilarCategoriesDialog::~SimilarCategoriesDialog() +{ + // no need to delete child widgets, TQt does it all for us +} + +/* + * Sets the strings of the subwidgets using the current + * language. + */ +void SimilarCategoriesDialog::languageChange() +{ + setCaption( i18n( "Similar Categories" ) ); + thresholdLabel->setText( i18n( "Threshold:" ) ); + categoryLabel->setText( i18n( "Category:" ) ); + searchButton->setText( i18n( "Search" ) ); + allLabel->setText( i18n( "Similar Categories:" ) ); + removeButton->setText( i18n( "<<" ) ); + addButton->setText( i18n( ">>" ) ); + toMergeLabel->setText( i18n( "Categories to Merge:" ) ); + mergeButton->setText( i18n( "Merge" ) ); + cancelButton->setText( i18n( "Cancel" ) ); + + allListView->addColumn( i18n( "Category" ) ); + //allListView->addColumn( i18n( "Id" ) ); + toMergeListView->addColumn( i18n( "Category" ) ); + //toMergeListView->addColumn( i18n( "Id" ) ); +} + +/*****************************************************/ +/*Function prototypes and libraries needed to compile*/ +/*****************************************************/ + +#include <stdlib.h> +#include <malloc.h> +#include <string.h> +int levenshtein_distance(const char *s,const char*t); +int minimum(int a,int b,int c); + +/****************************************/ +/*Implementation of Levenshtein distance*/ +/****************************************/ + +int levenshtein_distance(const char *s,const char*t) +/*Compute levenshtein distance between s and t*/ +{ + //Step 1 + int k,i,j,n,m,cost,*d,distance; + n=strlen(s); + m=strlen(t); + if(n!=0&&m!=0) + { + d=(int*)malloc((sizeof(int))*(m+1)*(n+1)); + m++; + n++; + //Step 2 + for(k=0;k<n;k++) + d[k]=k; + for(k=0;k<m;k++) + d[k*n]=k; + //Step 3 and 4 + for(i=1;i<n;i++) + for(j=1;j<m;j++) + { + //Step 5 + if(s[i-1]==t[j-1]) + cost=0; + else + cost=1; + //Step 6 + d[j*n+i]=minimum(d[(j-1)*n+i]+1,d[j*n+i-1]+1,d[(j-1)*n+i-1]+cost); + } + distance=d[n*m-1]; + free(d); + return distance; + } + else + return -1; //a negative return value means that one or both strings are empty. +} + +int minimum(int a,int b,int c) +/*Gets the minimum of three values*/ +{ + int min=a; + if(b<min) + min=b; + if(c<min) + min=c; + return min; +} + +/** @return an array of adjacent letter pairs contained in the input string */ +TQStringList letterPairs(const TQString& str) { + int numPairs = str.length()-1; + TQStringList pairs; + for (int i=0; i<numPairs; i++) { + pairs << str.mid(i,2); + } + return pairs; +} + +/** @return an ArrayList of 2-character Strings. */ +TQValueList<TQStringList> wordLetterPairs(const TQString &str) { + TQValueList<TQStringList> allPairs; + // Tokenize the string and put the tokens/words into an array + TQStringList words = TQStringList::split("\\s",str); + // For each word + for (uint w=0; w < words.count(); w++) { + // Find the pairs of characters + TQStringList pairsInWord = letterPairs(words[w]); + for (uint p=0; p < pairsInWord.count(); p++) { + allPairs.append(pairsInWord[p]); + } + } + return allPairs; +} + +/** @return lexical similarity value in the range [0,1] */ +double compareStrings(const TQString &str1, const TQString &str2) { + TQValueList<TQStringList> pairs1 = wordLetterPairs(str1.upper()); + TQValueList<TQStringList> pairs2 = wordLetterPairs(str2.upper()); + int intersection = 0; + int size_union = pairs1.count() + pairs2.count(); + for (uint i=0; i<pairs1.count(); i++) { + TQStringList pair1=pairs1[i]; + for(uint j=0; j<pairs2.count(); j++) { + TQStringList pair2=pairs2[j]; + if (pair1 == pair2) { + intersection++; + pairs2.remove( pairs2.at(j) ); + break; + } + } + } + return (2.0*intersection)/size_union; +} + + + +#include <kdebug.h> + +#if 0 +void RecipeActionsHandler::mergeSimilar() +{ + TQPtrList<TQListViewItem> items = parentListView->selectedItems(); + if ( items.count() > 1 ) + KMessageBox::sorry( kapp->mainWidget(), i18n("Please select only one category."), TQString::null ); + else if ( items.count() == 1 && items.at(0)->rtti() == 1001 ) { + CategoryListItem * cat_it = ( CategoryListItem* ) items.at(0); + TQString name = cat_it->categoryName(); + const double max_allowed_distance = 0.60; + const int length = name.length(); + ElementList categories; + database->loadCategories( &categories ); + + ElementList matches; + for ( ElementList::const_iterator it = categories.begin(); it != categories.end(); ++it ) { + #if 0 + if ( levenshtein_distance(name.latin1(),(*it).name.latin1())/double(TQMAX(length,(*it).name.length())) >= max_allowed_distance ) { + #else + if ( compareStrings(name,(*it).name) >= max_allowed_distance ) { + #endif + kdDebug()<<(*it).name<<" matches"<<endl; + if ( cat_it->categoryId() != (*it).id ) + matches.append(*it); + } + } + + + for ( ElementList::const_iterator it = categories.begin(); it != categories.end(); ++it ) { + database->mergeCategories(cat_it->categoryId(),(*it).id); + } + + } + else //either nothing was selected or a recipe was selected + KMessageBox::sorry( kapp->mainWidget(), i18n("No recipes selected."), i18n("Edit Recipe") ); +} +#endif + +void SimilarCategoriesDialog::findMatches() +{ + allListView->clear(); + toMergeListView->clear(); + + const double threshold = (100 - thresholdSlider->value())/100.0; + const TQString name = categoriesBox->text(); + + for ( ElementList::const_iterator it = m_elementList.begin(); it != m_elementList.end(); ++it ) { + //kdDebug()<<(*it).name<<" (result/threshold): "<<compareStrings(name,(*it).name)<<"/"<<threshold<<endl; + #if 0 + if ( levenshtein_distance(name.latin1(),(*it).name.latin1())/double(TQMAX(length,(*it).name.length())) >= max_allowed_distance ) { + #else + if ( compareStrings(name,(*it).name) >= threshold ) { + #endif + kdDebug()<<(*it).name<<" matches"<<endl; + //if ( id != (*it).id ) { + (void) new TQListViewItem(allListView,(*it).name,TQString::number((*it).id)); + (void) new TQListViewItem(toMergeListView,(*it).name,TQString::number((*it).id)); + //} + } + } +} + +void SimilarCategoriesDialog::mergeMatches() +{ + if ( !toMergeListView->firstChild() ) { + KMessageBox::sorry( this, i18n("No categories selected to merge."), TQString::null ); + return; + } + + //const int id = categoriesBox->id(categoriesBox->currentItem()); + //for ( TQListViewItem *item = toMergeListView->firstChild(); item; item = item->nextSibling() ) { + // m_database->mergeCategories(id,item->text(1).toInt()); + //} + + allListView->clear(); + //toMergeListView->clear(); + + TQDialog::accept(); +} + +TQValueList<int> SimilarCategoriesDialog::matches() const +{ + TQValueList<int> ids; + for ( TQListViewItem *item = toMergeListView->firstChild(); item; item = item->nextSibling() ) { + ids << item->text(1).toInt(); + } + + return ids; +} + +TQString SimilarCategoriesDialog::element() const +{ + return categoriesBox->text(); +} + +void SimilarCategoriesDialog::addCategory() +{ + TQListViewItem *item = allListView->selectedItem(); + if ( item ) + { + //make sure it isn't already in the list + for ( TQListViewItem *search_it = toMergeListView->firstChild(); search_it; search_it = search_it->nextSibling() ) { + if ( search_it->text(0) == item->text(0) ) + return; + } + + (void) new TQListViewItem(toMergeListView,item->text(0),item->text(1)); + } +} + +void SimilarCategoriesDialog::removeCategory() +{ + TQListViewItem *item = toMergeListView->selectedItem(); + if ( item ) + delete item; +} + +#include "similarcategoriesdialog.moc" diff --git a/src/dialogs/similarcategoriesdialog.h b/src/dialogs/similarcategoriesdialog.h new file mode 100644 index 0000000..67d6d03 --- /dev/null +++ b/src/dialogs/similarcategoriesdialog.h @@ -0,0 +1,84 @@ +/*************************************************************************** +* Copyright (C) 2003-2006 Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef SIMILARCATEGORIESDIALOG_H +#define SIMILARCATEGORIESDIALOG_H + +#include <tqvariant.h> +#include <tqdialog.h> +#include <tqvaluevector.h> + +#include "datablocks/elementlist.h" + +class TQVBoxLayout; +class TQHBoxLayout; +class TQGridLayout; +class TQSpacerItem; +class TQSlider; +class TQLabel; +class TQPushButton; +class TQListViewItem; + +class TDEListView; +class KLineEdit; + +class RecipeDB; + +class SimilarCategoriesDialog : public TQDialog +{ +TQ_OBJECT + +public: + SimilarCategoriesDialog( ElementList &, TQWidget* parent = 0 ); + ~SimilarCategoriesDialog(); + + TQValueList<int> matches() const; + TQString element() const; + + KLineEdit* categoriesBox; + TQSlider* thresholdSlider; + TQLabel* thresholdLabel; + TQLabel* categoryLabel; + TQPushButton* searchButton; + TQLabel* allLabel; + TDEListView* allListView; + TQPushButton* removeButton; + TQPushButton* addButton; + TQLabel* toMergeLabel; + TDEListView* toMergeListView; + TQPushButton* mergeButton; + TQPushButton* cancelButton; + +protected: + TQVBoxLayout* SimilarCategoriesDialogLayout; + TQHBoxLayout* layout6; + TQGridLayout* layout4; + TQVBoxLayout* layout5; + TQSpacerItem* spacer4; + TQHBoxLayout* layout9; + TQVBoxLayout* layout8; + TQVBoxLayout* layout1; + TQSpacerItem* spacer1; + TQVBoxLayout* layout7; + TQHBoxLayout* layout10; + TQSpacerItem* spacer2; + +protected slots: + virtual void languageChange(); + void findMatches(); + void mergeMatches(); + void addCategory(); + void removeCategory(); + +private: + ElementList m_elementList; + +}; + +#endif // SIMILARCATEGORIESDIALOG_H diff --git a/src/dialogs/unitsdialog.cpp b/src/dialogs/unitsdialog.cpp new file mode 100644 index 0000000..d52328a --- /dev/null +++ b/src/dialogs/unitsdialog.cpp @@ -0,0 +1,211 @@ +/*************************************************************************** +* Copyright (C) 2003-2004 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include <tqlayout.h> +#include <tqtabwidget.h> + +#include "unitsdialog.h" +#include "createelementdialog.h" +#include "dependanciesdialog.h" +#include "backends/recipedb.h" +#include "widgets/conversiontable.h" +#include "widgets/unitlistview.h" + +#include <tdeapplication.h> +#include <kdebug.h> +#include <kdialog.h> +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <kprogress.h> + +UnitsDialog::UnitsDialog( TQWidget *parent, RecipeDB *db ) : TQWidget( parent ) +{ + + // Store pointer to database + database = db; + + // Design dialog + TQHBoxLayout* page_layout = new TQHBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); + + TQTabWidget *tabWidget = new TQTabWidget( this ); + + TQWidget *unitTab = new TQWidget( tabWidget ); + TQHBoxLayout* layout = new TQHBoxLayout( unitTab, KDialog::marginHint(), KDialog::spacingHint() ); + + unitListView = new StdUnitListView( unitTab, database, true ); + layout->addWidget( unitListView ); + + TQVBoxLayout* vboxl = new TQVBoxLayout( KDialog::spacingHint() ); + newUnitButton = new TQPushButton( unitTab ); + newUnitButton->setText( i18n( "Create ..." ) ); + newUnitButton->setFlat( true ); + vboxl->addWidget( newUnitButton ); + + removeUnitButton = new TQPushButton( unitTab ); + removeUnitButton->setText( i18n( "Delete" ) ); + removeUnitButton->setFlat( true ); + vboxl->addWidget( removeUnitButton ); + vboxl->addStretch(); + layout->addLayout( vboxl ); + + tabWidget->insertTab( unitTab, i18n( "Units" ) ); + + massConversionTable = new ConversionTable( tabWidget, 1, 1 ); + tabWidget->insertTab( massConversionTable, i18n( "Mass Conversions" ) ); + + volumeConversionTable = new ConversionTable( tabWidget, 1, 1 ); + tabWidget->insertTab( volumeConversionTable, i18n( "Volume Conversions" ) ); + + page_layout->addWidget( tabWidget ); + + // Connect signals & slots + connect( newUnitButton, TQ_SIGNAL( clicked() ), unitListView, TQ_SLOT( createNew() ) ); + connect( removeUnitButton, TQ_SIGNAL( clicked() ), unitListView, TQ_SLOT( remove() ) ); + connect( massConversionTable, TQ_SIGNAL( ratioChanged( int, int, double ) ), this, TQ_SLOT( saveRatio( int, int, double ) ) ); + connect( massConversionTable, TQ_SIGNAL( ratioRemoved( int, int ) ), this, TQ_SLOT( removeRatio( int, int ) ) ); + connect( volumeConversionTable, TQ_SIGNAL( ratioChanged( int, int, double ) ), this, TQ_SLOT( saveRatio( int, int, double ) ) ); + connect( volumeConversionTable, TQ_SIGNAL( ratioRemoved( int, int ) ), this, TQ_SLOT( removeRatio( int, int ) ) ); + + //TODO: I'm too lazy right now, so do a complete reload to keep in sync with db + connect( database, TQ_SIGNAL( unitCreated( const Unit& ) ), this, TQ_SLOT( loadConversionTables() ) ); + connect( database, TQ_SIGNAL( unitRemoved( int ) ), this, TQ_SLOT( loadConversionTables() ) ); + + //this is for the above TODO, but it still has some bugs to be worked out + //connect(database,TQ_SIGNAL(unitCreated(const Element&)),conversionTable,TQ_SLOT(unitCreated(const Element&))); + //connect(database,TQ_SIGNAL(unitRemoved(int)),conversionTable,TQ_SLOT(unitRemoved(int))); + + //Populate data into the table + loadConversionTables(); + + //FIXME: We've got some sort of build issue... we get undefined references to CreateElementDialog without this dummy code here + CreateElementDialog d( this, "" ); +} + +UnitsDialog::~UnitsDialog() +{} + +void UnitsDialog::reload( ReloadFlags flag ) +{ + unitListView->reload( flag ); + loadConversionTables(); +} + +void UnitsDialog::loadConversionTables( void ) +{ + loadConversionTable( massConversionTable, Unit::Mass ); + loadConversionTable( volumeConversionTable, Unit::Volume ); +} + +void UnitsDialog::loadConversionTable( ConversionTable *table, Unit::Type type ) +{ + UnitList unitList; + database->loadUnits( &unitList, type ); + + TQStringList unitNames; + IDList unitIDs; // We need to store these in the table, so rows and cols are identified by unitID, not name. + table->clear(); + for ( UnitList::const_iterator unit_it = unitList.begin(); unit_it != unitList.end(); ++unit_it ) { + unitNames.append( ( *unit_it ).name ); + unitIDs.append( ( *unit_it ).id ); // append the element + } + + // Resize the table + table->resize( unitNames.count(), unitNames.count() ); + + // Set the table labels, and id's + table->setRowLabels( unitNames ); + table->setColumnLabels( unitNames ); + table->setUnitIDs( unitIDs ); + + + // Load and Populate the data into the table + UnitRatioList ratioList; + database->loadUnitRatios( &ratioList, type ); + for ( UnitRatioList::const_iterator ratio_it = ratioList.begin(); ratio_it != ratioList.end(); ++ratio_it ) { + table->setRatio( ( *ratio_it ).uID1, ( *ratio_it ).uID2, ( *ratio_it ).ratio ); + } +} + +void UnitsDialog::saveRatio( int r, int c, double value ) +{ + ConversionTable *conversionTable = (ConversionTable*)sender(); + UnitRatio ratio; + + ratio.uID1 = conversionTable->getUnitID( r ); + ratio.uID2 = conversionTable->getUnitID( c ); + ratio.ratio = value; + database->saveUnitRatio( &ratio ); + + UnitRatio reverse_ratio; + reverse_ratio.uID1 = ratio.uID2; + reverse_ratio.uID2 = ratio.uID1; + reverse_ratio.ratio = 1.0 / ratio.ratio; + database->saveUnitRatio( &reverse_ratio ); + conversionTable->setRatio( reverse_ratio ); + +#if 0 + UnitRatioList ratioList; + database->loadUnitRatios( &ratioList, Unit::Mass ); + + saveAllRatios( ratioList ); +#endif +} + +void UnitsDialog::removeRatio( int r, int c ) +{ + ConversionTable *conversionTable = (ConversionTable*)sender(); + database->removeUnitRatio( conversionTable->getUnitID( r ), conversionTable->getUnitID( c ) ); +} + +void UnitsDialog::saveAllRatios( UnitRatioList &ratioList ) +{ +#if 0 + ConversionTable *conversionTable = massConversionTable; + + KProgressDialog progress_dialog( this, "progress_dialog", i18n( "Finding Unit Ratios" ), TQString::null, true ); + progress_dialog.progressBar() ->setTotalSteps( ratioList.count() * ratioList.count() ); + + for ( UnitRatioList::const_iterator current_it = ratioList.begin(); current_it != ratioList.end(); ++current_it ) { + UnitRatio current_ratio = *current_it; + for ( UnitRatioList::const_iterator ratio_it = ratioList.begin(); ratio_it != ratioList.end(); ++ratio_it ) { + if ( progress_dialog.wasCancelled() ) + return ; + + progress_dialog.progressBar() ->advance( 1 ); + kapp->processEvents(); + + UnitRatio new_ratio; + new_ratio.uID1 = current_ratio.uID1; + new_ratio.uID2 = ( *ratio_it ).uID2; + new_ratio.ratio = ( *ratio_it ).ratio * current_ratio.ratio; + + if ( ratioList.contains( new_ratio ) ) + continue; + + if ( ( ( *ratio_it ).uID1 == current_ratio.uID2 ) && ( ( *ratio_it ).uID2 != current_ratio.uID1 ) ) { + UnitRatio reverse_ratio; + reverse_ratio.uID1 = new_ratio.uID2; + reverse_ratio.uID2 = new_ratio.uID1; + reverse_ratio.ratio = 1.0 / new_ratio.ratio; + + database->saveUnitRatio( &new_ratio ); + database->saveUnitRatio( &reverse_ratio ); + conversionTable->setRatio( new_ratio ); + conversionTable->setRatio( reverse_ratio ); + //ratioList.append(new_ratio); ratioList.append(reverse_ratio); + } + } + } +#endif +} + +#include "unitsdialog.moc" diff --git a/src/dialogs/unitsdialog.h b/src/dialogs/unitsdialog.h new file mode 100644 index 0000000..0810656 --- /dev/null +++ b/src/dialogs/unitsdialog.h @@ -0,0 +1,65 @@ +/*************************************************************************** +* Copyright (C) 2003-2004 by * +* Unai Garro (ugarro@users.sourceforge.net) * +* Cyril Bosselut (bosselut@b1project.com) * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef UNITSDIALOG_H +#define UNITSDIALOG_H +#include <tqwidget.h> +#include <tdelistview.h> +#include <tqpushbutton.h> + +#include "datablocks/unitratiolist.h" +#include "datablocks/unit.h" +#include "widgets/dblistviewbase.h" + +class RecipeDB; +class ConversionTable; +class StdUnitListView; + +/** +@author Unai Garro +*/ +class UnitsDialog: public TQWidget +{ + TQ_OBJECT +public: + UnitsDialog( TQWidget *parent, RecipeDB *db ); + ~UnitsDialog(); + virtual TQSize sizeHint () const + { + return TQSize( 300, 200 ); + } + +public slots: + void reload( ReloadFlags flag = Load ); + +private: + // Widgets + StdUnitListView *unitListView; + ConversionTable *massConversionTable; + ConversionTable *volumeConversionTable; + TQPushButton *newUnitButton; + TQPushButton *removeUnitButton; + + // Internal methods + void saveAllRatios( UnitRatioList &ratioList ); + bool checkBounds( const TQString &name ); + + // Internal Variables + RecipeDB *database; +private slots: + void loadConversionTables(); + void loadConversionTable( ConversionTable*, Unit::Type ); + void saveRatio( int r, int c, double value ); + void removeRatio( int r, int c ); +}; + +#endif diff --git a/src/dialogs/usdadatadialog.cpp b/src/dialogs/usdadatadialog.cpp new file mode 100644 index 0000000..fd771c6 --- /dev/null +++ b/src/dialogs/usdadatadialog.cpp @@ -0,0 +1,200 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#include "usdadatadialog.h" + +#include <kdebug.h> +#include <kstandarddirs.h> +#include <klineedit.h> +#include <tdelistview.h> +#include <tdelocale.h> +#include <tdemessagebox.h> + +#include <tqfile.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqpushbutton.h> +#include <tqtextstream.h> +#include <tqvbox.h> + +#include "backends/recipedb.h" +#include "backends/usda_property_data.h" +#include "backends/usda_unit_data.h" +#include "widgets/krelistview.h" +#include "datablocks/weight.h" + +USDADataDialog::USDADataDialog( const Element &ing, RecipeDB *db, TQWidget *parent ) + : KDialogBase( parent, "usdaDataDialog", true, TQString::null, + KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok ), + ingredient( ing ), + database( db ) +{ + setCaption( TQString( i18n( "Load ingredient properties for: \"%1\"" ) ).arg( ingredient.name ) ); + + TQVBox *page = makeVBoxMainWidget(); + + setButtonText( KDialogBase::Ok, i18n( "&Load" ) ); + + KreListView *krelistview = new KreListView( page, TQString::null, true, 0 ); + + listView = krelistview->listView(); + listView->addColumn( i18n( "USDA Ingredient" ) ); + listView->addColumn( i18n( "Id" ) ); + listView->setAllColumnsShowFocus( true ); + + loadDataFromFile(); + + connect( listView, TQ_SIGNAL( doubleClicked( TQListViewItem*, const TQPoint &, int ) ), this, TQ_SLOT( slotOk() ) ); +} + +USDADataDialog::~USDADataDialog() +{} + +void USDADataDialog::loadDataFromFile() +{ + TQString abbrev_file = locate( "appdata", "data/abbrev.txt" ); + if ( abbrev_file.isEmpty() ) { + kdDebug() << "Unable to find abbrev.txt data file." << endl; + return ; + } + + TQFile file( abbrev_file ); + if ( !file.open( IO_ReadOnly ) ) { + kdDebug() << "Unable to open data file: " << abbrev_file << endl; + return ; + } + + int index = 0; + TQTextStream stream( &file ); + while ( !stream.atEnd() ) { + TQString line = stream.readLine(); + if ( line.isEmpty() ) { + continue; + } + + TQStringList fields = TQStringList::split( "^", line, true ); + loaded_data << fields; + + TQString ing_id = fields[ 0 ].mid( 1, fields[ 1 ].length() - 2 ); + TQString ing_name = fields[ 1 ].mid( 1, fields[ 1 ].length() - 2 ); + ( void ) new TQListViewItem( listView, ing_name, TQString::number( index ) ); //using an index instead of the actual id will help find the data later + + index++; + } +} + +void USDADataDialog::slotOk() +{ + TQListViewItem * item = listView->selectedItem(); + if ( item ) { + int index = item->text( 1 ).toInt(); + TQStringList data = loaded_data[ index ]; + + int grams_id = database->findExistingUnitByName( "g" ); //get this id because all data is given per gram + if ( grams_id == -1 ) { + //FIXME: take advantage of abbreviations + Unit unit("g","g"); + unit.type = Unit::Mass; + database->createNewUnit( unit ); + grams_id = database->lastInsertID(); + } + else { + Unit unit = database->unitName(grams_id); + if ( unit.type != Unit::Mass ) { + unit.type = Unit::Mass; + database->modUnit( unit ); + } + } + + IngredientPropertyList property_list; + database->loadProperties( &property_list ); + IngredientPropertyList existing_ing_props; + database->loadProperties( &existing_ing_props, ingredient.id ); + + int i = 0; + for ( TQStringList::const_iterator it = data.at( 2 ); !property_data_list[ i ].name.isEmpty(); ++it, ++i ) { + int property_id = property_list.findByName( property_data_list[ i ].name ); + if ( property_id == -1 ) { + database->addProperty( property_data_list[ i ].name, property_data_list[ i ].unit ); + property_id = database->lastInsertID(); + } + + double amount = ( *it ).toDouble() / 100.0; //data givin per 100g so divide by 100 to get the amount in 1 gram + + if ( existing_ing_props.find( property_id ) != existing_ing_props.end() ) //property already added to ingredient, so just update + database->changePropertyAmountToIngredient( ingredient.id, property_id, amount, grams_id ); + else + database->addPropertyToIngredient( ingredient.id, property_id, amount, grams_id ); + } + + i+=2; + + int i_initial = i; + WeightList weights = database->ingredientWeightUnits( ingredient.id ); + for ( ; i < i_initial+3; ++i ) { + Weight w; + w.weight = data[i].toDouble(); + + i++; + + TQString amountAndWeight = data[i].mid( 1, data[i].length() - 2 ); + if ( !amountAndWeight.isEmpty() ) { + int spaceIndex = amountAndWeight.find(" "); + w.perAmount = amountAndWeight.left(spaceIndex).toDouble(); + + TQString perAmountUnit = amountAndWeight.right(amountAndWeight.length()-spaceIndex-1); + if ( !parseUSDAUnitAndPrep( perAmountUnit, w.perAmountUnit, w.prepMethod ) ) + continue; + + int unitID = database->findExistingUnitByName( w.perAmountUnit ); + if ( unitID == -1 ) { + for ( int i = 0; unit_data_list[ i ].name; ++i ) { + if ( w.perAmountUnit == unit_data_list[ i ].name || w.perAmountUnit == unit_data_list[ i ].plural ) { + database->createNewUnit( Unit(unit_data_list[ i ].name,unit_data_list[ i ].plural) ); + } + } + + unitID = database->lastInsertID(); + } + w.perAmountUnitID = unitID; + + if ( !w.prepMethod.isEmpty() ) { + int prepID = database->findExistingPrepByName( w.prepMethod ); + if ( prepID == -1 ) { + database->createNewPrepMethod( w.prepMethod ); + prepID = database->lastInsertID(); + } + w.prepMethodID = prepID; + } + + bool exists = false; + for ( WeightList::const_iterator it = weights.begin(); it != weights.end(); ++it ) { + if ( (*it).perAmountUnitID == w.perAmountUnitID && (*it).prepMethodID == w.prepMethodID ) { + exists = true; + break; + } + } + if ( exists ) + continue; + + w.weightUnitID = grams_id; + w.ingredientID = ingredient.id; + database->addIngredientWeight( w ); + } + } + + accept(); + } + else + reject(); +} + + +#include "usdadatadialog.moc" diff --git a/src/dialogs/usdadatadialog.h b/src/dialogs/usdadatadialog.h new file mode 100644 index 0000000..b96d9de --- /dev/null +++ b/src/dialogs/usdadatadialog.h @@ -0,0 +1,47 @@ +/*************************************************************************** +* Copyright (C) 2003 by * +* Jason Kivlighn (jkivlighn@gmail.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 of the License, or * +* (at your option) any later version. * +***************************************************************************/ + +#ifndef USDADATADIALOG_H +#define USDADATADIALOG_H + +#include <kdialogbase.h> + +#include <tqstringlist.h> +#include <tqvaluelist.h> + +#include "datablocks/element.h" + +class RecipeDB; + +class TDEListView; + +class USDADataDialog : public KDialogBase +{ + TQ_OBJECT + +public: + USDADataDialog( const Element &, RecipeDB *database, TQWidget *parent = 0 ); + ~USDADataDialog(); + +private: + void loadDataFromFile(); + + TDEListView *listView; + + Element ingredient; + RecipeDB *database; + + TQValueList<TQStringList> loaded_data; + +private slots: + void slotOk(); +}; + +#endif //USDADATADIALOG_H |