chalk

layerlist.cpp
1/*
2 Copyright (c) 2005 Gábor Lehel <illissius@gmail.com>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18*/
19
20
21#include "layerlist.h"
22
23#include <tqtooltip.h>
24#include <tqbitmap.h>
25#include <tqcursor.h>
26#include <tqimage.h>
27#include <tqheader.h>
28#include <tqpainter.h>
29#include <tqpixmap.h>
30#include <tqsimplerichtext.h>
31#include <tqtimer.h>
32
33#include <tdeapplication.h>
34#include <kdebug.h>
35#include <tdeglobal.h>
36#include <tdeglobalsettings.h>
37#include <kiconloader.h>
38#include <klineedit.h>
39#include <tdelocale.h>
40#include <tdepopupmenu.h>
41#include <kstringhandler.h>
42
43class LayerItemIterator: public TQListViewItemIterator
44{
45public:
46 LayerItemIterator( LayerList *list ): TQListViewItemIterator( list ) { }
47 LayerItemIterator( LayerList *list, IteratorFlag flags ): TQListViewItemIterator( list, flags ) { }
48 LayerItemIterator( LayerItem *item ): TQListViewItemIterator( item ) { }
49 LayerItemIterator( LayerItem *item, IteratorFlag flags ): TQListViewItemIterator( item, flags ) { }
50 LayerItem *operator*() { return static_cast<LayerItem*>( TQListViewItemIterator::operator*() ); }
51};
52
53struct LayerProperty
54{
55 TQString name;
56 TQString displayName;
57 TQPixmap enabledIcon;
58 TQPixmap disabledIcon;
59 bool defaultValue;
60 bool validForFolders;
61
62 LayerProperty(): defaultValue( false ), validForFolders( true ) { }
63 LayerProperty( const TQString &pname, const TQString &pdisplayName, const TQPixmap &enabled, const TQPixmap &disabled,
64 bool pdefaultValue, bool pvalidForFolders )
65 : name( pname ),
66 displayName( pdisplayName ),
67 enabledIcon( enabled ),
68 disabledIcon( disabled ),
69 defaultValue( pdefaultValue ),
70 validForFolders( pvalidForFolders )
71 { }
72};
73
74class LayerToolTip;
75class LayerList::Private
76{
77public:
78 LayerItem *activeLayer;
79 bool foldersCanBeActive;
80 bool previewsShown;
81 int itemHeight;
82 TQValueList<LayerProperty> properties;
83 TDEPopupMenu contextMenu;
84 LayerToolTip *tooltip;
85
86 Private( TQWidget *parent, LayerList *list );
87 ~Private();
88};
89
90class LayerItem::Private
91{
92public:
93 bool isFolder;
94 int id;
95 TQValueList<bool> properties;
96 TQImage *previewImage;
97 bool previewChanged;
98 TQPixmap scaledPreview;
99 TQSize previewSize;
100 TQPoint previewOffset;
101
102 Private( int pid ): isFolder( false ), id( pid ), previewImage( 0 ), previewChanged( false )
103 { }
104};
105
106static const int MAX_SIZE = 256;
107class LayerToolTip: public TQToolTip, public TQFrame
108{
109 LayerList *m_list;
110 LayerItem *m_item;
111 TQPoint m_pos;
112 TQTimer m_timer;
113 TQImage m_img;
114
115public:
116 LayerToolTip( TQWidget *parent, LayerList *list )
117 : TQToolTip( parent ),
118 TQFrame( 0, 0, WStyle_Customize | WStyle_NoBorder | WStyle_Tool | WStyle_StaysOnTop | WX11BypassWM | WNoAutoErase ),
119 m_list( list )
120 {
121 TQFrame::setPalette( TQToolTip::palette() );
122 connect( &m_timer, TQ_SIGNAL( timeout() ), m_list, TQ_SLOT( hideTip() ) );
123 tqApp->installEventFilter( this );
124 }
125
126 virtual void maybeTip( const TQPoint &pos )
127 {
128 m_pos = pos;
129 LayerItem *prev = m_item;
130 m_item = static_cast<LayerItem*>(m_list->itemAt( m_pos ));
131 if( TQToolTip::parentWidget() && m_list->showToolTips() && m_item )
132 {
133 if( m_item != prev )
134 hideTip();
135 showTip();
136 }
137 else
138 hideTip();
139 }
140
141 void showTip()
142 {
143 m_img = m_item->tooltipPreview();
144 m_timer.start( 15000, true );
145 if( !isVisible() || sizeHint() != size() )
146 {
147 resize( sizeHint() );
148 position();
149 }
150 if( !isVisible() )
151 show();
152 else
153 update();
154 }
155
156 void hideTip()
157 {
158 if( !isVisible() )
159 return;
160 TQFrame::hide();
161 TQToolTip::hide();
162 m_timer.stop();
163 m_img.reset();
164 m_list->triggerUpdate();
165 }
166
167 virtual void drawContents( TQPainter *painter )
168 {
169 TQPixmap buf( width(), height() );
170 TQPainter p( &buf );
171 buf.fill( colorGroup().background() );
172 p.setPen( colorGroup().foreground() );
173 p.drawRect( buf.rect() );
174
175 TQSimpleRichText text( m_item->tooltip(), TQToolTip::font() );
176 text.setWidth( TQCOORD_MAX );
177
178 p.translate( 5, 5 );
179 if( !m_img.isNull() )
180 {
181 if( m_img.width() > MAX_SIZE || m_img.height() > MAX_SIZE )
182 m_img = m_img.scale( MAX_SIZE, MAX_SIZE, TQImage::ScaleMin );
183 int y = 0;
184 if( m_img.height() < text.height() )
185 y = text.height()/2 - m_img.height()/2;
186 p.drawImage( 0, y, m_img );
187 p.drawRect( -1, y-1, m_img.width()+2, m_img.height()+2 );
188 p.translate( m_img.width() + 10, 0 );
189 }
190
191 text.draw( &p, 0, 0, rect(), colorGroup() );
192
193 painter->drawPixmap( 0, 0, buf );
194 }
195
196 virtual TQSize sizeHint() const
197 {
198 if( !m_item )
199 return TQSize( 0, 0 );
200
201 TQSimpleRichText text( m_item->tooltip(), TQToolTip::font() );
202 text.setWidth( TQCOORD_MAX );
203
204 int width = text.widthUsed();
205 if( !m_img.isNull() )
206 width += kMin( m_img.width(), MAX_SIZE ) + 10;
207 width += 10;
208
209 int height = text.height();
210 if( !m_img.isNull() && kMin( m_img.height(), MAX_SIZE ) > height )
211 height = kMin( m_img.height(), MAX_SIZE );
212 height += 10;
213
214 return TQSize( width, height );
215 }
216
217 void position()
218 {
219 const TQRect drect = TQApplication::desktop()->availableGeometry( TQToolTip::parentWidget() );
220 const TQSize size = sizeHint();
221 const int width = size.width(), height = size.height();
222 const TQRect tmp = m_item->rect();
223 const TQRect irect( m_list->viewport()->mapToGlobal( m_list->contentsToViewport(tmp.topLeft()) ), tmp.size() );
224
225 int y;
226 if( irect.bottom() + height < drect.bottom() )
227 y = irect.bottom();
228 else
229 y = kMax( drect.top(), irect.top() - height );
230
231 int x = kMax( drect.x(), TQToolTip::parentWidget()->mapToGlobal( m_pos ).x() - width/2 );
232 if( x + width > drect.right() )
233 x = drect.right() - width;
234
235 move( x, y );
236 }
237
238 virtual bool eventFilter( TQObject *, TQEvent *e )
239 {
240 if( isVisible() )
241 switch ( e->type() )
242 {
243 case TQEvent::KeyPress:
244 case TQEvent::KeyRelease:
245 case TQEvent::MouseButtonPress:
246 case TQEvent::MouseButtonRelease:
247 //case TQEvent::MouseMove:
248 case TQEvent::FocusIn:
249 case TQEvent::FocusOut:
250 case TQEvent::Wheel:
251 case TQEvent::Leave:
252 hideTip();
253 default: break;
254 }
255
256 return false;
257 }
258};
259
260LayerList::Private::Private( TQWidget *parent, LayerList *list )
261 : activeLayer( 0 ), foldersCanBeActive( false ), previewsShown( false ), itemHeight( 32 ),
262 tooltip( new LayerToolTip( parent, list ) ) { }
263
264LayerList::Private::~Private()
265{
266 delete tooltip;
267 tooltip = 0;
268}
269
270static int getID()
271{
272 static int id = -2;
273 return id--;
274}
275
276static TQSize iconSize() { return TQIconSet::iconSize( TQIconSet::Small ); }
277
278
280// LayerList //
282
283LayerList::LayerList( TQWidget *parent, const char *name )
284 : super( parent, name ), d( new Private( viewport(), this ) )
285{
286 setSelectionMode( TQListView::Extended );
287 setRootIsDecorated( true );
288 setSorting( -1 );
289 setSortColumn( -1 );
290 setAllColumnsShowFocus( true );
291 setFullWidth( true );
292 setItemsRenameable( false );
293 setDropHighlighter( true );
294 setDefaultRenameAction( TQListView::Accept );
295 setDragEnabled( true );
296 setAcceptDrops( true );
297 setItemsMovable( true );
298 addColumn( TQString() );
299 header()->hide();
300
301 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."));
302
303 setNumRows( 2 );
304
305 connect( this, TQ_SIGNAL( itemRenamed( TQListViewItem*, const TQString&, int ) ),
306 TQ_SLOT( slotItemRenamed( TQListViewItem*, const TQString&, int ) ) );
307 connect( this, TQ_SIGNAL( moved( TQPtrList<TQListViewItem>&, TQPtrList<TQListViewItem>&, TQPtrList<TQListViewItem>& ) ),
308 TQ_SLOT( slotItemMoved( TQPtrList<TQListViewItem>&, TQPtrList<TQListViewItem>&, TQPtrList<TQListViewItem>& ) ) );
309 connect( this, TQ_SIGNAL( onItem( TQListViewItem* ) ), TQ_SLOT( hideTip() ) );
310 connect( this, TQ_SIGNAL( onViewport() ), TQ_SLOT( hideTip() ) );
311}
312
313LayerList::~LayerList()
314{
315 delete d;
316}
317
318void LayerList::addProperty( const TQString &name, const TQString &displayName, const TQIconSet &icon,
319 bool defaultValue, bool validForFolders )
320{
321 addProperty( name, displayName, icon.pixmap( TQIconSet::Small, TQIconSet::Normal ), icon.pixmap( TQIconSet::Small, TQIconSet::Disabled ), defaultValue, validForFolders );
322}
323
324void LayerList::addProperty( const TQString &name, const TQString &displayName, TQPixmap enabled, TQPixmap disabled,
325 bool defaultValue, bool validForFolders )
326{
327 d->properties.append( LayerProperty( name, displayName, enabled, disabled, defaultValue, validForFolders ) );
328
329 for( LayerItemIterator it( this ); *it; ++it )
330 (*it)->d->properties.append( defaultValue );
331
332 //we do this only afterwards in case someone wants to access the other items in a connected slot...
333 for( LayerItemIterator it( this ); *it; ++it )
334 if( validForFolders || !(*it)->isFolder() )
335 {
336 emit propertyChanged( *it, name, defaultValue );
337 emit propertyChanged( (*it)->id(), name, defaultValue );
338 }
339
340 triggerUpdate();
341}
342
343LayerItem *LayerList::layer( int id ) const
344{
345 if( !firstChild() || id == -1 )
346 return 0;
347
348 for( LayerItemIterator it( firstChild() ); *it; ++it )
349 if( (*it)->id() == id )
350 return (*it);
351
352 return 0;
353}
354
355LayerItem *LayerList::folder( int id ) const
356{
357 if( !firstChild() || id == -1 )
358 return 0;
359
360 for( LayerItemIterator it( firstChild() ); *it; ++it )
361 if( (*it)->id() == id && (*it)->isFolder() )
362 return (*it);
363
364 return 0;
365}
366
367LayerItem *LayerList::activeLayer() const
368{
369 return d->activeLayer;
370}
371
372int LayerList::activeLayerID() const
373{
374 if( activeLayer() )
375 return activeLayer()->id();
376 return -1;
377}
378
379TQValueList<LayerItem*> LayerList::selectedLayers() const
380{
381 if( !firstChild() )
382 return TQValueList<LayerItem*>();
383
384 TQValueList<LayerItem*> layers;
385 for( LayerItemIterator it( firstChild() ); *it; ++it )
386 if( (*it)->isSelected() )
387 layers.append( *it );
388
389 return layers;
390}
391
392TQValueList<int> LayerList::selectedLayerIDs() const
393{
394 const TQValueList<LayerItem*> layers = selectedLayers();
395 TQValueList<int> ids;
396 for( int i = 0, n = layers.count(); i < n; ++i )
397 ids.append( layers[i]->id() );
398
399 return ids;
400}
401
402bool LayerList::foldersCanBeActive() const
403{
404 return d->foldersCanBeActive;
405}
406
407bool LayerList::previewsShown() const
408{
409 return d->previewsShown;
410}
411
412int LayerList::itemHeight() const
413{
414 return d->itemHeight;
415}
416
417int LayerList::numRows() const
418{
419 if( itemHeight() < kMax( fontMetrics().height(), iconSize().height() ) )
420 return 0;
421
422 return ( itemHeight() - fontMetrics().height() ) / iconSize().height() + 1;
423}
424
425void LayerList::makeFolder( int id )
426{
427 LayerItem* const l = layer( id );
428 if( l )
429 l->makeFolder();
430}
431
432bool LayerList::isFolder( int id ) const
433{
434 LayerItem* const l = layer( id );
435 if( !l )
436 return false;
437
438 return l->isFolder();
439}
440
441TQString LayerList::displayName( int id ) const
442{
443 LayerItem* const l = layer( id );
444 if( !l )
445 return TQString(); //should be more severe...
446
447 return l->displayName();
448}
449
450bool LayerList::property( int id, const TQString &name ) const
451{
452 LayerItem* const l = layer( id );
453 if( !l )
454 return false; //should be more severe...
455
456 return l->property( name );
457}
458
459TDEPopupMenu *LayerList::contextMenu() const
460{
461 return &( d->contextMenu );
462}
463
464void LayerList::setFoldersCanBeActive( bool can ) //SLOT
465{
466 d->foldersCanBeActive = can;
467 if( !can && activeLayer() && activeLayer()->isFolder() )
468 {
469 d->activeLayer = 0;
470 emit activated( static_cast<LayerItem*>( 0 ) );
471 emit activated( -1 );
472 }
473}
474
475void LayerList::setPreviewsShown( bool show ) //SLOT
476{
477 d->previewsShown = show;
478 triggerUpdate();
479}
480
481void LayerList::setItemHeight( int height ) //SLOT
482{
483 d->itemHeight = height;
484 for( LayerItemIterator it( this ); *it; ++it )
485 (*it)->setup();
486 triggerUpdate();
487}
488
489void LayerList::setNumRows( int rows )
490{
491 if( rows < 1 )
492 return;
493
494 if( rows == 1 )
495 setItemHeight( kMax( fontMetrics().height(), iconSize().height() ) );
496 else
497 setItemHeight( fontMetrics().height() + ( rows - 1 ) * iconSize().height() );
498}
499
500void LayerList::setActiveLayer( LayerItem *layer ) //SLOT
501{
502 if( !foldersCanBeActive() && layer && layer->isFolder() )
503 return;
504
505 ensureItemVisible( layer );
506
507 if( d->activeLayer == layer )
508 return;
509
510 d->activeLayer = layer;
511
512 if( currentItem() != layer )
513 setCurrentItem( layer );
514 else
515 {
516 int n = 0;
517 for( LayerItemIterator it( this, LayerItemIterator::Selected ); n < 2 && (*it); ++it ) { n++; }
518 if( n == 1 )
519 (*LayerItemIterator( this, LayerItemIterator::Selected ))->setSelected( false );
520 if( layer )
521 layer->setSelected( true );
522 }
523
524 emit activated( layer );
525 if( layer )
526 emit activated( layer->id() );
527 else
528 emit activated( -1 );
529}
530
531void LayerList::setActiveLayer( int id ) //SLOT
532{
533 setActiveLayer( layer( id ) );
534}
535
536void LayerList::setLayerDisplayName( LayerItem *layer, const TQString &displayName )
537{
538 if( !layer )
539 return;
540
541 layer->setDisplayName( displayName );
542}
543
544void LayerList::setLayerDisplayName( int id, const TQString &displayName )
545{
546 setLayerDisplayName( layer( id ), displayName );
547}
548
549void LayerList::setLayerProperty( LayerItem *layer, const TQString &name, bool on ) //SLOT
550{
551 if( !layer )
552 return;
553
554 layer->setProperty( name, on );
555}
556
557void LayerList::setLayerProperty( int id, const TQString &name, bool on ) //SLOT
558{
559 setLayerProperty( layer( id ), name, on );
560}
561
562void LayerList::toggleLayerProperty( LayerItem *layer, const TQString &name ) //SLOT
563{
564 if( !layer )
565 return;
566
567 layer->toggleProperty( name );
568}
569
570void LayerList::toggleLayerProperty( int id, const TQString &name ) //SLOT
571{
572 toggleLayerProperty( layer( id ), name );
573}
574
575void LayerList::setLayerPreviewImage( LayerItem *layer, TQImage *image )
576{
577 if( !layer )
578 return;
579
580 layer->setPreviewImage( image );
581}
582
583void LayerList::setLayerPreviewImage( int id, TQImage *image )
584{
585 setLayerPreviewImage( layer( id ), image );
586}
587
588void LayerList::layerPreviewChanged( LayerItem *layer )
589{
590 if( !layer )
591 return;
592
593 layer->previewChanged();
594}
595
596void LayerList::layerPreviewChanged( int id )
597{
598 layerPreviewChanged( layer( id ) );
599}
600
601LayerItem *LayerList::addLayer( const TQString &displayName, LayerItem *after, int id ) //SLOT
602{
603 return new LayerItem( displayName, this, after, id );
604}
605
606LayerItem *LayerList::addLayer( const TQString &displayName, int afterID, int id ) //SLOT
607{
608 return new LayerItem( displayName, this, layer( afterID ), id );
609}
610
611//SLOT
612LayerItem *LayerList::addLayerToParent( const TQString &displayName, LayerItem *parent, LayerItem *after, int id )
613{
614 if( parent && parent->isFolder() )
615 return parent->addLayer( displayName, after, id );
616 else
617 return 0;
618}
619
620LayerItem *LayerList::addLayerToParent( const TQString &displayName, int parentID, int afterID, int id ) //SLOT
621{
622 return addLayerToParent( displayName, folder( parentID ), layer( afterID ), id );
623}
624
625void LayerList::moveLayer( LayerItem *layer, LayerItem *parent, LayerItem *after ) //SLOT
626{
627 if( !layer )
628 return;
629
630 if( parent && !parent->isFolder() )
631 parent = 0;
632
633 if( layer->parent() == parent && layer->prevSibling() == after )
634 return;
635
636 TQListViewItem *current = currentItem();
637
638 moveItem( layer, parent, after );
639
640 emit layerMoved( layer, parent, after );
641 emit layerMoved( layer->id(), parent ? parent->id() : -1, after ? after->id() : -1 );
642
643 setCurrentItem( current ); //HACK, sometimes TQt changes this under us
644}
645
646void LayerList::moveLayer( int id, int parentID, int afterID ) //SLOT
647{
648 moveLayer( layer( id ), folder( parentID ), layer( afterID ) );
649}
650
651void LayerList::removeLayer( LayerItem *layer ) //SLOT
652{
653 delete layer;
654}
655
656void LayerList::removeLayer( int id ) //SLOT
657{
658 delete layer( id );
659}
660
661void LayerList::contentsMousePressEvent( TQMouseEvent *e )
662{
663 LayerItem *item = static_cast<LayerItem*>( itemAt( contentsToViewport( e->pos() ) ) );
664
665 if( item )
666 {
667 TQMouseEvent m( TQEvent::MouseButtonPress, item->mapFromListView( e->pos() ), e->button(), e->state() );
668 if( !item->mousePressEvent( &m ) )
669 super::contentsMousePressEvent( e );
670 }
671 else
672 {
673 super::contentsMousePressEvent( e );
674 if( e->button() == TQt::RightButton )
675 showContextMenu();
676 }
677}
678
679void LayerList::contentsMouseDoubleClickEvent( TQMouseEvent *e )
680{
681 super::contentsMouseDoubleClickEvent( e );
682 if( LayerItem *layer = static_cast<LayerItem*>( itemAt( contentsToViewport( e->pos() ) ) ) )
683 {
684 if( !layer->iconsRect().contains( layer->mapFromListView( e->pos() ) ) )
685 {
686 emit requestLayerProperties( layer );
687 emit requestLayerProperties( layer->id() );
688 }
689 }
690 else
691 {
692 emit requestNewLayer( static_cast<LayerItem*>( 0 ), static_cast<LayerItem*>( 0 ) );
693 emit requestNewLayer( -1, -1 );
694 }
695}
696
697void LayerList::findDrop( const TQPoint &pos, TQListViewItem *&parent, TQListViewItem *&after )
698{
699 LayerItem *item = static_cast<LayerItem*>( itemAt( contentsToViewport( pos ) ) );
700 if( item && item->isFolder() )
701 {
702 parent = item;
703 after = 0;
704 }
705 else
706 super::findDrop( pos, parent, after );
707}
708
709void LayerList::showContextMenu()
710{
711 LayerItem *layer = static_cast<LayerItem*>( itemAt( viewport()->mapFromGlobal( TQCursor::pos() ) ) );
712 if( layer )
713 setCurrentItem( layer );
714 d->contextMenu.clear();
715 constructMenu( layer );
716 menuActivated( d->contextMenu.exec( TQCursor::pos() ), layer );
717}
718
719void LayerList::hideTip()
720{
721 d->tooltip->hideTip();
722}
723
724void LayerList::maybeTip()
725{
726 d->tooltip->maybeTip( d->tooltip->TQToolTip::parentWidget()->mapFromGlobal( TQCursor::pos() ) );
727}
728
729void LayerList::constructMenu( LayerItem *layer )
730{
731 if( layer )
732 {
733 for( int i = 0, n = d->properties.count(); i < n; ++i )
734 if( !layer->isFolder() || d->properties[i].validForFolders )
735 d->contextMenu.insertItem( layer->d->properties[i] ? d->properties[i].enabledIcon : d->properties[i].disabledIcon, d->properties[i].displayName, MenuItems::COUNT + i );
736 d->contextMenu.insertItem( SmallIconSet( "application-vnd.tde.info" ), i18n( "&Properties" ), MenuItems::LayerProperties );
737 d->contextMenu.insertSeparator();
738 d->contextMenu.insertItem( SmallIconSet( "edit-delete" ),
739 selectedLayers().count() > 1 ? i18n( "Remove Layers" )
740 : layer->isFolder() ? i18n( "&Remove Folder" )
741 : i18n( "&Remove Layer" ), MenuItems::RemoveLayer );
742 }
743 d->contextMenu.insertItem( SmallIconSet( "document-new" ), i18n( "&New Layer" ), MenuItems::NewLayer );
744 d->contextMenu.insertItem( SmallIconSet( "folder" ), i18n( "New &Folder" ), MenuItems::NewFolder );
745}
746
747void LayerList::menuActivated( int id, LayerItem *layer )
748{
749 const TQValueList<LayerItem*> selected = selectedLayers();
750
751 LayerItem *parent = ( layer && layer->isFolder() ) ? layer : 0;
752 LayerItem *after = 0;
753 if( layer && !parent )
754 {
755 parent = layer->parent();
756 after = layer->prevSibling();
757 }
758 switch( id )
759 {
760 case MenuItems::NewLayer:
761 emit requestNewLayer( parent, after );
762 emit requestNewLayer( parent ? parent->id() : -1, after ? after->id() : -1 );
763 break;
764 case MenuItems::NewFolder:
765 emit requestNewFolder( parent, after );
766 emit requestNewFolder( parent ? parent->id() : -1, after ? after->id() : -1 );
767 break;
768 case MenuItems::RemoveLayer:
769 {
770 TQValueList<int> ids;
771 for( int i = 0, n = selected.count(); i < n; ++i )
772 {
773 ids.append( selected[i]->id() );
774 emit requestRemoveLayer( selected[i]->id() );
775 }
776 emit requestRemoveLayers( ids );
777 }
778 for( int i = 0, n = selected.count(); i < n; ++i )
779 emit requestRemoveLayer( selected[i] );
780 emit requestRemoveLayers( selected );
781 break;
782 case MenuItems::LayerProperties:
783 if( layer )
784 {
785 emit requestLayerProperties( layer );
786 emit requestLayerProperties( layer->id() );
787 }
788 break;
789 default:
790 if( id >= MenuItems::COUNT && layer )
791 for( int i = 0, n = selected.count(); i < n; ++i )
792 selected[i]->toggleProperty( d->properties[ id - MenuItems::COUNT ].name );
793 }
794}
795
796void LayerList::slotItemRenamed( TQListViewItem *item, const TQString &text, int col )
797{
798 if( !item || col != 0 )
799 return;
800
801 emit displayNameChanged( static_cast<LayerItem*>( item ), text );
802 emit displayNameChanged( static_cast<LayerItem*>( item )->id(), text );
803}
804
805void LayerList::slotItemMoved( TQPtrList<TQListViewItem> &items, TQPtrList<TQListViewItem> &/*afterBefore*/, TQPtrList<TQListViewItem> &afterNow )
806{
807 for( int i = 0, n = items.count(); i < n; ++i )
808 {
809 LayerItem *l = static_cast<LayerItem*>( items.at(i) ), *a = static_cast<LayerItem*>( afterNow.at(i) );
810 if( !l )
811 continue;
812
813 if( l->parent() )
814 l->parent()->setOpen( true );
815
816 emit layerMoved( l, l->parent(), a );
817 emit layerMoved( l->id(), l->parent() ? l->parent()->id() : -1, a ? a->id() : -1 );
818 }
819}
820
821void LayerList::setCurrentItem( TQListViewItem *item )
822{
823 if( !item )
824 return;
825
826 super::setCurrentItem( item );
827 ensureItemVisible( item );
828 int n = 0;
829 for( LayerItemIterator it( this, LayerItemIterator::Selected ); n < 2 && (*it); ++it ) { n++; }
830 if( n == 1 )
831 (*LayerItemIterator( this, LayerItemIterator::Selected ))->setSelected( false );
832 item->setSelected( true );
833 if( activeLayer() != item )
834 setActiveLayer( static_cast<LayerItem*>(item) );
835}
836
837
839// LayerItem //
841
842LayerItem::LayerItem( const TQString &displayName, LayerList *p, LayerItem *after, int id )
843 : super( p, after ), d( new Private( id ) )
844{
845 init();
846 setDisplayName( displayName );
847}
848
849LayerItem::LayerItem( const TQString &displayName, LayerItem *p, LayerItem *after, int id )
850 : super( ( p && p->isFolder() ) ? p : 0, after ), d( new Private( id ) )
851{
852 init();
853 setDisplayName( displayName );
854}
855
856void LayerItem::init()
857{
858 if( d->id < 0 )
859 d->id = getID();
860
861 for( int i = 0, n = listView()->d->properties.count(); i < n; ++i )
862 d->properties.append( listView()->d->properties[i].defaultValue );
863
864 if( parent())
865 parent()->setOpen( true );
866}
867
868LayerItem::~LayerItem()
869{
870 if (listView() && (listView()->activeLayer() == this || contains(listView()->activeLayer())))
871 listView()->setActiveLayer( static_cast<LayerItem*>( 0 ) );
872 delete d;
873}
874
875void LayerItem::makeFolder()
876{
877 d->isFolder = true;
878 setPixmap( 0, SmallIcon( "folder", 16 ) );
879 if( isActive() && !listView()->foldersCanBeActive() )
880 listView()->setActiveLayer( static_cast<LayerItem*>( 0 ) );
881}
882
883bool LayerItem::isFolder() const
884{
885 return d->isFolder;
886}
887
888bool LayerItem::contains(const LayerItem *item)
889{
890 TQListViewItemIterator it(this);
891
892 while (it.current()) {
893 if (static_cast<const LayerItem *>(it.current()) == item) {
894 return true;
895 }
896 ++it;
897 }
898 return false;
899}
900
901int LayerItem::id() const
902{
903 return d->id;
904}
905
906TQString LayerItem::displayName() const
907{
908 return text( 0 );
909}
910
911void LayerItem::setDisplayName( const TQString &s )
912{
913 if( displayName() == s )
914 return;
915 setText( 0, s );
916 emit listView()->displayNameChanged( this, s );
917 emit listView()->displayNameChanged( id(), s );
918}
919
920bool LayerItem::isActive() const
921{
922 return listView()->activeLayer() == this;
923}
924
925void LayerItem::setActive()
926{
927 listView()->setActiveLayer( this );
928}
929
930bool LayerItem::property( const TQString &name ) const
931{
932 int i = listView()->d->properties.count() - 1;
933 while( i && listView()->d->properties[i].name != name )
934 --i;
935
936 if( i < 0 )
937 return false; //should do something more severe... but what?
938
939 return d->properties[i];
940}
941
942void LayerItem::setProperty( const TQString &name, bool on )
943{
944 int i = listView()->d->properties.count() - 1;
945 while( i && listView()->d->properties[i].name != name )
946 --i;
947
948 if( i < 0 || ( isFolder() && !listView()->d->properties[i].validForFolders ) )
949 return;
950
951 const bool notify = ( on != d->properties[i] );
952 d->properties[i] = on;
953 if( notify )
954 {
955 emit listView()->propertyChanged( this, name, on );
956 emit listView()->propertyChanged( id(), name, on );
957 }
958
959 update();
960}
961
962void LayerItem::toggleProperty( const TQString &name )
963{
964 int i = listView()->d->properties.count() - 1;
965 while( i && listView()->d->properties[i].name != name )
966 --i;
967
968 if( i < 0 || ( isFolder() && !listView()->d->properties[i].validForFolders ) )
969 return;
970
971 d->properties[i] = !(d->properties[i]);
972 emit listView()->propertyChanged( this, name, d->properties[i] );
973 emit listView()->propertyChanged( id(), name, d->properties[i] );
974
975 update();
976}
977
978void LayerItem::setPreviewImage( TQImage *image )
979{
980 d->previewImage = image;
981 previewChanged();
982}
983
984void LayerItem::previewChanged()
985{
986 d->previewChanged = true;
987 update();
988}
989
990LayerItem *LayerItem::addLayer( const TQString &displayName, LayerItem *after, int id )
991{
992 if( !isFolder() )
993 return 0;
994 return new LayerItem( displayName, this, after, id );
995}
996
997LayerItem *LayerItem::prevSibling() const
998{
999 LayerItem *item = parent() ? parent()->firstChild() : listView()->firstChild();
1000 if( !item || this == item )
1001 return 0;
1002 for(; item && this != item->nextSibling(); item = item->nextSibling() );
1003 return item;
1004}
1005
1006int LayerItem::mapXFromListView( int x ) const
1007{
1008 return x - rect().left();
1009}
1010
1011int LayerItem::mapYFromListView( int y ) const
1012{
1013 return y - rect().top();
1014}
1015
1016TQPoint LayerItem::mapFromListView( const TQPoint &point ) const
1017{
1018 return TQPoint( mapXFromListView( point.x() ), mapYFromListView( point.y() ) );
1019}
1020
1021TQRect LayerItem::mapFromListView( const TQRect &rect ) const
1022{
1023 return TQRect( mapFromListView( rect.topLeft() ), rect.size() );
1024}
1025
1026int LayerItem::mapXToListView( int x ) const
1027{
1028 return x + rect().left();
1029}
1030
1031int LayerItem::mapYToListView( int y ) const
1032{
1033 return y + rect().top();
1034}
1035
1036TQPoint LayerItem::mapToListView( const TQPoint &point ) const
1037{
1038 return TQPoint( mapXToListView( point.x() ), mapYToListView( point.y() ) );
1039}
1040
1041TQRect LayerItem::mapToListView( const TQRect &rect ) const
1042{
1043 return TQRect( mapToListView( rect.topLeft() ), rect.size() );
1044}
1045
1046TQRect LayerItem::rect() const
1047{
1048 const int indent = listView()->treeStepSize() * ( depth() + 1 );
1049 return TQRect( listView()->header()->sectionPos( 0 ) + indent, itemPos(),
1050 listView()->header()->sectionSize( 0 ) - indent, height() );
1051}
1052
1053TQRect LayerItem::textRect() const
1054{
1055 static TQFont f;
1056 static int minbearing = 1337 + 666; //can be 0 or negative, 2003 is less likely
1057 if( minbearing == 2003 || f != font() )
1058 {
1059 f = font(); //getting your bearings can be expensive, so we cache them
1060 minbearing = fontMetrics().minLeftBearing() + fontMetrics().minRightBearing();
1061 }
1062
1063 const int margin = listView()->itemMargin();
1064 int indent = previewRect().right() + margin;
1065 if( pixmap( 0 ) )
1066 indent += pixmap( 0 )->width() + margin;
1067
1068 const int width = ( multiline() ? rect().right() : iconsRect().left() ) - indent - margin + minbearing;
1069
1070 return TQRect( indent, 0, width, fontMetrics().height() );
1071}
1072
1073TQRect LayerItem::iconsRect() const
1074{
1075 const TQValueList<LayerProperty> &lp = listView()->d->properties;
1076 int propscount = 0;
1077 for( int i = 0, n = lp.count(); i < n; ++i )
1078 if( !lp[i].enabledIcon.isNull() && ( !multiline() || !isFolder() || lp[i].validForFolders ) )
1079 propscount++;
1080
1081 const int iconswidth = propscount * iconSize().width() + (propscount - 1) * listView()->itemMargin();
1082
1083 const int x = multiline() ? previewRect().right() + listView()->itemMargin() : rect().width() - iconswidth;
1084 const int y = multiline() ? fontMetrics().height() : 0;
1085
1086 return TQRect( x, y, iconswidth, iconSize().height() );
1087}
1088
1089TQRect LayerItem::previewRect() const
1090{
1091 return TQRect( 0, 0, listView()->previewsShown() ? height() : 0, height() );
1092}
1093
1094void LayerItem::drawText( TQPainter *p, const TQColorGroup &cg, const TQRect &r )
1095{
1096 p->translate( r.left(), r.top() );
1097
1098 p->setPen( isSelected() ? cg.highlightedText() : cg.text() );
1099
1100 const TQString text = KStringHandler::rPixelSqueeze( displayName(), p->fontMetrics(), r.width() );
1101 p->drawText( listView()->itemMargin(), 0, r.width(), r.height(), TQt::AlignAuto | TQt::AlignTop, text );
1102
1103 p->translate( -r.left(), -r.top() );
1104}
1105
1106void LayerItem::drawIcons( TQPainter *p, const TQColorGroup &/*cg*/, const TQRect &r )
1107{
1108 p->translate( r.left(), r.top() );
1109
1110 int x = 0;
1111 const TQValueList<LayerProperty> &lp = listView()->d->properties;
1112 for( int i = 0, n = lp.count(); i < n; ++i )
1113 if( !lp[i].enabledIcon.isNull() && ( !multiline() || !isFolder() || lp[i].validForFolders ) )
1114 {
1115 if( !isFolder() || lp[i].validForFolders )
1116 p->drawPixmap( x, 0, d->properties[i] ? lp[i].enabledIcon : lp[i].disabledIcon );
1117 x += iconSize().width() + listView()->itemMargin();
1118 }
1119
1120 p->translate( -r.left(), -r.top() );
1121}
1122
1123void LayerItem::drawPreview( TQPainter *p, const TQColorGroup &/*cg*/, const TQRect &r )
1124{
1125 if( !showPreview() )
1126 return;
1127
1128 if( d->previewChanged || r.size() != d->previewSize )
1129 { //TODO handle width() != height()
1130 const int size = kMin( r.width(), kMax( previewImage()->width(), previewImage()->height() ) );
1131 const TQImage i = previewImage()->smoothScale( size, size, TQImage::ScaleMin );
1132 d->scaledPreview.convertFromImage( i );
1133 d->previewOffset.setX( r.width()/2 - i.width()/2 );
1134 d->previewOffset.setY( r.height()/2 - i.height()/2 );
1135
1136 d->previewChanged = false;
1137 d->previewSize = r.size();
1138 }
1139
1140 p->drawPixmap( r.topLeft() + d->previewOffset, d->scaledPreview );
1141}
1142
1143bool LayerItem::showPreview() const
1144{
1145 return listView()->previewsShown() && previewImage() && !previewImage()->isNull();
1146}
1147
1148bool LayerItem::multiline() const
1149{
1150 return height() >= fontMetrics().height() + iconSize().height();
1151}
1152
1153TQFont LayerItem::font() const
1154{
1155 if( isActive() )
1156 {
1157 TQFont f = listView()->font();
1158 f.setBold( !f.bold() );
1159 f.setItalic( !f.italic() );
1160 return f;
1161 }
1162 else
1163 return listView()->font();
1164}
1165
1166TQFontMetrics LayerItem::fontMetrics() const
1167{
1168 return TQFontMetrics( font() );
1169}
1170
1171bool LayerItem::mousePressEvent( TQMouseEvent *e )
1172{
1173 if( e->button() == TQt::RightButton )
1174 {
1175 if ( !(e->state() & TQt::ControlButton) && !(e->state() & TQt::ShiftButton) )
1176 setActive();
1177 TQTimer::singleShot( 0, listView(), TQ_SLOT( showContextMenu() ) );
1178 return false;
1179 }
1180
1181 const TQRect ir = iconsRect(), tr = textRect();
1182
1183 if( ir.contains( e->pos() ) )
1184 {
1185 const int iconWidth = iconSize().width();
1186 int x = e->pos().x() - ir.left();
1187 if( x % ( iconWidth + listView()->itemMargin() ) < iconWidth ) //it's on an icon, not a margin
1188 {
1189 const TQValueList<LayerProperty> &lp = listView()->d->properties;
1190 int p = -1;
1191 for( int i = 0, n = lp.count(); i < n; ++i )
1192 {
1193 if( !lp[i].enabledIcon.isNull() && ( !multiline() || !isFolder() || lp[i].validForFolders ) )
1194 x -= iconWidth + listView()->itemMargin();
1195 p += 1;
1196 if( x < 0 )
1197 break;
1198 }
1199 toggleProperty( lp[p].name );
1200 }
1201 return true;
1202 }
1203
1204 else if( tr.contains( e->pos() ) && isSelected() && !listView()->renameLineEdit()->isVisible() )
1205 {
1206 listView()->rename( this, 0 );
1207 TQRect r( listView()->contentsToViewport( mapToListView( tr.topLeft() ) ), tr.size() );
1208 listView()->renameLineEdit()->setGeometry( r );
1209 return true;
1210 }
1211
1212 if ( !(e->state() & TQt::ControlButton) && !(e->state() & TQt::ShiftButton) )
1213 setActive();
1214
1215 return false;
1216}
1217
1218TQString LayerItem::tooltip() const
1219{
1220 TQString tip;
1221 tip += "<table cellspacing=\"0\" cellpadding=\"0\">";
1222 tip += TQString("<tr><td colspan=\"2\" align=\"center\"><b>%1</b></td></tr>").arg( displayName() );
1223 TQString row = "<tr><td>%1</td><td>%2</td></tr>";
1224 for( int i = 0, n = listView()->d->properties.count(); i < n; ++i )
1225 if( !isFolder() || listView()->d->properties[i].validForFolders )
1226 {
1227 if( d->properties[i] )
1228 tip += row.arg( i18n( "%1:" ).arg( listView()->d->properties[i].displayName ) ).arg( i18n( "Yes" ) );
1229 else
1230 tip += row.arg( i18n( "%1:" ).arg( listView()->d->properties[i].displayName ) ).arg( i18n( "No" ) );
1231 }
1232 tip += "</table>";
1233 return tip;
1234}
1235
1236TQImage *LayerItem::previewImage() const
1237{
1238 return d->previewImage;
1239}
1240
1241TQImage LayerItem::tooltipPreview() const
1242{
1243 if( previewImage() )
1244 return *previewImage();
1245 return TQImage();
1246}
1247
1248int LayerItem::width( const TQFontMetrics &fm, const TQListView *lv, int c ) const
1249{
1250 if( c != 0 )
1251 return super::width( fm, lv, c );
1252
1253 const TQValueList<LayerProperty> &lp = listView()->d->properties;
1254 int propscount = 0;
1255 for( int i = 0, n = d->properties.count(); i < n; ++i )
1256 if( !lp[i].enabledIcon.isNull() && ( !multiline() || !isFolder() || lp[i].validForFolders ) )
1257 propscount++;
1258
1259 const int iconswidth = propscount * iconSize().width() + (propscount - 1) * listView()->itemMargin();
1260
1261 if( multiline() )
1262 return kMax( super::width( fm, lv, 0 ), iconswidth );
1263 else
1264 return super::width( fm, lv, 0 ) + iconswidth;
1265}
1266
1267void LayerItem::paintCell( TQPainter *painter, const TQColorGroup &cg, int column, int width, int align )
1268{
1269 if( column != 0 )
1270 {
1271 super::paintCell( painter, cg, column, width, align );
1272 return;
1273 }
1274
1275 TQPixmap buf( width, height() );
1276 TQPainter p( &buf );
1277
1278 p.setFont( font() );
1279
1280 const TQColorGroup cg_ = isEnabled() ? listView()->palette().active() : listView()->palette().disabled();
1281
1282 const TQColor bg = isSelected() ? cg_.highlight()
1283 : isAlternate() ? listView()->alternateBackground()
1284 : listView()->viewport()->backgroundColor();
1285
1286 buf.fill( bg );
1287
1288 if( pixmap( 0 ) )
1289 p.drawPixmap( previewRect().right() + listView()->itemMargin(), 0, *pixmap( 0 ) );
1290
1291 drawText( &p, cg_, textRect() );
1292 drawIcons( &p, cg_, iconsRect() );
1293 drawPreview( &p, cg_, previewRect() );
1294
1295 painter->drawPixmap( 0, 0, buf );
1296}
1297
1298void LayerItem::setup()
1299{
1300 super::setup();
1301 setHeight( listView()->d->itemHeight );
1302}
1303
1304void LayerItem::setSelected( bool selected )
1305{
1306 if( !selected && ( isActive() || this == listView()->currentItem() ) )
1307 return;
1308 super::setSelected( selected );
1309}
1310
1311
1313// Convenience Methods //
1315
1316LayerItem *LayerList::firstChild() const { return static_cast<LayerItem*>( super::firstChild() ); }
1317LayerItem *LayerList::lastChild() const { return static_cast<LayerItem*>( super::lastChild() ); }
1318LayerList *LayerItem::listView() const { return static_cast<LayerList*>( super::listView() ); }
1319void LayerItem::update() const { listView()->repaintItem( this ); }
1320LayerItem *LayerItem::firstChild() const { return static_cast<LayerItem*>( super::firstChild() ); }
1321LayerItem *LayerItem::nextSibling() const { return static_cast<LayerItem*>( super::nextSibling() ); }
1322LayerItem *LayerItem::parent() const { return static_cast<LayerItem*>( super::parent() ); }
1323
1324
1325#include "layerlist.moc"