You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
601 lines
16 KiB
601 lines
16 KiB
/***************************************************************************
|
|
* 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 <tdeversion.h>
|
|
#include <kstringhandler.h>
|
|
#include <tqimage.h>
|
|
#include <tqpainter.h>
|
|
#include <tqheader.h>
|
|
#include <tdelocale.h>
|
|
#include <kurldrag.h>
|
|
#include <tqapplication.h>
|
|
|
|
|
|
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, TQ_SIGNAL(onItem(TQListViewItem *) ), TQ_SLOT(slotOnItem(TQListViewItem *) ) );
|
|
connect(onItemTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotTimeout()) );
|
|
}
|
|
|
|
|
|
TastyListView::~TastyListView()
|
|
{
|
|
}
|
|
|
|
void TastyListView::startDrag()
|
|
{
|
|
if( !currentItem() )
|
|
return;
|
|
TastyListViewItem *item = dynamic_cast<TastyListViewItem *>(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<TastyListViewItem *>(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<TastyListViewItem *>(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<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 TQt::Key_Up:
|
|
case TQt::Key_Down:
|
|
TDEListView::keyPressEvent( e );
|
|
break;
|
|
|
|
case TQt::Key_Right:
|
|
{
|
|
if(!currentItem())
|
|
return;
|
|
TastyListViewItem *item = dynamic_cast<TastyListViewItem *>(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<TastyListViewItem *>(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<TastyListViewItem *>(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<TastyListViewItem *>(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<TastyListViewItem *>(underCursorItem);
|
|
|
|
if( easyOpen && tastyUnderCursorItem &&
|
|
tastyUnderCursorItem->getType() == TastyListViewItem::ServiceGroup )
|
|
{
|
|
emit(activated(underCursorItem, TQPoint(underCursorItem->listView()->width()/2,1), 0));
|
|
TastyListViewItem *oldOpenItem = dynamic_cast<TastyListViewItem *>(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<TastyListViewItem *>(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<TastyListView *>(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<TastyListView *>( 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 );
|
|
}
|
|
#include "tastylistview.moc"
|
|
|
|
|
|
//EOF
|