Factor out the shared parts of the agent action manager setup.
[kdepim.git] / knode / headerview.cpp
blobb888eb6001ffbe934d929d6907797ef1e4344910
1 /*
2 KNode, the KDE newsreader
3 Copyright (c) 1999-2005 the KNode authors.
4 See file AUTHORS for details
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 You should have received a copy of the GNU General Public License
11 along with this program; if not, write to the Free Software Foundation,
12 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
15 #include <QCursor>
16 #include <q3header.h>
17 #include <q3stylesheet.h>
18 #include <QTimer>
19 //Added by qt3to4:
20 #include <QKeyEvent>
21 #include <QEvent>
22 #include <QMouseEvent>
24 #include <klocale.h>
25 #include <kdebug.h>
26 #include <kmenu.h>
28 #include "knglobals.h"
29 #include "headerview.h"
30 #include "knhdrviewitem.h"
31 #include "kngroupmanager.h"
32 #include "knarticle.h"
33 #include "knarticlemanager.h"
34 #include "knmainwidget.h"
35 #include "settings.h"
38 KNHeaderView::KNHeaderView( QWidget *parent ) :
39 K3ListView( parent ),
40 mSortCol( -1 ),
41 mSortAsc( true ),
42 mSortByThreadChangeDate( false ),
43 mDelayedCenter( -1 ),
44 mActiveItem( 0 ),
45 mShowingFolder( false ),
46 mInitDone( false )
48 mPaintInfo.subCol = addColumn( i18n("Subject"), 310 );
49 mPaintInfo.senderCol = addColumn( i18n("From"), 115 );
50 mPaintInfo.scoreCol = addColumn( i18n("Score"), 42 );
51 mPaintInfo.sizeCol = addColumn( i18n("Lines"), 42 );
52 mPaintInfo.dateCol = addColumn( i18n("Date"), 102 );
54 setDropVisualizer( false );
55 setDropHighlighter( false );
56 setItemsRenameable( false );
57 setItemsMovable( false );
58 setAcceptDrops( false );
59 setDragEnabled( true );
60 setAllColumnsShowFocus( true );
61 setSelectionMode( Q3ListView::Extended );
62 setShowSortIndicator( true );
63 setShadeSortColumn ( true );
64 setRootIsDecorated( true );
65 setSorting( mPaintInfo.dateCol );
66 header()->setMovingEnabled( true );
67 setColumnAlignment( mPaintInfo.sizeCol, Qt::AlignRight );
68 setColumnAlignment( mPaintInfo.scoreCol, Qt::AlignRight );
70 // due to our own column text squeezing we need to repaint on column resizing
71 disconnect( header(), SIGNAL(sizeChange(int,int,int)) );
72 connect( header(), SIGNAL(sizeChange(int,int,int)),
73 SLOT(slotSizeChanged(int,int,int)) );
75 // column selection RMB menu
76 mPopup = new KMenu( this );
77 mPopup->addTitle( i18n("View Columns") );
78 mPopup->setCheckable( true );
79 mPopup->insertItem( i18n("Line Count"), KPaintInfo::COL_SIZE );
80 mPopup->insertItem( i18n("Score"), KPaintInfo::COL_SCORE );
82 connect( mPopup, SIGNAL(activated(int)), this, SLOT(toggleColumn(int)) );
84 // connect to the article manager
85 connect( knGlobals.articleManager(), SIGNAL(aboutToShowGroup()), SLOT(prepareForGroup()) );
86 connect( knGlobals.articleManager(), SIGNAL(aboutToShowFolder()), SLOT(prepareForFolder()) );
88 #ifdef __GNUC__
89 #warning Port me!
90 #endif
91 // new KNHeaderViewToolTip( this );
93 installEventFilter( this );
97 KNHeaderView::~KNHeaderView()
99 // ### crash because KNConfigManager is already deleted here
100 // writeConfig();
104 void KNHeaderView::readConfig()
106 if ( !mInitDone ) {
107 KConfigGroup conf(knGlobals.config(), "HeaderView" );
108 mSortByThreadChangeDate = conf.readEntry( "sortByThreadChangeDate", false );
109 restoreLayout( knGlobals.config(), "HeaderView" );
110 mInitDone = true;
113 toggleColumn( KPaintInfo::COL_SIZE, knGlobals.settings()->showLines() );
114 if ( !mShowingFolder ) // score column is always hidden when showing a folder
115 toggleColumn( KPaintInfo::COL_SCORE, knGlobals.settings()->showScore() );
117 mDateFormatter.setCustomFormat( knGlobals.settings()->customDateFormat() );
118 mDateFormatter.setFormat( knGlobals.settings()->dateFormat() );
120 QPalette p = palette();
121 p.setColor( QPalette::Base, knGlobals.settings()->backgroundColor() );
122 p.setColor( QPalette::Text, knGlobals.settings()->textColor() );
123 setPalette( p );
124 setAlternateBackground( knGlobals.settings()->alternateBackgroundColor() );
125 setFont( knGlobals.settings()->articleListFont() );
129 void KNHeaderView::writeConfig()
131 KConfigGroup conf(knGlobals.config(), "HeaderView" );
132 conf.writeEntry( "sortByThreadChangeDate", mSortByThreadChangeDate );
133 saveLayout( knGlobals.config(), "HeaderView" );
135 knGlobals.settings()->setShowLines( mPaintInfo.showSize );
136 if ( !mShowingFolder ) // score column is always hidden when showing a folder
137 knGlobals.settings()->setShowScore( mPaintInfo.showScore );
141 void KNHeaderView::setActive( Q3ListViewItem *i )
143 KNHdrViewItem *item = static_cast<KNHdrViewItem*>( i );
145 if ( !item || item->isActive() )
146 return;
148 if ( mActiveItem ) {
149 mActiveItem->setActive( false );
150 repaintItem( mActiveItem );
151 mActiveItem = 0;
154 item->setActive( true );
155 setSelected( item, true );
156 setCurrentItem( i );
157 ensureItemVisibleWithMargin( i );
158 mActiveItem = item;
159 emit( itemSelected(item) );
163 void KNHeaderView::clear()
165 mActiveItem = 0;
166 Q3ListView::clear();
170 void KNHeaderView::ensureItemVisibleWithMargin( const Q3ListViewItem *i )
172 if ( !i )
173 return;
175 Q3ListViewItem *parent = i->parent();
176 while ( parent ) {
177 if ( !parent->isOpen() )
178 parent->setOpen( true );
179 parent = parent->parent();
182 mDelayedCenter = -1;
183 int y = itemPos( i );
184 int h = i->height();
186 if ( knGlobals.settings()->smartScrolling() &&
187 ((y + h + 5) >= (contentsY() + visibleHeight()) ||
188 (y - 5 < contentsY())) )
190 ensureVisible( contentsX(), y + h/2, 0, h/2 );
191 mDelayedCenter = y + h/2;
192 QTimer::singleShot( 300, this, SLOT(slotCenterDelayed()) );
193 } else {
194 ensureVisible( contentsX(), y + h/2, 0, h/2 );
199 void KNHeaderView::slotCenterDelayed()
201 if ( mDelayedCenter != -1 )
202 ensureVisible( contentsX(), mDelayedCenter, 0, visibleHeight() / 2 );
206 void KNHeaderView::setSorting( int column, bool ascending )
208 if ( column == mSortCol ) {
209 mSortAsc = ascending;
210 if ( mInitDone && column == mPaintInfo.dateCol && ascending )
211 mSortByThreadChangeDate = !mSortByThreadChangeDate;
212 } else {
213 mSortCol = column;
214 emit sortingChanged( column );
217 K3ListView::setSorting( column, ascending );
219 if ( currentItem() )
220 ensureItemVisible( currentItem() );
222 if ( mSortByThreadChangeDate )
223 setColumnText( mPaintInfo.dateCol , i18n("Date (thread changed)") );
224 else
225 setColumnText( mPaintInfo.dateCol, i18n("Date") );
229 void KNHeaderView::nextArticle()
231 KNHdrViewItem *it = static_cast<KNHdrViewItem*>( currentItem() );
233 if (it) {
234 if (it->isActive()) { // take current article, if not selected
235 if (it->isExpandable())
236 it->setOpen(true);
237 it = static_cast<KNHdrViewItem*>(it->itemBelow());
239 } else
240 it = static_cast<KNHdrViewItem*>( firstChild() );
242 if(it) {
243 clearSelection();
244 setActive( it );
245 setSelectionAnchor( currentItem() );
250 void KNHeaderView::prevArticle()
252 KNHdrViewItem *it = static_cast<KNHdrViewItem*>( currentItem() );
254 if (it && it->isActive()) { // take current article, if not selected
255 it = static_cast<KNHdrViewItem*>(it->itemAbove());
256 clearSelection();
257 setActive( it );
258 setSelectionAnchor( currentItem() );
263 void KNHeaderView::incCurrentArticle()
265 Q3ListViewItem *lvi = currentItem();
266 if ( lvi && lvi->isExpandable() )
267 lvi->setOpen( true );
268 if ( lvi && lvi->itemBelow() ) {
269 setCurrentItem( lvi->itemBelow() );
270 ensureItemVisible( currentItem() );
271 setFocus();
275 void KNHeaderView::decCurrentArticle()
277 Q3ListViewItem *lvi = currentItem();
278 if ( lvi && lvi->itemAbove() ) {
279 if ( lvi->itemAbove()->isExpandable() )
280 lvi->itemAbove()->setOpen( true );
281 setCurrentItem( lvi->itemAbove() );
282 ensureItemVisible( currentItem() );
283 setFocus();
288 void KNHeaderView::selectCurrentArticle()
290 clearSelection();
291 setActive( currentItem() );
295 bool KNHeaderView::nextUnreadArticle()
297 if ( !knGlobals.groupManager()->currentGroup() )
298 return false;
300 KNHdrViewItem *next, *current;
301 KNRemoteArticle::Ptr art;
303 current = static_cast<KNHdrViewItem*>( currentItem() );
304 if ( !current )
305 current = static_cast<KNHdrViewItem*>( firstChild() );
307 if(!current)
308 return false;
310 art = boost::static_pointer_cast<KNRemoteArticle>( current->art );
312 if ( !current->isActive() && !art->isRead() ) // take current article, if unread & not selected
313 next = current;
314 else {
315 if ( current->isExpandable() && art->hasUnreadFollowUps() && !current->isOpen() )
316 setOpen( current, true );
317 next = static_cast<KNHdrViewItem*>( current->itemBelow() );
320 while ( next ) {
321 art = boost::static_pointer_cast<KNRemoteArticle>( next->art );
322 if ( !art->isRead() )
323 break;
324 else {
325 if ( next->isExpandable() && art->hasUnreadFollowUps() && !next->isOpen() )
326 setOpen( next, true );
327 next = static_cast<KNHdrViewItem*>( next->itemBelow() );
331 if ( next ) {
332 clearSelection();
333 setActive( next );
334 setSelectionAnchor( currentItem() );
335 return true;
337 return false;
341 bool KNHeaderView::nextUnreadThread()
343 KNHdrViewItem *next, *current;
344 KNRemoteArticle::Ptr art;
346 if ( !knGlobals.groupManager()->currentGroup() )
347 return false;
349 current = static_cast<KNHdrViewItem*>( currentItem() );
350 if ( !current )
351 current = static_cast<KNHdrViewItem*>( firstChild() );
353 if ( !current )
354 return false;
356 art = boost::static_pointer_cast<KNRemoteArticle>( current->art );
358 if ( current->depth() == 0 && !current->isActive() && (!art->isRead() || art->hasUnreadFollowUps()) )
359 next = current; // take current article, if unread & not selected
360 else
361 next = static_cast<KNHdrViewItem*>( current->itemBelow() );
363 while ( next ) {
364 art = boost::static_pointer_cast<KNRemoteArticle>( next->art );
366 if ( next->depth() == 0 ) {
367 if ( !art->isRead() || art->hasUnreadFollowUps() )
368 break;
370 next = static_cast<KNHdrViewItem*>( next->itemBelow() );
373 if ( next ) {
374 setCurrentItem( next );
375 if ( art->isRead() )
376 nextUnreadArticle();
377 else {
378 clearSelection();
379 setActive( next );
380 setSelectionAnchor( currentItem() );
382 return true;
384 return false;
388 void KNHeaderView::toggleColumn( int column, int mode )
390 bool *show = 0;
391 int *col = 0;
392 int width = 0;
394 switch ( static_cast<KPaintInfo::ColumnIds>( column ) )
396 case KPaintInfo::COL_SIZE:
397 show = &mPaintInfo.showSize;
398 col = &mPaintInfo.sizeCol;
399 width = 42;
400 break;
401 case KPaintInfo::COL_SCORE:
402 show = &mPaintInfo.showScore;
403 col = &mPaintInfo.scoreCol;
404 width = 42;
405 break;
406 default:
407 return;
410 if ( mode == -1 )
411 *show = !*show;
412 else
413 *show = mode;
415 mPopup->setItemChecked( column, *show );
417 if (*show) {
418 header()->setResizeEnabled( true, *col );
419 setColumnWidth( *col, width );
421 else {
422 header()->setResizeEnabled( false, *col );
423 header()->setStretchEnabled( false, *col );
424 hideColumn( *col );
427 if ( mode == -1 ) // save config when toggled
428 writeConfig();
432 void KNHeaderView::prepareForGroup()
434 mShowingFolder = false;
435 header()->setLabel( mPaintInfo.senderCol, i18n("From") );
436 toggleColumn( KPaintInfo::COL_SCORE, knGlobals.settings()->showScore() );
440 void KNHeaderView::prepareForFolder()
442 mShowingFolder = true;
443 header()->setLabel( mPaintInfo.senderCol, i18n("Newsgroups / To") );
444 toggleColumn( KPaintInfo::COL_SCORE, false ); // local folders have no score
448 bool KNHeaderView::event( QEvent *e )
450 // we don't want to have the alternate list background restored
451 // to the system defaults!
452 if (e->type() == QEvent::ApplicationPaletteChange)
453 return Q3ListView::event(e);
454 else
455 return K3ListView::event(e);
458 void KNHeaderView::contentsMousePressEvent( QMouseEvent *e )
460 if (!e) return;
462 bool selectMode=(( e->modifiers() & Qt::ShiftModifier ) || ( e->modifiers() & Qt::ControlModifier ));
464 QPoint vp = contentsToViewport(e->pos());
465 Q3ListViewItem *i = itemAt(vp);
467 K3ListView::contentsMousePressEvent( e );
469 if ( i ) {
470 int decoLeft = header()->sectionPos( 0 ) +
471 treeStepSize() * ( (i->depth() - 1) + ( rootIsDecorated() ? 1 : 0) );
472 int decoRight = qMin( decoLeft + treeStepSize() + itemMargin(),
473 header()->sectionPos( 0 ) + header()->sectionSize( 0 ) );
474 bool rootDecoClicked = vp.x() > decoLeft && vp.x() < decoRight;
476 if( !selectMode && i->isSelected() && !rootDecoClicked )
477 setActive( i );
482 void KNHeaderView::contentsMouseDoubleClickEvent( QMouseEvent *e )
484 if (!e) return;
486 Q3ListViewItem *i = itemAt( contentsToViewport(e->pos()) );
487 if (i) {
488 emit doubleClick( i );
489 return;
492 K3ListView::contentsMouseDoubleClickEvent( e );
496 void KNHeaderView::keyPressEvent(QKeyEvent *e)
498 if (!e) return;
500 Q3ListViewItem *i = currentItem();
502 switch(e->key()) {
503 case Qt::Key_Space:
504 case Qt::Key_Backspace:
505 case Qt::Key_Delete:
506 e->ignore(); // don't eat them
507 break;
508 case Qt::Key_Enter:
509 case Qt::Key_Return:
510 setActive( i );
511 break;
513 default:
514 K3ListView::keyPressEvent (e);
519 #ifdef __GNUC__
520 #warning Port this to QDrag once the view doesnot derive from K3ListView any more
521 #endif
522 Q3DragObject* KNHeaderView::dragObject()
524 KNHdrViewItem *item = static_cast<KNHdrViewItem*>( itemAt(viewport()->mapFromGlobal(QCursor::pos())) );
525 if (item)
526 return item->dragObject();
527 else
528 return 0;
532 void KNHeaderView::slotSizeChanged( int section, int, int newSize )
534 viewport()->repaint( header()->sectionPos(section), 0, newSize, visibleHeight() );
538 bool KNHeaderView::eventFilter(QObject *o, QEvent *e)
540 // right click on header
541 if ( e->type() == QEvent::MouseButtonPress &&
542 static_cast<QMouseEvent*>(e)->button() == Qt::RightButton &&
543 qobject_cast<Q3Header*>( o ) )
545 mPopup->popup( static_cast<QMouseEvent*>(e)->globalPos() );
546 return true;
549 return K3ListView::eventFilter(o, e);
553 //BEGIN: KNHeaderViewToolTip ==================================================
555 #ifdef __GNUC__
556 #warning Port me!
557 #endif
558 #if 0
559 KNHeaderViewToolTip::KNHeaderViewToolTip( KNHeaderView *parent ) :
560 QToolTip( parent->viewport() ),
561 listView( parent )
566 void KNHeaderViewToolTip::maybeTip( const QPoint &p )
568 const KNHdrViewItem *item = static_cast<KNHdrViewItem*>( listView->itemAt( p ) );
569 if ( !item )
570 return;
571 const int column = listView->header()->sectionAt( p.x() );
572 if ( column == -1 )
573 return;
575 if ( !item->showToolTip( column ) )
576 return;
578 const QRect itemRect = listView->itemRect( item );
579 if ( !itemRect.isValid() )
580 return;
581 const QRect headerRect = listView->header()->sectionRect( column );
582 if ( !headerRect.isValid() )
583 return;
585 tip( QRect( headerRect.left(), itemRect.top(), headerRect.width(), itemRect.height() ),
586 Qt::escape( item->text( column ) ) );
588 #endif
590 //END: KNHeaderViewToolTip ====================================================
592 #include "headerview.moc"