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 
55 namespace Kontact
56 {
57 
58 //ugly wrapper class for adding an operator< to the Plugin class
59 
60 class 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 
93 using namespace Kontact;
94 
95 EntryItem::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 
106 EntryItem::~EntryItem()
107 {
108 }
109 
110 void 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 
123 Navigator* EntryItem::navigator() const
124 {
125  return static_cast<Navigator*>( listBox() );
126 }
127 
128 int 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 
145 int 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 
159 void 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 
243 void EntryItem::setHover( bool hasHover )
244 {
245  mHasHover = hasHover;
246 }
247 
248 void EntryItem::setPaintActive( bool paintActive )
249 {
250  mPaintActive = paintActive;
251 }
252 
253 Navigator::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 
287 TQSize Navigator::sizeHint() const
288 {
289  return TQSize( 100, 100 );
290 }
291 
292 void Navigator::highlightItem( EntryItem * item )
293 {
294  mHighlightItem = item;
295 
296  setPaintActiveItem( mHighlightItem, true );
297 
298  TQTimer::singleShot( 2000, this, TQ_SLOT( slotStopHighlight() ) );
299 }
300 
301 void Navigator::slotStopHighlight()
302 {
303  setPaintActiveItem( mHighlightItem, false );
304 }
305 
306 void 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 
317 void 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 
350 void Navigator::dragEnterEvent( TQDragEnterEvent *event )
351 {
352  kdDebug(5600) << "Navigator::dragEnterEvent()" << endl;
353 
354  dragMoveEvent( event );
355 }
356 
357 void 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 
377 void 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 
394 void Navigator::resizeEvent( TQResizeEvent *event )
395 {
396  TQListBox::resizeEvent( event );
397  triggerUpdate( true );
398 }
399 
400 void 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 
407 void Navigator::leaveEvent( TQEvent *event )
408 {
409  TDEListBox::leaveEvent( event );
410  slotMouseOn( 0 );
411  mMouseOn = 0;
412 }
413 
414 void 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 
424 IconViewMode 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 
444 void 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 
499 void Navigator::shortCutSelected( int pos )
500 {
501  setCurrentItem( pos );
502 }
503 
504 void Navigator::setHoverItem( TQListBoxItem* item, bool hover )
505 {
506  static_cast<EntryItem*>( item )->setHover( hover );
507  updateItem( item );
508 }
509 
510 void Navigator::setPaintActiveItem( TQListBoxItem* item, bool paintActive )
511 {
512  static_cast<EntryItem*>( item )->setPaintActive( paintActive );
513  updateItem( item );
514 }
515 
516 void 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 
533 void Navigator::slotMouseOff()
534 {
535  slotMouseOn( 0 );
536 }
537 
538 IconSidePane::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 
548 IconSidePane::~IconSidePane()
549 {
550 }
551 
552 void IconSidePane::updatePlugins()
553 {
554  mNavigator->updatePlugins( core()->pluginList() );
555 }
556 
557 void 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 
573 void 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 
589 void 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