/*************************************************************************** * Copyright (C) 2006 by Marco Martin * * notmart@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the Lesser GNU General Public * * License as published by the Free Software Foundation; * * either version 2 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "tastylistview.h" #include "misc.h" #include #include #include #include #include #include #include #include TastyListView::TastyListView( TQWidget * parent, const char * name) : TDEListView(parent, name), highLightGroups(true), easyOpen(true) { onItemTimer = new TQTimer(this, "onItemTimer"); underCursorItem = openItem = NULL; mouseDown = false; actionIconSize = 16; actionIconSpace = 32; listItemTip = new TastyListViewToolTip(viewport(), this); connect(this, SIGNAL(onItem(TQListViewItem *) ), SLOT(slotOnItem(TQListViewItem *) ) ); connect(onItemTimer, SIGNAL(timeout()), this, SLOT(slotTimeout()) ); } TastyListView::~TastyListView() { } void TastyListView::startDrag() { if( !currentItem() ) return; TastyListViewItem *item = dynamic_cast(currentItem()); if( !item ) return; TQDragObject *d = new KURLDrag( KURL(item->getDeskopEntryPath()) , viewport() ); if(!d) return; if (d->drag() && d->target() != viewport()) emit moved(); } void TastyListView::contentsMouseReleaseEvent( TQMouseEvent * e ) { int x = e->x(); if( x > width() || x < 0) return; if( !currentItem() ) return; TastyListViewItem *item = dynamic_cast(currentItem()); if( !item ) return; if( e->button() == RightButton ) emit(contextMenuRequested( currentItem(), e->globalPos(), 0) ); else emit(activated( currentItem(), TQPoint(x, e->y()), 0) ); if(item && (item->getType() == TastyListViewItem::ServiceGroup)) { if( !openItem ) { openItem = currentItem(); return; } TastyListViewItem *oldOpenItem = dynamic_cast(openItem); openItem = currentItem(); if( !oldOpenItem || !oldOpenItem->listView() ) return; oldOpenItem->repaint(); } TDEListView::contentsMouseReleaseEvent(e); } void TastyListView::contentsMouseMoveEvent( TQMouseEvent * e ) { TDEListView::contentsMouseMoveEvent(e); mouseDown = (e->state() & TQt::LeftButton); if( itemAt( contentsToViewport(TQPoint(e->x(), e->y()))) == 0 ) underCursorItem = NULL; } void TastyListView::leaveEvent( TQEvent * e ) { TDEListView::leaveEvent( e ); onItemTimer->stop(); if( openItem ) setCurrentItem( openItem ); } void TastyListView::keyPressEvent( TQKeyEvent * e ) { switch(e->key()) { case TQt::Key_Enter: case TQt::Key_Return: case TQt::Key_Space: { emit(activated(currentItem(), TQPoint(0,0), 0)); if(!currentItem()) return; TastyListViewItem *item = dynamic_cast(currentItem()); if(item && item->getType() == TastyListViewItem::ServiceGroup) { if( !openItem ) { openItem = currentItem(); return; } TastyListViewItem *oldOpenItem = dynamic_cast(openItem); openItem = currentItem(); if( !oldOpenItem || !oldOpenItem->listView() ) return; oldOpenItem->repaint(); } } break; case TQt::Key_Up: case TQt::Key_Down: TDEListView::keyPressEvent( e ); break; case TQt::Key_Right: { if(!currentItem()) return; TastyListViewItem *item = dynamic_cast(currentItem()); if(item && easyOpen && !TQApplication::reverseLayout() && item->getType() == TastyListViewItem::ServiceGroup) { emit( activated( currentItem(), TQPoint(0,0), 0)); if( !openItem ) { openItem = currentItem(); return; } TastyListViewItem *oldOpenItem = dynamic_cast(openItem); openItem = currentItem(); if( !oldOpenItem || !oldOpenItem->listView() ) return; oldOpenItem->repaint(); } focusNextPrevChild(!TQApplication::reverseLayout()); break; } case TQt::Key_Left: { if( !currentItem() ) return; TastyListViewItem *item = dynamic_cast(currentItem()); if(item && easyOpen && TQApplication::reverseLayout() && item->getType() == TastyListViewItem::ServiceGroup) { emit( activated( currentItem(), TQPoint(0,0), 0)); if( !openItem ) { openItem = currentItem(); return; } TastyListViewItem *oldOpenItem = dynamic_cast(openItem); openItem = currentItem(); if( !oldOpenItem || !oldOpenItem->listView() ) return; oldOpenItem->repaint(); } focusNextPrevChild(TQApplication::reverseLayout()); break; } case TQt::Key_Tab: TDEListView::keyPressEvent( e ); break; default: break; } } void TastyListView::slotOnItem( TQListViewItem * listItem ) { if( !listItem || listItem->listView() != this ) return; if( listItem != underCursorItem ) { underCursorItem = listItem; setCurrentItem(listItem); if(mouseDown) onItemTimer->start(250, true); else onItemTimer->start(1000, true); } } void TastyListView::slotTimeout( ) { if( !underCursorItem /*|| !openItem*/ ) return; TastyListViewItem *tastyUnderCursorItem = dynamic_cast(underCursorItem); if( easyOpen && tastyUnderCursorItem && tastyUnderCursorItem->getType() == TastyListViewItem::ServiceGroup ) { emit(activated(underCursorItem, TQPoint(underCursorItem->listView()->width()/2,1), 0)); TastyListViewItem *oldOpenItem = dynamic_cast(openItem); openItem = currentItem(); if( !oldOpenItem || !oldOpenItem->listView() ) return; oldOpenItem->repaint(); } } ///////////TASTYLISTVIEWTOOLTIP TastyListViewToolTip::TastyListViewToolTip( TQWidget *parent, TastyListView *tListView ) : TQToolTip( parent ), listView( tListView ) { } void TastyListViewToolTip::maybeTip( const TQPoint &pos ) { if( !parentWidget() || !listView || !listView->showToolTips() ) return; TastyListViewItem *item = static_cast(listView->itemAt( pos )); TQPoint contentsPos = listView->viewportToContents( pos ); if( !item || !listView->columns() ) return; int actionWidth = 0; TastyListViewItem::ActionType actionType = item->getActionType(); if( actionType != TastyListViewItem::NoAction ) actionWidth = listView->getActionIconSpace(); int column = listView->header()->sectionAt( contentsPos.x() ); TQRect r = listView->itemRect( item ); int headerPos = listView->header()->sectionPos( column ); r.setLeft( headerPos ); r.setRight( headerPos + listView->header()->sectionSize( column ) ); int actionLeft = r.right()-actionWidth; if( pos.x() >= actionLeft ) { r.setLeft( actionLeft ); switch( actionType ) { case TastyListViewItem::AddBookMark: tip( r, i18n( "Add" )+" \""+item->text( column )+"\" "+i18n( "to your favourite applications" ) ); return; case TastyListViewItem::RemoveBookMark: tip( r, i18n( "Remove" )+" \""+item->text( column )+"\" "+i18n( "from your favourite applications" ) ); return; case TastyListViewItem::OpenGroup: tip( r, i18n( "Browse" )+" \""+item->text( column )+"\"" ); return; case TastyListViewItem::Expand: tip( r, i18n( "Expand" )+" \""+item->text( column )+"\"" ); return; case TastyListViewItem::Collapse: tip( r, i18n( "Collapse" )+" \""+item->text( column )+"\"" ); return; default: break; } } else if( actionType == TastyListViewItem::OpenGroup && !item->hasEllipsis() ) { tip( r, i18n( "Browse" )+" \""+item->text( column )+"\"" ); return; } if( !item->hasEllipsis() ) return; tip( r, item->text( column )+"\n"+item->getSubText() ); } ///////////TASTYLISTVIEWITEM TastyListViewItem::TastyListViewItem( TastyListView * parent ) : TDEListViewItem(parent) {commonConstructor();} TastyListViewItem::TastyListViewItem( TastyListViewItem * parent ) : TDEListViewItem(parent) {commonConstructor();} TastyListViewItem::TastyListViewItem( TastyListView * parent, TastyListViewItem * after, TQString label1 ) : TDEListViewItem(parent, after, label1) {commonConstructor();cellText = label1;} TastyListViewItem::TastyListViewItem( TastyListViewItem * parent, TastyListViewItem * after, TQString label1 ) : TDEListViewItem(parent, after, label1) {commonConstructor();cellText = label1;} TastyListViewItem::TastyListViewItem( TastyListView * parent, TQString label1 ) : TDEListViewItem(parent, label1) {commonConstructor();cellText = label1;} TastyListViewItem::TastyListViewItem( TastyListViewItem * parent, TQString label1 ) : TDEListViewItem(parent, label1) {commonConstructor();cellText = label1;} TastyListViewItem::~TastyListViewItem() { } void TastyListViewItem::commonConstructor() { subText="";cellText=""; actionType = NoAction; actionPix = TQPixmap(); menuId = TQString(); desktopEntryPath = TQString(); path = TQString(); ellipsis = false; highLight = false; displaySubText = true; } void TastyListViewItem::loadPixmap() { TQString iconFile = ""; iconLoader = TDEGlobal::iconLoader(); if( !listView() ) return; TastyListView *lv = dynamic_cast(listView()); if( !lv ) return; switch( actionType ) { case AddBookMark: actionPix = iconLoader->loadIcon("bookmark_add", TDEIcon::Small, lv->getActionIconSize()); break; case RemoveBookMark: actionPix = iconLoader->loadIcon("remove", TDEIcon::Small, lv->getActionIconSize()); break; case OpenGroup: if( TQApplication::reverseLayout() ) actionPix = iconLoader->loadIcon("1leftarrow", TDEIcon::Small, lv->getActionIconSize()); else actionPix = iconLoader->loadIcon("1rightarrow", TDEIcon::Small, lv->getActionIconSize()); break; case Expand: actionPix = iconLoader->loadIcon("1downarrow", TDEIcon::Small, lv->getActionIconSize()); break; case Collapse: actionPix = iconLoader->loadIcon("1uparrow", TDEIcon::Small, lv->getActionIconSize()); break; default: return; } if ( actionPix.height () > lv->getActionIconSize()) { TQImage img = actionPix.convertToImage(); if( !img.isNull() ) { img = img.smoothScale ( lv->getActionIconSize(), lv->getActionIconSize()); actionPix = TQPixmap (img); } } } TQString TastyListViewItem::key( int column, bool ascending ) const { ascending = ascending; TQString prefix; //ensure all the categories are before the leaf items if( itemType == ServiceGroup ) prefix = "0"; else prefix = "1"; return prefix.append(text( column )); } void TastyListViewItem::setup ( ) { //TDEListViewItem::setup(); //calculate listitem height TQFontMetrics fm( listView()->font() ); int pixmapHeight = 5; if( pixmap(0) ) pixmapHeight = pixmap(0)->height()+4; if( displaySubText && !subText.isEmpty() ) { int textHeight = (int)(fm.height()*2.5); setHeight( (pixmapHeight > textHeight) ? pixmapHeight : textHeight ); } else setHeight( pixmapHeight ); } /*Adapted from Amarok's Statistic listView Copyright (c) 2006 Seb Ruiz*/ void TastyListViewItem::paintCell ( TQPainter * p, const TQColorGroup & cg, int column, int width, int align ) { int textHeight = height(); TQString name = cellText; int textX = 0; TQColor fillColor, textColor; # if TDE_VERSION < TDE_MAKE_VERSION(3,3,91) # define BackgroundColor backgroundColor() # else # define BackgroundColor backgroundColor(0) # endif fillColor = isSelected() ? cg.highlight() : BackgroundColor; textColor = isSelected() ? cg.highlightedText() : cg.text(); if( !listView() ) return; TastyListView *lv = dynamic_cast( listView() ); if( !lv ) return; TQFont font( lv->font() ); if( !isSelected() && (lv->getOpenItem() == this|| (lv->getHighLightGroups() && itemType == ServiceGroup)) ) fillColor = alphaBlendColors( fillColor, cg.highlight(), 200); else if( !isSelected() && highLight ) { int hue, saturation, value; cg.highlight().getHsv(&hue, &saturation, &value); //calculate the inverse color 128 means rotating the spectral value by 180 degrees fillColor.setHsv( (hue+128)%256, saturation/2, value ); } else if( isSelected() && !lv->hasFocus() ) fillColor = alphaBlendColors( fillColor, BackgroundColor, 150); TQFontMetrics fm( font ); widthChanged(column); TQPixmap buffer(width*2, textHeight); if( buffer.isNull() ) return; buffer.fill( fillColor ); TQPainter pBuf(&buffer); if( pixmap( column ) ) { int y = (textHeight - pixmap(column)->height())/2; pBuf.drawPixmap( 0, y, *pixmap(column) ); textX += pixmap(column)->width() + 4; } //Calculate the ellipsis for the MAIN text int extraSpace = fm.width("...") + textX + lv->getActionIconSpace(); ellipsis = false; while( (fm.width(name)+extraSpace) > width && name.length() > 4) { name.truncate(name.length()-1); ellipsis = true; } if( ellipsis ) name.append("..."); if( name == "separator" ) { int y = textHeight/2; pBuf.setPen(cg.background().dark(140)); pBuf.drawLine(textX, y, width, y); pBuf.setPen(textColor); pBuf.end(); p->drawPixmap( 0, 0, buffer ); return; } if( fm.width( name ) + textX + lv->itemMargin()*2 > width ) { const int _width = width - textX - lv->itemMargin()*2; name = KStringHandler::rPixelSqueeze( name, pBuf.fontMetrics(), _width ); } pBuf.setPen(textColor); pBuf.drawText( textX, 3, width, textHeight, AlignTop, name ); if( displaySubText && !subText.isEmpty() ) { font.setPointSize( max((int)(font.pointSize()/1.2), 7) ); pBuf.setFont( font ); TQString subTextCopy = subText; TQFontMetrics sfm( font ); //Calculate the ellipsis for the subtext int extraSpace = fm.width("...") + textX + lv->getActionIconSpace(); bool ellipsisSubText = false; while( (sfm.width(subTextCopy)+extraSpace) > width && subTextCopy.length() > 4) { subTextCopy.truncate(subTextCopy.length()-1); ellipsisSubText = true; } if( ellipsisSubText ) { subTextCopy.append("..."); ellipsis = true; } pBuf.setPen(cg.background().dark(140)); pBuf.drawLine(textX, fm.height() + 3, width-textX-5, fm.height() + 3); pBuf.setPen(textColor.light(130)); pBuf.drawText( textX, fm.height() + 4, width, fm.height(), AlignTop, subTextCopy ); } if( !actionPix.isNull() && (actionType == OpenGroup || actionType == Expand || actionType == Collapse || lv->currentItem() == this) ) { int y = (textHeight - actionPix.height())/2; pBuf.drawPixmap( width-(actionPix.width()+5), y, actionPix ); } pBuf.end(); p->drawPixmap( 0, 0, buffer ); } //EOF