libtdepim

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