diff options
Diffstat (limited to 'src/tastylistview.cpp')
-rw-r--r-- | src/tastylistview.cpp | 600 |
1 files changed, 600 insertions, 0 deletions
diff --git a/src/tastylistview.cpp b/src/tastylistview.cpp new file mode 100644 index 0000000..ed5e2a7 --- /dev/null +++ b/src/tastylistview.cpp @@ -0,0 +1,600 @@ +/*************************************************************************** + * 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 <kdeversion.h> +#include <kstringhandler.h> +#include <qimage.h> +#include <qpainter.h> +#include <qheader.h> +#include <klocale.h> +#include <kurldrag.h> +#include <qapplication.h> + + +TastyListView::TastyListView( QWidget * parent, const char * name) + : KListView(parent, name), highLightGroups(true), easyOpen(true) +{ + + onItemTimer = new QTimer(this, "onItemTimer"); + underCursorItem = openItem = NULL; + mouseDown = false; + actionIconSize = 16; + actionIconSpace = 32; + + listItemTip = new TastyListViewToolTip(viewport(), this); + + connect(this, SIGNAL(onItem(QListViewItem *) ), SLOT(slotOnItem(QListViewItem *) ) ); + connect(onItemTimer, SIGNAL(timeout()), this, SLOT(slotTimeout()) ); +} + + +TastyListView::~TastyListView() +{ +} + +void TastyListView::startDrag() +{ + if( !currentItem() ) + return; + TastyListViewItem *item = dynamic_cast<TastyListViewItem *>(currentItem()); + if( !item ) + return; + + QDragObject *d = new KURLDrag( KURL(item->getDeskopEntryPath()) , viewport() ); + if(!d) + return; + + if (d->drag() && d->target() != viewport()) + emit moved(); +} + +void TastyListView::contentsMouseReleaseEvent( QMouseEvent * e ) +{ + int x = e->x(); + if( x > width() || x < 0) + return; + + if( !currentItem() ) + return; + TastyListViewItem *item = dynamic_cast<TastyListViewItem *>(currentItem()); + if( !item ) + return; + + if( e->button() == RightButton ) + emit(contextMenuRequested( currentItem(), e->globalPos(), 0) ); + else + emit(activated( currentItem(), QPoint(x, e->y()), 0) ); + + if(item && (item->getType() == TastyListViewItem::ServiceGroup)) + { + if( !openItem ) + { + openItem = currentItem(); + return; + } + + TastyListViewItem *oldOpenItem = dynamic_cast<TastyListViewItem *>(openItem); + openItem = currentItem(); + if( !oldOpenItem || !oldOpenItem->listView() ) + return; + + oldOpenItem->repaint(); + } + KListView::contentsMouseReleaseEvent(e); +} + +void TastyListView::contentsMouseMoveEvent( QMouseEvent * e ) +{ + KListView::contentsMouseMoveEvent(e); + mouseDown = (e->state() & Qt::LeftButton); + + if( itemAt( contentsToViewport(QPoint(e->x(), e->y()))) == 0 ) + underCursorItem = NULL; +} + +void TastyListView::leaveEvent( QEvent * e ) +{ + KListView::leaveEvent( e ); + onItemTimer->stop(); + if( openItem ) + setCurrentItem( openItem ); +} + + +void TastyListView::keyPressEvent( QKeyEvent * e ) +{ + + switch(e->key()) + { + case Qt::Key_Enter: + case Qt::Key_Return: + case Qt::Key_Space: + { + emit(activated(currentItem(), QPoint(0,0), 0)); + if(!currentItem()) + return; + TastyListViewItem *item = dynamic_cast<TastyListViewItem *>(currentItem()); + if(item && item->getType() == TastyListViewItem::ServiceGroup) + { + if( !openItem ) + { + openItem = currentItem(); + return; + } + TastyListViewItem *oldOpenItem = dynamic_cast<TastyListViewItem *>(openItem); + openItem = currentItem(); + if( !oldOpenItem || !oldOpenItem->listView() ) + return; + + oldOpenItem->repaint(); + } + } + break; + + case Qt::Key_Up: + case Qt::Key_Down: + KListView::keyPressEvent( e ); + break; + + case Qt::Key_Right: + { + if(!currentItem()) + return; + TastyListViewItem *item = dynamic_cast<TastyListViewItem *>(currentItem()); + if(item && easyOpen && !QApplication::reverseLayout() && item->getType() == TastyListViewItem::ServiceGroup) + { + emit( activated( currentItem(), QPoint(0,0), 0)); + if( !openItem ) + { + openItem = currentItem(); + return; + } + TastyListViewItem *oldOpenItem = dynamic_cast<TastyListViewItem *>(openItem); + openItem = currentItem(); + if( !oldOpenItem || !oldOpenItem->listView() ) + return; + + oldOpenItem->repaint(); + } + focusNextPrevChild(!QApplication::reverseLayout()); + break; + } + case Qt::Key_Left: + { + if( !currentItem() ) + return; + TastyListViewItem *item = dynamic_cast<TastyListViewItem *>(currentItem()); + if(item && easyOpen && QApplication::reverseLayout() && item->getType() == TastyListViewItem::ServiceGroup) + { + emit( activated( currentItem(), QPoint(0,0), 0)); + if( !openItem ) + { + openItem = currentItem(); + return; + } + TastyListViewItem *oldOpenItem = dynamic_cast<TastyListViewItem *>(openItem); + openItem = currentItem(); + if( !oldOpenItem || !oldOpenItem->listView() ) + return; + + oldOpenItem->repaint(); + } + focusNextPrevChild(QApplication::reverseLayout()); + break; + } + case Qt::Key_Tab: + KListView::keyPressEvent( e ); + break; + + default: + break; + } +} + + +void TastyListView::slotOnItem( QListViewItem * 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<TastyListViewItem *>(underCursorItem); + + if( easyOpen && tastyUnderCursorItem && + tastyUnderCursorItem->getType() == TastyListViewItem::ServiceGroup ) + { + emit(activated(underCursorItem, QPoint(underCursorItem->listView()->width()/2,1), 0)); + TastyListViewItem *oldOpenItem = dynamic_cast<TastyListViewItem *>(openItem); + openItem = currentItem(); + if( !oldOpenItem || !oldOpenItem->listView() ) + return; + + oldOpenItem->repaint(); + } +} + +///////////TASTYLISTVIEWTOOLTIP +TastyListViewToolTip::TastyListViewToolTip( QWidget *parent, TastyListView *tListView ) + : QToolTip( parent ), listView( tListView ) +{ +} + +void TastyListViewToolTip::maybeTip( const QPoint &pos ) +{ + if( !parentWidget() || !listView || !listView->showToolTips() ) + return; + + TastyListViewItem *item = static_cast<TastyListViewItem *>(listView->itemAt( pos )); + QPoint 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() ); + + + QRect 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 ) + : KListViewItem(parent) +{commonConstructor();} + +TastyListViewItem::TastyListViewItem( TastyListViewItem * parent ) + : KListViewItem(parent) +{commonConstructor();} + +TastyListViewItem::TastyListViewItem( TastyListView * parent, TastyListViewItem * after, QString label1 ) + : KListViewItem(parent, after, label1) +{commonConstructor();cellText = label1;} + +TastyListViewItem::TastyListViewItem( TastyListViewItem * parent, TastyListViewItem * after, QString label1 ) + : KListViewItem(parent, after, label1) +{commonConstructor();cellText = label1;} + +TastyListViewItem::TastyListViewItem( TastyListView * parent, QString label1 ) + : KListViewItem(parent, label1) +{commonConstructor();cellText = label1;} + +TastyListViewItem::TastyListViewItem( TastyListViewItem * parent, QString label1 ) + : KListViewItem(parent, label1) +{commonConstructor();cellText = label1;} + +TastyListViewItem::~TastyListViewItem() +{ +} + +void TastyListViewItem::commonConstructor() +{ + + subText="";cellText=""; + + actionType = NoAction; + + actionPix = QPixmap(); + + menuId = QString(); + desktopEntryPath = QString(); + path = QString(); + + ellipsis = false; + highLight = false; + displaySubText = true; + +} + +void TastyListViewItem::loadPixmap() +{ + QString iconFile = ""; + iconLoader = KGlobal::iconLoader(); + + if( !listView() ) + return; + + TastyListView *lv = dynamic_cast<TastyListView *>(listView()); + if( !lv ) + return; + + switch( actionType ) + { + case AddBookMark: + actionPix = iconLoader->loadIcon("bookmark_add", KIcon::Small, lv->getActionIconSize()); + break; + + case RemoveBookMark: + actionPix = iconLoader->loadIcon("remove", KIcon::Small, lv->getActionIconSize()); + break; + + case OpenGroup: + if( QApplication::reverseLayout() ) + actionPix = iconLoader->loadIcon("1leftarrow", KIcon::Small, lv->getActionIconSize()); + else + actionPix = iconLoader->loadIcon("1rightarrow", KIcon::Small, lv->getActionIconSize()); + break; + + case Expand: + actionPix = iconLoader->loadIcon("1downarrow", KIcon::Small, lv->getActionIconSize()); + break; + + case Collapse: + actionPix = iconLoader->loadIcon("1uparrow", KIcon::Small, lv->getActionIconSize()); + break; + + default: + return; + } + + + if ( actionPix.height () > lv->getActionIconSize()) + { + QImage img = actionPix.convertToImage(); + if( !img.isNull() ) + { + img = img.smoothScale ( lv->getActionIconSize(), lv->getActionIconSize()); + actionPix = QPixmap (img); + } + } +} + +QString TastyListViewItem::key( int column, bool ascending ) const +{ + ascending = ascending; + QString 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 ( ) +{ + //KListViewItem::setup(); + + //calculate listitem height + QFontMetrics 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 ( QPainter * p, const QColorGroup & cg, int column, int width, int align ) +{ + int textHeight = height(); + QString name = cellText; + + int textX = 0; + + QColor fillColor, textColor; + +# if KDE_VERSION < KDE_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<TastyListView *>( listView() ); + if( !lv ) + return; + + QFont 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); + + QFontMetrics fm( font ); + widthChanged(column); + + QPixmap buffer(width*2, textHeight); + + if( buffer.isNull() ) + return; + + buffer.fill( fillColor ); + + QPainter 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 ); + + QString subTextCopy = subText; + QFontMetrics 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 |