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 //-----------------------------------------------------------------------------
13 KFolderTreeItem::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 //-----------------------------------------------------------------------------
21 KFolderTreeItem::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 //-----------------------------------------------------------------------------
30 int 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 //-----------------------------------------------------------------------------
50 int 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 //-----------------------------------------------------------------------------
83 int 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 //-----------------------------------------------------------------------------
144 void 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 //-----------------------------------------------------------------------------
163 void 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 //-----------------------------------------------------------------------------
182 void 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 //-----------------------------------------------------------------------------
210 TQ_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 //-----------------------------------------------------------------------------
225 int 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 //-----------------------------------------------------------------------------
239 void 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 
336 TQString KFolderTreeItem::squeezeFolderName( const TQString &text,
337  const TQFontMetrics &fm,
338  uint width ) const
339 {
340  return KStringHandler::rPixelSqueeze( text, fm, width );
341 }
342 
343 bool KFolderTreeItem::folderIsCloseToQuota() const
344 {
345  return mFolderIsCloseToQuota;
346 }
347 
348 void KFolderTreeItem::setFolderIsCloseToQuota( bool v )
349 {
350  if ( mFolderIsCloseToQuota != v) {
351  mFolderIsCloseToQuota = v;
352  repaint();
353  }
354 }
355 
356 
357 //=============================================================================
358 
359 
360 KFolderTree::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 //-----------------------------------------------------------------------------
385 void 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 //-----------------------------------------------------------------------------
400 void KFolderTree::styleChange( TQStyle& oldStyle )
401 {
402  setStyleDependantFrameWidth();
403  TDEListView::styleChange( oldStyle );
404 }
405 
406 //-----------------------------------------------------------------------------
407 void 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 //-----------------------------------------------------------------------------
417 void KFolderTree::contentsMousePressEvent( TQMouseEvent *e )
418 {
419  setSelectionModeExt(Single);
420  TDEListView::contentsMousePressEvent(e);
421 }
422 
423 //-----------------------------------------------------------------------------
424 void KFolderTree::contentsMouseReleaseEvent( TQMouseEvent *e )
425 {
426  TDEListView::contentsMouseReleaseEvent(e);
427  setSelectionModeExt(Extended);
428 }
429 
430 //-----------------------------------------------------------------------------
431 void 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 //-----------------------------------------------------------------------------
442 bool 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 //-----------------------------------------------------------------------------
460 void 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 //-----------------------------------------------------------------------------
468 void 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 //-----------------------------------------------------------------------------
476 void 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 //-----------------------------------------------------------------------------
490 void 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 //-----------------------------------------------------------------------------
503 void 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 //-----------------------------------------------------------------------------
511 void 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 //-----------------------------------------------------------------------------
525 void KFolderTree::setFullWidth( bool fullWidth )
526 {
527  if (fullWidth)
528  header()->setStretchEnabled( true, 0 );
529 }
530 
531 //-----------------------------------------------------------------------------
532 void 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"