summaryrefslogtreecommitdiffstats
path: root/chalk/ui/layerlist.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chalk/ui/layerlist.cpp')
-rw-r--r--chalk/ui/layerlist.cpp1325
1 files changed, 1325 insertions, 0 deletions
diff --git a/chalk/ui/layerlist.cpp b/chalk/ui/layerlist.cpp
new file mode 100644
index 00000000..976ec84d
--- /dev/null
+++ b/chalk/ui/layerlist.cpp
@@ -0,0 +1,1325 @@
+/*
+ Copyright (c) 2005 Gábor Lehel <illissius@gmail.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#include "layerlist.h"
+
+#include <tqtooltip.h>
+#include <tqbitmap.h>
+#include <tqcursor.h>
+#include <tqimage.h>
+#include <tqheader.h>
+#include <tqpainter.h>
+#include <tqpixmap.h>
+#include <tqsimplerichtext.h>
+#include <tqtimer.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kpopupmenu.h>
+#include <kstringhandler.h>
+
+class LayerItemIterator: public TQListViewItemIterator
+{
+public:
+ LayerItemIterator( LayerList *list ): TQListViewItemIterator( list ) { }
+ LayerItemIterator( LayerList *list, IteratorFlag flags ): TQListViewItemIterator( list, flags ) { }
+ LayerItemIterator( LayerItem *item ): TQListViewItemIterator( item ) { }
+ LayerItemIterator( LayerItem *item, IteratorFlag flags ): TQListViewItemIterator( item, flags ) { }
+ LayerItem *operator*() { return static_cast<LayerItem*>( TQListViewItemIterator::operator*() ); }
+};
+
+struct LayerProperty
+{
+ TQString name;
+ TQString displayName;
+ TQPixmap enabledIcon;
+ TQPixmap disabledIcon;
+ bool defaultValue;
+ bool validForFolders;
+
+ LayerProperty(): defaultValue( false ), validForFolders( true ) { }
+ LayerProperty( const TQString &pname, const TQString &pdisplayName, const TQPixmap &enabled, const TQPixmap &disabled,
+ bool pdefaultValue, bool pvalidForFolders )
+ : name( pname ),
+ displayName( pdisplayName ),
+ enabledIcon( enabled ),
+ disabledIcon( disabled ),
+ defaultValue( pdefaultValue ),
+ validForFolders( pvalidForFolders )
+ { }
+};
+
+class LayerToolTip;
+class LayerList::Private
+{
+public:
+ LayerItem *activeLayer;
+ bool foldersCanBeActive;
+ bool previewsShown;
+ int itemHeight;
+ TQValueList<LayerProperty> properties;
+ KPopupMenu contextMenu;
+ LayerToolTip *tooltip;
+
+ Private( TQWidget *tqparent, LayerList *list );
+ ~Private();
+};
+
+class LayerItem::Private
+{
+public:
+ bool isFolder;
+ int id;
+ TQValueList<bool> properties;
+ TQImage *previewImage;
+ bool previewChanged;
+ TQPixmap scaledPreview;
+ TQSize previewSize;
+ TQPoint previewOffset;
+
+ Private( int pid ): isFolder( false ), id( pid ), previewImage( 0 ), previewChanged( false )
+ { }
+};
+
+static const int MAX_SIZE = 256;
+class LayerToolTip: public TQToolTip, public TQFrame
+{
+ LayerList *m_list;
+ LayerItem *m_item;
+ TQPoint m_pos;
+ TQTimer m_timer;
+ TQImage m_img;
+
+public:
+ LayerToolTip( TQWidget *tqparent, LayerList *list )
+ : TQToolTip( tqparent ),
+ TQFrame( 0, 0, WStyle_Customize | WStyle_NoBorder | WStyle_Tool | WStyle_StaysOnTop | WX11BypassWM | WNoAutoErase ),
+ m_list( list )
+ {
+ TQFrame::setPalette( TQToolTip::palette() );
+ connect( &m_timer, TQT_SIGNAL( timeout() ), m_list, TQT_SLOT( hideTip() ) );
+ tqApp->installEventFilter( this );
+ }
+
+ virtual void maybeTip( const TQPoint &pos )
+ {
+ m_pos = pos;
+ LayerItem *prev = m_item;
+ m_item = static_cast<LayerItem*>(m_list->itemAt( m_pos ));
+ if( TQToolTip::tqparentWidget() && m_list->showToolTips() && m_item )
+ {
+ if( m_item != prev )
+ hideTip();
+ showTip();
+ }
+ else
+ hideTip();
+ }
+
+ void showTip()
+ {
+ m_img = m_item->tooltipPreview();
+ m_timer.start( 15000, true );
+ if( !isVisible() || tqsizeHint() != size() )
+ {
+ resize( tqsizeHint() );
+ position();
+ }
+ if( !isVisible() )
+ show();
+ else
+ update();
+ }
+
+ void hideTip()
+ {
+ if( !isVisible() )
+ return;
+ TQFrame::hide();
+ TQToolTip::hide();
+ m_timer.stop();
+ m_img.reset();
+ m_list->triggerUpdate();
+ }
+
+ virtual void drawContents( TQPainter *painter )
+ {
+ TQPixmap buf( width(), height() );
+ TQPainter p( &buf );
+ buf.fill( tqcolorGroup().background() );
+ p.setPen( tqcolorGroup().foreground() );
+ p.drawRect( buf.rect() );
+
+ TQSimpleRichText text( m_item->tooltip(), TQToolTip::font() );
+ text.setWidth( TQCOORD_MAX );
+
+ p.translate( 5, 5 );
+ if( !m_img.isNull() )
+ {
+ if( m_img.width() > MAX_SIZE || m_img.height() > MAX_SIZE )
+ m_img = m_img.scale( MAX_SIZE, MAX_SIZE, TQ_ScaleMin );
+ int y = 0;
+ if( m_img.height() < text.height() )
+ y = text.height()/2 - m_img.height()/2;
+ p.drawImage( 0, y, m_img );
+ p.drawRect( -1, y-1, m_img.width()+2, m_img.height()+2 );
+ p.translate( m_img.width() + 10, 0 );
+ }
+
+ text.draw( &p, 0, 0, rect(), tqcolorGroup() );
+
+ painter->drawPixmap( 0, 0, buf );
+ }
+
+ virtual TQSize tqsizeHint() const
+ {
+ if( !m_item )
+ return TQSize( 0, 0 );
+
+ TQSimpleRichText text( m_item->tooltip(), TQToolTip::font() );
+ text.setWidth( TQCOORD_MAX );
+
+ int width = text.widthUsed();
+ if( !m_img.isNull() )
+ width += kMin( m_img.width(), MAX_SIZE ) + 10;
+ width += 10;
+
+ int height = text.height();
+ if( !m_img.isNull() && kMin( m_img.height(), MAX_SIZE ) > height )
+ height = kMin( m_img.height(), MAX_SIZE );
+ height += 10;
+
+ return TQSize( width, height );
+ }
+
+ void position()
+ {
+ const TQRect drect = TQApplication::desktop()->availableGeometry( TQToolTip::tqparentWidget() );
+ const TQSize size = tqsizeHint();
+ const int width = size.width(), height = size.height();
+ const TQRect tmp = m_item->rect();
+ const TQRect irect( m_list->viewport()->mapToGlobal( m_list->contentsToViewport(tmp.topLeft()) ), tmp.size() );
+
+ int y;
+ if( irect.bottom() + height < drect.bottom() )
+ y = irect.bottom();
+ else
+ y = kMax( drect.top(), irect.top() - height );
+
+ int x = kMax( drect.x(), TQToolTip::tqparentWidget()->mapToGlobal( m_pos ).x() - width/2 );
+ if( x + width > drect.right() )
+ x = drect.right() - width;
+
+ move( x, y );
+ }
+
+ virtual bool eventFilter( TQObject *, TQEvent *e )
+ {
+ if( isVisible() )
+ switch ( e->type() )
+ {
+ case TQEvent::KeyPress:
+ case TQEvent::KeyRelease:
+ case TQEvent::MouseButtonPress:
+ case TQEvent::MouseButtonRelease:
+ //case TQEvent::MouseMove:
+ case TQEvent::FocusIn:
+ case TQEvent::FocusOut:
+ case TQEvent::Wheel:
+ case TQEvent::Leave:
+ hideTip();
+ default: break;
+ }
+
+ return false;
+ }
+};
+
+LayerList::Private::Private( TQWidget *tqparent, LayerList *list )
+ : activeLayer( 0 ), foldersCanBeActive( false ), previewsShown( false ), itemHeight( 32 ),
+ tooltip( new LayerToolTip( tqparent, list ) ) { }
+
+LayerList::Private::~Private()
+{
+ delete tooltip;
+ tooltip = 0;
+}
+
+static int getID()
+{
+ static int id = -2;
+ return id--;
+}
+
+static TQSize iconSize() { return TQIconSet::iconSize( TQIconSet::Small ); }
+
+
+///////////////
+// LayerList //
+///////////////
+
+LayerList::LayerList( TQWidget *tqparent, const char *name )
+ : super( tqparent, name ), d( new Private( viewport(), this ) )
+{
+ setSelectionMode( TQListView::Extended );
+ setRootIsDecorated( true );
+ setSorting( -1 );
+ setSortColumn( -1 );
+ setAllColumnsShowFocus( true );
+ setFullWidth( true );
+ setItemsRenameable( false );
+ setDropHighlighter( true );
+ setDefaultRenameAction( TQListView::Accept );
+ setDragEnabled( true );
+ setAcceptDrops( true );
+ setItemsMovable( true );
+ addColumn( TQString() );
+ header()->hide();
+
+ TQToolTip::add(this, i18n("Right-click to create folders. Click on the layername to change the layer's name. Click and drag to move layers."));
+
+ setNumRows( 2 );
+
+ connect( this, TQT_SIGNAL( itemRenamed( TQListViewItem*, const TQString&, int ) ),
+ TQT_SLOT( slotItemRenamed( TQListViewItem*, const TQString&, int ) ) );
+ connect( this, TQT_SIGNAL( moved( TQPtrList<TQListViewItem>&, TQPtrList<TQListViewItem>&, TQPtrList<TQListViewItem>& ) ),
+ TQT_SLOT( slotItemMoved( TQPtrList<TQListViewItem>&, TQPtrList<TQListViewItem>&, TQPtrList<TQListViewItem>& ) ) );
+ connect( this, TQT_SIGNAL( onItem( TQListViewItem* ) ), TQT_SLOT( hideTip() ) );
+ connect( this, TQT_SIGNAL( onViewport() ), TQT_SLOT( hideTip() ) );
+}
+
+LayerList::~LayerList()
+{
+ delete d;
+}
+
+void LayerList::addProperty( const TQString &name, const TQString &displayName, const TQIconSet &icon,
+ bool defaultValue, bool validForFolders )
+{
+ addProperty( name, displayName, icon.pixmap( TQIconSet::Small, TQIconSet::Normal ), icon.pixmap( TQIconSet::Small, TQIconSet::Disabled ), defaultValue, validForFolders );
+}
+
+void LayerList::addProperty( const TQString &name, const TQString &displayName, TQPixmap enabled, TQPixmap disabled,
+ bool defaultValue, bool validForFolders )
+{
+ d->properties.append( LayerProperty( name, displayName, enabled, disabled, defaultValue, validForFolders ) );
+
+ for( LayerItemIterator it( this ); *it; ++it )
+ (*it)->d->properties.append( defaultValue );
+
+ //we do this only afterwards in case someone wants to access the other items in a connected slot...
+ for( LayerItemIterator it( this ); *it; ++it )
+ if( validForFolders || !(*it)->isFolder() )
+ {
+ emit propertyChanged( *it, name, defaultValue );
+ emit propertyChanged( (*it)->id(), name, defaultValue );
+ }
+
+ triggerUpdate();
+}
+
+LayerItem *LayerList::layer( int id ) const
+{
+ if( !firstChild() || id == -1 )
+ return 0;
+
+ for( LayerItemIterator it( firstChild() ); *it; ++it )
+ if( (*it)->id() == id )
+ return (*it);
+
+ return 0;
+}
+
+LayerItem *LayerList::folder( int id ) const
+{
+ if( !firstChild() || id == -1 )
+ return 0;
+
+ for( LayerItemIterator it( firstChild() ); *it; ++it )
+ if( (*it)->id() == id && (*it)->isFolder() )
+ return (*it);
+
+ return 0;
+}
+
+LayerItem *LayerList::activeLayer() const
+{
+ return d->activeLayer;
+}
+
+int LayerList::activeLayerID() const
+{
+ if( activeLayer() )
+ return activeLayer()->id();
+ return -1;
+}
+
+TQValueList<LayerItem*> LayerList::selectedLayers() const
+{
+ if( !firstChild() )
+ return TQValueList<LayerItem*>();
+
+ TQValueList<LayerItem*> layers;
+ for( LayerItemIterator it( firstChild() ); *it; ++it )
+ if( (*it)->isSelected() )
+ layers.append( *it );
+
+ return layers;
+}
+
+TQValueList<int> LayerList::selectedLayerIDs() const
+{
+ const TQValueList<LayerItem*> layers = selectedLayers();
+ TQValueList<int> ids;
+ for( int i = 0, n = layers.count(); i < n; ++i )
+ ids.append( layers[i]->id() );
+
+ return ids;
+}
+
+bool LayerList::foldersCanBeActive() const
+{
+ return d->foldersCanBeActive;
+}
+
+bool LayerList::previewsShown() const
+{
+ return d->previewsShown;
+}
+
+int LayerList::itemHeight() const
+{
+ return d->itemHeight;
+}
+
+int LayerList::numRows() const
+{
+ if( itemHeight() < kMax( fontMetrics().height(), iconSize().height() ) )
+ return 0;
+
+ return ( itemHeight() - fontMetrics().height() ) / iconSize().height() + 1;
+}
+
+void LayerList::makeFolder( int id )
+{
+ LayerItem* const l = layer( id );
+ if( l )
+ l->makeFolder();
+}
+
+bool LayerList::isFolder( int id ) const
+{
+ LayerItem* const l = layer( id );
+ if( !l )
+ return false;
+
+ return l->isFolder();
+}
+
+TQString LayerList::displayName( int id ) const
+{
+ LayerItem* const l = layer( id );
+ if( !l )
+ return TQString(); //should be more severe...
+
+ return l->displayName();
+}
+
+bool LayerList::property( int id, const TQString &name ) const
+{
+ LayerItem* const l = layer( id );
+ if( !l )
+ return false; //should be more severe...
+
+ return l->property( name );
+}
+
+KPopupMenu *LayerList::contextMenu() const
+{
+ return &( d->contextMenu );
+}
+
+void LayerList::setFoldersCanBeActive( bool can ) //SLOT
+{
+ d->foldersCanBeActive = can;
+ if( !can && activeLayer() && activeLayer()->isFolder() )
+ {
+ d->activeLayer = 0;
+ emit activated( static_cast<LayerItem*>( 0 ) );
+ emit activated( -1 );
+ }
+}
+
+void LayerList::setPreviewsShown( bool show ) //SLOT
+{
+ d->previewsShown = show;
+ triggerUpdate();
+}
+
+void LayerList::setItemHeight( int height ) //SLOT
+{
+ d->itemHeight = height;
+ for( LayerItemIterator it( this ); *it; ++it )
+ (*it)->setup();
+ triggerUpdate();
+}
+
+void LayerList::setNumRows( int rows )
+{
+ if( rows < 1 )
+ return;
+
+ if( rows == 1 )
+ setItemHeight( kMax( fontMetrics().height(), iconSize().height() ) );
+ else
+ setItemHeight( fontMetrics().height() + ( rows - 1 ) * iconSize().height() );
+}
+
+void LayerList::setActiveLayer( LayerItem *layer ) //SLOT
+{
+ if( !foldersCanBeActive() && layer && layer->isFolder() )
+ return;
+
+ ensureItemVisible( layer );
+
+ if( d->activeLayer == layer )
+ return;
+
+ d->activeLayer = layer;
+
+ if( currentItem() != layer )
+ setCurrentItem( layer );
+ else
+ {
+ int n = 0;
+ for( LayerItemIterator it( this, LayerItemIterator::Selected ); n < 2 && (*it); ++it ) { n++; }
+ if( n == 1 )
+ (*LayerItemIterator( this, LayerItemIterator::Selected ))->setSelected( false );
+ if( layer )
+ layer->setSelected( true );
+ }
+
+ emit activated( layer );
+ if( layer )
+ emit activated( layer->id() );
+ else
+ emit activated( -1 );
+}
+
+void LayerList::setActiveLayer( int id ) //SLOT
+{
+ setActiveLayer( layer( id ) );
+}
+
+void LayerList::setLayerDisplayName( LayerItem *layer, const TQString &displayName )
+{
+ if( !layer )
+ return;
+
+ layer->setDisplayName( displayName );
+}
+
+void LayerList::setLayerDisplayName( int id, const TQString &displayName )
+{
+ setLayerDisplayName( layer( id ), displayName );
+}
+
+void LayerList::setLayerProperty( LayerItem *layer, const TQString &name, bool on ) //SLOT
+{
+ if( !layer )
+ return;
+
+ layer->setProperty( name, on );
+}
+
+void LayerList::setLayerProperty( int id, const TQString &name, bool on ) //SLOT
+{
+ setLayerProperty( layer( id ), name, on );
+}
+
+void LayerList::toggleLayerProperty( LayerItem *layer, const TQString &name ) //SLOT
+{
+ if( !layer )
+ return;
+
+ layer->toggleProperty( name );
+}
+
+void LayerList::toggleLayerProperty( int id, const TQString &name ) //SLOT
+{
+ toggleLayerProperty( layer( id ), name );
+}
+
+void LayerList::setLayerPreviewImage( LayerItem *layer, TQImage *image )
+{
+ if( !layer )
+ return;
+
+ layer->setPreviewImage( image );
+}
+
+void LayerList::setLayerPreviewImage( int id, TQImage *image )
+{
+ setLayerPreviewImage( layer( id ), image );
+}
+
+void LayerList::layerPreviewChanged( LayerItem *layer )
+{
+ if( !layer )
+ return;
+
+ layer->previewChanged();
+}
+
+void LayerList::layerPreviewChanged( int id )
+{
+ layerPreviewChanged( layer( id ) );
+}
+
+LayerItem *LayerList::addLayer( const TQString &displayName, LayerItem *after, int id ) //SLOT
+{
+ return new LayerItem( displayName, this, after, id );
+}
+
+LayerItem *LayerList::addLayer( const TQString &displayName, int afterID, int id ) //SLOT
+{
+ return new LayerItem( displayName, this, layer( afterID ), id );
+}
+
+//SLOT
+LayerItem *LayerList::addLayerToParent( const TQString &displayName, LayerItem *tqparent, LayerItem *after, int id )
+{
+ if( tqparent && tqparent->isFolder() )
+ return tqparent->addLayer( displayName, after, id );
+ else
+ return 0;
+}
+
+LayerItem *LayerList::addLayerToParent( const TQString &displayName, int tqparentID, int afterID, int id ) //SLOT
+{
+ return addLayerToParent( displayName, folder( tqparentID ), layer( afterID ), id );
+}
+
+void LayerList::moveLayer( LayerItem *layer, LayerItem *tqparent, LayerItem *after ) //SLOT
+{
+ if( !layer )
+ return;
+
+ if( tqparent && !tqparent->isFolder() )
+ tqparent = 0;
+
+ if( layer->tqparent() == tqparent && layer->prevSibling() == after )
+ return;
+
+ TQListViewItem *current = currentItem();
+
+ moveItem( layer, tqparent, after );
+
+ emit layerMoved( layer, tqparent, after );
+ emit layerMoved( layer->id(), tqparent ? tqparent->id() : -1, after ? after->id() : -1 );
+
+ setCurrentItem( current ); //HACK, sometimes TQt changes this under us
+}
+
+void LayerList::moveLayer( int id, int tqparentID, int afterID ) //SLOT
+{
+ moveLayer( layer( id ), folder( tqparentID ), layer( afterID ) );
+}
+
+void LayerList::removeLayer( LayerItem *layer ) //SLOT
+{
+ delete layer;
+}
+
+void LayerList::removeLayer( int id ) //SLOT
+{
+ delete layer( id );
+}
+
+void LayerList::contentsMousePressEvent( TQMouseEvent *e )
+{
+ LayerItem *item = static_cast<LayerItem*>( itemAt( contentsToViewport( e->pos() ) ) );
+
+ if( item )
+ {
+ TQMouseEvent m( TQEvent::MouseButtonPress, item->mapFromListView( e->pos() ), e->button(), e->state() );
+ if( !item->mousePressEvent( &m ) )
+ super::contentsMousePressEvent( e );
+ }
+ else
+ {
+ super::contentsMousePressEvent( e );
+ if( e->button() == Qt::RightButton )
+ showContextMenu();
+ }
+}
+
+void LayerList::contentsMouseDoubleClickEvent( TQMouseEvent *e )
+{
+ super::contentsMouseDoubleClickEvent( e );
+ if( LayerItem *layer = static_cast<LayerItem*>( itemAt( contentsToViewport( e->pos() ) ) ) )
+ {
+ if( !layer->iconsRect().tqcontains( layer->mapFromListView( e->pos() ) ) )
+ {
+ emit requestLayerProperties( layer );
+ emit requestLayerProperties( layer->id() );
+ }
+ }
+ else
+ {
+ emit requestNewLayer( static_cast<LayerItem*>( 0 ), static_cast<LayerItem*>( 0 ) );
+ emit requestNewLayer( -1, -1 );
+ }
+}
+
+void LayerList::findDrop( const TQPoint &pos, TQListViewItem *&tqparent, TQListViewItem *&after )
+{
+ LayerItem *item = static_cast<LayerItem*>( itemAt( contentsToViewport( pos ) ) );
+ if( item && item->isFolder() )
+ {
+ tqparent = item;
+ after = 0;
+ }
+ else
+ super::findDrop( pos, tqparent, after );
+}
+
+void LayerList::showContextMenu()
+{
+ LayerItem *layer = static_cast<LayerItem*>( itemAt( viewport()->mapFromGlobal( TQCursor::pos() ) ) );
+ if( layer )
+ setCurrentItem( layer );
+ d->contextMenu.clear();
+ constructMenu( layer );
+ menuActivated( d->contextMenu.exec( TQCursor::pos() ), layer );
+}
+
+void LayerList::hideTip()
+{
+ d->tooltip->hideTip();
+}
+
+void LayerList::maybeTip()
+{
+ d->tooltip->maybeTip( d->tooltip->TQToolTip::tqparentWidget()->mapFromGlobal( TQCursor::pos() ) );
+}
+
+void LayerList::constructMenu( LayerItem *layer )
+{
+ if( layer )
+ {
+ for( int i = 0, n = d->properties.count(); i < n; ++i )
+ if( !layer->isFolder() || d->properties[i].validForFolders )
+ d->contextMenu.insertItem( layer->d->properties[i] ? d->properties[i].enabledIcon : d->properties[i].disabledIcon, d->properties[i].displayName, MenuItems::COUNT + i );
+ d->contextMenu.insertItem( SmallIconSet( "info" ), i18n( "&Properties" ), MenuItems::LayerProperties );
+ d->contextMenu.insertSeparator();
+ d->contextMenu.insertItem( SmallIconSet( "editdelete" ),
+ selectedLayers().count() > 1 ? i18n( "Remove Layers" )
+ : layer->isFolder() ? i18n( "&Remove Folder" )
+ : i18n( "&Remove Layer" ), MenuItems::RemoveLayer );
+ }
+ d->contextMenu.insertItem( SmallIconSet( "filenew" ), i18n( "&New Layer" ), MenuItems::NewLayer );
+ d->contextMenu.insertItem( SmallIconSet( "folder" ), i18n( "New &Folder" ), MenuItems::NewFolder );
+}
+
+void LayerList::menuActivated( int id, LayerItem *layer )
+{
+ const TQValueList<LayerItem*> selected = selectedLayers();
+
+ LayerItem *tqparent = ( layer && layer->isFolder() ) ? layer : 0;
+ LayerItem *after = 0;
+ if( layer && !tqparent )
+ {
+ tqparent = layer->tqparent();
+ after = layer->prevSibling();
+ }
+ switch( id )
+ {
+ case MenuItems::NewLayer:
+ emit requestNewLayer( tqparent, after );
+ emit requestNewLayer( tqparent ? tqparent->id() : -1, after ? after->id() : -1 );
+ break;
+ case MenuItems::NewFolder:
+ emit requestNewFolder( tqparent, after );
+ emit requestNewFolder( tqparent ? tqparent->id() : -1, after ? after->id() : -1 );
+ break;
+ case MenuItems::RemoveLayer:
+ {
+ TQValueList<int> ids;
+ for( int i = 0, n = selected.count(); i < n; ++i )
+ {
+ ids.append( selected[i]->id() );
+ emit requestRemoveLayer( selected[i]->id() );
+ }
+ emit requestRemoveLayers( ids );
+ }
+ for( int i = 0, n = selected.count(); i < n; ++i )
+ emit requestRemoveLayer( selected[i] );
+ emit requestRemoveLayers( selected );
+ break;
+ case MenuItems::LayerProperties:
+ if( layer )
+ {
+ emit requestLayerProperties( layer );
+ emit requestLayerProperties( layer->id() );
+ }
+ break;
+ default:
+ if( id >= MenuItems::COUNT && layer )
+ for( int i = 0, n = selected.count(); i < n; ++i )
+ selected[i]->toggleProperty( d->properties[ id - MenuItems::COUNT ].name );
+ }
+}
+
+void LayerList::slotItemRenamed( TQListViewItem *item, const TQString &text, int col )
+{
+ if( !item || col != 0 )
+ return;
+
+ emit displayNameChanged( static_cast<LayerItem*>( item ), text );
+ emit displayNameChanged( static_cast<LayerItem*>( item )->id(), text );
+}
+
+void LayerList::slotItemMoved( TQPtrList<TQListViewItem> &items, TQPtrList<TQListViewItem> &/*afterBefore*/, TQPtrList<TQListViewItem> &afterNow )
+{
+ for( int i = 0, n = items.count(); i < n; ++i )
+ {
+ LayerItem *l = static_cast<LayerItem*>( items.at(i) ), *a = static_cast<LayerItem*>( afterNow.at(i) );
+ if( !l )
+ continue;
+
+ if( l->tqparent() )
+ l->tqparent()->setOpen( true );
+
+ emit layerMoved( l, l->tqparent(), a );
+ emit layerMoved( l->id(), l->tqparent() ? l->tqparent()->id() : -1, a ? a->id() : -1 );
+ }
+}
+
+void LayerList::setCurrentItem( TQListViewItem *item )
+{
+ if( !item )
+ return;
+
+ super::setCurrentItem( item );
+ ensureItemVisible( item );
+ int n = 0;
+ for( LayerItemIterator it( this, LayerItemIterator::Selected ); n < 2 && (*it); ++it ) { n++; }
+ if( n == 1 )
+ (*LayerItemIterator( this, LayerItemIterator::Selected ))->setSelected( false );
+ item->setSelected( true );
+ if( activeLayer() != item )
+ setActiveLayer( static_cast<LayerItem*>(item) );
+}
+
+
+///////////////
+// LayerItem //
+///////////////
+
+LayerItem::LayerItem( const TQString &displayName, LayerList *p, LayerItem *after, int id )
+ : super( p, after ), d( new Private( id ) )
+{
+ init();
+ setDisplayName( displayName );
+}
+
+LayerItem::LayerItem( const TQString &displayName, LayerItem *p, LayerItem *after, int id )
+ : super( ( p && p->isFolder() ) ? p : 0, after ), d( new Private( id ) )
+{
+ init();
+ setDisplayName( displayName );
+}
+
+void LayerItem::init()
+{
+ if( d->id < 0 )
+ d->id = getID();
+
+ for( int i = 0, n = listView()->d->properties.count(); i < n; ++i )
+ d->properties.append( listView()->d->properties[i].defaultValue );
+
+ if( tqparent())
+ tqparent()->setOpen( true );
+}
+
+LayerItem::~LayerItem()
+{
+ if (listView() && (listView()->activeLayer() == this || tqcontains(listView()->activeLayer())))
+ listView()->setActiveLayer( static_cast<LayerItem*>( 0 ) );
+ delete d;
+}
+
+void LayerItem::makeFolder()
+{
+ d->isFolder = true;
+ setPixmap( 0, SmallIcon( "folder", 16 ) );
+ if( isActive() && !listView()->foldersCanBeActive() )
+ listView()->setActiveLayer( static_cast<LayerItem*>( 0 ) );
+}
+
+bool LayerItem::isFolder() const
+{
+ return d->isFolder;
+}
+
+bool LayerItem::tqcontains(const LayerItem *item)
+{
+ TQListViewItemIterator it(this);
+
+ while (it.current()) {
+ if (static_cast<const LayerItem *>(it.current()) == item) {
+ return true;
+ }
+ ++it;
+ }
+ return false;
+}
+
+int LayerItem::id() const
+{
+ return d->id;
+}
+
+TQString LayerItem::displayName() const
+{
+ return text( 0 );
+}
+
+void LayerItem::setDisplayName( const TQString &s )
+{
+ if( displayName() == s )
+ return;
+ setText( 0, s );
+ emit listView()->displayNameChanged( this, s );
+ emit listView()->displayNameChanged( id(), s );
+}
+
+bool LayerItem::isActive() const
+{
+ return listView()->activeLayer() == this;
+}
+
+void LayerItem::setActive()
+{
+ listView()->setActiveLayer( this );
+}
+
+bool LayerItem::property( const TQString &name ) const
+{
+ int i = listView()->d->properties.count() - 1;
+ while( i && listView()->d->properties[i].name != name )
+ --i;
+
+ if( i < 0 )
+ return false; //should do something more severe... but what?
+
+ return d->properties[i];
+}
+
+void LayerItem::setProperty( const TQString &name, bool on )
+{
+ int i = listView()->d->properties.count() - 1;
+ while( i && listView()->d->properties[i].name != name )
+ --i;
+
+ if( i < 0 || ( isFolder() && !listView()->d->properties[i].validForFolders ) )
+ return;
+
+ const bool notify = ( on != d->properties[i] );
+ d->properties[i] = on;
+ if( notify )
+ {
+ emit listView()->propertyChanged( this, name, on );
+ emit listView()->propertyChanged( id(), name, on );
+ }
+
+ update();
+}
+
+void LayerItem::toggleProperty( const TQString &name )
+{
+ int i = listView()->d->properties.count() - 1;
+ while( i && listView()->d->properties[i].name != name )
+ --i;
+
+ if( i < 0 || ( isFolder() && !listView()->d->properties[i].validForFolders ) )
+ return;
+
+ d->properties[i] = !(d->properties[i]);
+ emit listView()->propertyChanged( this, name, d->properties[i] );
+ emit listView()->propertyChanged( id(), name, d->properties[i] );
+
+ update();
+}
+
+void LayerItem::setPreviewImage( TQImage *image )
+{
+ d->previewImage = image;
+ previewChanged();
+}
+
+void LayerItem::previewChanged()
+{
+ d->previewChanged = true;
+ update();
+}
+
+LayerItem *LayerItem::addLayer( const TQString &displayName, LayerItem *after, int id )
+{
+ if( !isFolder() )
+ return 0;
+ return new LayerItem( displayName, this, after, id );
+}
+
+LayerItem *LayerItem::prevSibling() const
+{
+ LayerItem *item = tqparent() ? tqparent()->firstChild() : listView()->firstChild();
+ if( !item || this == item )
+ return 0;
+ for(; item && this != item->nextSibling(); item = item->nextSibling() );
+ return item;
+}
+
+int LayerItem::mapXFromListView( int x ) const
+{
+ return x - rect().left();
+}
+
+int LayerItem::mapYFromListView( int y ) const
+{
+ return y - rect().top();
+}
+
+TQPoint LayerItem::mapFromListView( const TQPoint &point ) const
+{
+ return TQPoint( mapXFromListView( point.x() ), mapYFromListView( point.y() ) );
+}
+
+TQRect LayerItem::mapFromListView( const TQRect &rect ) const
+{
+ return TQRect( mapFromListView( rect.topLeft() ), rect.size() );
+}
+
+int LayerItem::mapXToListView( int x ) const
+{
+ return x + rect().left();
+}
+
+int LayerItem::mapYToListView( int y ) const
+{
+ return y + rect().top();
+}
+
+TQPoint LayerItem::mapToListView( const TQPoint &point ) const
+{
+ return TQPoint( mapXToListView( point.x() ), mapYToListView( point.y() ) );
+}
+
+TQRect LayerItem::mapToListView( const TQRect &rect ) const
+{
+ return TQRect( mapToListView( rect.topLeft() ), rect.size() );
+}
+
+TQRect LayerItem::rect() const
+{
+ const int indent = listView()->treeStepSize() * ( depth() + 1 );
+ return TQRect( listView()->header()->sectionPos( 0 ) + indent, itemPos(),
+ listView()->header()->sectionSize( 0 ) - indent, height() );
+}
+
+TQRect LayerItem::textRect() const
+{
+ static TQFont f;
+ static int minbearing = 1337 + 666; //can be 0 or negative, 2003 is less likely
+ if( minbearing == 2003 || f != font() )
+ {
+ f = font(); //getting your bearings can be expensive, so we cache them
+ minbearing = fontMetrics().minLeftBearing() + fontMetrics().minRightBearing();
+ }
+
+ const int margin = listView()->itemMargin();
+ int indent = previewRect().right() + margin;
+ if( pixmap( 0 ) )
+ indent += pixmap( 0 )->width() + margin;
+
+ const int width = ( multiline() ? rect().right() : iconsRect().left() ) - indent - margin + minbearing;
+
+ return TQRect( indent, 0, width, fontMetrics().height() );
+}
+
+TQRect LayerItem::iconsRect() const
+{
+ const TQValueList<LayerProperty> &lp = listView()->d->properties;
+ int propscount = 0;
+ for( int i = 0, n = lp.count(); i < n; ++i )
+ if( !lp[i].enabledIcon.isNull() && ( !multiline() || !isFolder() || lp[i].validForFolders ) )
+ propscount++;
+
+ const int iconswidth = propscount * iconSize().width() + (propscount - 1) * listView()->itemMargin();
+
+ const int x = multiline() ? previewRect().right() + listView()->itemMargin() : rect().width() - iconswidth;
+ const int y = multiline() ? fontMetrics().height() : 0;
+
+ return TQRect( x, y, iconswidth, iconSize().height() );
+}
+
+TQRect LayerItem::previewRect() const
+{
+ return TQRect( 0, 0, listView()->previewsShown() ? height() : 0, height() );
+}
+
+void LayerItem::drawText( TQPainter *p, const TQColorGroup &cg, const TQRect &r )
+{
+ p->translate( r.left(), r.top() );
+
+ p->setPen( isSelected() ? cg.highlightedText() : cg.text() );
+
+ const TQString text = KStringHandler::rPixelSqueeze( displayName(), p->fontMetrics(), r.width() );
+ p->drawText( listView()->itemMargin(), 0, r.width(), r.height(), TQt::AlignAuto | TQt::AlignTop, text );
+
+ p->translate( -r.left(), -r.top() );
+}
+
+void LayerItem::drawIcons( TQPainter *p, const TQColorGroup &/*cg*/, const TQRect &r )
+{
+ p->translate( r.left(), r.top() );
+
+ int x = 0;
+ const TQValueList<LayerProperty> &lp = listView()->d->properties;
+ for( int i = 0, n = lp.count(); i < n; ++i )
+ if( !lp[i].enabledIcon.isNull() && ( !multiline() || !isFolder() || lp[i].validForFolders ) )
+ {
+ if( !isFolder() || lp[i].validForFolders )
+ p->drawPixmap( x, 0, d->properties[i] ? lp[i].enabledIcon : lp[i].disabledIcon );
+ x += iconSize().width() + listView()->itemMargin();
+ }
+
+ p->translate( -r.left(), -r.top() );
+}
+
+void LayerItem::drawPreview( TQPainter *p, const TQColorGroup &/*cg*/, const TQRect &r )
+{
+ if( !showPreview() )
+ return;
+
+ if( d->previewChanged || r.size() != d->previewSize )
+ { //TODO handle width() != height()
+ const int size = kMin( r.width(), kMax( previewImage()->width(), previewImage()->height() ) );
+ const TQImage i = previewImage()->smoothScale( size, size, TQ_ScaleMin );
+ d->scaledPreview.convertFromImage( i );
+ d->previewOffset.setX( r.width()/2 - i.width()/2 );
+ d->previewOffset.setY( r.height()/2 - i.height()/2 );
+
+ d->previewChanged = false;
+ d->previewSize = r.size();
+ }
+
+ p->drawPixmap( r.topLeft() + d->previewOffset, d->scaledPreview );
+}
+
+bool LayerItem::showPreview() const
+{
+ return listView()->previewsShown() && previewImage() && !previewImage()->isNull();
+}
+
+bool LayerItem::multiline() const
+{
+ return height() >= fontMetrics().height() + iconSize().height();
+}
+
+TQFont LayerItem::font() const
+{
+ if( isActive() )
+ {
+ TQFont f = listView()->font();
+ f.setBold( !f.bold() );
+ f.setItalic( !f.italic() );
+ return f;
+ }
+ else
+ return listView()->font();
+}
+
+TQFontMetrics LayerItem::fontMetrics() const
+{
+ return TQFontMetrics( font() );
+}
+
+bool LayerItem::mousePressEvent( TQMouseEvent *e )
+{
+ if( e->button() == Qt::RightButton )
+ {
+ if ( !(e->state() & TQt::ControlButton) && !(e->state() & TQt::ShiftButton) )
+ setActive();
+ TQTimer::singleShot( 0, listView(), TQT_SLOT( showContextMenu() ) );
+ return false;
+ }
+
+ const TQRect ir = iconsRect(), tr = textRect();
+
+ if( ir.tqcontains( e->pos() ) )
+ {
+ const int iconWidth = iconSize().width();
+ int x = e->pos().x() - ir.left();
+ if( x % ( iconWidth + listView()->itemMargin() ) < iconWidth ) //it's on an icon, not a margin
+ {
+ const TQValueList<LayerProperty> &lp = listView()->d->properties;
+ int p = -1;
+ for( int i = 0, n = lp.count(); i < n; ++i )
+ {
+ if( !lp[i].enabledIcon.isNull() && ( !multiline() || !isFolder() || lp[i].validForFolders ) )
+ x -= iconWidth + listView()->itemMargin();
+ p += 1;
+ if( x < 0 )
+ break;
+ }
+ toggleProperty( lp[p].name );
+ }
+ return true;
+ }
+
+ else if( tr.tqcontains( e->pos() ) && isSelected() && !listView()->renameLineEdit()->isVisible() )
+ {
+ listView()->rename( this, 0 );
+ TQRect r( listView()->contentsToViewport( mapToListView( tr.topLeft() ) ), tr.size() );
+ listView()->renameLineEdit()->setGeometry( r );
+ return true;
+ }
+
+ if ( !(e->state() & TQt::ControlButton) && !(e->state() & TQt::ShiftButton) )
+ setActive();
+
+ return false;
+}
+
+TQString LayerItem::tooltip() const
+{
+ TQString tip;
+ tip += "<table cellspacing=\"0\" cellpadding=\"0\">";
+ tip += TQString("<tr><td colspan=\"2\" align=\"center\"><b>%1</b></td></tr>").tqarg( displayName() );
+ TQString row = "<tr><td>%1</td><td>%2</td></tr>";
+ for( int i = 0, n = listView()->d->properties.count(); i < n; ++i )
+ if( !isFolder() || listView()->d->properties[i].validForFolders )
+ {
+ if( d->properties[i] )
+ tip += row.tqarg( i18n( "%1:" ).tqarg( listView()->d->properties[i].displayName ) ).tqarg( i18n( "Yes" ) );
+ else
+ tip += row.tqarg( i18n( "%1:" ).tqarg( listView()->d->properties[i].displayName ) ).tqarg( i18n( "No" ) );
+ }
+ tip += "</table>";
+ return tip;
+}
+
+TQImage *LayerItem::previewImage() const
+{
+ return d->previewImage;
+}
+
+TQImage LayerItem::tooltipPreview() const
+{
+ if( previewImage() )
+ return *previewImage();
+ return TQImage();
+}
+
+int LayerItem::width( const TQFontMetrics &fm, const TQListView *lv, int c ) const
+{
+ if( c != 0 )
+ return super::width( fm, lv, c );
+
+ const TQValueList<LayerProperty> &lp = listView()->d->properties;
+ int propscount = 0;
+ for( int i = 0, n = d->properties.count(); i < n; ++i )
+ if( !lp[i].enabledIcon.isNull() && ( !multiline() || !isFolder() || lp[i].validForFolders ) )
+ propscount++;
+
+ const int iconswidth = propscount * iconSize().width() + (propscount - 1) * listView()->itemMargin();
+
+ if( multiline() )
+ return kMax( super::width( fm, lv, 0 ), iconswidth );
+ else
+ return super::width( fm, lv, 0 ) + iconswidth;
+}
+
+void LayerItem::paintCell( TQPainter *painter, const TQColorGroup &cg, int column, int width, int align )
+{
+ if( column != 0 )
+ {
+ super::paintCell( painter, cg, column, width, align );
+ return;
+ }
+
+ TQPixmap buf( width, height() );
+ TQPainter p( &buf );
+
+ p.setFont( font() );
+
+ const TQColorGroup cg_ = isEnabled() ? listView()->tqpalette().active() : listView()->tqpalette().disabled();
+
+ const TQColor bg = isSelected() ? cg_.highlight()
+ : isAlternate() ? listView()->alternateBackground()
+ : listView()->viewport()->backgroundColor();
+
+ buf.fill( bg );
+
+ if( pixmap( 0 ) )
+ p.drawPixmap( previewRect().right() + listView()->itemMargin(), 0, *pixmap( 0 ) );
+
+ drawText( &p, cg_, textRect() );
+ drawIcons( &p, cg_, iconsRect() );
+ drawPreview( &p, cg_, previewRect() );
+
+ painter->drawPixmap( 0, 0, buf );
+}
+
+void LayerItem::setup()
+{
+ super::setup();
+ setHeight( listView()->d->itemHeight );
+}
+
+void LayerItem::setSelected( bool selected )
+{
+ if( !selected && ( isActive() || this == listView()->currentItem() ) )
+ return;
+ super::setSelected( selected );
+}
+
+
+/////////////////////////
+// Convenience Methods //
+/////////////////////////
+
+LayerItem *LayerList::firstChild() const { return static_cast<LayerItem*>( super::firstChild() ); }
+LayerItem *LayerList::lastChild() const { return static_cast<LayerItem*>( super::lastChild() ); }
+LayerList *LayerItem::listView() const { return static_cast<LayerList*>( super::listView() ); }
+void LayerItem::update() const { listView()->tqrepaintItem( this ); }
+LayerItem *LayerItem::firstChild() const { return static_cast<LayerItem*>( super::firstChild() ); }
+LayerItem *LayerItem::nextSibling() const { return static_cast<LayerItem*>( super::nextSibling() ); }
+LayerItem *LayerItem::tqparent() const { return static_cast<LayerItem*>( super::tqparent() ); }
+
+
+#include "layerlist.moc"