summaryrefslogtreecommitdiffstats
path: root/src/widgets/recipelistview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/recipelistview.cpp')
-rw-r--r--src/widgets/recipelistview.cpp447
1 files changed, 447 insertions, 0 deletions
diff --git a/src/widgets/recipelistview.cpp b/src/widgets/recipelistview.cpp
new file mode 100644
index 0000000..536d06c
--- /dev/null
+++ b/src/widgets/recipelistview.cpp
@@ -0,0 +1,447 @@
+/***************************************************************************
+* Copyright (C) 2004 by *
+* Jason Kivlighn ([email protected]) *
+* Unai Garro ([email protected]) *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+***************************************************************************/
+
+#include "recipelistview.h"
+
+#include <tqintdict.h>
+#include <tqdatastream.h>
+#include <tqtooltip.h>
+
+#include <tdeapplication.h>
+#include <kdebug.h>
+#include <tdeconfig.h>
+#include <tdeglobal.h>
+#include <tdelocale.h>
+#include <kiconloader.h>
+#include <kprogress.h>
+
+#include "backends/recipedb.h"
+
+class UncategorizedItem : public TQListViewItem
+{
+public:
+ UncategorizedItem( TQListView *lv ) : TQListViewItem( lv, i18n("Uncategorized") ){}
+ int rtti() const { return 1006; }
+};
+
+RecipeItemDrag::RecipeItemDrag( RecipeListItem *recipeItem, TQWidget *dragSource, const char *name )
+ : TQStoredDrag( RECIPEITEMMIMETYPE, dragSource, name )
+{
+ if ( recipeItem ) {
+ TQByteArray data;
+ TQDataStream out( data, IO_WriteOnly );
+ out << recipeItem->recipeID();
+ out << recipeItem->title();
+ setEncodedData( data );
+ }
+}
+
+bool RecipeItemDrag::canDecode( TQMimeSource* e )
+{
+ return e->provides( RECIPEITEMMIMETYPE );
+}
+
+bool RecipeItemDrag::decode( const TQMimeSource* e, RecipeListItem& item )
+{
+ if ( !e )
+ return false;
+
+ TQByteArray data = e->encodedData( RECIPEITEMMIMETYPE );
+ if ( data.isEmpty() )
+ return false;
+
+ TQString title;
+ int recipeID;
+ TQDataStream in( data, IO_ReadOnly );
+ in >> recipeID;
+ in >> title;
+
+ item.setTitle( title );
+ item.setRecipeID( recipeID );
+
+ return true;
+}
+
+class RecipeListToolTip : public TQToolTip
+{
+public:
+ RecipeListToolTip( RecipeListView *view ) : TQToolTip(view->viewport()), m_view(view)
+ {}
+
+ void maybeTip( const TQPoint &point )
+ {
+ TQListViewItem *item = m_view->itemAt( point );
+ if ( item ) {
+ TQString text = m_view->tooltip(item,0);
+ if ( !text.isEmpty() )
+ tip( m_view->itemRect( item ), text );
+ }
+ }
+
+private:
+ RecipeListView *m_view;
+
+};
+
+
+RecipeListView::RecipeListView( TQWidget *parent, RecipeDB *db ) : StdCategoryListView( parent, db ),
+ flat_list( false ),
+ m_uncat_item(0),
+ m_progress_dlg(0)
+{
+ setColumnText( 0, i18n( "Recipe" ) );
+
+ TDEConfig *config = TDEGlobal::config(); config->setGroup( "Performance" );
+ curr_limit = config->readNumEntry("CategoryLimit",-1);
+
+ TDEIconLoader il;
+ setPixmap( il.loadIcon( "categories", TDEIcon::NoGroup, 16 ) );
+
+ setSelectionMode( TQListView::Extended );
+
+ (void)new RecipeListToolTip(this);
+}
+
+void RecipeListView::init()
+{
+ connect( database, TQ_SIGNAL( recipeCreated( const Element &, const ElementList & ) ), TQ_SLOT( createRecipe( const Element &, const ElementList & ) ) );
+ connect( database, TQ_SIGNAL( recipeRemoved( int ) ), TQ_SLOT( removeRecipe( int ) ) );
+ connect( database, TQ_SIGNAL( recipeRemoved( int, int ) ), TQ_SLOT( removeRecipe( int, int ) ) );
+ connect( database, TQ_SIGNAL( recipeModified( const Element &, const ElementList & ) ), TQ_SLOT( modifyRecipe( const Element &, const ElementList & ) ) );
+
+ StdCategoryListView::init();
+}
+
+TQDragObject *RecipeListView::dragObject()
+{
+ RecipeListItem * item = dynamic_cast<RecipeListItem*>( currentItem() );
+ 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;
+}
+
+bool RecipeListView::acceptDrag( TQDropEvent *event ) const
+{
+ return RecipeItemDrag::canDecode( event );
+}
+
+TQString RecipeListView::tooltip(TQListViewItem *item, int /*column*/) const
+{
+ if ( item->rtti() == RECIPELISTITEM_RTTI ) {
+ RecipeListItem *recipe_it = (RecipeListItem*)item;
+
+ Recipe r;
+ database->loadRecipe(&r,RecipeDB::Meta|RecipeDB::Noatime,recipe_it->recipeID() );
+
+ TDELocale *locale = TDEGlobal::locale();
+
+ return TQString("<center><b>%7</b></center><center>__________</center>%1 %2<br />%3 %4<br />%5 %6")
+ .arg(i18n("Created:")).arg(locale->formatDateTime(r.ctime))
+ .arg(i18n("Modified:")).arg(locale->formatDateTime(r.mtime))
+ .arg(i18n("Last Accessed:")).arg(locale->formatDateTime(r.atime))
+ .arg(recipe_it->title());
+ }/* Maybe this would be handy
+ else if ( item->rtti() == CATEGORYLISTITEM_RTTI ) {
+ CategoryListItem *cat_it = (CategoryListItem*)item;
+
+ return TQString("<b>%1</b><hr />%2: %3")
+ .arg(cat_it->categoryName())
+ .arg(i18n("Recipes"))
+ .arg(TQString::number(WHATEVER THE CHILD COUNT IS));
+ }*/
+
+ return TQString::null;
+}
+
+void RecipeListView::load(int limit, int offset)
+{
+ m_uncat_item = 0;
+
+ if ( flat_list ) {
+ ElementList recipeList;
+ database->loadRecipeList( &recipeList );
+
+ ElementList::const_iterator recipe_it;
+ for ( recipe_it = recipeList.begin();recipe_it != recipeList.end();++recipe_it ) {
+ Recipe recipe;
+ recipe.recipeID = ( *recipe_it ).id;
+ recipe.title = ( *recipe_it ).name;
+ createRecipe( recipe, -1 );
+ }
+ }
+ else {
+ StdCategoryListView::load(limit,offset);
+
+ if ( offset == 0 ) {
+ ElementList recipeList;
+ database->loadUncategorizedRecipes( &recipeList );
+
+ ElementList::const_iterator recipe_it;
+ for ( recipe_it = recipeList.begin();recipe_it != recipeList.end();++recipe_it ) {
+ Recipe recipe;
+ recipe.recipeID = ( *recipe_it ).id;
+ recipe.title = ( *recipe_it ).name;
+ createRecipe( recipe, -1 );
+ }
+ }
+ }
+}
+
+void RecipeListView::populate( TQListViewItem *item )
+{
+ CategoryItemInfo *cat_item = dynamic_cast<CategoryItemInfo*>(item);
+ if ( !cat_item || cat_item->isPopulated() ) return;
+
+ delete item->firstChild(); //delete the "pseudo item"
+
+ if ( m_progress_dlg ){
+ m_progress_dlg->progressBar()->advance(1);
+ kapp->processEvents();
+ }
+
+ StdCategoryListView::populate(item);
+
+ if ( !flat_list ) {
+ int id = cat_item->categoryId();
+
+ // Now show the recipes
+ ElementList recipeList;
+ database->loadRecipeList( &recipeList, id );
+
+ ElementList::const_iterator recipe_it;
+ for ( recipe_it = recipeList.begin(); recipe_it != recipeList.end(); ++recipe_it ) {
+ Recipe recipe;
+ recipe.recipeID = ( *recipe_it ).id;
+ recipe.title = ( *recipe_it ).name;
+ createRecipe( recipe, id );
+ }
+ }
+}
+
+void RecipeListView::populateAll( TQListViewItem *parent )
+{
+ bool first = false;
+ if ( !parent ) {
+ first = true;
+ m_progress_dlg = new KProgressDialog(this,"populate_all_prog_dlg",TQString::null,i18n("Loading recipes"),true);
+ m_progress_dlg->setAllowCancel(false);
+ m_progress_dlg->progressBar()->setTotalSteps(0);
+ m_progress_dlg->progressBar()->setPercentageVisible(false);
+
+ m_progress_dlg->grabKeyboard(); //don't let the user keep hitting keys
+
+ parent = firstChild();
+ }
+ else {
+ populate( parent );
+ parent = parent->firstChild();
+ }
+
+ for ( TQListViewItem *item = parent; item; item = item->nextSibling() ) {
+ if ( m_progress_dlg && m_progress_dlg->wasCancelled() )
+ break;
+
+ populateAll( item );
+ }
+
+ if ( first ) {
+ delete m_progress_dlg;
+ m_progress_dlg = 0;
+ }
+}
+
+void RecipeListView::createRecipe( const Recipe &recipe, int parent_id )
+{
+ if ( parent_id == -1 ) {
+ if ( !m_uncat_item && curr_offset == 0 ) {
+ m_uncat_item = new UncategorizedItem(this);
+ if ( childCount() == 1 ) //only call createElement if this is the only item in the list
+ createElement(m_uncat_item); //otherwise, this item won't stay at the top
+ }
+
+ if ( m_uncat_item )
+ new RecipeListItem( m_uncat_item, recipe );
+ }
+ else {
+ CategoryListItem *parent = (CategoryListItem*)items_map[ parent_id ];
+ if ( parent && parent->isPopulated() )
+ createElement(new RecipeListItem( parent, recipe ));
+ }
+}
+
+void RecipeListView::createRecipe( const Element &recipe_el, const ElementList &categories )
+{
+ Recipe recipe;
+ recipe.recipeID = recipe_el.id;
+ recipe.title = recipe_el.name;
+
+ if ( categories.count() == 0 ) {
+ createRecipe( recipe, -1 );
+ }
+ else {
+ for ( ElementList::const_iterator cat_it = categories.begin(); cat_it != categories.end(); ++cat_it ) {
+ int cur_cat_id = ( *cat_it ).id;
+
+ TQListViewItemIterator iterator( this );
+ while ( iterator.current() ) {
+ if ( iterator.current() ->rtti() == 1001 ) {
+ CategoryListItem * cat_item = ( CategoryListItem* ) iterator.current();
+ if ( cat_item->categoryId() == cur_cat_id ) {
+ createRecipe( recipe, cur_cat_id );
+ }
+ }
+ ++iterator;
+ }
+ }
+ }
+}
+
+void RecipeListView::createElement( TQListViewItem *item )
+{
+ CategoryItemInfo *cat_item = dynamic_cast<CategoryItemInfo*>(item);
+ if ( cat_item && !cat_item->isPopulated() ) {
+ new PseudoListItem( item );
+ }
+
+ //if ( cat_item && !cat_item->isPopulated() && item->rtti() == RECIPELISTITEM_RTTI )
+ // return;
+
+ #if 0
+ ElementList list;
+ database->loadRecipeList( &list, cat_item->categoryId() );
+ if ( list.count() > 0 )
+ #endif
+
+ CategoryListView::createElement(item);
+}
+
+void RecipeListView::modifyRecipe( const Element &recipe, const ElementList &categories )
+{
+ removeRecipe( recipe.id );
+ createRecipe( recipe, categories );
+}
+
+void RecipeListView::removeRecipe( int id )
+{
+ TQListViewItemIterator iterator( this );
+ while ( iterator.current() ) {
+ if ( iterator.current() ->rtti() == 1000 ) {
+ RecipeListItem * recipe_it = ( RecipeListItem* ) iterator.current();
+ if ( recipe_it->recipeID() == id ) {
+ removeElement(recipe_it);
+
+ //delete the "Uncategorized" item if we removed the last recipe that was under it
+ if ( m_uncat_item && m_uncat_item->childCount() == 0 ) {
+ delete m_uncat_item;
+ m_uncat_item = 0;
+ }
+ }
+ }
+ ++iterator;
+ }
+}
+
+void RecipeListView::removeRecipe( int recipe_id, int cat_id )
+{
+ TQListViewItem * item = items_map[ cat_id ];
+
+ //find out if this is the only category the recipe belongs to
+ int finds = 0;
+ TQListViewItemIterator iterator( this );
+ while ( iterator.current() ) {
+ if ( iterator.current() ->rtti() == 1000 ) {
+ RecipeListItem * recipe_it = ( RecipeListItem* ) iterator.current();
+
+ if ( recipe_it->recipeID() == recipe_id ) {
+ if ( finds > 1 )
+ break;
+ finds++;
+ }
+ }
+ ++iterator;
+ }
+
+ //do this to only iterate over children of 'item'
+ TQListViewItem *pEndItem = NULL;
+ TQListViewItem *pStartItem = item;
+ do {
+ if ( pStartItem->nextSibling() )
+ pEndItem = pStartItem->nextSibling();
+ else
+ pStartItem = pStartItem->parent();
+ }
+ while ( pStartItem && !pEndItem );
+
+ iterator = TQListViewItemIterator( item );
+ while ( iterator.current() != pEndItem ) {
+ if ( iterator.current() ->rtti() == 1000 ) {
+ RecipeListItem * recipe_it = ( RecipeListItem* ) iterator.current();
+
+ if ( recipe_it->recipeID() == recipe_id ) {
+
+ if ( finds == 1 ) {
+ //the item is now uncategorized
+ if ( !m_uncat_item && curr_offset == 0 )
+ m_uncat_item = new UncategorizedItem(this);
+ if ( m_uncat_item ) {
+ Recipe r;
+ r.title = recipe_it->title(); r.recipeID = recipe_id;
+ new RecipeListItem(m_uncat_item,r);
+ }
+ }
+ removeElement(recipe_it);
+ break;
+ }
+ }
+ ++iterator;
+ }
+}
+
+void RecipeListView::removeCategory( int id )
+{
+ TQListViewItem * item = items_map[ id ];
+ if ( !item )
+ return ; //this may have been deleted already by its parent being deleted
+
+ moveChildrenToRoot( item );
+
+ StdCategoryListView::removeCategory( id );
+}
+
+void RecipeListView::moveChildrenToRoot( TQListViewItem *item )
+{
+ TQListViewItem * next_sibling;
+ for ( TQListViewItem * it = item->firstChild(); it; it = next_sibling ) {
+ next_sibling = it->nextSibling();
+ if ( it->rtti() == 1000 ) {
+ RecipeListItem *recipe_it = (RecipeListItem*) it;
+ Recipe r;
+ r.title = recipe_it->title(); r.recipeID = recipe_it->recipeID();
+
+ //the item is now uncategorized
+ removeElement(it,false);
+ it->parent() ->takeItem( it );
+ if ( !m_uncat_item && curr_offset == 0 )
+ m_uncat_item = new UncategorizedItem(this);
+ if ( m_uncat_item )
+ new RecipeListItem(m_uncat_item,r);
+ }
+ moveChildrenToRoot( it );
+ delete it;
+ }
+}
+
+#include "recipelistview.moc"