iconsidepane.cpp
00001 /* 00002 This file is part of KDE Kontact. 00003 00004 Copyright (C) 2003 Cornelius Schumacher <schumacher@kde.org> 00005 00006 This program is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU General Public 00008 License as published by the Free Software Foundation; either 00009 version 2 of the License, or (at your option) any later version. 00010 00011 This program is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with this program; see the file COPYING. If not, write to 00018 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 Boston, MA 02110-1301, USA. 00020 */ 00021 00022 #include <tqptrlist.h> 00023 #include <tqwidgetstack.h> 00024 #include <tqsignal.h> 00025 #include <tqobjectlist.h> 00026 #include <tqlabel.h> 00027 #include <tqimage.h> 00028 #include <tqpainter.h> 00029 #include <tqbitmap.h> 00030 #include <tqfontmetrics.h> 00031 #include <tqsignalmapper.h> 00032 #include <tqstyle.h> 00033 #include <tqframe.h> 00034 #include <tqdrawutil.h> 00035 #include <tqcursor.h> 00036 #include <tqtimer.h> 00037 #include <tqtooltip.h> 00038 00039 #include <tdepopupmenu.h> 00040 #include <tdeapplication.h> 00041 #include <kdialog.h> 00042 #include <tdelocale.h> 00043 #include <kiconloader.h> 00044 #include <sidebarextension.h> 00045 00046 #include <kdebug.h> 00047 00048 #include "mainwindow.h" 00049 00050 #include "plugin.h" 00051 00052 #include "prefs.h" 00053 #include "iconsidepane.h" 00054 00055 namespace Kontact 00056 { 00057 00058 //ugly wrapper class for adding an operator< to the Plugin class 00059 00060 class PluginProxy 00061 { 00062 public: 00063 PluginProxy() 00064 : mPlugin( 0 ) 00065 { } 00066 00067 PluginProxy( Plugin *plugin ) 00068 : mPlugin( plugin ) 00069 { } 00070 00071 PluginProxy & operator=( Plugin *plugin ) 00072 { 00073 mPlugin = plugin; 00074 return *this; 00075 } 00076 00077 bool operator<( PluginProxy &rhs ) const 00078 { 00079 return mPlugin->weight() < rhs.mPlugin->weight(); 00080 } 00081 00082 Plugin *plugin() const 00083 { 00084 return mPlugin; 00085 } 00086 00087 private: 00088 Plugin *mPlugin; 00089 }; 00090 00091 } //namespace 00092 00093 using namespace Kontact; 00094 00095 EntryItem::EntryItem( Navigator *parent, Kontact::Plugin *plugin ) 00096 : TQListBoxItem( parent ), 00097 mPlugin( plugin ), 00098 mHasHover( false ), 00099 mPaintActive( false ) 00100 { 00101 reloadPixmap(); 00102 setCustomHighlighting( true ); 00103 setText( plugin->title() ); 00104 } 00105 00106 EntryItem::~EntryItem() 00107 { 00108 } 00109 00110 void EntryItem::reloadPixmap() 00111 { 00112 int size = (int)navigator()->viewMode(); 00113 if ( size != 0 ) 00114 mPixmap = TDEGlobal::iconLoader()->loadIcon( mPlugin->icon(), 00115 TDEIcon::Desktop, size, 00116 mPlugin->disabled() ? 00117 TDEIcon::DisabledState 00118 : TDEIcon::DefaultState); 00119 else 00120 mPixmap = TQPixmap(); 00121 } 00122 00123 Navigator* EntryItem::navigator() const 00124 { 00125 return static_cast<Navigator*>( listBox() ); 00126 } 00127 00128 int EntryItem::width( const TQListBox *listbox ) const 00129 { 00130 int w = 0; 00131 if( navigator()->showIcons() ) { 00132 w = navigator()->viewMode(); 00133 if ( navigator()->viewMode() == SmallIcons ) 00134 w += 4; 00135 } 00136 if( navigator()->showText() ) { 00137 if ( navigator()->viewMode() == SmallIcons ) 00138 w += listbox->fontMetrics().width( text() ); 00139 else 00140 w = TQMAX( w, listbox->fontMetrics().width( text() ) ); 00141 } 00142 return w + ( KDialog::marginHint() * 2 ); 00143 } 00144 00145 int EntryItem::height( const TQListBox *listbox ) const 00146 { 00147 int h = 0; 00148 if ( navigator()->showIcons() ) 00149 h = (int)navigator()->viewMode() + 4; 00150 if ( navigator()->showText() ) { 00151 if ( navigator()->viewMode() == SmallIcons || !navigator()->showIcons() ) 00152 h = TQMAX( h, listbox->fontMetrics().lineSpacing() ) + KDialog::spacingHint() * 2; 00153 else 00154 h = (int)navigator()->viewMode() + listbox->fontMetrics().lineSpacing() + 4; 00155 } 00156 return h; 00157 } 00158 00159 void EntryItem::paint( TQPainter *p ) 00160 { 00161 reloadPixmap(); 00162 00163 TQListBox *box = listBox(); 00164 bool iconAboveText = ( navigator()->viewMode() > SmallIcons ) 00165 && navigator()->showIcons(); 00166 int w = box->viewport()->width(); 00167 int y = iconAboveText ? 2 : 00168 ( ( height( box ) - mPixmap.height() ) / 2 ); 00169 00170 // draw selected 00171 if ( isCurrent() || isSelected() || mHasHover || mPaintActive ) { 00172 int h = height( box ); 00173 00174 TQBrush brush; 00175 if ( isCurrent() || isSelected() || mPaintActive ) 00176 brush = box->colorGroup().brush( TQColorGroup::Highlight ); 00177 else 00178 brush = TQBrush(box->colorGroup().highlight().light( 115 )); 00179 p->fillRect( 1, 0, w - 2, h - 1, brush ); 00180 TQPen pen = p->pen(); 00181 TQPen oldPen = pen; 00182 pen.setColor( box->colorGroup().mid() ); 00183 p->setPen( pen ); 00184 00185 p->drawPoint( 1, 0 ); 00186 p->drawPoint( 1, h - 2 ); 00187 p->drawPoint( w - 2, 0 ); 00188 p->drawPoint( w - 2, h - 2 ); 00189 00190 p->setPen( oldPen ); 00191 } 00192 00193 if ( !mPixmap.isNull() && navigator()->showIcons() ) { 00194 int x = iconAboveText ? ( ( w - mPixmap.width() ) / 2 ) : 00195 KDialog::marginHint(); 00196 p->drawPixmap( x, y, mPixmap ); 00197 } 00198 00199 TQColor shadowColor = listBox()->colorGroup().background().dark(115); 00200 if ( isCurrent() || isSelected() ) { 00201 p->setPen( box->colorGroup().highlightedText() ); 00202 } 00203 00204 if ( !text().isEmpty() && navigator()->showText() ) { 00205 TQFontMetrics fm = p->fontMetrics(); 00206 00207 int x = 0; 00208 if ( iconAboveText ) { 00209 x = ( w - fm.width( text() ) ) / 2; 00210 y += fm.height() - fm.descent(); 00211 if ( navigator()->showIcons() ) 00212 y += mPixmap.height(); 00213 } else { 00214 x = KDialog::marginHint() + 4; 00215 if( navigator()->showIcons() ) { 00216 x += mPixmap.width(); 00217 } 00218 00219 if ( !navigator()->showIcons() || mPixmap.height() < fm.height() ) 00220 y = height( box )/2 - fm.height()/2 + fm.ascent(); 00221 else 00222 y += mPixmap.height()/2 - fm.height()/2 + fm.ascent(); 00223 } 00224 00225 if ( plugin()->disabled() ) { 00226 p->setPen( box->palette().disabled().text( ) ); 00227 } else if ( isCurrent() || isSelected() || mHasHover ) { 00228 p->setPen( box->colorGroup().highlight().dark(115) ); 00229 p->drawText( x + ( TQApplication::reverseLayout() ? -1 : 1), 00230 y + 1, text() ); 00231 p->setPen( box->colorGroup().highlightedText() ); 00232 } 00233 else 00234 p->setPen( box->colorGroup().text() ); 00235 00236 p->drawText( x, y, text() ); 00237 } 00238 00239 // ensure that we don't have a stale flag around 00240 if ( isCurrent() || isSelected() ) mHasHover = false; 00241 } 00242 00243 void EntryItem::setHover( bool hasHover ) 00244 { 00245 mHasHover = hasHover; 00246 } 00247 00248 void EntryItem::setPaintActive( bool paintActive ) 00249 { 00250 mPaintActive = paintActive; 00251 } 00252 00253 Navigator::Navigator( IconSidePane *parent, const char *name ) 00254 : TDEListBox( parent, name ), mSidePane( parent ), 00255 mShowIcons( true ), mShowText( true ) 00256 { 00257 mMouseOn = 0; 00258 mHighlightItem = 0; 00259 mViewMode = sizeIntToEnum( Prefs::self()->sidePaneIconSize() ); 00260 mShowIcons = Prefs::self()->sidePaneShowIcons(); 00261 mShowText = Prefs::self()->sidePaneShowText(); 00262 setSelectionMode( TDEListBox::Single ); 00263 viewport()->setBackgroundMode( PaletteBackground ); 00264 setFrameStyle( TQFrame::NoFrame ); 00265 setHScrollBarMode( TQScrollView::AlwaysOff ); 00266 setAcceptDrops( true ); 00267 00268 setFocusPolicy( TQ_NoFocus ); 00269 00270 connect( this, TQT_SIGNAL( selectionChanged( TQListBoxItem* ) ), 00271 TQT_SLOT( slotExecuted( TQListBoxItem* ) ) ); 00272 connect( this, TQT_SIGNAL( rightButtonPressed( TQListBoxItem*, const TQPoint& ) ), 00273 TQT_SLOT( slotShowRMBMenu( TQListBoxItem*, const TQPoint& ) ) ); 00274 connect( this, TQT_SIGNAL( onItem( TQListBoxItem * ) ), 00275 TQT_SLOT( slotMouseOn( TQListBoxItem * ) ) ); 00276 connect( this, TQT_SIGNAL( onViewport() ), TQT_SLOT( slotMouseOff() ) ); 00277 00278 mMapper = new TQSignalMapper( TQT_TQOBJECT(this) ); 00279 connect( mMapper, TQT_SIGNAL( mapped( int ) ), TQT_SLOT( shortCutSelected( int ) ) ); 00280 00281 TQToolTip::remove( this ); 00282 if ( !mShowText ) 00283 new EntryItemToolTip( this ); 00284 00285 } 00286 00287 TQSize Navigator::sizeHint() const 00288 { 00289 return TQSize( 100, 100 ); 00290 } 00291 00292 void Navigator::highlightItem( EntryItem * item ) 00293 { 00294 mHighlightItem = item; 00295 00296 setPaintActiveItem( mHighlightItem, true ); 00297 00298 TQTimer::singleShot( 2000, this, TQT_SLOT( slotStopHighlight() ) ); 00299 } 00300 00301 void Navigator::slotStopHighlight() 00302 { 00303 setPaintActiveItem( mHighlightItem, false ); 00304 } 00305 00306 void Navigator::setSelected( TQListBoxItem *item, bool selected ) 00307 { 00308 // Reimplemented to avoid the immediate activation of 00309 // the item. might turn out it doesn't work, we check that 00310 // an confirm from MainWindow::selectPlugin() 00311 if ( selected ) { 00312 EntryItem *entry = static_cast<EntryItem*>( item ); 00313 emit pluginActivated( entry->plugin() ); 00314 } 00315 } 00316 00317 void Navigator::updatePlugins( TQValueList<Kontact::Plugin*> plugins_ ) 00318 { 00319 TQValueList<Kontact::PluginProxy> plugins; 00320 TQValueList<Kontact::Plugin*>::ConstIterator end_ = plugins_.end(); 00321 TQValueList<Kontact::Plugin*>::ConstIterator it_ = plugins_.begin(); 00322 for ( ; it_ != end_; ++it_ ) 00323 plugins += PluginProxy( *it_ ); 00324 00325 clear(); 00326 00327 mActions.setAutoDelete( true ); 00328 mActions.clear(); 00329 mActions.setAutoDelete( false ); 00330 00331 int minWidth = 0; 00332 qBubbleSort( plugins ); 00333 TQValueList<Kontact::PluginProxy>::ConstIterator end = plugins.end(); 00334 TQValueList<Kontact::PluginProxy>::ConstIterator it = plugins.begin(); 00335 for ( ; it != end; ++it ) { 00336 Kontact::Plugin *plugin = ( *it ).plugin(); 00337 if ( !plugin->showInSideBar() ) 00338 continue; 00339 00340 EntryItem *item = new EntryItem( this, plugin ); 00341 item->setSelectable( !plugin->disabled() ); 00342 00343 if ( item->width( this ) > minWidth ) 00344 minWidth = item->width( this ); 00345 } 00346 00347 parentWidget()->setFixedWidth( minWidth ); 00348 } 00349 00350 void Navigator::dragEnterEvent( TQDragEnterEvent *event ) 00351 { 00352 kdDebug(5600) << "Navigator::dragEnterEvent()" << endl; 00353 00354 dragMoveEvent( event ); 00355 } 00356 00357 void Navigator::dragMoveEvent( TQDragMoveEvent *event ) 00358 { 00359 kdDebug(5600) << "Navigator::dragEnterEvent()" << endl; 00360 00361 kdDebug(5600) << " Format: " << event->format() << endl; 00362 00363 TQListBoxItem *item = itemAt( event->pos() ); 00364 00365 if ( !item ) { 00366 event->accept( false ); 00367 return; 00368 } 00369 00370 EntryItem *entry = static_cast<EntryItem*>( item ); 00371 00372 kdDebug(5600) << " PLUGIN: " << entry->plugin()->identifier() << endl; 00373 00374 event->accept( entry->plugin()->canDecodeDrag( event ) ); 00375 } 00376 00377 void Navigator::dropEvent( TQDropEvent *event ) 00378 { 00379 kdDebug(5600) << "Navigator::dropEvent()" << endl; 00380 00381 TQListBoxItem *item = itemAt( event->pos() ); 00382 00383 if ( !item ) { 00384 return; 00385 } 00386 00387 EntryItem *entry = static_cast<EntryItem*>( item ); 00388 00389 kdDebug(5600) << " PLUGIN: " << entry->plugin()->identifier() << endl; 00390 00391 entry->plugin()->processDropEvent( event ); 00392 } 00393 00394 void Navigator::resizeEvent( TQResizeEvent *event ) 00395 { 00396 TQListBox::resizeEvent( event ); 00397 triggerUpdate( true ); 00398 } 00399 00400 void Navigator::enterEvent( TQEvent *event ) 00401 { 00402 // work around TQt behaviour: onItem is not emmitted in enterEvent() 00403 TDEListBox::enterEvent( event ); 00404 emit onItem( itemAt( mapFromGlobal( TQCursor::pos() ) ) ); 00405 } 00406 00407 void Navigator::leaveEvent( TQEvent *event ) 00408 { 00409 TDEListBox::leaveEvent( event ); 00410 slotMouseOn( 0 ); 00411 mMouseOn = 0; 00412 } 00413 00414 void Navigator::slotExecuted( TQListBoxItem *item ) 00415 { 00416 if ( !item ) 00417 return; 00418 00419 EntryItem *entry = static_cast<EntryItem*>( item ); 00420 00421 emit pluginActivated( entry->plugin() ); 00422 } 00423 00424 IconViewMode Navigator::sizeIntToEnum(int size) const 00425 { 00426 switch ( size ) { 00427 case int(LargeIcons): 00428 return LargeIcons; 00429 break; 00430 case int(NormalIcons): 00431 return NormalIcons; 00432 break; 00433 case int(SmallIcons): 00434 return SmallIcons; 00435 break; 00436 default: 00437 // Stick with sane values 00438 return NormalIcons; 00439 kdDebug() << "View mode not implemented!" << endl; 00440 break; 00441 } 00442 } 00443 00444 void Navigator::slotShowRMBMenu( TQListBoxItem *, const TQPoint &pos ) 00445 { 00446 TDEPopupMenu menu; 00447 menu.insertTitle( i18n( "Icon Size" ) ); 00448 menu.insertItem( i18n( "Large" ), (int)LargeIcons ); 00449 menu.setItemEnabled( (int)LargeIcons, mShowIcons ); 00450 menu.insertItem( i18n( "Normal" ), (int)NormalIcons ); 00451 menu.setItemEnabled( (int)NormalIcons, mShowIcons ); 00452 menu.insertItem( i18n( "Small" ), (int)SmallIcons ); 00453 menu.setItemEnabled( (int)SmallIcons, mShowIcons ); 00454 00455 menu.setItemChecked( (int)mViewMode, true ); 00456 menu.insertSeparator(); 00457 00458 menu.insertItem( i18n( "Show Icons" ), (int)ShowIcons ); 00459 menu.setItemChecked( (int)ShowIcons, mShowIcons ); 00460 menu.setItemEnabled( (int)ShowIcons, mShowText ); 00461 menu.insertItem( i18n( "Show Text" ), (int)ShowText ); 00462 menu.setItemChecked( (int)ShowText, mShowText ); 00463 menu.setItemEnabled( (int)ShowText, mShowIcons ); 00464 int choice = menu.exec( pos ); 00465 00466 if ( choice == -1 ) 00467 return; 00468 00469 if ( choice >= SmallIcons ) { 00470 mViewMode = sizeIntToEnum( choice ); 00471 Prefs::self()->setSidePaneIconSize( choice ); 00472 } else { 00473 // either icons or text were toggled 00474 if ( choice == ShowIcons ) { 00475 mShowIcons = !mShowIcons; 00476 Prefs::self()->setSidePaneShowIcons( mShowIcons ); 00477 TQToolTip::remove( this ); 00478 if ( !mShowText ) 00479 new EntryItemToolTip( this ); 00480 } else { 00481 mShowText = !mShowText; 00482 Prefs::self()->setSidePaneShowText( mShowText ); 00483 TQToolTip::remove( this ); 00484 } 00485 } 00486 int maxWidth = 0; 00487 TQListBoxItem* it = 0; 00488 for (int i = 0; (it = item(i)) != 0; ++i) 00489 { 00490 int width = it->width(this); 00491 if (width > maxWidth) 00492 maxWidth = width; 00493 } 00494 parentWidget()->setFixedWidth( maxWidth ); 00495 00496 triggerUpdate( true ); 00497 } 00498 00499 void Navigator::shortCutSelected( int pos ) 00500 { 00501 setCurrentItem( pos ); 00502 } 00503 00504 void Navigator::setHoverItem( TQListBoxItem* item, bool hover ) 00505 { 00506 static_cast<EntryItem*>( item )->setHover( hover ); 00507 updateItem( item ); 00508 } 00509 00510 void Navigator::setPaintActiveItem( TQListBoxItem* item, bool paintActive ) 00511 { 00512 static_cast<EntryItem*>( item )->setPaintActive( paintActive ); 00513 updateItem( item ); 00514 } 00515 00516 void Navigator::slotMouseOn( TQListBoxItem* newItem ) 00517 { 00518 TQListBoxItem* oldItem = mMouseOn; 00519 if ( oldItem == newItem ) return; 00520 00521 if ( oldItem && !oldItem->isCurrent() && !oldItem->isSelected() ) 00522 { 00523 setHoverItem( oldItem, false ); 00524 } 00525 00526 if ( newItem && !newItem->isCurrent() && !newItem->isSelected() ) 00527 { 00528 setHoverItem( newItem, true ); 00529 } 00530 mMouseOn = newItem; 00531 } 00532 00533 void Navigator::slotMouseOff() 00534 { 00535 slotMouseOn( 0 ); 00536 } 00537 00538 IconSidePane::IconSidePane( Core *core, TQWidget *parent, const char *name ) 00539 : SidePaneBase( core, parent, name ) 00540 { 00541 mNavigator = new Navigator( this ); 00542 connect( mNavigator, TQT_SIGNAL( pluginActivated( Kontact::Plugin* ) ), 00543 TQT_SIGNAL( pluginSelected( Kontact::Plugin* ) ) ); 00544 00545 setAcceptDrops( true ); 00546 } 00547 00548 IconSidePane::~IconSidePane() 00549 { 00550 } 00551 00552 void IconSidePane::updatePlugins() 00553 { 00554 mNavigator->updatePlugins( core()->pluginList() ); 00555 } 00556 00557 void IconSidePane::selectPlugin( Kontact::Plugin *plugin ) 00558 { 00559 bool blocked = signalsBlocked(); 00560 blockSignals( true ); 00561 00562 for ( uint i = 0; i < mNavigator->count(); ++i ) { 00563 EntryItem *item = static_cast<EntryItem*>( mNavigator->item( i ) ); 00564 if ( item->plugin() == plugin ) { 00565 mNavigator->setCurrentItem( i ); 00566 break; 00567 } 00568 } 00569 00570 blockSignals( blocked ); 00571 } 00572 00573 void IconSidePane::selectPlugin( const TQString &name ) 00574 { 00575 bool blocked = signalsBlocked(); 00576 blockSignals( true ); 00577 00578 for ( uint i = 0; i < mNavigator->count(); ++i ) { 00579 EntryItem *item = static_cast<EntryItem*>( mNavigator->item( i ) ); 00580 if ( item->plugin()->identifier() == name ) { 00581 mNavigator->setCurrentItem( i ); 00582 break; 00583 } 00584 } 00585 00586 blockSignals( blocked ); 00587 } 00588 00589 void IconSidePane::indicateForegrunding( Kontact::Plugin *plugin ) 00590 { 00591 for ( uint i = 0; i < mNavigator->count(); ++i ) { 00592 EntryItem *item = static_cast<EntryItem*>( mNavigator->item( i ) ); 00593 if ( item->plugin() == plugin ) { 00594 mNavigator->highlightItem( item ); 00595 break; 00596 } 00597 } 00598 00599 00600 } 00601 #include "iconsidepane.moc" 00602 00603 // vim: sw=2 sts=2 et tw=80