/*************************************************************************** * 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 "dblistviewbase.h" #include #include #include #include #include #include #include //These two classes are used to identify the "Next" and "Prev" items, which are identified through rtti(). This also prevents renaming, even if it is enabled. class PrevListViewItem : public TQListViewItem { public: PrevListViewItem( TQListView *parent ) : TQListViewItem(parent){} virtual int rtti() const { return PREVLISTITEM_RTTI; } TQString text( int c ) const { if ( c == 0 ) { return TQString("<< %1").arg(i18n("Previous")); } else return TQString::null; } }; class NextListViewItem : public TQListViewItem { public: NextListViewItem( TQListView *parent, TQListViewItem *after ) : TQListViewItem(parent,after){} virtual int rtti() const { return NEXTLISTITEM_RTTI; } TQString text( int c ) const { if ( c == 0 ) { return TQString("%1 >>").arg(i18n("Next")); } else return TQString::null; } }; DBListViewBase::DBListViewBase( TQWidget *parent, RecipeDB *db, int t ) : TDEListView(parent), database(db), curr_limit(-1), curr_offset(0), total(t), bulk_load(false), delete_me_later(0), m_progress(0), m_totalSteps(0) { setSorting(-1); if ( curr_limit == -1 ) { //only use the default limit if a subclass hasn't given curr_limit its own value TDEConfig * config = TDEGlobal::config();config->setGroup( "Performance" ); curr_limit = config->readNumEntry( "Limit", -1 ); } connect(this,TQ_SIGNAL(executed(TQListViewItem*)),TQ_SLOT(slotDoubleClicked(TQListViewItem*))); } DBListViewBase::~DBListViewBase() { delete m_progress; } void DBListViewBase::activatePrev() { if ( curr_offset != 0 ) { curr_offset -= curr_limit; if ( curr_offset < 0 ) curr_offset = 0; reload(ForceReload); emit prevGroupLoaded(); } } void DBListViewBase::activateNext() { curr_offset += curr_limit; reload(ForceReload); emit nextGroupLoaded(); } void DBListViewBase::rename( TQListViewItem *it, int c ) { if ( it->rtti() == PREVLISTITEM_RTTI || it->rtti() == NEXTLISTITEM_RTTI ) { return; } TDEListView::rename(it,c); } void DBListViewBase::slotDoubleClicked( TQListViewItem *it ) { //we can't delete the item the was double clicked //and yet these functions will clear() the listview. //We'll take the item from the view so it isn't deleted //and delete it ourselves. delete delete_me_later; delete_me_later = 0; if ( it->rtti() == PREVLISTITEM_RTTI ) { delete_me_later = it; takeItem(it); activatePrev(); } else if ( it->rtti() == NEXTLISTITEM_RTTI ) { delete_me_later = it; takeItem(it); activateNext(); } } void DBListViewBase::keyPressEvent( TQKeyEvent *k ) { if ( k->state() == TQt::ShiftButton ) { switch ( k->key() ) { case TQt::Key_N: { if ( curr_offset + curr_limit >= total || curr_limit == -1 ) { k->accept(); return; } kapp->processEvents(); //if auto-repeating, user won't otherwise see change in the listview activateNext(); k->accept(); break; } case TQt::Key_P: { kapp->processEvents(); //if auto-repeating, user won't otherwise see change in the listview activatePrev(); k->accept(); break; } default: break; } } TDEListView::keyPressEvent(k); } void DBListViewBase::reload( ReloadFlags flag ) { if ( flag == ForceReload || (!firstChild() && flag == Load) || (firstChild() && flag == ReloadIfPopulated) ) { TDEApplication::setOverrideCursor( KCursor::waitCursor() ); init(); //m_progress = new KProgressDialog(this,0,TQString::null,i18n("Loading..."),true); //m_progress->setAllowCancel(false); //m_progress->progressBar()->setPercentageVisible(false); //m_progress->progressBar()->setTotalSteps( m_totalSteps ); //m_progress->show(); //kapp->processEvents(); //reset some things clear(); lastElementMap.clear(); bulk_load=true; load(curr_limit,curr_offset); bulk_load=false; if ( curr_limit != -1 && curr_offset + curr_limit < total ) new NextListViewItem(this,lastElementMap[0]); if ( curr_offset != 0 ) new PrevListViewItem(this); //delete m_progress; m_progress = 0; TDEApplication::restoreOverrideCursor(); } } void DBListViewBase::setTotalItems(int i) { m_totalSteps = i; if ( m_progress ) { m_progress->progressBar()->setTotalSteps( m_totalSteps ); } } void DBListViewBase::createElement( TQListViewItem *it ) { Q_ASSERT(it); TQListViewItem *lastElement; TQMap::iterator map_it = lastElementMap.find(it->parent()); if ( map_it != lastElementMap.end() ) { lastElement = map_it.data(); } else lastElement = 0; if ( bulk_load ) { //this can be much faster if we know the elements are already in order if ( lastElement ) it->moveItem(lastElement); lastElementMap.insert(it->parent(),it); if ( m_progress ) { m_progress->progressBar()->advance(1); } } else { if ( lastElement == 0 ) { lastElementMap.insert(it->parent(),it); } else { int c = 0;//FIXME: the column used should be variable (set by a subclass) if ( it->parent() == 0 ) { //start it out below the "Prev" item... currently it will be at firstChild() if ( firstChild()->nextSibling() && ( firstChild()->nextSibling()->rtti() == PREVLISTITEM_RTTI || firstChild()->nextSibling()->rtti() == 1006 ) ) { //A hack to skip the Uncategorized item it->moveItem( firstChild()->nextSibling() ); } } if ( TQString::localeAwareCompare(it->text(c),lastElement->text(c)) >= 0 ) { it->moveItem(lastElement); lastElementMap.insert(it->parent(),it); } else { TQListViewItem *last_it = 0; for ( TQListViewItem *search_it = it; search_it; search_it = search_it->nextSibling() ) { if ( search_it->rtti() == NEXTLISTITEM_RTTI ) { it->moveItem(lastElement); lastElementMap.insert(it->parent(),it); } else if ( TQString::localeAwareCompare(it->text(c),search_it->text(c)) < 0 ) { //we assume the list is sorted, as it should stay if ( last_it ) it->moveItem(last_it); break; } last_it = search_it; } } } } } void DBListViewBase::removeElement( TQListViewItem *it, bool delete_item ) { total--; if ( !it ) return; TQListViewItem *lastElement = lastElementMap[it->parent()]; if ( it == lastElement ) { for ( TQListViewItem *search_it = (it->parent())?it->parent()->firstChild():firstChild(); search_it->nextSibling(); search_it = search_it->nextSibling() ) { if ( it == search_it->nextSibling() ) { lastElementMap.insert(it->parent(),search_it); lastElement = search_it; break; } } if ( lastElement == it || lastElement->rtti() == PREVLISTITEM_RTTI ) { //there are no more items in the view if this happens if ( firstChild() && firstChild()->rtti() == PREVLISTITEM_RTTI ) { activatePrev(); it = 0; //keep 'delete it' below from segfault'ing } else if ( lastElement->nextSibling() && lastElement->nextSibling()->rtti() == NEXTLISTITEM_RTTI ) { reload(); it = 0; //keep 'delete it' below from segfault'ing } else //the list is now empty, there is no last element lastElementMap.remove(it->parent()); } } if ( delete_item ) delete it; } bool DBListViewBase::handleElement( const TQString &name ) { total++; TQListViewItem *lastElement = lastElementMap[0]; int c = 0;//FIXME: the column used should be variable (set by a subclass) int child_count = childCount(); if ( child_count == 0 ) return true; if ( firstChild()->rtti() == PREVLISTITEM_RTTI || firstChild()->rtti() == 1006 ){ child_count--; } //"Prev" item if ( child_count == 0 ) return true; if ( lastElement->nextSibling() ){ child_count--; } //"Next" item if ( curr_limit != -1 && child_count >= curr_limit ) { TQListViewItem *firstElement = firstChild(); if (firstElement->rtti() == PREVLISTITEM_RTTI || firstElement->rtti() == 1006 ) { firstElement = firstElement->nextSibling(); } else if ( name < firstElement->text(c) ) { //provide access to this new element if we need to new PrevListViewItem(this); curr_offset++; return false; } if ( name < firstElement->text(c) ) { curr_offset++; return false; } else if ( name >= lastElement->text(c) ) { if ( lastElement->nextSibling() == 0 ) new NextListViewItem(this,lastElement); return false; } else { removeElement(lastElement); } } return true; } #include "dblistviewbase.moc"