akonadi
agentinstancewidget.cpp
00001 /* 00002 Copyright (c) 2006-2008 Tobias Koenig <tokoe@kde.org> 00003 00004 This library is free software; you can redistribute it and/or modify it 00005 under the terms of the GNU Library General Public License as published by 00006 the Free Software Foundation; either version 2 of the License, or (at your 00007 option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, but WITHOUT 00010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00011 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00012 License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to the 00016 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00017 02110-1301, USA. 00018 */ 00019 00020 #include "agentinstancewidget.h" 00021 00022 #include "agentfilterproxymodel.h" 00023 #include "agentinstance.h" 00024 #include "agentinstancemodel.h" 00025 00026 #include <KIcon> 00027 #include <KGlobal> 00028 00029 #include <QtCore/QUrl> 00030 #include <QtGui/QAbstractTextDocumentLayout> 00031 #include <QtGui/QApplication> 00032 #include <QtGui/QHBoxLayout> 00033 #include <QtGui/QListView> 00034 #include <QtGui/QPainter> 00035 #include <QtGui/QTextDocument> 00036 00037 namespace Akonadi { 00038 namespace Internal { 00039 00040 static void iconsEarlyCleanup(); 00041 00042 struct Icons 00043 { 00044 Icons() 00045 : readyPixmap( KIcon( QLatin1String( "user-online" ) ).pixmap( QSize( 16, 16 ) ) ) 00046 , syncPixmap( KIcon( QLatin1String( "network-connect" ) ).pixmap( QSize( 16, 16 ) ) ) 00047 , errorPixmap( KIcon( QLatin1String( "dialog-error" ) ).pixmap( QSize( 16, 16 ) ) ) 00048 , offlinePixmap( KIcon( QLatin1String( "network-disconnect" ) ).pixmap( QSize( 16, 16 ) ) ) 00049 { 00050 qAddPostRoutine( iconsEarlyCleanup ); 00051 } 00052 QPixmap readyPixmap, syncPixmap, errorPixmap, offlinePixmap; 00053 }; 00054 00055 K_GLOBAL_STATIC( Icons, s_icons ) 00056 00057 // called as a Qt post routine, to prevent pixmap leaking 00058 void iconsEarlyCleanup() { 00059 Icons * const ic = s_icons; 00060 ic->readyPixmap = ic->syncPixmap = ic->errorPixmap = ic->offlinePixmap = QPixmap(); 00061 } 00062 00066 class AgentInstanceWidgetDelegate : public QAbstractItemDelegate 00067 { 00068 public: 00069 AgentInstanceWidgetDelegate( QObject *parent = 0 ); 00070 00071 virtual void paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const; 00072 virtual QSize sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const; 00073 00074 private: 00075 void drawFocus( QPainter*, const QStyleOptionViewItem&, const QRect& ) const; 00076 00077 QTextDocument* document( const QStyleOptionViewItem &option, const QModelIndex &index ) const; 00078 }; 00079 00080 } 00081 00082 using Akonadi::Internal::AgentInstanceWidgetDelegate; 00083 00087 class AgentInstanceWidget::Private 00088 { 00089 public: 00090 Private( AgentInstanceWidget *parent ) 00091 : mParent( parent ) 00092 { 00093 } 00094 00095 void currentAgentInstanceChanged( const QModelIndex&, const QModelIndex& ); 00096 void currentAgentInstanceDoubleClicked( const QModelIndex& ); 00097 00098 AgentInstanceWidget *mParent; 00099 QListView *mView; 00100 AgentInstanceModel *mModel; 00101 AgentFilterProxyModel *proxy; 00102 }; 00103 00104 void AgentInstanceWidget::Private::currentAgentInstanceChanged( const QModelIndex ¤tIndex, const QModelIndex &previousIndex ) 00105 { 00106 AgentInstance currentInstance; 00107 if ( currentIndex.isValid() ) 00108 currentInstance = currentIndex.data( AgentInstanceModel::InstanceRole ).value<AgentInstance>(); 00109 00110 AgentInstance previousInstance; 00111 if ( previousIndex.isValid() ) 00112 previousInstance = previousIndex.data( AgentInstanceModel::InstanceRole ).value<AgentInstance>(); 00113 00114 emit mParent->currentChanged( currentInstance, previousInstance ); 00115 } 00116 00117 void AgentInstanceWidget::Private::currentAgentInstanceDoubleClicked( const QModelIndex ¤tIndex ) 00118 { 00119 AgentInstance currentInstance; 00120 if ( currentIndex.isValid() ) 00121 currentInstance = currentIndex.data( AgentInstanceModel::InstanceRole ).value<AgentInstance>(); 00122 00123 emit mParent->doubleClicked( currentInstance ); 00124 } 00125 00126 AgentInstanceWidget::AgentInstanceWidget( QWidget *parent ) 00127 : QWidget( parent ), d( new Private( this ) ) 00128 { 00129 QHBoxLayout *layout = new QHBoxLayout( this ); 00130 layout->setMargin( 0 ); 00131 00132 d->mView = new QListView( this ); 00133 d->mView->setContextMenuPolicy( Qt::NoContextMenu ); 00134 d->mView->setItemDelegate( new Internal::AgentInstanceWidgetDelegate( d->mView ) ); 00135 d->mView->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel ); 00136 d->mView->setAlternatingRowColors( true ); 00137 d->mView->setSelectionMode( QAbstractItemView::ExtendedSelection ); 00138 layout->addWidget( d->mView ); 00139 00140 d->mModel = new AgentInstanceModel( this ); 00141 00142 d->proxy = new AgentFilterProxyModel( this ); 00143 d->proxy->setSourceModel( d->mModel ); 00144 d->mView->setModel( d->proxy ); 00145 00146 d->mView->selectionModel()->setCurrentIndex( d->mView->model()->index( 0, 0 ), QItemSelectionModel::Select ); 00147 d->mView->scrollTo( d->mView->model()->index( 0, 0 ) ); 00148 00149 connect( d->mView->selectionModel(), SIGNAL( currentChanged( const QModelIndex&, const QModelIndex& ) ), 00150 this, SLOT( currentAgentInstanceChanged( const QModelIndex&, const QModelIndex& ) ) ); 00151 connect( d->mView, SIGNAL( doubleClicked( const QModelIndex& ) ), 00152 this, SLOT( currentAgentInstanceDoubleClicked( const QModelIndex& ) ) ); 00153 } 00154 00155 AgentInstanceWidget::~AgentInstanceWidget() 00156 { 00157 delete d; 00158 } 00159 00160 AgentInstance AgentInstanceWidget::currentAgentInstance() const 00161 { 00162 QItemSelectionModel *selectionModel = d->mView->selectionModel(); 00163 if ( !selectionModel ) 00164 return AgentInstance(); 00165 00166 QModelIndex index = selectionModel->currentIndex(); 00167 if ( !index.isValid() ) 00168 return AgentInstance(); 00169 00170 return index.data( AgentInstanceModel::InstanceRole ).value<AgentInstance>(); 00171 } 00172 00173 QList<AgentInstance> AgentInstanceWidget::selectedAgentInstances() const 00174 { 00175 QList<AgentInstance> list; 00176 QItemSelectionModel *selectionModel = d->mView->selectionModel(); 00177 if ( !selectionModel ) 00178 return list; 00179 00180 QModelIndexList indexes = selectionModel->selection().indexes(); 00181 00182 foreach (const QModelIndex &index, indexes ) 00183 { 00184 list.append( index.data( AgentInstanceModel::InstanceRole ).value<AgentInstance>() ); 00185 } 00186 00187 return list; 00188 } 00189 00190 QAbstractItemView* AgentInstanceWidget::view() const 00191 { 00192 return d->mView; 00193 } 00194 00195 00196 AgentFilterProxyModel* AgentInstanceWidget::agentFilterProxyModel() const 00197 { 00198 return d->proxy; 00199 } 00200 00201 00202 00203 00204 00205 AgentInstanceWidgetDelegate::AgentInstanceWidgetDelegate( QObject *parent ) 00206 : QAbstractItemDelegate( parent ) 00207 { 00208 } 00209 00210 QTextDocument* AgentInstanceWidgetDelegate::document( const QStyleOptionViewItem &option, const QModelIndex &index ) const 00211 { 00212 if ( !index.isValid() ) 00213 return 0; 00214 00215 const QString name = index.model()->data( index, Qt::DisplayRole ).toString(); 00216 int status = index.model()->data( index, AgentInstanceModel::StatusRole ).toInt(); 00217 uint progress = index.model()->data( index, AgentInstanceModel::ProgressRole ).toUInt(); 00218 const QString statusMessage = index.model()->data( index, AgentInstanceModel::StatusMessageRole ).toString(); 00219 const QStringList capabilities = index.model()->data( index, AgentInstanceModel::CapabilitiesRole ).toStringList(); 00220 00221 QTextDocument *document = new QTextDocument( 0 ); 00222 00223 const QVariant data = index.model()->data( index, Qt::DecorationRole ); 00224 if ( data.isValid() && data.type() == QVariant::Icon ) { 00225 document->addResource( QTextDocument::ImageResource, QUrl( QLatin1String( "agent_icon" ) ), 00226 qvariant_cast<QIcon>( data ).pixmap( QSize( 64, 64 ) ) ); 00227 } 00228 00229 if ( !index.data( AgentInstanceModel::OnlineRole ).toBool() ) 00230 document->addResource( QTextDocument::ImageResource, QUrl( QLatin1String( "status_icon" ) ), s_icons->offlinePixmap ); 00231 else if ( status == AgentInstance::Idle ) 00232 document->addResource( QTextDocument::ImageResource, QUrl( QLatin1String( "status_icon" ) ), s_icons->readyPixmap ); 00233 else if ( status == AgentInstance::Running ) 00234 document->addResource( QTextDocument::ImageResource, QUrl( QLatin1String( "status_icon" ) ), s_icons->syncPixmap ); 00235 else 00236 document->addResource( QTextDocument::ImageResource, QUrl( QLatin1String( "status_icon" ) ), s_icons->errorPixmap ); 00237 00238 00239 QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; 00240 if ( cg == QPalette::Normal && !(option.state & QStyle::State_Active) ) 00241 cg = QPalette::Inactive; 00242 00243 QColor textColor; 00244 if ( option.state & QStyle::State_Selected ) { 00245 textColor = option.palette.color( cg, QPalette::HighlightedText ); 00246 } else { 00247 textColor = option.palette.color( cg, QPalette::Text ); 00248 } 00249 00250 QString content = QString::fromLatin1( 00251 "<html style=\"color:%1\">" 00252 "<body>" 00253 "<table>" 00254 "<tr>" 00255 "<td rowspan=\"2\"><img src=\"agent_icon\"> </td>" 00256 "<td><b>%2</b></td>" 00257 "</tr>" ).arg(textColor.name().toUpper()).arg( name ) 00258 + QString::fromLatin1( 00259 "<tr>" 00260 "<td><img src=\"status_icon\"/> %1 %2</td>" 00261 "</tr>" ).arg( statusMessage ).arg( status == 1 ? QString( QLatin1String( "(%1%)" ) ).arg( progress ) : QLatin1String( "" ) ) 00262 + QLatin1String( "</table></body></html>" ); 00263 00264 document->setHtml( content ); 00265 00266 return document; 00267 } 00268 00269 void AgentInstanceWidgetDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const 00270 { 00271 if ( !index.isValid() ) 00272 return; 00273 00274 QTextDocument *doc = document( option, index ); 00275 if ( !doc ) 00276 return; 00277 00278 painter->setRenderHint( QPainter::Antialiasing ); 00279 00280 QPen pen = painter->pen(); 00281 00282 QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; 00283 if ( cg == QPalette::Normal && !(option.state & QStyle::State_Active) ) 00284 cg = QPalette::Inactive; 00285 00286 QStyleOptionViewItemV4 opt(option); 00287 opt.showDecorationSelected = true; 00288 QApplication::style()->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter ); 00289 00290 painter->save(); 00291 painter->translate( option.rect.topLeft() ); 00292 doc->drawContents( painter ); 00293 delete doc; 00294 painter->restore(); 00295 00296 painter->setPen(pen); 00297 00298 drawFocus( painter, option, option.rect ); 00299 } 00300 00301 QSize AgentInstanceWidgetDelegate::sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const 00302 { 00303 if ( !index.isValid() ) 00304 return QSize( 0, 0 ); 00305 00306 QTextDocument *doc = document( option, index ); 00307 if ( !doc ) 00308 return QSize( 0, 0 ); 00309 00310 const QSize size = doc->documentLayout()->documentSize().toSize(); 00311 delete doc; 00312 00313 return size; 00314 } 00315 00316 void AgentInstanceWidgetDelegate::drawFocus( QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect ) const 00317 { 00318 if ( option.state & QStyle::State_HasFocus ) { 00319 QStyleOptionFocusRect o; 00320 o.QStyleOption::operator=( option ); 00321 o.rect = rect; 00322 o.state |= QStyle::State_KeyboardFocusChange; 00323 QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) ? QPalette::Normal : QPalette::Disabled; 00324 o.backgroundColor = option.palette.color( cg, (option.state & QStyle::State_Selected) 00325 ? QPalette::Highlight : QPalette::Background ); 00326 QApplication::style()->drawPrimitive( QStyle::PE_FrameFocusRect, &o, painter ); 00327 } 00328 } 00329 00330 } 00331 00332 #include "agentinstancewidget.moc"