summaryrefslogtreecommitdiffstats
path: root/krecipes/src/widgets/dblistviewbase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'krecipes/src/widgets/dblistviewbase.cpp')
-rw-r--r--krecipes/src/widgets/dblistviewbase.cpp334
1 files changed, 334 insertions, 0 deletions
diff --git a/krecipes/src/widgets/dblistviewbase.cpp b/krecipes/src/widgets/dblistviewbase.cpp
new file mode 100644
index 0000000..0be4f38
--- /dev/null
+++ b/krecipes/src/widgets/dblistviewbase.cpp
@@ -0,0 +1,334 @@
+/***************************************************************************
+* 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 <kapplication.h>
+#include <kconfig.h>
+#include <kcursor.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kprogress.h>
+
+
+//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 QListViewItem
+{
+public:
+ PrevListViewItem( QListView *parent ) : QListViewItem(parent){}
+
+ virtual int rtti() const { return PREVLISTITEM_RTTI; }
+
+ QString text( int c ) const {
+ if ( c == 0 ) {
+ return QString("<< %1").arg(i18n("Previous"));
+ }
+ else
+ return QString::null;
+ }
+};
+
+class NextListViewItem : public QListViewItem
+{
+public:
+ NextListViewItem( QListView *parent, QListViewItem *after ) : QListViewItem(parent,after){}
+
+ virtual int rtti() const { return NEXTLISTITEM_RTTI; }
+
+ QString text( int c ) const {
+ if ( c == 0 ) {
+ return QString("%1 >>").arg(i18n("Next"));
+ }
+ else
+ return QString::null;
+ }
+};
+
+DBListViewBase::DBListViewBase( QWidget *parent, RecipeDB *db, int t ) : KListView(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
+ KConfig * config = KGlobal::config();config->setGroup( "Performance" );
+ curr_limit = config->readNumEntry( "Limit", -1 );
+ }
+
+ connect(this,SIGNAL(executed(QListViewItem*)),SLOT(slotDoubleClicked(QListViewItem*)));
+}
+
+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( QListViewItem *it, int c )
+{
+ if ( it->rtti() == PREVLISTITEM_RTTI || it->rtti() == NEXTLISTITEM_RTTI ) {
+ return;
+ }
+
+ KListView::rename(it,c);
+}
+
+void DBListViewBase::slotDoubleClicked( QListViewItem *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( QKeyEvent *k )
+{
+ if ( k->state() == Qt::ShiftButton ) {
+ switch ( k->key() ) {
+ case Qt::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 Qt::Key_P: {
+ kapp->processEvents(); //if auto-repeating, user won't otherwise see change in the listview
+ activatePrev();
+ k->accept();
+ break;
+ }
+ default: break;
+ }
+ }
+
+ KListView::keyPressEvent(k);
+}
+
+void DBListViewBase::reload( ReloadFlags flag )
+{
+ if ( flag == ForceReload || (!firstChild() && flag == Load) || (firstChild() && flag == ReloadIfPopulated) ) {
+ KApplication::setOverrideCursor( KCursor::waitCursor() );
+
+ init();
+
+ //m_progress = new KProgressDialog(this,0,QString::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;
+
+ KApplication::restoreOverrideCursor();
+ }
+}
+
+void DBListViewBase::setTotalItems(int i)
+{
+ m_totalSteps = i;
+ if ( m_progress ) {
+ m_progress->progressBar()->setTotalSteps( m_totalSteps );
+ }
+}
+
+void DBListViewBase::createElement( QListViewItem *it )
+{
+ Q_ASSERT(it);
+
+ QListViewItem *lastElement;
+ QMap<QListViewItem*,QListViewItem*>::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 ( QString::localeAwareCompare(it->text(c),lastElement->text(c)) >= 0 ) {
+ it->moveItem(lastElement);
+ lastElementMap.insert(it->parent(),it);
+ }
+ else {
+ QListViewItem *last_it = 0;
+
+ for ( QListViewItem *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 ( QString::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( QListViewItem *it, bool delete_item )
+{
+ total--;
+ if ( !it ) return;
+
+ QListViewItem *lastElement = lastElementMap[it->parent()];
+ if ( it == lastElement ) {
+ for ( QListViewItem *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 QString &name )
+{
+ total++;
+
+ QListViewItem *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 ) {
+ QListViewItem *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"