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 #if KDE_IS_VERSION( 3, 3, 90 )
375  setShadeSortColumn ( false );
376 #endif
377  setFullWidth(true);
378  disableAutoSelection();
379  setColumnWidth( 0, 120 ); //reasonable default size
380 
381  disconnect( header(), TQT_SIGNAL( sizeChange( int, int, int ) ) );
382  connect( header(), TQT_SIGNAL( sizeChange( int, int, int ) ),
383  TQT_SLOT( slotSizeChanged( int, int, int ) ) );
384 }
385 
386 //-----------------------------------------------------------------------------
387 void KFolderTree::setStyleDependantFrameWidth()
388 {
389  // set the width of the frame to a reasonable value for the current GUI style
390  int frameWidth;
391  if( style().isA("KeramikStyle") )
392  frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth ) - 1;
393  else
394  frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth );
395  if ( frameWidth < 0 )
396  frameWidth = 0;
397  if ( frameWidth != lineWidth() )
398  setLineWidth( frameWidth );
399 }
400 
401 //-----------------------------------------------------------------------------
402 void KFolderTree::styleChange( TQStyle& oldStyle )
403 {
404  setStyleDependantFrameWidth();
405  TDEListView::styleChange( oldStyle );
406 }
407 
408 //-----------------------------------------------------------------------------
409 void KFolderTree::drawContentsOffset( TQPainter * p, int ox, int oy,
410  int cx, int cy, int cw, int ch )
411 {
412  bool oldUpdatesEnabled = isUpdatesEnabled();
413  setUpdatesEnabled(false);
414  TDEListView::drawContentsOffset( p, ox, oy, cx, cy, cw, ch );
415  setUpdatesEnabled(oldUpdatesEnabled);
416 }
417 
418 //-----------------------------------------------------------------------------
419 void KFolderTree::contentsMousePressEvent( TQMouseEvent *e )
420 {
421  setSelectionModeExt(Single);
422  TDEListView::contentsMousePressEvent(e);
423 }
424 
425 //-----------------------------------------------------------------------------
426 void KFolderTree::contentsMouseReleaseEvent( TQMouseEvent *e )
427 {
428  TDEListView::contentsMouseReleaseEvent(e);
429  setSelectionModeExt(Extended);
430 }
431 
432 //-----------------------------------------------------------------------------
433 void KFolderTree::addAcceptableDropMimetype( const char *mimeType, bool outsideOk )
434 {
435  int oldSize = mAcceptableDropMimetypes.size();
436  mAcceptableDropMimetypes.resize(oldSize+1);
437  mAcceptOutside.resize(oldSize+1);
438 
439  mAcceptableDropMimetypes.at(oldSize) = mimeType;
440  mAcceptOutside.setBit(oldSize, outsideOk);
441 }
442 
443 //-----------------------------------------------------------------------------
444 bool KFolderTree::acceptDrag( TQDropEvent* event ) const
445 {
446  TQListViewItem* item = itemAt(contentsToViewport(event->pos()));
447 
448  for (uint i = 0; i < mAcceptableDropMimetypes.size(); i++)
449  {
450  if (event->provides(mAcceptableDropMimetypes[i]))
451  {
452  if (item)
453  return (static_cast<KFolderTreeItem*>(item))->acceptDrag(event);
454  else
455  return mAcceptOutside[i];
456  }
457  }
458  return false;
459 }
460 
461 //-----------------------------------------------------------------------------
462 void KFolderTree::addUnreadColumn( const TQString & name, int width )
463 {
464  mUnreadIndex = addColumn( name, width );
465  setColumnAlignment( mUnreadIndex, tqApp->reverseLayout() ? TQt::AlignLeft : TQt::AlignRight );
466  header()->adjustHeaderSize();
467 }
468 
469 //-----------------------------------------------------------------------------
470 void KFolderTree::addTotalColumn( const TQString & name, int width )
471 {
472  mTotalIndex = addColumn( name, width );
473  setColumnAlignment( mTotalIndex, tqApp->reverseLayout() ? TQt::AlignLeft : TQt::AlignRight );
474  header()->adjustHeaderSize();
475 }
476 
477 //-----------------------------------------------------------------------------
478 void KFolderTree::removeUnreadColumn()
479 {
480  if ( !isUnreadActive() ) return;
481  removeColumn( mUnreadIndex );
482  if ( isTotalActive() && mTotalIndex > mUnreadIndex )
483  mTotalIndex--;
484  if ( isSizeActive() && mSizeIndex > mUnreadIndex )
485  mSizeIndex--;
486 
487  mUnreadIndex = -1;
488  header()->adjustHeaderSize();
489 }
490 
491 //-----------------------------------------------------------------------------
492 void KFolderTree::removeTotalColumn()
493 {
494  if ( !isTotalActive() ) return;
495  removeColumn( mTotalIndex );
496  if ( isUnreadActive() && mTotalIndex < mUnreadIndex )
497  mUnreadIndex--;
498  if ( isSizeActive() && mTotalIndex < mSizeIndex )
499  mSizeIndex--;
500  mTotalIndex = -1;
501  header()->adjustHeaderSize();
502 }
503 
504 //-----------------------------------------------------------------------------
505 void KFolderTree::addSizeColumn( const TQString & name, int width )
506 {
507  mSizeIndex = addColumn( name, width );
508  setColumnAlignment( mSizeIndex, tqApp->reverseLayout() ? TQt::AlignLeft : TQt::AlignRight );
509  header()->adjustHeaderSize();
510 }
511 
512 //-----------------------------------------------------------------------------
513 void KFolderTree::removeSizeColumn()
514 {
515  if ( !isSizeActive() ) return;
516  removeColumn( mSizeIndex );
517  if ( isUnreadActive() && mSizeIndex < mUnreadIndex )
518  mUnreadIndex--;
519  if ( isTotalActive() && mSizeIndex < mTotalIndex )
520  mTotalIndex--;
521  mSizeIndex = -1;
522  header()->adjustHeaderSize();
523 }
524 
525 
526 //-----------------------------------------------------------------------------
527 void KFolderTree::setFullWidth( bool fullWidth )
528 {
529  if (fullWidth)
530  header()->setStretchEnabled( true, 0 );
531 }
532 
533 //-----------------------------------------------------------------------------
534 void KFolderTree::slotSizeChanged( int section, int, int newSize )
535 {
536  viewport()->repaint(
537  header()->sectionPos(section), 0, newSize, visibleHeight(), false );
538 }
539 
540 #include "kfoldertree.moc"