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
17 #include <q3stylesheet.h>
22 #include <QMouseEvent>
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"
38 KNHeaderView::KNHeaderView( QWidget
*parent
) :
42 mSortByThreadChangeDate( false ),
45 mShowingFolder( 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()) );
91 // new KNHeaderViewToolTip( this );
93 installEventFilter( this );
97 KNHeaderView::~KNHeaderView()
99 // ### crash because KNConfigManager is already deleted here
104 void KNHeaderView::readConfig()
107 KConfigGroup
conf(knGlobals
.config(), "HeaderView" );
108 mSortByThreadChangeDate
= conf
.readEntry( "sortByThreadChangeDate", false );
109 restoreLayout( knGlobals
.config(), "HeaderView" );
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() );
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() )
149 mActiveItem
->setActive( false );
150 repaintItem( mActiveItem
);
154 item
->setActive( true );
155 setSelected( item
, true );
157 ensureItemVisibleWithMargin( i
);
159 emit( itemSelected(item
) );
163 void KNHeaderView::clear()
170 void KNHeaderView::ensureItemVisibleWithMargin( const Q3ListViewItem
*i
)
175 Q3ListViewItem
*parent
= i
->parent();
177 if ( !parent
->isOpen() )
178 parent
->setOpen( true );
179 parent
= parent
->parent();
183 int y
= itemPos( i
);
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()) );
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
;
214 emit
sortingChanged( column
);
217 K3ListView::setSorting( column
, ascending
);
220 ensureItemVisible( currentItem() );
222 if ( mSortByThreadChangeDate
)
223 setColumnText( mPaintInfo
.dateCol
, i18n("Date (thread changed)") );
225 setColumnText( mPaintInfo
.dateCol
, i18n("Date") );
229 void KNHeaderView::nextArticle()
231 KNHdrViewItem
*it
= static_cast<KNHdrViewItem
*>( currentItem() );
234 if (it
->isActive()) { // take current article, if not selected
235 if (it
->isExpandable())
237 it
= static_cast<KNHdrViewItem
*>(it
->itemBelow());
240 it
= static_cast<KNHdrViewItem
*>( firstChild() );
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());
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() );
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() );
288 void KNHeaderView::selectCurrentArticle()
291 setActive( currentItem() );
295 bool KNHeaderView::nextUnreadArticle()
297 if ( !knGlobals
.groupManager()->currentGroup() )
300 KNHdrViewItem
*next
, *current
;
301 KNRemoteArticle::Ptr art
;
303 current
= static_cast<KNHdrViewItem
*>( currentItem() );
305 current
= static_cast<KNHdrViewItem
*>( firstChild() );
310 art
= boost::static_pointer_cast
<KNRemoteArticle
>( current
->art
);
312 if ( !current
->isActive() && !art
->isRead() ) // take current article, if unread & not selected
315 if ( current
->isExpandable() && art
->hasUnreadFollowUps() && !current
->isOpen() )
316 setOpen( current
, true );
317 next
= static_cast<KNHdrViewItem
*>( current
->itemBelow() );
321 art
= boost::static_pointer_cast
<KNRemoteArticle
>( next
->art
);
322 if ( !art
->isRead() )
325 if ( next
->isExpandable() && art
->hasUnreadFollowUps() && !next
->isOpen() )
326 setOpen( next
, true );
327 next
= static_cast<KNHdrViewItem
*>( next
->itemBelow() );
334 setSelectionAnchor( currentItem() );
341 bool KNHeaderView::nextUnreadThread()
343 KNHdrViewItem
*next
, *current
;
344 KNRemoteArticle::Ptr art
;
346 if ( !knGlobals
.groupManager()->currentGroup() )
349 current
= static_cast<KNHdrViewItem
*>( currentItem() );
351 current
= static_cast<KNHdrViewItem
*>( firstChild() );
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
361 next
= static_cast<KNHdrViewItem
*>( current
->itemBelow() );
364 art
= boost::static_pointer_cast
<KNRemoteArticle
>( next
->art
);
366 if ( next
->depth() == 0 ) {
367 if ( !art
->isRead() || art
->hasUnreadFollowUps() )
370 next
= static_cast<KNHdrViewItem
*>( next
->itemBelow() );
374 setCurrentItem( next
);
380 setSelectionAnchor( currentItem() );
388 void KNHeaderView::toggleColumn( int column
, int mode
)
394 switch ( static_cast<KPaintInfo::ColumnIds
>( column
) )
396 case KPaintInfo::COL_SIZE
:
397 show
= &mPaintInfo
.showSize
;
398 col
= &mPaintInfo
.sizeCol
;
401 case KPaintInfo::COL_SCORE
:
402 show
= &mPaintInfo
.showScore
;
403 col
= &mPaintInfo
.scoreCol
;
415 mPopup
->setItemChecked( column
, *show
);
418 header()->setResizeEnabled( true, *col
);
419 setColumnWidth( *col
, width
);
422 header()->setResizeEnabled( false, *col
);
423 header()->setStretchEnabled( false, *col
);
427 if ( mode
== -1 ) // save config when toggled
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
);
455 return K3ListView::event(e
);
458 void KNHeaderView::contentsMousePressEvent( QMouseEvent
*e
)
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
);
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
)
482 void KNHeaderView::contentsMouseDoubleClickEvent( QMouseEvent
*e
)
486 Q3ListViewItem
*i
= itemAt( contentsToViewport(e
->pos()) );
488 emit
doubleClick( i
);
492 K3ListView::contentsMouseDoubleClickEvent( e
);
496 void KNHeaderView::keyPressEvent(QKeyEvent
*e
)
500 Q3ListViewItem
*i
= currentItem();
504 case Qt::Key_Backspace
:
506 e
->ignore(); // don't eat them
514 K3ListView::keyPressEvent (e
);
520 #warning Port this to QDrag once the view doesnot derive from K3ListView any more
522 Q3DragObject
* KNHeaderView::dragObject()
524 KNHdrViewItem
*item
= static_cast<KNHdrViewItem
*>( itemAt(viewport()->mapFromGlobal(QCursor::pos())) );
526 return item
->dragObject();
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() );
549 return K3ListView::eventFilter(o
, e
);
553 //BEGIN: KNHeaderViewToolTip ==================================================
559 KNHeaderViewToolTip::KNHeaderViewToolTip( KNHeaderView
*parent
) :
560 QToolTip( parent
->viewport() ),
566 void KNHeaderViewToolTip::maybeTip( const QPoint
&p
)
568 const KNHdrViewItem
*item
= static_cast<KNHdrViewItem
*>( listView
->itemAt( p
) );
571 const int column
= listView
->header()->sectionAt( p
.x() );
575 if ( !item
->showToolTip( column
) )
578 const QRect itemRect
= listView
->itemRect( item
);
579 if ( !itemRect
.isValid() )
581 const QRect headerRect
= listView
->header()->sectionRect( column
);
582 if ( !headerRect
.isValid() )
585 tip( QRect( headerRect
.left(), itemRect
.top(), headerRect
.width(), itemRect
.height() ),
586 Qt::escape( item
->text( column
) ) );
590 //END: KNHeaderViewToolTip ====================================================
592 #include "headerview.moc"