summaryrefslogtreecommitdiffstats
path: root/knode/headerview.cpp
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit460c52653ab0dcca6f19a4f492ed2c5e4e963ab0 (patch)
tree67208f7c145782a7e90b123b982ca78d88cc2c87 /knode/headerview.cpp
downloadtdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.tar.gz
tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'knode/headerview.cpp')
-rw-r--r--knode/headerview.cpp617
1 files changed, 617 insertions, 0 deletions
diff --git a/knode/headerview.cpp b/knode/headerview.cpp
new file mode 100644
index 000000000..aef02f13a
--- /dev/null
+++ b/knode/headerview.cpp
@@ -0,0 +1,617 @@
+/*
+ KNode, the KDE newsreader
+ Copyright (c) 1999-2005 the KNode authors.
+ See file AUTHORS for details
+
+ 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.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
+*/
+
+#include <qcursor.h>
+#include <qheader.h>
+#include <qstylesheet.h>
+#include <qtimer.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kdeversion.h>
+#include <kpopupmenu.h>
+
+#include "knglobals.h"
+#include "knconfigmanager.h"
+#include "headerview.h"
+#include "knhdrviewitem.h"
+#include "kngroupmanager.h"
+#include "knarticle.h"
+#include "knarticlemanager.h"
+#include "knmainwidget.h"
+
+
+KNHeaderView::KNHeaderView(QWidget *parent, const char *name) :
+ KListView(parent,name),
+ mSortCol( -1 ),
+ mSortAsc( true ),
+ mSortByThreadChangeDate( false ),
+ mDelayedCenter( -1 ),
+ mActiveItem( 0 ),
+ mShowingFolder( false ),
+ mInitDone( false )
+{
+ mPaintInfo.subCol = addColumn( i18n("Subject"), 310 );
+ mPaintInfo.senderCol = addColumn( i18n("From"), 115 );
+ mPaintInfo.scoreCol = addColumn( i18n("Score"), 42 );
+ mPaintInfo.sizeCol = addColumn( i18n("Lines"), 42 );
+ mPaintInfo.dateCol = addColumn( i18n("Date"), 102 );
+
+ setDropVisualizer( false );
+ setDropHighlighter( false );
+ setItemsRenameable( false );
+ setItemsMovable( false );
+ setAcceptDrops( false );
+ setDragEnabled( true );
+ setAllColumnsShowFocus( true );
+ setSelectionMode( QListView::Extended );
+ setShowSortIndicator( true );
+ setShadeSortColumn ( true );
+ setRootIsDecorated( true );
+ setSorting( mPaintInfo.dateCol );
+ header()->setMovingEnabled( true );
+ setColumnAlignment( mPaintInfo.sizeCol, Qt::AlignRight );
+ setColumnAlignment( mPaintInfo.scoreCol, Qt::AlignRight );
+
+ // due to our own column text squeezing we need to repaint on column resizing
+ disconnect( header(), SIGNAL(sizeChange(int, int, int)) );
+ connect( header(), SIGNAL(sizeChange(int, int, int)),
+ SLOT(slotSizeChanged(int, int, int)) );
+
+ // column selection RMB menu
+ mPopup = new KPopupMenu( this );
+ mPopup->insertTitle( i18n("View Columns") );
+ mPopup->setCheckable( true );
+ mPopup->insertItem( i18n("Line Count"), KPaintInfo::COL_SIZE );
+ mPopup->insertItem( i18n("Score"), KPaintInfo::COL_SCORE );
+
+ connect( mPopup, SIGNAL(activated(int)), this, SLOT(toggleColumn(int)) );
+
+ // connect to the article manager
+ connect( knGlobals.articleManager(), SIGNAL(aboutToShowGroup()), SLOT(prepareForGroup()) );
+ connect( knGlobals.articleManager(), SIGNAL(aboutToShowFolder()), SLOT(prepareForFolder()) );
+
+ new KNHeaderViewToolTip( this );
+
+ installEventFilter( this );
+}
+
+
+KNHeaderView::~KNHeaderView()
+{
+ // ### crash because KNConfigManager is already deleted here
+ // writeConfig();
+}
+
+
+void KNHeaderView::readConfig()
+{
+ if ( !mInitDone ) {
+ KConfig *conf = knGlobals.config();
+ conf->setGroup( "HeaderView" );
+ mSortByThreadChangeDate = conf->readBoolEntry( "sortByThreadChangeDate", false );
+ restoreLayout( conf, "HeaderView" );
+ mInitDone = true;
+ }
+
+ KNConfig::ReadNewsGeneral *rngConf = knGlobals.configManager()->readNewsGeneral();
+ toggleColumn( KPaintInfo::COL_SIZE, rngConf->showLines() );
+ if ( !mShowingFolder ) // score column is always hidden when showing a folder
+ toggleColumn( KPaintInfo::COL_SCORE, rngConf->showScore() );
+
+ mDateFormatter.setCustomFormat( rngConf->dateCustomFormat() );
+ mDateFormatter.setFormat( rngConf->dateFormat() );
+
+ KNConfig::Appearance *app = knGlobals.configManager()->appearance();
+ QPalette p = palette();
+ p.setColor( QColorGroup::Base, app->backgroundColor() );
+ p.setColor( QColorGroup::Text, app->textColor() );
+ setPalette( p );
+ setAlternateBackground( app->alternateBackgroundColor() );
+ setFont( app->articleListFont() );
+}
+
+
+void KNHeaderView::writeConfig()
+{
+ KConfig *conf = knGlobals.config();
+ conf->setGroup( "HeaderView" );
+ conf->writeEntry( "sortByThreadChangeDate", mSortByThreadChangeDate );
+ saveLayout( conf, "HeaderView" );
+
+ KNConfig::ReadNewsGeneral *rngConf = knGlobals.configManager()->readNewsGeneral();
+ rngConf->setShowLines( mPaintInfo.showSize );
+ if ( !mShowingFolder ) // score column is always hidden when showing a folder
+ rngConf->setShowScore( mPaintInfo.showScore );
+}
+
+
+void KNHeaderView::setActive( QListViewItem *i )
+{
+ KNHdrViewItem *item = static_cast<KNHdrViewItem*>( i );
+
+ if ( !item || item->isActive() )
+ return;
+
+ if ( mActiveItem ) {
+ mActiveItem->setActive( false );
+ repaintItem( mActiveItem );
+ mActiveItem = 0;
+ }
+
+ item->setActive( true );
+ setSelected( item, true );
+ setCurrentItem( i );
+ ensureItemVisibleWithMargin( i );
+ mActiveItem = item;
+ emit( itemSelected(item) );
+}
+
+
+void KNHeaderView::clear()
+{
+ mActiveItem = 0;
+ QListView::clear();
+}
+
+
+void KNHeaderView::ensureItemVisibleWithMargin( const QListViewItem *i )
+{
+ if ( !i )
+ return;
+
+ QListViewItem *parent = i->parent();
+ while ( parent ) {
+ if ( !parent->isOpen() )
+ parent->setOpen( true );
+ parent = parent->parent();
+ }
+
+ mDelayedCenter = -1;
+ int y = itemPos( i );
+ int h = i->height();
+
+ if ( knGlobals.configManager()->readNewsGeneral()->smartScrolling() &&
+ ((y + h + 5) >= (contentsY() + visibleHeight()) ||
+ (y - 5 < contentsY())) )
+ {
+ ensureVisible( contentsX(), y + h/2, 0, h/2 );
+ mDelayedCenter = y + h/2;
+ QTimer::singleShot( 300, this, SLOT(slotCenterDelayed()) );
+ } else {
+ ensureVisible( contentsX(), y + h/2, 0, h/2 );
+ }
+}
+
+
+void KNHeaderView::slotCenterDelayed()
+{
+ if ( mDelayedCenter != -1 )
+ ensureVisible( contentsX(), mDelayedCenter, 0, visibleHeight() / 2 );
+}
+
+
+void KNHeaderView::setSorting( int column, bool ascending )
+{
+ if ( column == mSortCol ) {
+ mSortAsc = ascending;
+ if ( mInitDone && column == mPaintInfo.dateCol && ascending )
+ mSortByThreadChangeDate = !mSortByThreadChangeDate;
+ } else {
+ mSortCol = column;
+ emit sortingChanged( column );
+ }
+
+ KListView::setSorting( column, ascending );
+
+ if ( currentItem() )
+ ensureItemVisible( currentItem() );
+
+ if ( mSortByThreadChangeDate )
+ setColumnText( mPaintInfo.dateCol , i18n("Date (thread changed)") );
+ else
+ setColumnText( mPaintInfo.dateCol, i18n("Date") );
+}
+
+
+void KNHeaderView::nextArticle()
+{
+ KNHdrViewItem *it = static_cast<KNHdrViewItem*>( currentItem() );
+
+ if (it) {
+ if (it->isActive()) { // take current article, if not selected
+ if (it->isExpandable())
+ it->setOpen(true);
+ it = static_cast<KNHdrViewItem*>(it->itemBelow());
+ }
+ } else
+ it = static_cast<KNHdrViewItem*>( firstChild() );
+
+ if(it) {
+ clearSelection();
+ setActive( it );
+ setSelectionAnchor( currentItem() );
+ }
+}
+
+
+void KNHeaderView::prevArticle()
+{
+ KNHdrViewItem *it = static_cast<KNHdrViewItem*>( currentItem() );
+
+ if (it && it->isActive()) { // take current article, if not selected
+ if (it)
+ it = static_cast<KNHdrViewItem*>(it->itemAbove());
+ else
+ it = static_cast<KNHdrViewItem*>( firstChild() );
+ }
+
+ if (it) {
+ clearSelection();
+ setActive( it );
+ setSelectionAnchor( currentItem() );
+ }
+}
+
+
+void KNHeaderView::incCurrentArticle()
+{
+ QListViewItem *lvi = currentItem();
+ if ( lvi && lvi->isExpandable() )
+ lvi->setOpen( true );
+ if ( lvi && lvi->itemBelow() ) {
+ setCurrentItem( lvi->itemBelow() );
+ ensureItemVisible( currentItem() );
+ setFocus();
+ }
+}
+
+void KNHeaderView::decCurrentArticle()
+{
+ QListViewItem *lvi = currentItem();
+ if ( lvi && lvi->itemAbove() ) {
+ if ( lvi->itemAbove()->isExpandable() )
+ lvi->itemAbove()->setOpen( true );
+ setCurrentItem( lvi->itemAbove() );
+ ensureItemVisible( currentItem() );
+ setFocus();
+ }
+}
+
+
+void KNHeaderView::selectCurrentArticle()
+{
+ clearSelection();
+ setActive( currentItem() );
+}
+
+
+bool KNHeaderView::nextUnreadArticle()
+{
+ if ( !knGlobals.groupManager()->currentGroup() )
+ return false;
+
+ KNHdrViewItem *next, *current;
+ KNRemoteArticle *art;
+
+ current = static_cast<KNHdrViewItem*>( currentItem() );
+ if ( !current )
+ current = static_cast<KNHdrViewItem*>( firstChild() );
+
+ if(!current)
+ return false;
+
+ art = static_cast<KNRemoteArticle*>( current->art );
+
+ if ( !current->isActive() && !art->isRead() ) // take current article, if unread & not selected
+ next = current;
+ else {
+ if ( current->isExpandable() && art->hasUnreadFollowUps() && !current->isOpen() )
+ setOpen( current, true );
+ next = static_cast<KNHdrViewItem*>( current->itemBelow() );
+ }
+
+ while ( next ) {
+ art = static_cast<KNRemoteArticle*>( next->art );
+ if ( !art->isRead() )
+ break;
+ else {
+ if ( next->isExpandable() && art->hasUnreadFollowUps() && !next->isOpen() )
+ setOpen( next, true );
+ next = static_cast<KNHdrViewItem*>( next->itemBelow() );
+ }
+ }
+
+ if ( next ) {
+ clearSelection();
+ setActive( next );
+ setSelectionAnchor( currentItem() );
+ return true;
+ }
+ return false;
+}
+
+
+bool KNHeaderView::nextUnreadThread()
+{
+ KNHdrViewItem *next, *current;
+ KNRemoteArticle *art;
+
+ if ( !knGlobals.groupManager()->currentGroup() )
+ return false;
+
+ current = static_cast<KNHdrViewItem*>( currentItem() );
+ if ( !current )
+ current = static_cast<KNHdrViewItem*>( firstChild() );
+
+ if ( !current )
+ return false;
+
+ art = static_cast<KNRemoteArticle*>( current->art );
+
+ if ( current->depth() == 0 && !current->isActive() && (!art->isRead() || art->hasUnreadFollowUps()) )
+ next = current; // take current article, if unread & not selected
+ else
+ next = static_cast<KNHdrViewItem*>( current->itemBelow() );
+
+ while ( next ) {
+ art = static_cast<KNRemoteArticle*>( next->art );
+
+ if ( next->depth() == 0 ) {
+ if ( !art->isRead() || art->hasUnreadFollowUps() )
+ break;
+ }
+ next = static_cast<KNHdrViewItem*>( next->itemBelow() );
+ }
+
+ if ( next ) {
+ setCurrentItem( next );
+ if ( art->isRead() )
+ nextUnreadArticle();
+ else {
+ clearSelection();
+ setActive( next );
+ setSelectionAnchor( currentItem() );
+ }
+ return true;
+ }
+ return false;
+}
+
+
+void KNHeaderView::toggleColumn( int column, int mode )
+{
+ bool *show = 0;
+ int *col = 0;
+ int width = 0;
+
+ switch ( static_cast<KPaintInfo::ColumnIds>( column ) )
+ {
+ case KPaintInfo::COL_SIZE:
+ show = &mPaintInfo.showSize;
+ col = &mPaintInfo.sizeCol;
+ width = 42;
+ break;
+ case KPaintInfo::COL_SCORE:
+ show = &mPaintInfo.showScore;
+ col = &mPaintInfo.scoreCol;
+ width = 42;
+ break;
+ default:
+ return;
+ }
+
+ if ( mode == -1 )
+ *show = !*show;
+ else
+ *show = mode;
+
+ mPopup->setItemChecked( column, *show );
+
+ if (*show) {
+ header()->setResizeEnabled( true, *col );
+ setColumnWidth( *col, width );
+ }
+ else {
+ header()->setResizeEnabled( false, *col );
+ header()->setStretchEnabled( false, *col );
+ hideColumn( *col );
+ }
+
+ if ( mode == -1 ) // save config when toggled
+ writeConfig();
+}
+
+
+void KNHeaderView::prepareForGroup()
+{
+ mShowingFolder = false;
+ header()->setLabel( mPaintInfo.senderCol, i18n("From") );
+ KNConfig::ReadNewsGeneral *rngConf = knGlobals.configManager()->readNewsGeneral();
+ toggleColumn( KPaintInfo::COL_SCORE, rngConf->showScore() );
+}
+
+
+void KNHeaderView::prepareForFolder()
+{
+ mShowingFolder = true;
+ header()->setLabel( mPaintInfo.senderCol, i18n("Newsgroups / To") );
+ toggleColumn( KPaintInfo::COL_SCORE, false ); // local folders have no score
+}
+
+
+bool KNHeaderView::event( QEvent *e )
+{
+ // we don't want to have the alternate list background restored
+ // to the system defaults!
+ if (e->type() == QEvent::ApplicationPaletteChange)
+ return QListView::event(e);
+ else
+ return KListView::event(e);
+}
+
+void KNHeaderView::contentsMousePressEvent( QMouseEvent *e )
+{
+ if (!e) return;
+
+ bool selectMode=(( e->state() & ShiftButton ) || ( e->state() & ControlButton ));
+
+ QPoint vp = contentsToViewport(e->pos());
+ QListViewItem *i = itemAt(vp);
+
+ KListView::contentsMousePressEvent( e );
+
+ if ( i ) {
+ int decoLeft = header()->sectionPos( 0 ) +
+ treeStepSize() * ( (i->depth() - 1) + ( rootIsDecorated() ? 1 : 0) );
+ int decoRight = kMin( decoLeft + treeStepSize() + itemMargin(),
+ header()->sectionPos( 0 ) + header()->sectionSize( 0 ) );
+ bool rootDecoClicked = vp.x() > decoLeft && vp.x() < decoRight;
+
+ if( !selectMode && i->isSelected() && !rootDecoClicked )
+ setActive( i );
+ }
+}
+
+
+void KNHeaderView::contentsMouseDoubleClickEvent( QMouseEvent *e )
+{
+ if (!e) return;
+
+ QListViewItem *i = itemAt( contentsToViewport(e->pos()) );
+ if (i) {
+ emit doubleClick( i );
+ return;
+ }
+
+ KListView::contentsMouseDoubleClickEvent( e );
+}
+
+
+void KNHeaderView::keyPressEvent(QKeyEvent *e)
+{
+ if (!e) return;
+
+ QListViewItem *i = currentItem();
+
+ switch(e->key()) {
+ case Key_Space:
+ case Key_Backspace:
+ case Key_Delete:
+ e->ignore(); // don't eat them
+ break;
+ case Key_Enter:
+ case Key_Return:
+ setActive( i );
+ break;
+
+ default:
+ KListView::keyPressEvent (e);
+ }
+}
+
+
+QDragObject* KNHeaderView::dragObject()
+{
+ KNHdrViewItem *item = static_cast<KNHdrViewItem*>( itemAt(viewport()->mapFromGlobal(QCursor::pos())) );
+ if (item)
+ return item->dragObject();
+ else
+ return 0;
+}
+
+
+void KNHeaderView::slotSizeChanged( int section, int, int newSize )
+{
+ viewport()->repaint( header()->sectionPos(section), 0, newSize, visibleHeight(), false);
+}
+
+
+bool KNHeaderView::eventFilter(QObject *o, QEvent *e)
+{
+ if ((e->type() == QEvent::KeyPress) && (static_cast<QKeyEvent*>(e)->key() == Key_Tab)) {
+ emit(focusChangeRequest(this));
+ if (!hasFocus()) // focusChangeRequest was successful
+ return true;
+ }
+
+ // right click on header
+ if ( e->type() == QEvent::MouseButtonPress &&
+ static_cast<QMouseEvent*>(e)->button() == RightButton &&
+ o->isA("QHeader") )
+ {
+ mPopup->popup( static_cast<QMouseEvent*>(e)->globalPos() );
+ return true;
+ }
+
+ return KListView::eventFilter(o, e);
+}
+
+
+void KNHeaderView::focusInEvent(QFocusEvent *e)
+{
+ QListView::focusInEvent(e);
+ emit focusChanged(e);
+}
+
+
+void KNHeaderView::focusOutEvent(QFocusEvent *e)
+{
+ QListView::focusOutEvent(e);
+ emit focusChanged(e);
+}
+
+
+void KNHeaderView::resetCurrentTime()
+{
+ mDateFormatter.reset();
+ QTimer::singleShot( 1000, this, SLOT(resetCurrentTime()) );
+}
+
+
+//BEGIN: KNHeaderViewToolTip ==================================================
+
+KNHeaderViewToolTip::KNHeaderViewToolTip( KNHeaderView *parent ) :
+ QToolTip( parent->viewport() ),
+ listView( parent )
+{
+}
+
+
+void KNHeaderViewToolTip::maybeTip( const QPoint &p )
+{
+ const KNHdrViewItem *item = static_cast<KNHdrViewItem*>( listView->itemAt( p ) );
+ if ( !item )
+ return;
+ const int column = listView->header()->sectionAt( p.x() );
+ if ( column == -1 )
+ return;
+
+ if ( !item->showToolTip( column ) )
+ return;
+
+ const QRect itemRect = listView->itemRect( item );
+ if ( !itemRect.isValid() )
+ return;
+ const QRect headerRect = listView->header()->sectionRect( column );
+ if ( !headerRect.isValid() )
+ return;
+
+ tip( QRect( headerRect.left(), itemRect.top(), headerRect.width(), itemRect.height() ),
+ QStyleSheet::escape( item->text( column ) ) );
+}
+
+//END: KNHeaderViewToolTip ====================================================
+
+#include "headerview.moc"