KDEUI
kpageview.cpp
Go to the documentation of this file.
00001 /* 00002 This file is part of the KDE Libraries 00003 00004 Copyright (C) 2006 Tobias Koenig (tokoe@kde.org) 00005 Copyright (C) 2007 Rafael Fernández López (ereslibre@kde.org) 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Library General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 Boston, MA 02110-1301, USA. 00021 */ 00022 00023 #include "kpageview.h" 00024 #include "kpageview_p.h" 00025 00026 #include "kpagemodel.h" 00027 00028 #include <kdialog.h> 00029 #include <kiconloader.h> 00030 #include <ktitlewidget.h> 00031 00032 #include <QAbstractItemView> 00033 #include <QGridLayout> 00034 #include <QLabel> 00035 #include <QSize> 00036 #include <QStackedWidget> 00037 #include <QTimer> 00038 00039 void KPageViewPrivate::_k_rebuildGui() 00040 { 00041 // clean up old view 00042 Q_Q(KPageView); 00043 00044 QModelIndex currentLastIndex; 00045 if ( view && view->selectionModel() ) { 00046 QObject::disconnect(view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), 00047 q, SLOT(_k_pageSelected(const QItemSelection &, const QItemSelection &))); 00048 currentLastIndex = view->selectionModel()->currentIndex(); 00049 } 00050 00051 delete view; 00052 view = q->createView(); 00053 00054 Q_ASSERT( view ); 00055 00056 view->setSelectionBehavior( QAbstractItemView::SelectItems ); 00057 view->setSelectionMode( QAbstractItemView::SingleSelection ); 00058 00059 if ( model ) { 00060 view->setModel( model ); 00061 } 00062 00063 // setup new view 00064 if ( view->selectionModel() ) { 00065 QObject::connect(view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), q, SLOT(_k_pageSelected(const QItemSelection &, const QItemSelection &))); 00066 00067 if ( currentLastIndex.isValid() ) 00068 view->selectionModel()->setCurrentIndex( currentLastIndex, QItemSelectionModel::Select ); 00069 else if ( model ) 00070 view->selectionModel()->setCurrentIndex( model->index( 0, 0 ), QItemSelectionModel::Select ); 00071 } 00072 00073 if (faceType == KPageView::Tabbed) { 00074 stack->setVisible(false); 00075 layout->removeWidget( stack ); 00076 } else { 00077 layout->addWidget( stack, 2, 1 ); 00078 stack->setVisible(true); 00079 } 00080 00081 titleWidget->setVisible(q->showPageHeader()); 00082 00083 Qt::Alignment alignment = q->viewPosition(); 00084 if ( alignment & Qt::AlignTop ) 00085 layout->addWidget( view, 2, 1 ); 00086 else if ( alignment & Qt::AlignRight ) 00087 layout->addWidget( view, 1, 2, 2, 1 ); 00088 else if ( alignment & Qt::AlignBottom ) 00089 layout->addWidget( view, 4, 1 ); 00090 else if ( alignment & Qt::AlignLeft ) 00091 layout->addWidget( view, 1, 0, 2, 1 ); 00092 } 00093 00094 void KPageViewPrivate::updateSelection() 00095 { 00100 if ( !model ) 00101 return; 00102 00103 if ( !view || !view->selectionModel() ) 00104 return; 00105 00106 const QModelIndex index = view->selectionModel()->currentIndex(); 00107 if ( !index.isValid() ) 00108 view->selectionModel()->setCurrentIndex( model->index( 0, 0 ), QItemSelectionModel::Select ); 00109 } 00110 00111 void KPageViewPrivate::cleanupPages() 00112 { 00117 const QList<QWidget*> widgets = collectPages(); 00118 00119 for ( int i = 0; i < stack->count(); ++i ) { 00120 QWidget *page = stack->widget( i ); 00121 00122 bool found = false; 00123 for ( int j = 0; j < widgets.count(); ++j ) { 00124 if ( widgets[ j ] == page ) 00125 found = true; 00126 } 00127 00128 if ( !found ) 00129 stack->removeWidget( page ); 00130 } 00131 } 00132 00133 QList<QWidget *> KPageViewPrivate::collectPages(const QModelIndex &parentIndex) 00134 { 00139 QList<QWidget*> retval; 00140 00141 int rows = model->rowCount( parentIndex ); 00142 for ( int j = 0; j < rows; ++j ) { 00143 const QModelIndex index = model->index( j, 0, parentIndex ); 00144 retval.append( qvariant_cast<QWidget*>( model->data( index, KPageModel::WidgetRole ) ) ); 00145 00146 if ( model->rowCount( index ) > 0 ) { 00147 retval += collectPages( index ); 00148 } 00149 } 00150 00151 return retval; 00152 } 00153 00154 KPageView::FaceType KPageViewPrivate::detectAutoFace() const 00155 { 00156 if ( !model ) 00157 return KPageView::Plain; 00158 00162 bool hasSubPages = false; 00163 const int count = model->rowCount(); 00164 for ( int i = 0; i < count; ++i ) { 00165 if ( model->rowCount( model->index( i, 0 ) ) > 0 ) { 00166 hasSubPages = true; 00167 break; 00168 } 00169 } 00170 00171 if ( hasSubPages ) 00172 return KPageView::Tree; 00173 00174 if ( model->rowCount() > 1 ) 00175 return KPageView::List; 00176 00177 return KPageView::Plain; 00178 } 00179 00180 void KPageViewPrivate::_k_modelChanged() 00181 { 00182 if ( !model ) 00183 return; 00184 00189 if (faceType == KPageView::Auto) { 00190 _k_rebuildGui(); 00191 // If you discover some crashes use the line below instead... 00192 //QTimer::singleShot(0, q, SLOT(_k_rebuildGui())); 00193 } 00194 00198 QSize size = stack->size(); 00199 const QList<QWidget*> widgets = collectPages(); 00200 for ( int i = 0; i < widgets.count(); ++i ) { 00201 const QWidget *widget = widgets[ i ]; 00202 if ( widget ) 00203 size = size.expandedTo( widget->minimumSizeHint() ); 00204 } 00205 stack->setMinimumSize( size ); 00206 00207 updateSelection(); 00208 } 00209 00210 void KPageViewPrivate::_k_pageSelected(const QItemSelection &index, const QItemSelection &previous) 00211 { 00212 if ( !model ) 00213 return; 00214 00215 // Return if the current Index is not valid 00216 if ( index.indexes().size() != 1 ) { 00217 return; 00218 } 00219 QModelIndex currentIndex = index.indexes().first(); 00220 00221 QModelIndex previousIndex; 00222 // The previous index can be invalid 00223 if ( previous.indexes().size() == 1 ) { 00224 previousIndex = previous.indexes().first(); 00225 } 00226 00227 if (faceType != KPageView::Tabbed) { 00228 QWidget *widget = qvariant_cast<QWidget*>( model->data( currentIndex, KPageModel::WidgetRole ) ); 00229 00230 if ( widget ) { 00231 if ( stack->indexOf( widget ) == -1 ) { // not included yet 00232 stack->addWidget( widget ); 00233 } 00234 00235 stack->setCurrentWidget( widget ); 00236 } else { 00237 stack->setCurrentWidget( defaultWidget ); 00238 } 00239 00240 updateTitleWidget(currentIndex); 00241 } 00242 00243 Q_Q(KPageView); 00244 emit q->currentPageChanged(currentIndex, previousIndex); 00245 } 00246 00247 void KPageViewPrivate::updateTitleWidget(const QModelIndex& index) 00248 { 00249 Q_Q(KPageView); 00250 00251 QString header = model->data( index, KPageModel::HeaderRole ).toString(); 00252 if ( header.isNull() ) { //TODO KDE5 remove that ugly logic, see also doxy-comments in KPageWidgetItem::setHeader() 00253 header = model->data( index, Qt::DisplayRole ).toString(); 00254 } 00255 00256 const QIcon icon = model->data( index, Qt::DecorationRole ).value<QIcon>(); 00257 titleWidget->setPixmap( icon.pixmap( 22, 22 ) ); 00258 titleWidget->setText( header ); 00259 00260 titleWidget->setVisible(q->showPageHeader()); 00261 } 00262 00263 void KPageViewPrivate::_k_dataChanged(const QModelIndex &, const QModelIndex &) 00264 { 00269 if ( !view ) 00270 return; 00271 00272 QModelIndex index = view->selectionModel()->currentIndex(); 00273 if ( !index.isValid() ) 00274 return; 00275 00276 updateTitleWidget( index ); 00277 } 00278 00279 KPageViewPrivate::KPageViewPrivate(KPageView *_parent) 00280 : q_ptr(_parent), model(0), faceType(KPageView::Auto), 00281 layout(0), stack(0), titleWidget(0), view(0) 00282 { 00283 } 00284 00285 void KPageViewPrivate::init() 00286 { 00287 Q_Q(KPageView); 00288 layout = new QGridLayout(q); 00289 stack = new KPageStackedWidget(q); 00290 titleWidget = new KTitleWidget(q); 00291 QPixmap emptyPixmap(22, 22); 00292 emptyPixmap.fill(Qt::transparent); 00293 titleWidget->setPixmap(emptyPixmap); 00294 layout->addWidget(titleWidget, 1, 1); 00295 layout->addWidget(stack, 2, 1); 00296 00297 defaultWidget = new QWidget(q); 00298 stack->addWidget(defaultWidget); 00299 00300 // stack should use most space 00301 layout->setColumnStretch(1, 1); 00302 layout->setRowStretch(2, 1); 00303 } 00304 00308 KPageView::KPageView( QWidget *parent ) 00309 : QWidget(parent), d_ptr(new KPageViewPrivate(this)) 00310 { 00311 d_ptr->init(); 00312 } 00313 00314 KPageView::KPageView(KPageViewPrivate &dd, QWidget *parent) 00315 : QWidget(parent), d_ptr(&dd) 00316 { 00317 d_ptr->init(); 00318 } 00319 00320 KPageView::~KPageView() 00321 { 00322 delete d_ptr; 00323 } 00324 00325 void KPageView::setModel(QAbstractItemModel *model) 00326 { 00327 Q_D(KPageView); 00328 // clean up old model 00329 if ( d->model ) { 00330 disconnect(d->model, SIGNAL(layoutChanged()), this, SLOT(_k_modelChanged())); 00331 disconnect(d->model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), 00332 this, SLOT(_k_dataChanged(const QModelIndex &, const QModelIndex &))); 00333 } 00334 00335 d->model = model; 00336 00337 if ( d->model ) { 00338 connect(d->model, SIGNAL(layoutChanged()), this, SLOT(_k_modelChanged())); 00339 connect(d->model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), 00340 this, SLOT(_k_dataChanged(const QModelIndex &, const QModelIndex &))); 00341 00342 // set new model in navigation view 00343 if ( d->view ) 00344 d->view->setModel( model ); 00345 } 00346 00347 d->_k_rebuildGui(); 00348 } 00349 00350 QAbstractItemModel* KPageView::model() const 00351 { 00352 return d_func()->model; 00353 } 00354 00355 void KPageView::setFaceType( FaceType faceType ) 00356 { 00357 Q_D(KPageView); 00358 d->faceType = faceType; 00359 00360 d->_k_rebuildGui(); 00361 } 00362 00363 KPageView::FaceType KPageView::faceType() const 00364 { 00365 return d_func()->faceType; 00366 } 00367 00368 void KPageView::setCurrentPage( const QModelIndex &index ) 00369 { 00370 Q_D(KPageView); 00371 if ( !d->view || !d->view->selectionModel() ) 00372 return; 00373 00374 d->view->selectionModel()->setCurrentIndex( index, QItemSelectionModel::SelectCurrent ); 00375 } 00376 00377 QModelIndex KPageView::currentPage() const 00378 { 00379 Q_D(const KPageView); 00380 if ( !d->view || !d->view->selectionModel() ) 00381 return QModelIndex(); 00382 00383 return d->view->selectionModel()->currentIndex(); 00384 } 00385 00386 void KPageView::setItemDelegate( QAbstractItemDelegate *delegate ) 00387 { 00388 Q_D(KPageView); 00389 if ( d->view ) 00390 d->view->setItemDelegate( delegate ); 00391 } 00392 00393 QAbstractItemDelegate* KPageView::itemDelegate() const 00394 { 00395 Q_D(const KPageView); 00396 if ( d->view ) 00397 return d->view->itemDelegate(); 00398 else 00399 return 0; 00400 } 00401 00402 void KPageView::setDefaultWidget( QWidget *widget ) 00403 { 00404 Q_D(KPageView); 00405 00406 Q_ASSERT(widget); 00407 00408 bool isCurrent = (d->stack->currentIndex() == d->stack->indexOf( d->defaultWidget )); 00409 00410 // remove old default widget 00411 d->stack->removeWidget( d->defaultWidget ); 00412 delete d->defaultWidget; 00413 00414 // add new default widget 00415 d->defaultWidget = widget; 00416 d->stack->addWidget(d->defaultWidget); 00417 00418 if (isCurrent) 00419 d->stack->setCurrentWidget(d->defaultWidget); 00420 } 00421 00422 QAbstractItemView* KPageView::createView() 00423 { 00424 Q_D(KPageView); 00425 if ( d->faceType == Auto ) { 00426 const FaceType faceType = d->detectAutoFace(); 00427 00428 if ( faceType == Plain ) 00429 return new KDEPrivate::KPagePlainView( this ); 00430 else if ( faceType == List ) 00431 return new KDEPrivate::KPageListView( this ); 00432 else if ( faceType == Tree ) 00433 return new KDEPrivate::KPageTreeView( this ); 00434 else // should never happen 00435 return 0; 00436 } else if ( d->faceType == Plain ) 00437 return new KDEPrivate::KPagePlainView( this ); 00438 else if ( d->faceType == List ) 00439 return new KDEPrivate::KPageListView( this ); 00440 else if ( d->faceType == Tree ) 00441 return new KDEPrivate::KPageTreeView( this ); 00442 else if ( d->faceType == Tabbed ) 00443 return new KDEPrivate::KPageTabbedView( this ); 00444 else 00445 return 0; 00446 } 00447 00448 bool KPageView::showPageHeader() const 00449 { 00450 Q_D(const KPageView); 00451 FaceType faceType = d->faceType; 00452 00453 if ( faceType == Auto ) 00454 faceType = d->detectAutoFace(); 00455 00456 if ( faceType == Tabbed ) { 00457 return false; 00458 } else { 00459 return !d->titleWidget->text().isEmpty(); 00460 } 00461 } 00462 00463 Qt::Alignment KPageView::viewPosition() const 00464 { 00465 Q_D(const KPageView); 00466 FaceType faceType = d->faceType; 00467 00468 if ( faceType == Auto ) 00469 faceType = d->detectAutoFace(); 00470 00471 if ( faceType == Plain || faceType == Tabbed ) 00472 return Qt::AlignTop; 00473 else 00474 return Qt::AlignLeft; 00475 } 00476 00477 #include "kpageview.moc"
KDE 4.6 API Reference