// -*- c-basic-offset: 2 -*- #include "kfoldertree.h" #include #include #include #include #include #include #include #include #include //----------------------------------------------------------------------------- KFolderTreeItem::KFolderTreeItem( KFolderTree *parent, const TQString & label, Protocol protocol, Type type ) : KListViewItem( parent, label ), mProtocol( protocol ), mType( type ), mUnread(-1), mTotal(0), mSize(0), mFolderIsCloseToQuota( false ) { } //----------------------------------------------------------------------------- KFolderTreeItem::KFolderTreeItem( KFolderTreeItem *parent, const TQString & label, Protocol protocol, Type type, int unread, int total ) : KListViewItem( parent, label ), mProtocol( protocol ), mType( type ), mUnread( unread ), mTotal( total ), mSize(0), mFolderIsCloseToQuota( false ) { } //----------------------------------------------------------------------------- int KFolderTreeItem::protocolSortingKey() const { // protocol dependant sorting order: // local < imap < news < search < other switch ( mProtocol ) { case Local: return 1; case CachedImap: case Imap: return 2; case News: return 3; case Search: return 4; default: return 42; } } //----------------------------------------------------------------------------- int KFolderTreeItem::typeSortingKey() const { // type dependant sorting order: // inbox < outbox < sent-mail < trash < drafts // < calendar < contacts < notes < tasks // < normal folders switch ( mType ) { case Inbox: return 1; case Outbox: return 2; case SentMail: return 3; case Trash: return 4; case Drafts: return 5; case Templates: return 6; case Calendar: return 7; case Contacts: return 8; case Notes: return 9; case Tasks: return 10; default: return 42; } } //----------------------------------------------------------------------------- int KFolderTreeItem::compare( TQListViewItem * i, int col, bool ) const { KFolderTreeItem* other = static_cast( i ); if (col == 0) { // sort by folder // local root-folder if ( depth() == 0 && mProtocol == NONE ) return -1; if ( other->depth() == 0 && other->protocol() == NONE ) return 1; // first compare by protocol int thisKey = protocolSortingKey(); int thatKey = other->protocolSortingKey(); if ( thisKey < thatKey ) return -1; if ( thisKey > thatKey ) return 1; // then compare by type thisKey = typeSortingKey(); thatKey = other->typeSortingKey(); if ( thisKey < thatKey ) return -1; if ( thisKey > thatKey ) return 1; // and finally compare by name return text( 0 ).localeAwareCompare( other->text( 0 ) ); } else { // sort by unread or total-column TQ_INT64 a = 0, b = 0; if (col == static_cast(listView())->unreadIndex()) { a = mUnread; b = other->unreadCount(); } else if (col == static_cast(listView())->totalIndex()) { a = mTotal; b = other->totalCount(); } else if (col == static_cast(listView())->sizeIndex()) { a = mSize; b = other->folderSize(); } if ( a == b ) return 0; else return (a < b ? -1 : 1); } } //----------------------------------------------------------------------------- void KFolderTreeItem::setUnreadCount( int aUnread ) { if ( aUnread < 0 ) return; mUnread = aUnread; TQString unread = TQString(); if (mUnread == 0) unread = "- "; else { unread.setNum(mUnread); unread += " "; } setText( static_cast(listView())->unreadIndex(), unread ); } //----------------------------------------------------------------------------- void KFolderTreeItem::setTotalCount( int aTotal ) { if ( aTotal < 0 ) return; mTotal = aTotal; TQString total = TQString(); if (mTotal == 0) total = "- "; else { total.setNum(mTotal); total += " "; } setText( static_cast(listView())->totalIndex(), total ); } //----------------------------------------------------------------------------- void KFolderTreeItem::setFolderSize( TQ_INT64 aSize ) { if ( aSize < 0 ) return; // we need to update even if nothing changed, kids ... mSize = aSize; TQString size; if (mType != Root) { if (mSize == 0 && (childCount() == 0 || isOpen() ) ) size = "- "; else size = KIO::convertSize(mSize); } if ( childCount() > 0 && !isOpen() ) { TQ_INT64 recursiveSize = recursiveFolderSize(); if ( recursiveSize != mSize ) { if ( mType != Root ) size += TQString::fromLatin1(" + %1").arg( KIO::convertSize( recursiveSize - mSize ) ); else size = KIO::convertSize( recursiveSize ); } } size += " "; setText( static_cast(listView())->sizeIndex(), size ); } //----------------------------------------------------------------------------- TQ_INT64 KFolderTreeItem::recursiveFolderSize() const { TQ_INT64 size = mSize; for ( TQListViewItem *item = firstChild() ; item ; item = item->nextSibling() ) { size += static_cast(item)->recursiveFolderSize(); } return size; } //----------------------------------------------------------------------------- int KFolderTreeItem::countUnreadRecursive() { int count = (mUnread > 0) ? mUnread : 0; for ( TQListViewItem *item = firstChild() ; item ; item = item->nextSibling() ) { count += static_cast(item)->countUnreadRecursive(); } return count; } //----------------------------------------------------------------------------- void KFolderTreeItem::paintCell( TQPainter * p, const TQColorGroup & cg, int column, int width, int align ) { KFolderTree *ft = static_cast(listView()); const int unreadRecursiveCount = countUnreadRecursive(); const int unreadCount = ( mUnread > 0 ) ? mUnread : 0; // use a special color for folders which are close to their quota TQColorGroup mycg = cg; if ( ( column == 0 || column == ft->sizeIndex() ) && folderIsCloseToQuota() ) { mycg.setColor( TQColorGroup::Text, ft->paintInfo().colCloseToQuota ); } // use a bold-font for the folder- and the unread-columns if ( (column == 0 || column == ft->unreadIndex()) && ( unreadCount > 0 || ( !isOpen() && unreadRecursiveCount > 0 ) ) ) { TQFont f = p->font(); f.setWeight(TQFont::Bold); p->setFont(f); } // most cells can be handled by KListView::paintCell, we only need to // deal with the folder column if the unread column is not shown /* The below is exceedingly silly, but Ingo insists that the unread * count that is shown in parenthesis after the folder name must * be configurable in color. That means that paintCell needs to do * two painting passes which flickers. Since that flicker is not * needed when there is the unread column, special case that. */ if ( ft->isUnreadActive() || column != 0 ) { KListViewItem::paintCell( p, mycg, column, width, align ); } else { TQListView *lv = listView(); TQString oldText = text(column); // set an empty text so that we can have our own implementation (see further down) // but still benefit from KListView::paintCell setText( column, "" ); KListViewItem::paintCell( p, mycg, column, width, align ); const TQPixmap *icon = pixmap( column ); int marg = lv ? lv->itemMargin() : 1; int r = marg; setText( column, oldText ); if ( isSelected() ) p->setPen( mycg.highlightedText() ); else p->setPen( mycg.color( TQColorGroup::Text ) ); if ( icon ) { r += icon->width() + marg; } TQString t = text( column ); if (t.isEmpty()) return; // draw the unread-count if the unread-column is not active TQString unread; if ( unreadCount > 0 || ( !isOpen() && unreadRecursiveCount > 0 ) ) { if ( isOpen() ) unread = " (" + TQString::number( unreadCount ) + ")"; else if ( unreadRecursiveCount == unreadCount || mType == Root ) unread = " (" + TQString::number( unreadRecursiveCount ) + ")"; else unread = " (" + TQString::number( unreadCount ) + " + " + TQString::number( unreadRecursiveCount-unreadCount ) + ")"; } // check if the text needs to be squeezed TQFontMetrics fm( p->fontMetrics() ); int unreadWidth = fm.width( unread ); if ( fm.width( t ) + marg + r + unreadWidth > width ) t = squeezeFolderName( t, fm, width - marg - r - unreadWidth ); TQRect br; p->drawText( r, 0, width-marg-r, height(), align | AlignVCenter, t, -1, &br ); if ( !unread.isEmpty() ) { if (!isSelected()) p->setPen( ft->paintInfo().colUnread ); p->drawText( br.right(), 0, width-marg-br.right(), height(), align | AlignVCenter, unread ); } } } TQString KFolderTreeItem::squeezeFolderName( const TQString &text, const TQFontMetrics &fm, uint width ) const { return KStringHandler::rPixelSqueeze( text, fm, width ); } bool KFolderTreeItem::folderIsCloseToQuota() const { return mFolderIsCloseToQuota; } void KFolderTreeItem::setFolderIsCloseToQuota( bool v ) { if ( mFolderIsCloseToQuota != v) { mFolderIsCloseToQuota = v; repaint(); } } //============================================================================= KFolderTree::KFolderTree( TQWidget *parent, const char* name ) : KListView( parent, name ), mUnreadIndex(-1), mTotalIndex(-1), mSizeIndex(-1) { // GUI-options setStyleDependantFrameWidth(); setAcceptDrops(true); setDropVisualizer(false); setAllColumnsShowFocus(true); setShowSortIndicator(true); setUpdatesEnabled(true); setItemsRenameable(false); setRootIsDecorated(true); setSelectionModeExt(Extended); setAlternateBackground(TQColor()); #if KDE_IS_VERSION( 3, 3, 90 ) setShadeSortColumn ( false ); #endif setFullWidth(true); disableAutoSelection(); setColumnWidth( 0, 120 ); //reasonable default size disconnect( header(), TQT_SIGNAL( sizeChange( int, int, int ) ) ); connect( header(), TQT_SIGNAL( sizeChange( int, int, int ) ), TQT_SLOT( slotSizeChanged( int, int, int ) ) ); } //----------------------------------------------------------------------------- void KFolderTree::setStyleDependantFrameWidth() { // set the width of the frame to a reasonable value for the current GUI style int frameWidth; if( style().isA("KeramikStyle") ) frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth ) - 1; else frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth ); if ( frameWidth < 0 ) frameWidth = 0; if ( frameWidth != lineWidth() ) setLineWidth( frameWidth ); } //----------------------------------------------------------------------------- void KFolderTree::styleChange( TQStyle& oldStyle ) { setStyleDependantFrameWidth(); KListView::styleChange( oldStyle ); } //----------------------------------------------------------------------------- void KFolderTree::drawContentsOffset( TQPainter * p, int ox, int oy, int cx, int cy, int cw, int ch ) { bool oldUpdatesEnabled = isUpdatesEnabled(); setUpdatesEnabled(false); KListView::drawContentsOffset( p, ox, oy, cx, cy, cw, ch ); setUpdatesEnabled(oldUpdatesEnabled); } //----------------------------------------------------------------------------- void KFolderTree::contentsMousePressEvent( TQMouseEvent *e ) { setSelectionModeExt(Single); KListView::contentsMousePressEvent(e); } //----------------------------------------------------------------------------- void KFolderTree::contentsMouseReleaseEvent( TQMouseEvent *e ) { KListView::contentsMouseReleaseEvent(e); setSelectionModeExt(Extended); } //----------------------------------------------------------------------------- void KFolderTree::addAcceptableDropMimetype( const char *mimeType, bool outsideOk ) { int oldSize = mAcceptableDropMimetypes.size(); mAcceptableDropMimetypes.resize(oldSize+1); mAcceptOutside.resize(oldSize+1); mAcceptableDropMimetypes.at(oldSize) = mimeType; mAcceptOutside.setBit(oldSize, outsideOk); } //----------------------------------------------------------------------------- bool KFolderTree::acceptDrag( TQDropEvent* event ) const { TQListViewItem* item = itemAt(contentsToViewport(event->pos())); for (uint i = 0; i < mAcceptableDropMimetypes.size(); i++) { if (event->provides(mAcceptableDropMimetypes[i])) { if (item) return (static_cast(item))->acceptDrag(event); else return mAcceptOutside[i]; } } return false; } //----------------------------------------------------------------------------- void KFolderTree::addUnreadColumn( const TQString & name, int width ) { mUnreadIndex = addColumn( name, width ); setColumnAlignment( mUnreadIndex, tqApp->reverseLayout() ? TQt::AlignLeft : TQt::AlignRight ); header()->adjustHeaderSize(); } //----------------------------------------------------------------------------- void KFolderTree::addTotalColumn( const TQString & name, int width ) { mTotalIndex = addColumn( name, width ); setColumnAlignment( mTotalIndex, tqApp->reverseLayout() ? TQt::AlignLeft : TQt::AlignRight ); header()->adjustHeaderSize(); } //----------------------------------------------------------------------------- void KFolderTree::removeUnreadColumn() { if ( !isUnreadActive() ) return; removeColumn( mUnreadIndex ); if ( isTotalActive() && mTotalIndex > mUnreadIndex ) mTotalIndex--; if ( isSizeActive() && mSizeIndex > mUnreadIndex ) mSizeIndex--; mUnreadIndex = -1; header()->adjustHeaderSize(); } //----------------------------------------------------------------------------- void KFolderTree::removeTotalColumn() { if ( !isTotalActive() ) return; removeColumn( mTotalIndex ); if ( isUnreadActive() && mTotalIndex < mUnreadIndex ) mUnreadIndex--; if ( isSizeActive() && mTotalIndex < mSizeIndex ) mSizeIndex--; mTotalIndex = -1; header()->adjustHeaderSize(); } //----------------------------------------------------------------------------- void KFolderTree::addSizeColumn( const TQString & name, int width ) { mSizeIndex = addColumn( name, width ); setColumnAlignment( mSizeIndex, tqApp->reverseLayout() ? TQt::AlignLeft : TQt::AlignRight ); header()->adjustHeaderSize(); } //----------------------------------------------------------------------------- void KFolderTree::removeSizeColumn() { if ( !isSizeActive() ) return; removeColumn( mSizeIndex ); if ( isUnreadActive() && mSizeIndex < mUnreadIndex ) mUnreadIndex--; if ( isTotalActive() && mSizeIndex < mTotalIndex ) mTotalIndex--; mSizeIndex = -1; header()->adjustHeaderSize(); } //----------------------------------------------------------------------------- void KFolderTree::setFullWidth( bool fullWidth ) { if (fullWidth) header()->setStretchEnabled( true, 0 ); } //----------------------------------------------------------------------------- void KFolderTree::slotSizeChanged( int section, int, int newSize ) { viewport()->repaint( header()->sectionPos(section), 0, newSize, visibleHeight(), false ); } #include "kfoldertree.moc"