00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "iconsidepane.h"
00024 #include "mainwindow.h"
00025 #include "plugin.h"
00026 #include "prefs.h"
00027
00028 #include <QtCore/QTimer>
00029 #include <QtGui/QStringListModel>
00030 #include <QtGui/QSortFilterProxyModel>
00031 #include <QtGui/QDragEnterEvent>
00032 #include <QtGui/QDragMoveEvent>
00033 #include <QtGui/QStyledItemDelegate>
00034 #include <QtGui/QScrollBar>
00035
00036 #include <KLocalizedString>
00037 #include <KStringHandler>
00038 #include <KDialog>
00039 #include <KIcon>
00040
00041 namespace Kontact
00042 {
00043
00044 class Navigator;
00045
00046 class SelectionModel : public QItemSelectionModel
00047 {
00048 public:
00049 SelectionModel( QAbstractItemModel *model, QObject *parent )
00050 : QItemSelectionModel( model, parent )
00051 {
00052 }
00053
00054 public slots:
00055 virtual void clear()
00056 {
00057
00058
00059
00060 }
00061
00062 virtual void select( const QModelIndex &index, QItemSelectionModel::SelectionFlags command )
00063 {
00064
00065 if ( !index.isValid() && ( command & QItemSelectionModel::Clear ) ) {
00066 return;
00067 }
00068 QItemSelectionModel::select( index, command );
00069 }
00070
00071 virtual void select( const QItemSelection &selection,
00072 QItemSelectionModel::SelectionFlags command )
00073 {
00074
00075 if ( !selection.count() && ( command & QItemSelectionModel::Clear ) ) {
00076 return;
00077 }
00078 QItemSelectionModel::select( selection, command );
00079 }
00080 };
00081
00082 class Model : public QStringListModel
00083 {
00084 public:
00085 enum SpecialRoles {
00086 PluginName = Qt::UserRole
00087 };
00088
00089 Model( Navigator *parentNavigator = 0 )
00090 : QStringListModel( parentNavigator ), mNavigator(parentNavigator)
00091 {
00092 }
00093
00094 void emitLayoutChanged()
00095 {
00096 emit layoutChanged();
00097 }
00098
00099 void setPluginList( const QList<Kontact::Plugin*> &list ) {
00100 pluginList = list;
00101 }
00102
00103 virtual Qt::ItemFlags flags( const QModelIndex &index ) const
00104 {
00105 Qt::ItemFlags flags = QStringListModel::flags( index );
00106
00107 flags &= ~Qt::ItemIsEditable;
00108
00109 if ( index.isValid() ) {
00110 if ( static_cast<Kontact::Plugin*>( index.internalPointer() )->disabled() ) {
00111 flags &= ~Qt::ItemIsEnabled;
00112 flags &= ~Qt::ItemIsSelectable;
00113 flags &= ~Qt::ItemIsDropEnabled;
00114 } else {
00115 flags |= Qt::ItemIsDropEnabled;
00116 }
00117 } else {
00118 flags &= ~Qt::ItemIsDropEnabled;
00119 }
00120
00121 return flags;
00122 }
00123
00124 virtual QModelIndex index( int row, int column,
00125 const QModelIndex &parent = QModelIndex() ) const
00126 {
00127 Q_UNUSED( parent );
00128 if ( row < 0 || row >= pluginList.count() ) {
00129 return QModelIndex();
00130 }
00131 return createIndex( row, column, pluginList[row] );
00132 }
00133
00134 virtual QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const
00135 {
00136 if ( !index.isValid() || !index.internalPointer() ) {
00137 return QVariant();
00138 }
00139
00140 if ( role == Qt::DisplayRole ) {
00141 if ( !mNavigator->showText() ) {
00142 return QVariant();
00143 }
00144 return static_cast<Kontact::Plugin*>( index.internalPointer() )->title();
00145 } else if ( role == Qt::DecorationRole ) {
00146 if ( !mNavigator->showIcons() ) {
00147 return QVariant();
00148 }
00149 return KIcon( static_cast<Kontact::Plugin*>( index.internalPointer() )->icon() );
00150 } else if ( role == Qt::TextAlignmentRole ) {
00151 return Qt::AlignCenter;
00152 } else if ( role == Qt::ToolTipRole ) {
00153 if ( !mNavigator->showText() ) {
00154 return static_cast<Kontact::Plugin*>( index.internalPointer() )->title();
00155 }
00156 return QVariant();
00157 } else if ( role == PluginName ) {
00158 return static_cast<Kontact::Plugin*>( index.internalPointer() )->identifier();
00159 }
00160 return QStringListModel::data( index, role );
00161 }
00162
00163 private:
00164 QList<Kontact::Plugin*> pluginList;
00165 Navigator *mNavigator;
00166 };
00167
00168 class SortFilterProxyModel
00169 : public QSortFilterProxyModel
00170 {
00171 public:
00172 SortFilterProxyModel( QObject *parent = 0 ): QSortFilterProxyModel( parent )
00173 {
00174 setDynamicSortFilter( true );
00175 sort ( 0 );
00176 }
00177 protected:
00178 bool lessThan( const QModelIndex &left, const QModelIndex &right ) const
00179 {
00180 Kontact::Plugin *leftPlugin = static_cast<Kontact::Plugin*>( left.internalPointer() );
00181 Kontact::Plugin *rightPlugin = static_cast<Kontact::Plugin*>( right.internalPointer() );
00182
00183 if ( leftPlugin->weight() == rightPlugin->weight() ) {
00184 return KStringHandler::naturalCompare( leftPlugin->title(), rightPlugin->title() ) < 0;
00185 }
00186
00187 return leftPlugin->weight() < rightPlugin->weight();
00188 }
00189 };
00190
00191 class Delegate : public QStyledItemDelegate
00192 {
00193 public:
00194 Delegate( Navigator *parentNavigator = 0 )
00195 : QStyledItemDelegate( parentNavigator ), mNavigator( parentNavigator )
00196 {
00197 }
00198
00199 void paint( QPainter *painter, const QStyleOptionViewItem &option,
00200 const QModelIndex &index ) const
00201 {
00202 if ( !index.isValid() || !index.internalPointer() ) {
00203 return;
00204 }
00205
00206 QStyleOptionViewItemV4 optionCopy( *static_cast<const QStyleOptionViewItemV4*>( &option ) );
00207 optionCopy.decorationPosition = QStyleOptionViewItem::Top;
00208 optionCopy.decorationSize = QSize( mNavigator->iconSize(), mNavigator->iconSize() );
00209 optionCopy.textElideMode = Qt::ElideNone;
00210 QStyledItemDelegate::paint( painter, optionCopy, index );
00211 }
00212
00213 QSize sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const
00214 {
00215 if ( !index.isValid() || !index.internalPointer() ) {
00216 return QSize();
00217 }
00218
00219 QStyleOptionViewItemV4 optionCopy( *static_cast<const QStyleOptionViewItemV4*>( &option ) );
00220 optionCopy.decorationPosition = QStyleOptionViewItem::Top;
00221 optionCopy.decorationSize =
00222 mNavigator->showIcons() ? QSize( mNavigator->iconSize(), mNavigator->iconSize() ) : QSize();
00223 optionCopy.textElideMode = Qt::ElideNone;
00224 return QStyledItemDelegate::sizeHint( optionCopy, index );
00225 }
00226
00227 private:
00228 Navigator *mNavigator;
00229 };
00230
00231 Navigator::Navigator( SidePaneBase *parent )
00232 : QListView( parent ), mSidePane( parent )
00233 {
00234 setViewport( new QWidget( this ) );
00235
00236 setVerticalScrollMode( ScrollPerPixel );
00237 setHorizontalScrollMode( ScrollPerPixel );
00238
00239 mIconSize = Prefs::self()->sidePaneIconSize();
00240 mShowIcons = Prefs::self()->sidePaneShowIcons();
00241 mShowText = Prefs::self()->sidePaneShowText();
00242
00243 QActionGroup *viewMode = new QActionGroup( this );
00244
00245 mShowIconsAction = new KAction( i18n( "Show Icons Only" ), this );
00246 mShowIconsAction->setCheckable( true );
00247 mShowIconsAction->setActionGroup( viewMode );
00248 mShowIconsAction->setChecked( !mShowText && mShowIcons );
00249 connect( mShowIconsAction, SIGNAL(triggered(bool)), this, SLOT(slotActionTriggered(bool)) );
00250
00251 mShowTextAction = new KAction( i18n( "Show Text Only" ), this );
00252 mShowTextAction->setCheckable( true );
00253 mShowTextAction->setActionGroup( viewMode );
00254 mShowTextAction->setChecked( mShowText && !mShowIcons );
00255 connect( mShowTextAction, SIGNAL(triggered(bool)), this, SLOT(slotActionTriggered(bool)) );
00256
00257 mShowBothAction = new KAction( i18n( "Show Icons and Text" ), this );
00258 mShowBothAction->setCheckable( true );
00259 mShowBothAction->setActionGroup( viewMode );
00260 mShowBothAction->setChecked( mShowText && mShowIcons );
00261 connect( mShowBothAction, SIGNAL(triggered(bool)), this, SLOT(slotActionTriggered(bool)) );
00262
00263 KAction *sep = new KAction( this );
00264 sep->setSeparator( true );
00265
00266 QActionGroup *iconSize = new QActionGroup( this );
00267
00268 mBigIconsAction = new KAction( i18n( "Big Icons" ), this );
00269 mBigIconsAction->setCheckable( iconSize );
00270 mBigIconsAction->setActionGroup( iconSize );
00271 mBigIconsAction->setChecked( mIconSize == KIconLoader::SizeLarge );
00272 connect( mBigIconsAction, SIGNAL(triggered(bool)), this, SLOT(slotActionTriggered(bool)) );
00273
00274 mNormalIconsAction = new KAction( i18n( "Normal Icons" ), this );
00275 mNormalIconsAction->setCheckable( true );
00276 mNormalIconsAction->setActionGroup( iconSize );
00277 mNormalIconsAction->setChecked( mIconSize == KIconLoader::SizeMedium );
00278 connect( mNormalIconsAction, SIGNAL(triggered(bool)), this, SLOT(slotActionTriggered(bool)) );
00279
00280 mSmallIconsAction = new KAction( i18n( "Small Icons" ), this );
00281 mSmallIconsAction->setCheckable( true );
00282 mSmallIconsAction->setActionGroup( iconSize );
00283 mSmallIconsAction->setChecked( mIconSize == KIconLoader::SizeSmallMedium );
00284 connect( mSmallIconsAction, SIGNAL(triggered(bool)), this, SLOT(slotActionTriggered(bool)) );
00285
00286 QList<QAction*> actionList;
00287 actionList << mShowIconsAction << mShowTextAction << mShowBothAction << sep
00288 << mBigIconsAction << mNormalIconsAction << mSmallIconsAction;
00289
00290 insertActions( 0, actionList );
00291
00292 setContextMenuPolicy( Qt::ActionsContextMenu );
00293 setViewMode( ListMode );
00294 setItemDelegate( new Delegate( this ) );
00295 mModel = new Model( this );
00296 SortFilterProxyModel *sortFilterProxyModel = new SortFilterProxyModel;
00297 sortFilterProxyModel->setSourceModel( mModel );
00298 setModel( sortFilterProxyModel );
00299 setSelectionModel( new SelectionModel( sortFilterProxyModel, this ) );
00300
00301 setDragDropMode( DropOnly );
00302 viewport()->setAcceptDrops( true );
00303 setDropIndicatorShown( true );
00304
00305 connect( selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
00306 this, SLOT(slotCurrentChanged(QModelIndex)) );
00307 }
00308
00309 void Navigator::updatePlugins( QList<Kontact::Plugin*> plugins_ )
00310 {
00311 QString currentPlugin;
00312 if ( currentIndex().isValid() ) {
00313 currentPlugin = currentIndex().model()->data( currentIndex(), Model::PluginName ).toString();
00314 }
00315
00316 QList<Kontact::Plugin*> pluginsToShow;
00317 foreach ( Kontact::Plugin *plugin, plugins_ ) {
00318 if ( plugin->showInSideBar() ) {
00319 pluginsToShow << plugin;
00320 }
00321 }
00322
00323 mModel->setPluginList( pluginsToShow );
00324
00325 mModel->removeRows( 0, mModel->rowCount() );
00326 mModel->insertRows( 0, pluginsToShow.count() );
00327
00328
00329 if ( !currentPlugin.isEmpty() ) {
00330 setCurrentPlugin( currentPlugin );
00331 }
00332 }
00333
00334 void Navigator::setCurrentPlugin( const QString &plugin )
00335 {
00336 for ( int i = 0; i < model()->rowCount(); i++ ) {
00337 const QModelIndex index = model()->index( i, 0 );
00338 const QString pluginName = model()->data( index, Model::PluginName ).toString();
00339
00340 if ( plugin == pluginName ) {
00341 selectionModel()->setCurrentIndex( index, QItemSelectionModel::SelectCurrent );
00342 break;
00343 }
00344 }
00345 }
00346
00347 QSize Navigator::sizeHint() const
00348 {
00349
00350
00351
00352
00353
00354 int maxWidth = 0;
00355 for ( int i = 0; i < model()->rowCount(); i++ ) {
00356 const QModelIndex index = model()->index( i, 0 );
00357 maxWidth = qMax( maxWidth, sizeHintForIndex( index ).width() );
00358 }
00359
00360 int viewHeight = QListView::sizeHint().height();
00361
00362 return QSize( maxWidth + rect().width() - contentsRect().width(), viewHeight );
00363 }
00364
00365 void Navigator::dragEnterEvent( QDragEnterEvent *event )
00366 {
00367 if ( event->proposedAction() == Qt::IgnoreAction ) {
00368 return;
00369 }
00370 event->acceptProposedAction();
00371 }
00372
00373 void Navigator::dragMoveEvent( QDragMoveEvent *event )
00374 {
00375 if ( event->proposedAction() == Qt::IgnoreAction ) {
00376 return;
00377 }
00378
00379 const QModelIndex dropIndex = indexAt( event->pos() );
00380
00381 if ( !dropIndex.isValid() ||
00382 !( dropIndex.model()->flags( dropIndex ) & Qt::ItemIsEnabled ) ) {
00383 event->setAccepted( false );
00384 return;
00385 } else {
00386 const QModelIndex sourceIndex =
00387 static_cast<const QSortFilterProxyModel*>( model() )->mapToSource( dropIndex );
00388 Kontact::Plugin *plugin =
00389 static_cast<Kontact::Plugin*>( sourceIndex.internalPointer() );
00390 if ( !plugin->canDecodeMimeData( event->mimeData() ) ) {
00391 event->setAccepted( false );
00392 return;
00393 }
00394 }
00395
00396 event->acceptProposedAction();
00397 }
00398
00399 void Navigator::dropEvent( QDropEvent *event )
00400 {
00401 if ( event->proposedAction() == Qt::IgnoreAction ) {
00402 return;
00403 }
00404
00405 const QModelIndex dropIndex = indexAt( event->pos() );
00406
00407 if ( !dropIndex.isValid() ) {
00408 return;
00409 } else {
00410 const QModelIndex sourceIndex =
00411 static_cast<const QSortFilterProxyModel*>( model() )->mapToSource( dropIndex );
00412 Kontact::Plugin *plugin =
00413 static_cast<Kontact::Plugin*>( sourceIndex.internalPointer() );
00414 plugin->processDropEvent( event );
00415 }
00416 }
00417
00418 void Navigator::showEvent( QShowEvent *event )
00419 {
00420 parentWidget()->setMaximumWidth( sizeHint().width() );
00421 parentWidget()->setMinimumWidth( sizeHint().width() );
00422
00423 QListView::showEvent( event );
00424 }
00425
00426 void Navigator::slotCurrentChanged( const QModelIndex ¤t )
00427 {
00428 if ( !current.isValid() || !current.internalPointer() ||
00429 !( current.model()->flags( current ) & Qt::ItemIsEnabled ) ) {
00430 return;
00431 }
00432
00433 QModelIndex source =
00434 static_cast<const QSortFilterProxyModel*>( current.model() )->mapToSource( current );
00435
00436 emit pluginActivated( static_cast<Kontact::Plugin*>( source.internalPointer() ) );
00437 }
00438
00439 void Navigator::slotActionTriggered( bool checked )
00440 {
00441 QObject *object = sender();
00442
00443 if ( object == mShowIconsAction ) {
00444 mShowIcons = checked;
00445 mShowText = !checked;
00446 } else if ( object == mShowTextAction ) {
00447 mShowIcons = !checked;
00448 mShowText = checked;
00449 } else if ( object == mShowBothAction ) {
00450 mShowIcons = checked;
00451 mShowText = checked;
00452 } else if ( object == mBigIconsAction ) {
00453 mIconSize = KIconLoader::SizeLarge;
00454 } else if ( object == mNormalIconsAction ) {
00455 mIconSize = KIconLoader::SizeMedium;
00456 } else if ( object == mSmallIconsAction ) {
00457 mIconSize = KIconLoader::SizeSmallMedium;
00458 }
00459
00460 Prefs::self()->setSidePaneIconSize( mIconSize );
00461 Prefs::self()->setSidePaneShowIcons( mShowIcons );
00462 Prefs::self()->setSidePaneShowText( mShowText );
00463
00464 mModel->emitLayoutChanged();
00465
00466 QTimer::singleShot( 0, this, SLOT(updateNavigatorSize()) );
00467 }
00468
00469 void Navigator::updateNavigatorSize()
00470 {
00471 parentWidget()->setMaximumWidth( sizeHint().width() );
00472 parentWidget()->setMinimumWidth( sizeHint().width() );
00473 }
00474
00475 IconSidePane::IconSidePane( Core *core, QWidget *parent )
00476 : SidePaneBase( core, parent )
00477 {
00478 mNavigator = new Navigator( this );
00479 mNavigator->setFocusPolicy( Qt::NoFocus );
00480 connect( mNavigator, SIGNAL(pluginActivated(Kontact::Plugin*)),
00481 SIGNAL(pluginSelected(Kontact::Plugin*)) );
00482 }
00483
00484 IconSidePane::~IconSidePane()
00485 {
00486 }
00487
00488 void IconSidePane::setCurrentPlugin( const QString &plugin )
00489 {
00490 mNavigator->setCurrentPlugin( plugin );
00491 }
00492
00493 void IconSidePane::updatePlugins()
00494 {
00495 mNavigator->updatePlugins( core()->pluginList() );
00496 }
00497
00498 void IconSidePane::resizeEvent( QResizeEvent *event )
00499 {
00500 Q_UNUSED( event );
00501 setMaximumWidth( mNavigator->sizeHint().width() );
00502 setMinimumWidth( mNavigator->sizeHint().width() );
00503 }
00504
00505 }
00506
00507 #include "iconsidepane.moc"
00508
00509