less Q3 (remove a lot of unused Q3 headers, port small things)
[kdenetwork.git] / kopete / libkopete / ui / kopetelistviewitem.cpp
bloba728d866cbcf97c2a21e997d9653c8b166de3416
1 /*
2 kopetelistviewitem.cpp - Kopete's modular QListViewItems
4 Copyright (c) 2005 by Engin AYDOGAN <engin@bzzzt.biz>
5 Copyright (c) 2004 by Richard Smith <kde@metafoo.co.uk>
7 Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
9 *************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 *************************************************************************
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
23 #include "kopetecontact.h"
24 #include "kopetelistviewitem.h"
25 #include "kopeteemoticons.h"
26 #include "kopeteonlinestatus.h"
28 #include <kdebug.h>
29 #include <kiconloader.h>
30 #include <kstringhandler.h>
32 #include <qapplication.h>
33 #include <qpixmap.h>
34 #include <qpainter.h>
35 #include <qrect.h>
36 #include <qtimer.h>
37 #include <q3header.h>
38 #include <qstyle.h>
39 #include <qstyleoption.h>
40 //Added by qt3to4:
41 #include <QList>
43 #ifdef HAVE_XRENDER
44 # include <X11/Xlib.h>
45 # include <X11/extensions/Xrender.h>
46 #endif
48 #include <limits.h>
50 namespace Kopete {
51 namespace UI {
52 namespace ListView {
54 // ComponentBase --------
56 class ComponentBase::Private
58 public:
59 QList<Component*> components;
62 ComponentBase::ComponentBase()
63 : d( new Private )
67 ComponentBase::~ComponentBase()
69 foreach( Component *c , d->components )
70 delete c;
71 delete d;
74 uint ComponentBase::components() { return d->components.count(); }
76 Component *ComponentBase::component( uint n )
78 if( n < components() )
79 return d->components.at( n );
80 return 0l;
84 Component *ComponentBase::componentAt( const QPoint &pt )
86 foreach( Component* n , d->components )
88 if ( n->rect().contains( pt ) )
90 if ( Component *comp = n->componentAt( pt ) )
91 return comp;
92 return n;
95 return 0;
98 void ComponentBase::componentAdded( Component *component )
100 d->components.append( component );
103 void ComponentBase::componentRemoved( Component *component )
105 //TODO: make sure the component is in d->components once and only once.
106 // if not, the situation is best referred to as 'very very broken indeed'.
107 d->components.removeAll( component );
110 void ComponentBase::clear()
112 foreach( Component *c , d->components )
113 delete c;
114 d->components.clear();
117 void ComponentBase::componentResized( Component * )
121 std::pair<QString,QRect> ComponentBase::toolTip( const QPoint &relativePos )
123 foreach( Component* n , d->components )
124 if ( n->rect().contains( relativePos ) )
125 return n->toolTip( relativePos );
127 return std::make_pair( QString::null, QRect() );
130 void ComponentBase::updateAnimationPosition( int p, int s )
132 foreach( Component* comp , d->components )
134 QRect start = comp->startRect();
135 QRect target = comp->targetRect();
136 QRect rc( start.left() + ((target.left() - start.left()) * p) / s,
137 start.top() + ((target.top() - start.top()) * p) / s,
138 start.width() + ((target.width() - start.width()) * p) / s,
139 start.height() + ((target.height() - start.height()) * p) / s );
140 comp->setRect( rc );
141 comp->updateAnimationPosition( p, s );
145 // Component --------
147 class Component::Private
149 public:
150 Private( ComponentBase *parent )
151 : parent( parent ), minWidth( 0 ), minHeight( 0 )
152 , growHoriz( false ), growVert( false )
153 , tipSource( 0 )
156 ComponentBase *parent;
157 QRect rect;
158 QRect startRect, targetRect;
159 int minWidth, minHeight;
160 bool growHoriz, growVert;
161 bool show; /** @since 23-03-2005 */
162 ToolTipSource *tipSource;
165 Component::Component( ComponentBase *parent )
166 : d( new Private( parent ) )
168 d->parent->componentAdded( this );
169 d->show = true;
172 int Component::RTTI = Rtti_Component;
174 Component::~Component()
176 d->parent->componentRemoved( this );
177 delete d;
181 void Component::hide()
183 d->show = false;
186 void Component::show()
188 d->show = true;
191 bool Component::isShown()
193 return d->show;
196 bool Component::isHidden()
198 return !d->show;
201 void Component::setToolTipSource( ToolTipSource *source )
203 d->tipSource = source;
206 std::pair<QString,QRect> Component::toolTip( const QPoint &relativePos )
208 if ( !d->tipSource )
209 return ComponentBase::toolTip( relativePos );
211 QRect rc = rect();
212 QString result = (*d->tipSource)( this, relativePos, rc );
213 return std::make_pair(result, rc);
216 QRect Component::rect() { return d->rect; }
217 QRect Component::startRect() { return d->startRect; }
218 QRect Component::targetRect() { return d->targetRect; }
220 int Component::minWidth() { return d->minWidth; }
221 int Component::minHeight() { return d->minHeight; }
222 int Component::widthForHeight( int ) { return minWidth(); }
223 int Component::heightForWidth( int ) { return minHeight(); }
225 bool Component::setMinWidth( int width )
227 if ( d->minWidth == width ) return false;
228 d->minWidth = width;
230 d->parent->componentResized( this );
231 return true;
233 bool Component::setMinHeight( int height )
235 if ( d->minHeight == height ) return false;
236 d->minHeight = height;
238 d->parent->componentResized( this );
239 return true;
242 void Component::layout( const QRect &newRect )
244 if ( rect().isNull() )
245 d->startRect = QRect( newRect.topLeft(), newRect.topLeft() );
246 else
247 d->startRect = rect();
248 d->targetRect = newRect;
249 //kdDebug(14000) << k_funcinfo << "At " << rect << endl;
252 void Component::setRect( const QRect &rect )
254 d->rect = rect;
257 void Component::paint( QPainter *painter, const QColorGroup &cg )
259 /*painter->setPen( Qt::red );
260 painter->drawRect( rect() );*/
261 for ( uint n = 0; n < components(); ++n )
263 if( component( n )->isShown() )
264 component( n )->paint( painter, cg );
268 void Component::repaint()
270 d->parent->repaint();
273 void Component::relayout()
275 d->parent->relayout();
278 void Component::componentAdded( Component *component )
280 ComponentBase::componentAdded( component );
281 //update( Relayout );
284 void Component::componentRemoved( Component *component )
286 ComponentBase::componentRemoved( component );
287 //update( Relayout );
290 // BoxComponent --------
292 class BoxComponent::Private
294 public:
295 Private( BoxComponent::Direction dir ) : direction( dir ) {}
296 BoxComponent::Direction direction;
298 static const int padding = 2;
301 BoxComponent::BoxComponent( ComponentBase *parent, Direction dir )
302 : Component( parent ), d( new Private( dir ) )
306 int BoxComponent::RTTI = Rtti_BoxComponent;
308 BoxComponent::~BoxComponent()
310 delete d;
313 int BoxComponent::widthForHeight( int height )
315 if ( d->direction != Horizontal )
317 int width = 0;
318 for ( uint n = 0; n < components(); ++n )
319 width = qMax( width, component( n )->widthForHeight( height ) );
320 return width;
322 else
324 int width = (components() - 1) * Private::padding;
325 for ( uint n = 0; n < components(); ++n )
326 width += component( n )->widthForHeight( height );
327 return width;
331 int BoxComponent::heightForWidth( int width )
333 if ( d->direction == Horizontal )
335 int height = 0;
336 for ( uint n = 0; n < components(); ++n )
337 height = qMax( height, component( n )->heightForWidth( width ) );
338 return height;
340 else
342 int height = (components() - 1) * Private::padding;
343 for ( uint n = 0; n < components(); ++n )
344 height += component( n )->heightForWidth( width );
345 return height;
349 void BoxComponent::calcMinSize()
351 int sum = (components() - 1) * Private::padding, max = 0;
352 for ( uint n = 0; n < components(); ++n )
354 Component *comp = component( n );
355 if ( d->direction == Horizontal )
357 max = qMax( max, comp->minHeight() );
358 sum += comp->minWidth();
360 else
362 max = qMax( max, comp->minWidth() );
363 sum += comp->minHeight();
367 bool sizeChanged = false;
368 if ( d->direction == Horizontal )
370 if ( setMinWidth( sum ) ) sizeChanged = true;
371 if ( setMinHeight( max ) ) sizeChanged = true;
373 else
375 if ( setMinWidth( max ) ) sizeChanged = true;
376 if ( setMinHeight( sum ) ) sizeChanged = true;
379 if ( sizeChanged )
380 repaint();
381 else
382 relayout();
385 void BoxComponent::layout( const QRect &rect )
387 Component::layout( rect );
389 bool horiz = (d->direction == Horizontal);
390 int fixedSize = 0;
391 for ( uint n = 0; n < components(); ++n )
393 Component *comp = component( n );
394 if ( horiz )
395 fixedSize += comp->minWidth();
396 else
397 fixedSize += comp->minHeight();
400 // remaining space after all fixed items have been allocated
401 int padding = Private::padding;
403 // ensure total is at least minXXX. the only time the rect
404 // will be smaller than that is when we don't fit, and in
405 // that cases we should pretend that we're wide/high enough.
406 int total;
407 if ( horiz )
408 total = qMax( rect.width(), minWidth() );
409 else
410 total = qMax( rect.height(), minHeight() );
412 int remaining = total - fixedSize - padding * (components() - 1);
414 // finally, lay everything out
415 int pos = 0;
416 for ( uint n = 0; n < components(); ++n )
418 Component *comp = component( n );
420 QRect rc;
421 if ( horiz )
423 rc.setLeft( rect.left() + pos );
424 rc.setTop( rect.top() );
425 rc.setHeight( rect.height() );
426 int minWidth = comp->minWidth();
427 int desiredWidth = comp->widthForHeight( rect.height() );
428 rc.setWidth( qMin( remaining + minWidth, desiredWidth ) );
429 pos += rc.width();
430 remaining -= rc.width() - minWidth;
432 else
434 rc.setLeft( rect.left() );
435 rc.setTop( rect.top() + pos );
436 rc.setWidth( rect.width() );
437 int minHeight = comp->minHeight();
438 int desiredHeight = comp->heightForWidth( rect.width() );
439 rc.setHeight( qMin( remaining + minHeight, desiredHeight ) );
440 pos += rc.height();
441 remaining -= rc.height() - minHeight;
443 comp->layout( rc & rect );
444 pos += padding;
448 void BoxComponent::componentAdded( Component *component )
450 Component::componentAdded( component );
451 calcMinSize();
454 void BoxComponent::componentRemoved( Component *component )
456 Component::componentRemoved( component );
457 calcMinSize();
460 void BoxComponent::componentResized( Component *component )
462 Component::componentResized( component );
463 calcMinSize();
466 // ImageComponent --------
468 class ImageComponent::Private
470 public:
471 QPixmap image;
474 ImageComponent::ImageComponent( ComponentBase *parent )
475 : Component( parent ), d( new Private )
479 int ImageComponent::RTTI = Rtti_ImageComponent;
481 ImageComponent::ImageComponent( ComponentBase *parent, int minW, int minH )
482 : Component( parent ), d( new Private )
484 setMinWidth( minW );
485 setMinHeight( minH );
486 repaint();
489 ImageComponent::~ImageComponent()
491 delete d;
494 QPixmap ImageComponent::pixmap()
496 return d->image;
499 void ImageComponent::setPixmap( const QPixmap &img, bool adjustSize)
501 d->image = img;
502 if ( adjustSize )
504 setMinWidth( img.width() );
505 setMinHeight( img.height() );
507 repaint();
510 static QPoint operator+( const QPoint &pt, const QSize &sz )
512 return QPoint( pt.x() + sz.width(), pt.y() + sz.height() );
515 /*static QPoint operator+( const QSize &sz, const QPoint &pt )
517 return pt + sz;
520 void ImageComponent::paint( QPainter *painter, const QColorGroup & )
522 QRect ourRc = rect();
523 QRect rc = d->image.rect();
524 // center rc within our rect
525 rc.moveTopLeft( ourRc.topLeft() + (ourRc.size() - rc.size()) / 2 );
526 // paint, shrunk to be within our rect
527 painter->drawPixmap( rc & ourRc, d->image );
530 void ImageComponent::scale( int w, int h, Qt::AspectRatioMode mode )
532 QImage im = d->image.convertToImage();
533 setPixmap( QPixmap( im.smoothScale( w, h, mode ) ) );
535 // TextComponent
537 class TextComponent::Private
539 public:
540 Private() : customColor( false ) {}
541 QString text;
542 bool customColor;
543 QColor color;
544 QFont font;
547 TextComponent::TextComponent( ComponentBase *parent, const QFont &font, const QString &text )
548 : Component( parent ), d( new Private )
550 setFont( font );
551 setText( text );
554 int TextComponent::RTTI = Rtti_TextComponent;
556 TextComponent::~TextComponent()
558 delete d;
561 QString TextComponent::text()
563 return d->text;
566 void TextComponent::setText( const QString &text )
568 if ( text == d->text ) return;
569 d->text = text;
570 relayout();
571 calcMinSize();
574 QFont TextComponent::font()
576 return d->font;
579 void TextComponent::setFont( const QFont &font )
581 if ( font == d->font ) return;
582 d->font = font;
583 calcMinSize();
586 void TextComponent::calcMinSize()
588 setMinWidth( 0 );
590 if ( !d->text.isEmpty() )
591 setMinHeight( QFontMetrics( font() ).height() );
592 else
593 setMinHeight( 0 );
595 repaint();
598 int TextComponent::widthForHeight( int )
600 // add 2 to place an extra gap between the text and things to its right.
601 // allegedly if this is not done the protocol icons overlap the text.
602 // i however have never seen this problem (which would almost certainly
603 // be a bug somewhere else).
604 return QFontMetrics( font() ).width( d->text ) + 2;
607 QColor TextComponent::color()
609 return d->customColor ? d->color : QColor();
612 void TextComponent::setColor( const QColor &color )
614 d->color = color;
615 d->customColor = true;
616 repaint();
619 void TextComponent::setDefaultColor()
621 d->customColor = false;
622 repaint();
625 void TextComponent::paint( QPainter *painter, const QColorGroup &cg )
627 if ( d->customColor )
628 painter->setPen( d->color );
629 else
630 painter->setPen( cg.text() );
631 QString dispStr = KStringHandler::rPixelSqueeze( d->text, QFontMetrics( font() ), rect().width() );
632 painter->setFont( font() );
633 painter->drawText( rect(), Qt::TextSingleLine, dispStr );
636 // DisplayNameComponent
638 class DisplayNameComponent::Private
640 public:
641 QString text;
642 QFont font;
645 DisplayNameComponent::DisplayNameComponent( ComponentBase *parent )
646 : BoxComponent( parent ), d( new Private )
650 int DisplayNameComponent::RTTI = Rtti_DisplayNameComponent;
652 DisplayNameComponent::~DisplayNameComponent()
656 void DisplayNameComponent::layout( const QRect &rect )
658 Component::layout( rect );
660 // finally, lay everything out
661 QRect rc;
662 int totalWidth = rect.width();
663 int usedWidth = 0;
664 bool exceeded = false;
665 for ( uint n = 0; n < components(); ++n )
667 Component *comp = component( n );
668 if ( !exceeded )
670 if ( ( usedWidth + comp->widthForHeight( rect.height() ) ) > totalWidth )
672 exceeded = true;
673 // TextComponents can squeeze themselves
674 if ( comp->rtti() == Rtti_TextComponent )
676 comp->show();
677 comp->layout( QRect( usedWidth+ rect.left(), rect.top(),
678 totalWidth - usedWidth,
679 comp->heightForWidth( totalWidth - usedWidth ) ) );
680 } else {
681 comp->hide();
684 else
686 comp->show();
687 comp->layout( QRect( usedWidth+ rect.left(), rect.top(),
688 comp->widthForHeight( rect.height() ),
689 comp->heightForWidth( rect.width() ) ) );
691 usedWidth+= comp->widthForHeight( rect.height() );
693 else
695 // Shall we implement a hide()/show() in Component class ?
696 comp->hide();
701 void DisplayNameComponent::setText( const QString& text )
703 if ( d->text == text )
704 return;
705 d->text = text;
707 redraw();
710 void DisplayNameComponent::redraw()
712 QColor color;
713 for ( uint n = 0; n < components(); ++n )
714 if( component( n )->rtti() == Rtti_TextComponent )
716 ((TextComponent*)component(n))->color();
719 Q3ValueList<Kopete::Emoticons::Token> tokens;
720 Q3ValueList<Kopete::Emoticons::Token>::const_iterator token;
722 clear(); // clear childs
724 tokens = Kopete::Emoticons::tokenizeEmoticons( d->text );
725 ImageComponent *ic;
726 TextComponent *t;
728 QFontMetrics fontMetrics( d->font );
729 int fontHeight = fontMetrics.height();
730 for ( token = tokens.begin(); token != tokens.end(); ++token )
732 switch ( (*token).type )
734 case Kopete::Emoticons::Text:
735 t = new TextComponent( this, d->font, (*token).text );
736 break;
737 case Kopete::Emoticons::Image:
738 ic = new ImageComponent( this );
739 ic->setPixmap( QPixmap( (*token).picPath ) );
740 ic->scale( INT_MAX, fontHeight, Qt::KeepAspectRatio );
741 break;
742 default:
743 kdDebug( 14010 ) << k_funcinfo << "This should have not happened!" << endl;
747 if(color.isValid())
748 setColor( color );
751 void DisplayNameComponent::setFont( const QFont& font )
753 for ( uint n = 0; n < components(); ++n )
754 if( component( n )->rtti() == Rtti_TextComponent )
755 ((TextComponent*)component(n))->setFont( font );
756 d->font = font;
759 void DisplayNameComponent::setColor( const QColor& color )
761 for ( uint n = 0; n < components(); ++n )
762 if( component( n )->rtti() == Rtti_TextComponent )
763 ((TextComponent*)component(n))->setColor( color );
766 void DisplayNameComponent::setDefaultColor()
768 for ( uint n = 0; n < components(); ++n )
769 if( component( n )->rtti() == Rtti_TextComponent )
770 ((TextComponent*)component(n))->setDefaultColor();
773 QString DisplayNameComponent::text()
775 return d->text;
778 // HSpacerComponent --------
780 HSpacerComponent::HSpacerComponent( ComponentBase *parent )
781 : Component( parent )
783 setMinWidth( 0 );
784 setMinHeight( 0 );
787 int HSpacerComponent::RTTI = Rtti_HSpacerComponent;
789 int HSpacerComponent::widthForHeight( int )
791 return INT_MAX;
794 // VSpacerComponent --------
796 VSpacerComponent::VSpacerComponent( ComponentBase *parent )
797 : Component( parent )
799 setMinWidth( 0 );
800 setMinHeight( 0 );
803 int VSpacerComponent::RTTI = Rtti_VSpacerComponent;
805 int VSpacerComponent::heightForWidth( int )
807 return INT_MAX;
810 ////////////////// ContactComponent /////////////////////////
812 class ContactComponent::Private
814 public:
815 Kopete::Contact *contact;
816 int iconSize;
819 ContactComponent::ContactComponent( ComponentBase *parent, Kopete::Contact *contact, int iconSize) : ImageComponent( parent ) , d( new Private )
821 d->contact = contact;
822 d->iconSize = iconSize;
823 updatePixmap();
826 ContactComponent::~ContactComponent()
828 delete d;
831 void ContactComponent::updatePixmap()
833 setPixmap( contact()->onlineStatus().iconFor( contact(), d->iconSize ) );
835 Kopete::Contact *ContactComponent::contact()
837 return d->contact;
840 // we don't need to use a tooltip source here - this way is simpler
841 std::pair<QString,QRect> ContactComponent::toolTip( const QPoint &/*relativePos*/ )
843 return std::make_pair(d->contact->toolTip(),rect());
846 ////////////////// SpacerComponent /////////////////////////
848 SpacerComponent::SpacerComponent( ComponentBase *parent, int w, int h ) : Component( parent )
850 setMinWidth(w);
851 setMinHeight(h);
854 // Item --------
857 * A periodic timer intended to be shared amongst multiple objects. Will run only
858 * if an object is attached to it.
860 class SharedTimer : private QTimer
862 int period;
863 int users;
864 public:
865 SharedTimer( int period ) : period(period), users(0) {}
866 void attach( QObject *target, const char *slot )
868 connect( this, SIGNAL(timeout()), target, slot );
869 if( users++ == 0 )
870 start( period );
871 //kdDebug(14000) << "SharedTimer::attach: users is now " << users << "\n";
873 void detach( QObject *target, const char *slot )
875 disconnect( this, SIGNAL(timeout()), target, slot );
876 if( --users == 0 )
877 stop();
878 //kdDebug(14000) << "SharedTimer::detach: users is now " << users << "\n";
882 class SharedTimerRef
884 SharedTimer &timer;
885 QObject * const object;
886 const char * const slot;
887 bool attached;
888 public:
889 SharedTimerRef( SharedTimer &timer, QObject *obj, const char *slot )
890 : timer(timer), object(obj), slot(slot), attached(false)
893 void start()
895 if( attached ) return;
896 timer.attach( object, slot );
897 attached = true;
899 void stop()
901 if( !attached ) return;
902 timer.detach( object, slot );
903 attached = false;
905 bool isActive()
907 return attached;
911 class Item::Private
913 public:
914 Private( Item *item )
915 : layoutAnimateTimer( theLayoutAnimateTimer(), item, SLOT( slotLayoutAnimateItems() ) )
916 , animateLayout( true ), opacity( 1.0 )
917 , visibilityTimer( theVisibilityTimer(), item, SLOT( slotUpdateVisibility() ) )
918 , visibilityLevel( 0 ), visibilityTarget( false ), searchMatch( true )
922 QTimer layoutTimer;
924 //QTimer layoutAnimateTimer;
925 SharedTimerRef layoutAnimateTimer;
926 SharedTimer &theLayoutAnimateTimer()
928 static SharedTimer timer( 10 );
929 return timer;
932 bool animateLayout;
933 int layoutAnimateSteps;
934 static const int layoutAnimateStepsTotal = 10;
936 float opacity;
938 //QTimer visibilityTimer;
939 SharedTimerRef visibilityTimer;
940 SharedTimer &theVisibilityTimer()
942 static SharedTimer timer( 40 );
943 return timer;
946 int visibilityLevel;
948 bool visibilityTarget;
950 static const int visibilityFoldSteps = 7;
951 #ifdef HAVE_XRENDER
952 static const int visibilityFadeSteps = 7;
953 #else
954 static const int visibilityFadeSteps = 0;
955 #endif
956 static const int visibilityStepsTotal = visibilityFoldSteps + visibilityFadeSteps;
958 bool searchMatch;
960 static bool animateChanges;
961 static bool fadeVisibility;
962 static bool foldVisibility;
965 bool Item::Private::animateChanges = true;
966 bool Item::Private::fadeVisibility = true;
967 bool Item::Private::foldVisibility = true;
969 Item::Item( Q3ListViewItem *parent, QObject *owner, const char *name )
970 : QObject( owner, name ), KListViewItem( parent ), d( new Private(this) )
972 initLVI();
975 Item::Item( Q3ListView *parent, QObject *owner, const char *name )
976 : QObject( owner, name ), KListViewItem( parent ), d( new Private(this) )
978 initLVI();
981 Item::~Item()
983 delete d;
986 void Item::setEffects( bool animation, bool fading, bool folding )
988 Private::animateChanges = animation;
989 Private::fadeVisibility = fading;
990 Private::foldVisibility = folding;
993 void Item::initLVI()
995 connect( listView()->header(), SIGNAL( sizeChange( int, int, int ) ), SLOT( slotColumnResized() ) );
996 connect( &d->layoutTimer, SIGNAL( timeout() ), SLOT( slotLayoutItems() ) );
997 //connect( &d->layoutAnimateTimer, SIGNAL( timeout() ), SLOT( slotLayoutAnimateItems() ) );
998 //connect( &d->visibilityTimer, SIGNAL( timeout() ), SLOT( slotUpdateVisibility() ) );
999 setVisible( false );
1000 setTargetVisibility( true );
1003 void Item::slotColumnResized()
1005 scheduleLayout();
1006 // if we've been resized, don't animate the layout
1007 d->animateLayout = false;
1010 void Item::scheduleLayout()
1012 // perform a delayed layout in order to speed it all up
1013 if ( ! d->layoutTimer.isActive() )
1014 d->layoutTimer.start( 30, true );
1017 void Item::slotLayoutItems()
1019 d->layoutTimer.stop();
1021 for ( uint n = 0; n < components(); ++n )
1023 int width = listView()->columnWidth(n);
1024 if ( n == 0 )
1026 int d = depth() + (listView()->rootIsDecorated() ? 1 : 0);
1027 width -= d * listView()->treeStepSize();
1030 int height = component( n )->heightForWidth( width );
1031 component( n )->layout( QRect( 0, 0, width, height ) );
1032 //kdDebug(14000) << k_funcinfo << "Component " << n << " is " << width << " x " << height << endl;
1035 if ( Private::animateChanges && d->animateLayout && !d->visibilityTimer.isActive() )
1037 d->layoutAnimateTimer.start();
1038 //if ( !d->layoutAnimateTimer.isActive() )
1039 // d->layoutAnimateTimer.start( 10 );
1040 d->layoutAnimateSteps = 0;
1042 else
1044 d->layoutAnimateSteps = Private::layoutAnimateStepsTotal;
1045 d->animateLayout = true;
1047 slotLayoutAnimateItems();
1050 void Item::slotLayoutAnimateItems()
1052 if ( ++d->layoutAnimateSteps >= Private::layoutAnimateStepsTotal )
1053 d->layoutAnimateTimer.stop();
1055 const int s = Private::layoutAnimateStepsTotal;
1056 const int p = qMin( d->layoutAnimateSteps, s );
1058 updateAnimationPosition( p, s );
1059 setHeight(0);
1060 repaint();
1063 float Item::opacity()
1065 return d->opacity;
1068 void Item::setOpacity( float opacity )
1070 if ( d->opacity == opacity ) return;
1071 d->opacity = opacity;
1072 repaint();
1075 void Item::setSearchMatch( bool match )
1077 d->searchMatch = match;
1079 if ( !match )
1080 setVisible( false );
1081 else
1083 kdDebug(14000) << k_funcinfo << " match: " << match << ", vis timer active: " << d->visibilityTimer.isActive()
1084 << ", target visibility: " << targetVisibility() << endl;
1085 if ( d->visibilityTimer.isActive() )
1086 setVisible( true );
1087 else
1088 setVisible( targetVisibility() );
1092 bool Item::targetVisibility()
1094 return d->visibilityTarget;
1097 void Item::setTargetVisibility( bool vis )
1099 if ( d->visibilityTarget == vis )
1101 // in case we're getting called because our parent was shown and
1102 // we need to be rehidden
1103 if ( !d->visibilityTimer.isActive() )
1104 setVisible( vis && d->searchMatch );
1105 return;
1107 d->visibilityTarget = vis;
1108 d->visibilityTimer.start();
1109 //d->visibilityTimer.start( 40 );
1110 if ( targetVisibility() )
1111 setVisible( d->searchMatch );
1112 slotUpdateVisibility();
1115 void Item::slotUpdateVisibility()
1117 if ( targetVisibility() )
1118 ++d->visibilityLevel;
1119 else
1120 --d->visibilityLevel;
1122 if ( !Private::foldVisibility && !Private::fadeVisibility )
1123 d->visibilityLevel = targetVisibility() ? Private::visibilityStepsTotal : 0;
1124 else if ( !Private::fadeVisibility && d->visibilityLevel >= Private::visibilityFoldSteps )
1125 d->visibilityLevel = targetVisibility() ? Private::visibilityStepsTotal : Private::visibilityFoldSteps - 1;
1126 else if ( !Private::foldVisibility && d->visibilityLevel <= Private::visibilityFoldSteps )
1127 d->visibilityLevel = targetVisibility() ? Private::visibilityFoldSteps + 1 : 0;
1129 if ( d->visibilityLevel >= Private::visibilityStepsTotal )
1131 d->visibilityLevel = Private::visibilityStepsTotal;
1132 d->visibilityTimer.stop();
1134 else if ( d->visibilityLevel <= 0 )
1136 d->visibilityLevel = 0;
1137 d->visibilityTimer.stop();
1138 setVisible( false );
1140 setHeight( 0 );
1141 repaint();
1144 void Item::repaint()
1146 // if we're about to relayout, don't bother painting yet.
1147 if ( d->layoutTimer.isActive() )
1148 return;
1149 listView()->repaintItem( this );
1152 void Item::relayout()
1154 scheduleLayout();
1157 void Item::setup()
1159 KListViewItem::setup();
1160 slotLayoutItems();
1163 void Item::setHeight( int )
1165 int minHeight = 0;
1166 for ( uint n = 0; n < components(); ++n )
1167 minHeight = qMax( minHeight, component( n )->rect().height() );
1168 //kdDebug(14000) << k_funcinfo << "Height is " << minHeight << endl;
1169 if ( Private::foldVisibility && d->visibilityTimer.isActive() )
1171 int vis = d->visibilityLevel;
1172 if ( vis > Private::visibilityFoldSteps )
1173 vis = Private::visibilityFoldSteps;
1174 minHeight = (minHeight * vis) / Private::visibilityFoldSteps;
1176 KListViewItem::setHeight( minHeight );
1179 int Item::width( const QFontMetrics &, const Q3ListView *lv, int c ) const
1181 // Qt computes the itemRect from this. we want the whole item to be
1182 // clickable, so we return the widest we could possibly be.
1183 return lv->header()->sectionSize( c );
1186 void Item::paintCell( QPainter *p, const QColorGroup &cg, int column, int width, int align )
1188 QPixmap back( width, height() );
1189 QPainter paint( &back );
1190 //KListViewItem::paintCell( &paint, cg, column, width, align );
1191 // PASTED FROM KLISTVIEWITEM:
1192 // set the alternate cell background colour if necessary
1193 QColorGroup _cg = cg;
1194 if (isAlternate())
1195 if (listView()->viewport()->backgroundMode()==Qt::FixedColor)
1196 _cg.setColor(QColorGroup::Background, static_cast< KListView* >(listView())->alternateBackground());
1197 else
1198 _cg.setColor(QColorGroup::Base, static_cast< KListView* >(listView())->alternateBackground());
1199 // PASTED FROM QLISTVIEWITEM
1201 QPainter *p = &paint;
1203 Q3ListView *lv = listView();
1204 if ( !lv )
1205 return;
1206 QFontMetrics fm( p->fontMetrics() );
1208 // any text we render is done by the Components, not by this class, so make sure we've nothing to write
1209 QString t;
1211 // removed text truncating code from Qt - we do that differently, further on
1213 int marg = lv->itemMargin();
1214 int r = marg;
1215 // const QPixmap * icon = pixmap( column );
1216 #warning Item::paintCell needs fixing
1218 const QPalette::ColorRole crole = backgroundRole();
1220 if ( _cg.brush( crole ) != lv->colorGroup().brush( crole ) )
1221 p->fillRect( 0, 0, width, height(), _cg.brush( crole ) );
1222 else
1224 // all copied from QListView::paintEmptyArea
1226 //lv->paintEmptyArea( p, QRect( 0, 0, width, height() ) );
1227 QStyleOption opt( lv->sortColumn(), 0 ); // ### hack; in 3.1, add a property in QListView and QHeader
1228 QStyle::SFlags how = QStyle::State_Default;
1229 if ( lv->isEnabled() )
1230 how |= QStyle::State_Enabled;
1232 lv->style()->drawComplexControl( QStyle::CC_Q3ListView,
1233 p, lv, QRect( 0, 0, width, height() ), lv->colorGroup(),
1234 how, QStyle::SC_Q3ListView, QStyle::SC_None,
1235 opt );
1240 if ( isSelected() &&
1241 (column == 0 || lv->allColumnsShowFocus()) ) {
1242 p->fillRect( r - marg, 0, width - r + marg, height(),
1243 _cg.brush( QColorGroup::Highlight ) );
1244 // removed text pen setting code from Qt
1247 // removed icon drawing code from Qt
1249 // draw the tree gubbins
1250 if ( multiLinesEnabled() && column == 0 && isOpen() && childCount() ) {
1251 int textheight = fm.size( align, t ).height() + 2 * lv->itemMargin();
1252 textheight = qMax( textheight, QApplication::globalStrut().height() );
1253 if ( textheight % 2 > 0 )
1254 textheight++;
1255 if ( textheight < height() ) {
1256 int w = lv->treeStepSize() / 2;
1257 lv->style()->drawComplexControl( QStyle::CC_Q3ListView, p, lv,
1258 QRect( 0, textheight, w + 1, height() - textheight + 1 ), _cg,
1259 lv->isEnabled() ? QStyle::State_Enabled : QStyle::State_Default,
1260 QStyle::SC_Q3ListViewExpand,
1261 (uint)QStyle::SC_All, QStyleOption( this ) );
1266 // END OF PASTE
1269 //do you see a better way to tell the TextComponent we are selected ? - Olivier 2004-09-02
1270 if ( isSelected() )
1271 _cg.setColor(QColorGroup::Text , _cg.highlightedText() );
1273 if ( Component *comp = component( column ) )
1274 comp->paint( &paint, _cg );
1275 paint.end();
1277 #ifdef HAVE_XRENDER
1278 QColor rgb = cg.base();//backgroundColor();
1279 float opac = 1.0;
1280 if ( d->visibilityTimer.isActive() && Private::fadeVisibility )
1282 int vis = d->visibilityLevel - Private::visibilityFoldSteps;
1283 if ( vis < 0 )
1284 vis = 0;
1286 opac = float(vis) / Private::visibilityFadeSteps;
1288 opac *= opacity();
1289 const int alpha = 257 - int(opac * 257);
1290 if ( alpha != 0 )
1292 XRenderColor clr = { alpha * rgb.red(), alpha * rgb.green(), alpha * rgb.blue(), alpha * 0xff };
1293 XRenderFillRectangle( back.x11Display(), PictOpOver, back.x11PictureHandle(),
1294 &clr, 0, 0, width, height() );
1296 #endif
1298 p->drawPixmap( 0, 0, back );
1301 void Item::componentAdded( Component *component )
1303 ComponentBase::componentAdded( component );
1304 scheduleLayout();
1307 void Item::componentRemoved( Component *component )
1309 ComponentBase::componentRemoved( component );
1310 scheduleLayout();
1313 void Item::componentResized( Component *component )
1315 ComponentBase::componentResized( component );
1316 scheduleLayout();
1319 } // END namespace ListView
1320 } // END namespace UI
1321 } // END namespace Kopete
1323 #include "kopetelistviewitem.moc"
1325 // vim: set noet ts=4 sts=4 sw=4: