kontact

iconsidepane.cpp
1/*
2 This file is part of KDE Kontact.
3
4 Copyright (C) 2003 Cornelius Schumacher <schumacher@kde.org>
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20 */
21
22#include <tqptrlist.h>
23#include <tqwidgetstack.h>
24#include <tqsignal.h>
25#include <tqobjectlist.h>
26#include <tqlabel.h>
27#include <tqimage.h>
28#include <tqpainter.h>
29#include <tqbitmap.h>
30#include <tqfontmetrics.h>
31#include <tqsignalmapper.h>
32#include <tqstyle.h>
33#include <tqframe.h>
34#include <tqdrawutil.h>
35#include <tqcursor.h>
36#include <tqtimer.h>
37#include <tqtooltip.h>
38
39#include <tdepopupmenu.h>
40#include <tdeapplication.h>
41#include <kdialog.h>
42#include <tdelocale.h>
43#include <kiconloader.h>
44#include <sidebarextension.h>
45
46#include <kdebug.h>
47
48#include "mainwindow.h"
49
50#include "plugin.h"
51
52#include "prefs.h"
53#include "iconsidepane.h"
54
55namespace Kontact
56{
57
58//ugly wrapper class for adding an operator< to the Plugin class
59
60class PluginProxy
61{
62 public:
63 PluginProxy()
64 : mPlugin( 0 )
65 { }
66
67 PluginProxy( Plugin *plugin )
68 : mPlugin( plugin )
69 { }
70
71 PluginProxy & operator=( Plugin *plugin )
72 {
73 mPlugin = plugin;
74 return *this;
75 }
76
77 bool operator<( PluginProxy &rhs ) const
78 {
79 return mPlugin->weight() < rhs.mPlugin->weight();
80 }
81
82 Plugin *plugin() const
83 {
84 return mPlugin;
85 }
86
87 private:
88 Plugin *mPlugin;
89};
90
91} //namespace
92
93using namespace Kontact;
94
95EntryItem::EntryItem( Navigator *parent, Kontact::Plugin *plugin )
96 : TQListBoxItem( parent ),
97 mPlugin( plugin ),
98 mHasHover( false ),
99 mPaintActive( false )
100{
101 reloadPixmap();
102 setCustomHighlighting( true );
103 setText( plugin->title() );
104}
105
106EntryItem::~EntryItem()
107{
108}
109
110void EntryItem::reloadPixmap()
111{
112 int size = (int)navigator()->viewMode();
113 if ( size != 0 )
114 mPixmap = TDEGlobal::iconLoader()->loadIcon( mPlugin->icon(),
115 TDEIcon::Desktop, size,
116 mPlugin->disabled() ?
117 TDEIcon::DisabledState
118 : TDEIcon::DefaultState);
119 else
120 mPixmap = TQPixmap();
121}
122
123Navigator* EntryItem::navigator() const
124{
125 return static_cast<Navigator*>( listBox() );
126}
127
128int EntryItem::width( const TQListBox *listbox ) const
129{
130 int w = 0;
131 if( navigator()->showIcons() ) {
132 w = navigator()->viewMode();
133 if ( navigator()->viewMode() == SmallIcons )
134 w += 4;
135 }
136 if( navigator()->showText() ) {
137 if ( navigator()->viewMode() == SmallIcons )
138 w += listbox->fontMetrics().width( text() );
139 else
140 w = TQMAX( w, listbox->fontMetrics().width( text() ) );
141 }
142 return w + ( KDialog::marginHint() * 2 );
143}
144
145int EntryItem::height( const TQListBox *listbox ) const
146{
147 int h = 0;
148 if ( navigator()->showIcons() )
149 h = (int)navigator()->viewMode() + 4;
150 if ( navigator()->showText() ) {
151 if ( navigator()->viewMode() == SmallIcons || !navigator()->showIcons() )
152 h = TQMAX( h, listbox->fontMetrics().lineSpacing() ) + KDialog::spacingHint() * 2;
153 else
154 h = (int)navigator()->viewMode() + listbox->fontMetrics().lineSpacing() + 4;
155 }
156 return h;
157}
158
159void EntryItem::paint( TQPainter *p )
160{
161 reloadPixmap();
162
163 TQListBox *box = listBox();
164 bool iconAboveText = ( navigator()->viewMode() > SmallIcons )
165 && navigator()->showIcons();
166 int w = box->viewport()->width();
167 int y = iconAboveText ? 2 :
168 ( ( height( box ) - mPixmap.height() ) / 2 );
169
170 // draw selected
171 if ( isCurrent() || isSelected() || mHasHover || mPaintActive ) {
172 int h = height( box );
173
174 TQBrush brush;
175 if ( isCurrent() || isSelected() || mPaintActive )
176 brush = box->colorGroup().brush( TQColorGroup::Highlight );
177 else
178 brush = TQBrush(box->colorGroup().highlight().light( 115 ));
179 p->fillRect( 1, 0, w - 2, h - 1, brush );
180 TQPen pen = p->pen();
181 TQPen oldPen = pen;
182 pen.setColor( box->colorGroup().mid() );
183 p->setPen( pen );
184
185 p->drawPoint( 1, 0 );
186 p->drawPoint( 1, h - 2 );
187 p->drawPoint( w - 2, 0 );
188 p->drawPoint( w - 2, h - 2 );
189
190 p->setPen( oldPen );
191 }
192
193 if ( !mPixmap.isNull() && navigator()->showIcons() ) {
194 int x = iconAboveText ? ( ( w - mPixmap.width() ) / 2 ) :
195 KDialog::marginHint();
196 p->drawPixmap( x, y, mPixmap );
197 }
198
199 TQColor shadowColor = listBox()->colorGroup().background().dark(115);
200 if ( isCurrent() || isSelected() ) {
201 p->setPen( box->colorGroup().highlightedText() );
202 }
203
204 if ( !text().isEmpty() && navigator()->showText() ) {
205 TQFontMetrics fm = p->fontMetrics();
206
207 int x = 0;
208 if ( iconAboveText ) {
209 x = ( w - fm.width( text() ) ) / 2;
210 y += fm.height() - fm.descent();
211 if ( navigator()->showIcons() )
212 y += mPixmap.height();
213 } else {
214 x = KDialog::marginHint() + 4;
215 if( navigator()->showIcons() ) {
216 x += mPixmap.width();
217 }
218
219 if ( !navigator()->showIcons() || mPixmap.height() < fm.height() )
220 y = height( box )/2 - fm.height()/2 + fm.ascent();
221 else
222 y += mPixmap.height()/2 - fm.height()/2 + fm.ascent();
223 }
224
225 if ( plugin()->disabled() ) {
226 p->setPen( box->palette().disabled().text( ) );
227 } else if ( isCurrent() || isSelected() || mHasHover ) {
228 p->setPen( box->colorGroup().highlight().dark(115) );
229 p->drawText( x + ( TQApplication::reverseLayout() ? -1 : 1),
230 y + 1, text() );
231 p->setPen( box->colorGroup().highlightedText() );
232 }
233 else
234 p->setPen( box->colorGroup().text() );
235
236 p->drawText( x, y, text() );
237 }
238
239 // ensure that we don't have a stale flag around
240 if ( isCurrent() || isSelected() ) mHasHover = false;
241}
242
243void EntryItem::setHover( bool hasHover )
244{
245 mHasHover = hasHover;
246}
247
248void EntryItem::setPaintActive( bool paintActive )
249{
250 mPaintActive = paintActive;
251}
252
253Navigator::Navigator( IconSidePane *parent, const char *name )
254 : TDEListBox( parent, name ), mSidePane( parent ),
255 mShowIcons( true ), mShowText( true )
256{
257 mMouseOn = 0;
258 mHighlightItem = 0;
259 mViewMode = sizeIntToEnum( Prefs::self()->sidePaneIconSize() );
260 mShowIcons = Prefs::self()->sidePaneShowIcons();
261 mShowText = Prefs::self()->sidePaneShowText();
262 setSelectionMode( TDEListBox::Single );
263 viewport()->setBackgroundMode( PaletteBackground );
264 setFrameStyle( TQFrame::NoFrame );
265 setHScrollBarMode( TQScrollView::AlwaysOff );
266 setAcceptDrops( true );
267
268 setFocusPolicy( TQWidget::NoFocus );
269
270 connect( this, TQ_SIGNAL( selectionChanged( TQListBoxItem* ) ),
271 TQ_SLOT( slotExecuted( TQListBoxItem* ) ) );
272 connect( this, TQ_SIGNAL( rightButtonPressed( TQListBoxItem*, const TQPoint& ) ),
273 TQ_SLOT( slotShowRMBMenu( TQListBoxItem*, const TQPoint& ) ) );
274 connect( this, TQ_SIGNAL( onItem( TQListBoxItem * ) ),
275 TQ_SLOT( slotMouseOn( TQListBoxItem * ) ) );
276 connect( this, TQ_SIGNAL( onViewport() ), TQ_SLOT( slotMouseOff() ) );
277
278 mMapper = new TQSignalMapper( this );
279 connect( mMapper, TQ_SIGNAL( mapped( int ) ), TQ_SLOT( shortCutSelected( int ) ) );
280
281 TQToolTip::remove( this );
282 if ( !mShowText )
283 new EntryItemToolTip( this );
284
285}
286
287TQSize Navigator::sizeHint() const
288{
289 return TQSize( 100, 100 );
290}
291
292void Navigator::highlightItem( EntryItem * item )
293{
294 mHighlightItem = item;
295
296 setPaintActiveItem( mHighlightItem, true );
297
298 TQTimer::singleShot( 2000, this, TQ_SLOT( slotStopHighlight() ) );
299}
300
301void Navigator::slotStopHighlight()
302{
303 setPaintActiveItem( mHighlightItem, false );
304}
305
306void Navigator::setSelected( TQListBoxItem *item, bool selected )
307{
308 // Reimplemented to avoid the immediate activation of
309 // the item. might turn out it doesn't work, we check that
310 // an confirm from MainWindow::selectPlugin()
311 if ( selected ) {
312 EntryItem *entry = static_cast<EntryItem*>( item );
313 emit pluginActivated( entry->plugin() );
314 }
315}
316
317void Navigator::updatePlugins( TQValueList<Kontact::Plugin*> plugins_ )
318{
319 TQValueList<Kontact::PluginProxy> plugins;
320 TQValueList<Kontact::Plugin*>::ConstIterator end_ = plugins_.end();
321 TQValueList<Kontact::Plugin*>::ConstIterator it_ = plugins_.begin();
322 for ( ; it_ != end_; ++it_ )
323 plugins += PluginProxy( *it_ );
324
325 clear();
326
327 mActions.setAutoDelete( true );
328 mActions.clear();
329 mActions.setAutoDelete( false );
330
331 int minWidth = 0;
332 qBubbleSort( plugins );
333 TQValueList<Kontact::PluginProxy>::ConstIterator end = plugins.end();
334 TQValueList<Kontact::PluginProxy>::ConstIterator it = plugins.begin();
335 for ( ; it != end; ++it ) {
336 Kontact::Plugin *plugin = ( *it ).plugin();
337 if ( !plugin->showInSideBar() )
338 continue;
339
340 EntryItem *item = new EntryItem( this, plugin );
341 item->setSelectable( !plugin->disabled() );
342
343 if ( item->width( this ) > minWidth )
344 minWidth = item->width( this );
345 }
346
347 parentWidget()->setFixedWidth( minWidth );
348}
349
350void Navigator::dragEnterEvent( TQDragEnterEvent *event )
351{
352 kdDebug(5600) << "Navigator::dragEnterEvent()" << endl;
353
354 dragMoveEvent( event );
355}
356
357void Navigator::dragMoveEvent( TQDragMoveEvent *event )
358{
359 kdDebug(5600) << "Navigator::dragEnterEvent()" << endl;
360
361 kdDebug(5600) << " Format: " << event->format() << endl;
362
363 TQListBoxItem *item = itemAt( event->pos() );
364
365 if ( !item ) {
366 event->accept( false );
367 return;
368 }
369
370 EntryItem *entry = static_cast<EntryItem*>( item );
371
372 kdDebug(5600) << " PLUGIN: " << entry->plugin()->identifier() << endl;
373
374 event->accept( entry->plugin()->canDecodeDrag( event ) );
375}
376
377void Navigator::dropEvent( TQDropEvent *event )
378{
379 kdDebug(5600) << "Navigator::dropEvent()" << endl;
380
381 TQListBoxItem *item = itemAt( event->pos() );
382
383 if ( !item ) {
384 return;
385 }
386
387 EntryItem *entry = static_cast<EntryItem*>( item );
388
389 kdDebug(5600) << " PLUGIN: " << entry->plugin()->identifier() << endl;
390
391 entry->plugin()->processDropEvent( event );
392}
393
394void Navigator::resizeEvent( TQResizeEvent *event )
395{
396 TQListBox::resizeEvent( event );
397 triggerUpdate( true );
398}
399
400void Navigator::enterEvent( TQEvent *event )
401{
402 // work around TQt behaviour: onItem is not emmitted in enterEvent()
403 TDEListBox::enterEvent( event );
404 emit onItem( itemAt( mapFromGlobal( TQCursor::pos() ) ) );
405}
406
407void Navigator::leaveEvent( TQEvent *event )
408{
409 TDEListBox::leaveEvent( event );
410 slotMouseOn( 0 );
411 mMouseOn = 0;
412}
413
414void Navigator::slotExecuted( TQListBoxItem *item )
415{
416 if ( !item )
417 return;
418
419 EntryItem *entry = static_cast<EntryItem*>( item );
420
421 emit pluginActivated( entry->plugin() );
422}
423
424IconViewMode Navigator::sizeIntToEnum(int size) const
425{
426 switch ( size ) {
427 case int(LargeIcons):
428 return LargeIcons;
429 break;
430 case int(NormalIcons):
431 return NormalIcons;
432 break;
433 case int(SmallIcons):
434 return SmallIcons;
435 break;
436 default:
437 // Stick with sane values
438 return NormalIcons;
439 kdDebug() << "View mode not implemented!" << endl;
440 break;
441 }
442}
443
444void Navigator::slotShowRMBMenu( TQListBoxItem *, const TQPoint &pos )
445{
446 TDEPopupMenu menu;
447 menu.insertTitle( i18n( "Icon Size" ) );
448 menu.insertItem( i18n( "Large" ), (int)LargeIcons );
449 menu.setItemEnabled( (int)LargeIcons, mShowIcons );
450 menu.insertItem( i18n( "Normal" ), (int)NormalIcons );
451 menu.setItemEnabled( (int)NormalIcons, mShowIcons );
452 menu.insertItem( i18n( "Small" ), (int)SmallIcons );
453 menu.setItemEnabled( (int)SmallIcons, mShowIcons );
454
455 menu.setItemChecked( (int)mViewMode, true );
456 menu.insertSeparator();
457
458 menu.insertItem( i18n( "Show Icons" ), (int)ShowIcons );
459 menu.setItemChecked( (int)ShowIcons, mShowIcons );
460 menu.setItemEnabled( (int)ShowIcons, mShowText );
461 menu.insertItem( i18n( "Show Text" ), (int)ShowText );
462 menu.setItemChecked( (int)ShowText, mShowText );
463 menu.setItemEnabled( (int)ShowText, mShowIcons );
464 int choice = menu.exec( pos );
465
466 if ( choice == -1 )
467 return;
468
469 if ( choice >= SmallIcons ) {
470 mViewMode = sizeIntToEnum( choice );
471 Prefs::self()->setSidePaneIconSize( choice );
472 } else {
473 // either icons or text were toggled
474 if ( choice == ShowIcons ) {
475 mShowIcons = !mShowIcons;
476 Prefs::self()->setSidePaneShowIcons( mShowIcons );
477 TQToolTip::remove( this );
478 if ( !mShowText )
479 new EntryItemToolTip( this );
480 } else {
481 mShowText = !mShowText;
482 Prefs::self()->setSidePaneShowText( mShowText );
483 TQToolTip::remove( this );
484 }
485 }
486 int maxWidth = 0;
487 TQListBoxItem* it = 0;
488 for (int i = 0; (it = item(i)) != 0; ++i)
489 {
490 int width = it->width(this);
491 if (width > maxWidth)
492 maxWidth = width;
493 }
494 parentWidget()->setFixedWidth( maxWidth );
495
496 triggerUpdate( true );
497}
498
499void Navigator::shortCutSelected( int pos )
500{
501 setCurrentItem( pos );
502}
503
504void Navigator::setHoverItem( TQListBoxItem* item, bool hover )
505{
506 static_cast<EntryItem*>( item )->setHover( hover );
507 updateItem( item );
508}
509
510void Navigator::setPaintActiveItem( TQListBoxItem* item, bool paintActive )
511{
512 static_cast<EntryItem*>( item )->setPaintActive( paintActive );
513 updateItem( item );
514}
515
516void Navigator::slotMouseOn( TQListBoxItem* newItem )
517{
518 TQListBoxItem* oldItem = mMouseOn;
519 if ( oldItem == newItem ) return;
520
521 if ( oldItem && !oldItem->isCurrent() && !oldItem->isSelected() )
522 {
523 setHoverItem( oldItem, false );
524 }
525
526 if ( newItem && !newItem->isCurrent() && !newItem->isSelected() )
527 {
528 setHoverItem( newItem, true );
529 }
530 mMouseOn = newItem;
531}
532
533void Navigator::slotMouseOff()
534{
535 slotMouseOn( 0 );
536}
537
538IconSidePane::IconSidePane( Core *core, TQWidget *parent, const char *name )
539 : SidePaneBase( core, parent, name )
540{
541 mNavigator = new Navigator( this );
542 connect( mNavigator, TQ_SIGNAL( pluginActivated( Kontact::Plugin* ) ),
543 TQ_SIGNAL( pluginSelected( Kontact::Plugin* ) ) );
544
545 setAcceptDrops( true );
546}
547
548IconSidePane::~IconSidePane()
549{
550}
551
552void IconSidePane::updatePlugins()
553{
554 mNavigator->updatePlugins( core()->pluginList() );
555}
556
557void IconSidePane::selectPlugin( Kontact::Plugin *plugin )
558{
559 bool blocked = signalsBlocked();
560 blockSignals( true );
561
562 for ( uint i = 0; i < mNavigator->count(); ++i ) {
563 EntryItem *item = static_cast<EntryItem*>( mNavigator->item( i ) );
564 if ( item->plugin() == plugin ) {
565 mNavigator->setCurrentItem( i );
566 break;
567 }
568 }
569
570 blockSignals( blocked );
571}
572
573void IconSidePane::selectPlugin( const TQString &name )
574{
575 bool blocked = signalsBlocked();
576 blockSignals( true );
577
578 for ( uint i = 0; i < mNavigator->count(); ++i ) {
579 EntryItem *item = static_cast<EntryItem*>( mNavigator->item( i ) );
580 if ( item->plugin()->identifier() == name ) {
581 mNavigator->setCurrentItem( i );
582 break;
583 }
584 }
585
586 blockSignals( blocked );
587}
588
589void IconSidePane::indicateForegrunding( Kontact::Plugin *plugin )
590{
591 for ( uint i = 0; i < mNavigator->count(); ++i ) {
592 EntryItem *item = static_cast<EntryItem*>( mNavigator->item( i ) );
593 if ( item->plugin() == plugin ) {
594 mNavigator->highlightItem( item );
595 break;
596 }
597 }
598
599
600}
601#include "iconsidepane.moc"
This class provides the interface to the Kontact core for the plugins.
Definition: core.h:42
Tooltip that changes text depending on the item it is above.
Definition: iconsidepane.h:92
A TQListBoxPixmap Square Box with an optional icon and a text underneath.
Definition: iconsidepane.h:52
virtual int width(const TQListBox *) const
returns the width of this item.
virtual int height(const TQListBox *) const
returns the height of this item.
Navigation pane showing all parts relevant to the user.
Definition: iconsidepane.h:119
Base class for all Plugins in Kontact.
Definition: plugin.h:59
TQString title() const
Returns the localized title.
Definition: plugin.cpp:94
virtual bool canDecodeDrag(TQMimeSource *)
Return, if the plugin can handle the drag object of the given mime type.
Definition: plugin.h:238
virtual bool showInSideBar() const
Returns whether the plugin provides a part that should be shown in the sidebar.
Definition: plugin.cpp:225
virtual void processDropEvent(TQDropEvent *)
Process drop event.
Definition: plugin.h:243
TQString identifier() const
Returns the identifier.
Definition: plugin.cpp:84
TQString icon() const
Returns the icon name.
Definition: plugin.cpp:104
virtual int weight() const
Return the weight of the plugin.
Definition: plugin.h:208