/*************************************************************************** * Copyright (C) 2004 by * * Jason Kivlighn (jkivlighn@gmail.com) * * 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 "recipelistview.h" #include #include #include #include #include #include #include #include #include #include #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( 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("
%7
__________
%1 %2
%3 %4
%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("%1
%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(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(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"