/* Copyright (c) 2005 Gábor Lehel 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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( 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 properties; KPopupMenu contextMenu; LayerToolTip *tooltip; Private( TQWidget *tqparent, LayerList *list ); ~Private(); }; class LayerItem::Private { public: bool isFolder; int id; TQValueList 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(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&, TQPtrList&, TQPtrList& ) ), TQT_SLOT( slotItemMoved( TQPtrList&, TQPtrList&, TQPtrList& ) ) ); 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 LayerList::selectedLayers() const { if( !firstChild() ) return TQValueList(); TQValueList layers; for( LayerItemIterator it( firstChild() ); *it; ++it ) if( (*it)->isSelected() ) layers.append( *it ); return layers; } TQValueList LayerList::selectedLayerIDs() const { const TQValueList layers = selectedLayers(); TQValueList 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( 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( 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( itemAt( contentsToViewport( e->pos() ) ) ) ) { if( !layer->iconsRect().tqcontains( layer->mapFromListView( e->pos() ) ) ) { emit requestLayerProperties( layer ); emit requestLayerProperties( layer->id() ); } } else { emit requestNewLayer( static_cast( 0 ), static_cast( 0 ) ); emit requestNewLayer( -1, -1 ); } } void LayerList::findDrop( const TQPoint &pos, TQListViewItem *&tqparent, TQListViewItem *&after ) { LayerItem *item = static_cast( itemAt( contentsToViewport( pos ) ) ); if( item && item->isFolder() ) { tqparent = item; after = 0; } else super::findDrop( pos, tqparent, after ); } void LayerList::showContextMenu() { LayerItem *layer = static_cast( 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 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 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( item ), text ); emit displayNameChanged( static_cast( item )->id(), text ); } void LayerList::slotItemMoved( TQPtrList &items, TQPtrList &/*afterBefore*/, TQPtrList &afterNow ) { for( int i = 0, n = items.count(); i < n; ++i ) { LayerItem *l = static_cast( items.at(i) ), *a = static_cast( 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(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( 0 ) ); delete d; } void LayerItem::makeFolder() { d->isFolder = true; setPixmap( 0, SmallIcon( "folder", 16 ) ); if( isActive() && !listView()->foldersCanBeActive() ) listView()->setActiveLayer( static_cast( 0 ) ); } bool LayerItem::isFolder() const { return d->isFolder; } bool LayerItem::tqcontains(const LayerItem *item) { TQListViewItemIterator it(this); while (it.current()) { if (static_cast(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 &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 &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 &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 += ""; tip += TQString("").tqarg( displayName() ); TQString row = ""; 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 += "
%1
%1%2
"; 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 &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()->palette().active() : listView()->palette().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( super::firstChild() ); } LayerItem *LayerList::lastChild() const { return static_cast( super::lastChild() ); } LayerList *LayerItem::listView() const { return static_cast( super::listView() ); } void LayerItem::update() const { listView()->tqrepaintItem( this ); } LayerItem *LayerItem::firstChild() const { return static_cast( super::firstChild() ); } LayerItem *LayerItem::nextSibling() const { return static_cast( super::nextSibling() ); } LayerItem *LayerItem::tqparent() const { return static_cast( super::tqparent() ); } #include "layerlist.moc"