libtdepim

kfoldertree.cpp
1#include "kfoldertree.h"
2#include <tdeversion.h>
3#include <tdelocale.h>
4#include <tdeio/global.h>
5#include <kiconloader.h>
6#include <kdebug.h>
7#include <kstringhandler.h>
8#include <tqpainter.h>
9#include <tqapplication.h>
10#include <tqheader.h>
11#include <tqstyle.h>
12
13//-----------------------------------------------------------------------------
14KFolderTreeItem::KFolderTreeItem( KFolderTree *parent, const TQString & label,
15 Protocol protocol, Type type )
16 : TDEListViewItem( parent, label ), mProtocol( protocol ), mType( type ),
17 mUnread(-1), mTotal(0), mSize(0), mFolderIsCloseToQuota( false )
18{
19}
20
21//-----------------------------------------------------------------------------
22KFolderTreeItem::KFolderTreeItem( KFolderTreeItem *parent,
23 const TQString & label, Protocol protocol, Type type,
24 int unread, int total )
25 : TDEListViewItem( parent, label ), mProtocol( protocol ), mType( type ),
26 mUnread( unread ), mTotal( total ), mSize(0), mFolderIsCloseToQuota( false )
27{
28}
29
30//-----------------------------------------------------------------------------
31int KFolderTreeItem::protocolSortingKey() const
32{
33 // protocol dependant sorting order:
34 // local < imap < news < search < other
35 switch ( mProtocol ) {
36 case Local:
37 return 1;
38 case CachedImap:
39 case Imap:
40 return 2;
41 case News:
42 return 3;
43 case Search:
44 return 4;
45 default:
46 return 42;
47 }
48}
49
50//-----------------------------------------------------------------------------
51int KFolderTreeItem::typeSortingKey() const
52{
53 // type dependant sorting order:
54 // inbox < outbox < sent-mail < trash < drafts
55 // < calendar < contacts < notes < tasks
56 // < normal folders
57 switch ( mType ) {
58 case Inbox:
59 return 1;
60 case Outbox:
61 return 2;
62 case SentMail:
63 return 3;
64 case Trash:
65 return 4;
66 case Drafts:
67 return 5;
68 case Templates:
69 return 6;
70 case Calendar:
71 return 7;
72 case Contacts:
73 return 8;
74 case Notes:
75 return 9;
76 case Tasks:
77 return 10;
78 default:
79 return 42;
80 }
81}
82
83//-----------------------------------------------------------------------------
84int KFolderTreeItem::compare( TQListViewItem * i, int col, bool ) const
85{
86 KFolderTreeItem* other = static_cast<KFolderTreeItem*>( i );
87
88 if (col == 0)
89 {
90 // sort by folder
91
92 // local root-folder
93 if ( depth() == 0 && mProtocol == NONE )
94 return -1;
95 if ( other->depth() == 0 && other->protocol() == NONE )
96 return 1;
97
98 // first compare by protocol
99 int thisKey = protocolSortingKey();
100 int thatKey = other->protocolSortingKey();
101 if ( thisKey < thatKey )
102 return -1;
103 if ( thisKey > thatKey )
104 return 1;
105
106 // then compare by type
107 thisKey = typeSortingKey();
108 thatKey = other->typeSortingKey();
109 if ( thisKey < thatKey )
110 return -1;
111 if ( thisKey > thatKey )
112 return 1;
113
114 // and finally compare by name
115 return text( 0 ).localeAwareCompare( other->text( 0 ) );
116 }
117 else
118 {
119 // sort by unread or total-column
120 TQ_INT64 a = 0, b = 0;
121 if (col == static_cast<KFolderTree*>(listView())->unreadIndex())
122 {
123 a = mUnread;
124 b = other->unreadCount();
125 }
126 else if (col == static_cast<KFolderTree*>(listView())->totalIndex())
127 {
128 a = mTotal;
129 b = other->totalCount();
130 }
131 else if (col == static_cast<KFolderTree*>(listView())->sizeIndex())
132 {
133 a = mSize;
134 b = other->folderSize();
135 }
136
137 if ( a == b )
138 return 0;
139 else
140 return (a < b ? -1 : 1);
141 }
142}
143
144//-----------------------------------------------------------------------------
145void KFolderTreeItem::setUnreadCount( int aUnread )
146{
147 if ( aUnread < 0 ) return;
148
149 mUnread = aUnread;
150
151 TQString unread = TQString();
152 if (mUnread == 0)
153 unread = "- ";
154 else {
155 unread.setNum(mUnread);
156 unread += " ";
157 }
158
159 setText( static_cast<KFolderTree*>(listView())->unreadIndex(),
160 unread );
161}
162
163//-----------------------------------------------------------------------------
164void KFolderTreeItem::setTotalCount( int aTotal )
165{
166 if ( aTotal < 0 ) return;
167
168 mTotal = aTotal;
169
170 TQString total = TQString();
171 if (mTotal == 0)
172 total = "- ";
173 else {
174 total.setNum(mTotal);
175 total += " ";
176 }
177
178 setText( static_cast<KFolderTree*>(listView())->totalIndex(),
179 total );
180}
181
182//-----------------------------------------------------------------------------
183void KFolderTreeItem::setFolderSize( TQ_INT64 aSize )
184{
185 if ( aSize < 0 ) return; // we need to update even if nothing changed, kids ...
186
187 mSize = aSize;
188
189 TQString size;
190 if (mType != Root) {
191 if (mSize == 0 && (childCount() == 0 || isOpen() ) )
192 size = "- ";
193 else
194 size = TDEIO::convertSize(mSize);
195 }
196 if ( childCount() > 0 && !isOpen() ) {
197 TQ_INT64 recursiveSize = recursiveFolderSize();
198 if ( recursiveSize != mSize ) {
199 if ( mType != Root )
200 size += TQString::fromLatin1(" + %1").arg( TDEIO::convertSize( recursiveSize - mSize ) );
201 else
202 size = TDEIO::convertSize( recursiveSize );
203 }
204 }
205 size += " ";
206
207 setText( static_cast<KFolderTree*>(listView())->sizeIndex(), size );
208}
209
210//-----------------------------------------------------------------------------
211TQ_INT64 KFolderTreeItem::recursiveFolderSize() const
212{
213 TQ_INT64 size = mSize;
214
215 for ( TQListViewItem *item = firstChild() ;
216 item ; item = item->nextSibling() )
217 {
218 size += static_cast<KFolderTreeItem*>(item)->recursiveFolderSize();
219 }
220 return size;
221}
222
223
224
225//-----------------------------------------------------------------------------
226int KFolderTreeItem::countUnreadRecursive()
227{
228 int count = (mUnread > 0) ? mUnread : 0;
229
230 for ( TQListViewItem *item = firstChild() ;
231 item ; item = item->nextSibling() )
232 {
233 count += static_cast<KFolderTreeItem*>(item)->countUnreadRecursive();
234 }
235
236 return count;
237}
238
239//-----------------------------------------------------------------------------
240void KFolderTreeItem::paintCell( TQPainter * p, const TQColorGroup & cg,
241 int column, int width, int align )
242{
243 KFolderTree *ft = static_cast<KFolderTree*>(listView());
244
245 const int unreadRecursiveCount = countUnreadRecursive();
246 const int unreadCount = ( mUnread > 0 ) ? mUnread : 0;
247
248
249 // use a special color for folders which are close to their quota
250 TQColorGroup mycg = cg;
251 if ( ( column == 0 || column == ft->sizeIndex() ) && folderIsCloseToQuota() )
252 {
253 mycg.setColor( TQColorGroup::Text, ft->paintInfo().colCloseToQuota );
254 }
255
256 // use a bold-font for the folder- and the unread-columns
257 if ( (column == 0 || column == ft->unreadIndex())
258 && ( unreadCount > 0
259 || ( !isOpen() && unreadRecursiveCount > 0 ) ) )
260 {
261 TQFont f = p->font();
262 f.setWeight(TQFont::Bold);
263 p->setFont(f);
264 }
265
266
267 // most cells can be handled by TDEListView::paintCell, we only need to
268 // deal with the folder column if the unread column is not shown
269
270 /* The below is exceedingly silly, but Ingo insists that the unread
271 * count that is shown in parenthesis after the folder name must
272 * be configurable in color. That means that paintCell needs to do
273 * two painting passes which flickers. Since that flicker is not
274 * needed when there is the unread column, special case that. */
275 if ( ft->isUnreadActive() || column != 0 ) {
276 TDEListViewItem::paintCell( p, mycg, column, width, align );
277 } else {
278 TQListView *lv = listView();
279 TQString oldText = text(column);
280
281 // set an empty text so that we can have our own implementation (see further down)
282 // but still benefit from TDEListView::paintCell
283 setText( column, "" );
284
285 TDEListViewItem::paintCell( p, mycg, column, width, align );
286
287 const TQPixmap *icon = pixmap( column );
288 int marg = lv ? lv->itemMargin() : 1;
289 int r = marg;
290
291 setText( column, oldText );
292 if ( isSelected() )
293 p->setPen( mycg.highlightedText() );
294 else
295 p->setPen( mycg.color( TQColorGroup::Text ) );
296
297 if ( icon ) {
298 r += icon->width() + marg;
299 }
300 TQString t = text( column );
301 if (t.isEmpty())
302 return;
303
304 // draw the unread-count if the unread-column is not active
305 TQString unread;
306
307 if ( unreadCount > 0 || ( !isOpen() && unreadRecursiveCount > 0 ) ) {
308 if ( isOpen() )
309 unread = " (" + TQString::number( unreadCount ) + ")";
310 else if ( unreadRecursiveCount == unreadCount || mType == Root )
311 unread = " (" + TQString::number( unreadRecursiveCount ) + ")";
312 else
313 unread = " (" + TQString::number( unreadCount ) + " + " +
314 TQString::number( unreadRecursiveCount-unreadCount ) + ")";
315 }
316
317 // check if the text needs to be squeezed
318 TQFontMetrics fm( p->fontMetrics() );
319 int unreadWidth = fm.width( unread );
320 if ( fm.width( t ) + marg + r + unreadWidth > width )
321 t = squeezeFolderName( t, fm, width - marg - r - unreadWidth );
322
323 TQRect br;
324 p->drawText( r, 0, width-marg-r, height(),
325 align | AlignVCenter, t, -1, &br );
326
327 if ( !unread.isEmpty() ) {
328 if (!isSelected())
329 p->setPen( ft->paintInfo().colUnread );
330 p->drawText( br.right(), 0, width-marg-br.right(), height(),
331 align | AlignVCenter, unread );
332 }
333 }
334}
335
336
337TQString KFolderTreeItem::squeezeFolderName( const TQString &text,
338 const TQFontMetrics &fm,
339 uint width ) const
340{
341 return KStringHandler::rPixelSqueeze( text, fm, width );
342}
343
344bool KFolderTreeItem::folderIsCloseToQuota() const
345{
346 return mFolderIsCloseToQuota;
347}
348
349void KFolderTreeItem::setFolderIsCloseToQuota( bool v )
350{
351 if ( mFolderIsCloseToQuota != v) {
352 mFolderIsCloseToQuota = v;
353 repaint();
354 }
355}
356
357
358//=============================================================================
359
360
361KFolderTree::KFolderTree( TQWidget *parent, const char* name )
362 : TDEListView( parent, name ), mUnreadIndex(-1), mTotalIndex(-1), mSizeIndex(-1)
363{
364 // GUI-options
365 setStyleDependantFrameWidth();
366 setAcceptDrops(true);
367 setDropVisualizer(false);
368 setAllColumnsShowFocus(true);
369 setShowSortIndicator(true);
370 setUpdatesEnabled(true);
371 setItemsRenameable(false);
372 setRootIsDecorated(true);
373 setSelectionModeExt(Extended);
374 setAlternateBackground(TQColor());
375#if KDE_IS_VERSION( 3, 3, 90 )
376 setShadeSortColumn ( false );
377#endif
378 setFullWidth(true);
379 disableAutoSelection();
380 setColumnWidth( 0, 120 ); //reasonable default size
381
382 disconnect( header(), TQ_SIGNAL( sizeChange( int, int, int ) ) );
383 connect( header(), TQ_SIGNAL( sizeChange( int, int, int ) ),
384 TQ_SLOT( slotSizeChanged( int, int, int ) ) );
385}
386
387//-----------------------------------------------------------------------------
388void KFolderTree::setStyleDependantFrameWidth()
389{
390 // set the width of the frame to a reasonable value for the current GUI style
391 int frameWidth;
392 if( style().isA("KeramikStyle") )
393 frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth ) - 1;
394 else
395 frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth );
396 if ( frameWidth < 0 )
397 frameWidth = 0;
398 if ( frameWidth != lineWidth() )
399 setLineWidth( frameWidth );
400}
401
402//-----------------------------------------------------------------------------
403void KFolderTree::styleChange( TQStyle& oldStyle )
404{
405 setStyleDependantFrameWidth();
406 TDEListView::styleChange( oldStyle );
407}
408
409//-----------------------------------------------------------------------------
410void KFolderTree::drawContentsOffset( TQPainter * p, int ox, int oy,
411 int cx, int cy, int cw, int ch )
412{
413 bool oldUpdatesEnabled = isUpdatesEnabled();
414 setUpdatesEnabled(false);
415 TDEListView::drawContentsOffset( p, ox, oy, cx, cy, cw, ch );
416 setUpdatesEnabled(oldUpdatesEnabled);
417}
418
419//-----------------------------------------------------------------------------
420void KFolderTree::contentsMousePressEvent( TQMouseEvent *e )
421{
422 setSelectionModeExt(Single);
423 TDEListView::contentsMousePressEvent(e);
424}
425
426//-----------------------------------------------------------------------------
427void KFolderTree::contentsMouseReleaseEvent( TQMouseEvent *e )
428{
429 TDEListView::contentsMouseReleaseEvent(e);
430 setSelectionModeExt(Extended);
431}
432
433//-----------------------------------------------------------------------------
434void KFolderTree::addAcceptableDropMimetype( const char *mimeType, bool outsideOk )
435{
436 int oldSize = mAcceptableDropMimetypes.size();
437 mAcceptableDropMimetypes.resize(oldSize+1);
438 mAcceptOutside.resize(oldSize+1);
439
440 mAcceptableDropMimetypes.at(oldSize) = mimeType;
441 mAcceptOutside.setBit(oldSize, outsideOk);
442}
443
444//-----------------------------------------------------------------------------
445bool KFolderTree::acceptDrag( TQDropEvent* event ) const
446{
447 TQListViewItem* item = itemAt(contentsToViewport(event->pos()));
448
449 for (uint i = 0; i < mAcceptableDropMimetypes.size(); i++)
450 {
451 if (event->provides(mAcceptableDropMimetypes[i]))
452 {
453 if (item)
454 return (static_cast<KFolderTreeItem*>(item))->acceptDrag(event);
455 else
456 return mAcceptOutside[i];
457 }
458 }
459 return false;
460}
461
462//-----------------------------------------------------------------------------
463void KFolderTree::addUnreadColumn( const TQString & name, int width )
464{
465 mUnreadIndex = addColumn( name, width );
466 setColumnAlignment( mUnreadIndex, tqApp->reverseLayout() ? TQt::AlignLeft : TQt::AlignRight );
467 header()->adjustHeaderSize();
468}
469
470//-----------------------------------------------------------------------------
471void KFolderTree::addTotalColumn( const TQString & name, int width )
472{
473 mTotalIndex = addColumn( name, width );
474 setColumnAlignment( mTotalIndex, tqApp->reverseLayout() ? TQt::AlignLeft : TQt::AlignRight );
475 header()->adjustHeaderSize();
476}
477
478//-----------------------------------------------------------------------------
479void KFolderTree::removeUnreadColumn()
480{
481 if ( !isUnreadActive() ) return;
482 removeColumn( mUnreadIndex );
483 if ( isTotalActive() && mTotalIndex > mUnreadIndex )
484 mTotalIndex--;
485 if ( isSizeActive() && mSizeIndex > mUnreadIndex )
486 mSizeIndex--;
487
488 mUnreadIndex = -1;
489 header()->adjustHeaderSize();
490}
491
492//-----------------------------------------------------------------------------
493void KFolderTree::removeTotalColumn()
494{
495 if ( !isTotalActive() ) return;
496 removeColumn( mTotalIndex );
497 if ( isUnreadActive() && mTotalIndex < mUnreadIndex )
498 mUnreadIndex--;
499 if ( isSizeActive() && mTotalIndex < mSizeIndex )
500 mSizeIndex--;
501 mTotalIndex = -1;
502 header()->adjustHeaderSize();
503}
504
505//-----------------------------------------------------------------------------
506void KFolderTree::addSizeColumn( const TQString & name, int width )
507{
508 mSizeIndex = addColumn( name, width );
509 setColumnAlignment( mSizeIndex, tqApp->reverseLayout() ? TQt::AlignLeft : TQt::AlignRight );
510 header()->adjustHeaderSize();
511}
512
513//-----------------------------------------------------------------------------
514void KFolderTree::removeSizeColumn()
515{
516 if ( !isSizeActive() ) return;
517 removeColumn( mSizeIndex );
518 if ( isUnreadActive() && mSizeIndex < mUnreadIndex )
519 mUnreadIndex--;
520 if ( isTotalActive() && mSizeIndex < mTotalIndex )
521 mTotalIndex--;
522 mSizeIndex = -1;
523 header()->adjustHeaderSize();
524}
525
526
527//-----------------------------------------------------------------------------
528void KFolderTree::setFullWidth( bool fullWidth )
529{
530 if (fullWidth)
531 header()->setStretchEnabled( true, 0 );
532}
533
534//-----------------------------------------------------------------------------
535void KFolderTree::slotSizeChanged( int section, int, int newSize )
536{
537 viewport()->repaint(
538 header()->sectionPos(section), 0, newSize, visibleHeight(), false );
539}
540
541#include "kfoldertree.moc"