You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
448 lines
12 KiB
448 lines
12 KiB
/***************************************************************************
|
|
* 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 <ntqintdict.h>
|
|
#include <ntqdatastream.h>
|
|
#include <ntqtooltip.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"
|