summaryrefslogtreecommitdiffstats
path: root/src/tastylistview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tastylistview.cpp')
-rw-r--r--src/tastylistview.cpp600
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 *
+ * *
+ * 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