/* Copyright (c) 2007 Volker Krause Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net Author: Sergio Martins This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "multiagendaview.h" #include "configdialoginterface.h" #include "prefs.h" #include "agenda/agenda.h" #include "agenda/agendaview.h" #include "agenda/timelabelszone.h" #include #include #include #include #include #include using namespace Future; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Akonadi; using namespace EventViews; /** Function for debugging purposes: prints an object's sizeHint()/minimumSizeHint()/policy and it's children's too, recursively */ /* static void printObject( QObject *o, int level = 0 ) { QMap map; map.insert( 0, "Fixed" ); map.insert( 1, "Minimum" ); map.insert( 4, "Maximum" ); map.insert( 5, "Preferred" ); map.insert( 7, "Expanding" ); map.insert( 3, "MinimumExpaning" ); map.insert( 13, "Ignored" ); QWidget *w = qobject_cast( o ); if ( w ) { qDebug() << QString( level*2, '-' ) << o << w->sizeHint() << "/" << map[w->sizePolicy().verticalPolicy()] << "; minimumSize = " << w->minimumSize() << "; minimumSizeHint = " << w->minimumSizeHint(); } else { qDebug() << QString( level*2, '-' ) << o ; } foreach( QObject *child, o->children() ) { printObject( child, level + 1 ); } } */ static QString generateColumnLabel( int c ) { return i18n( "Agenda %1", c + 1 ); } class MultiAgendaView::Private { public: Private( MultiAgendaView *qq ) : q( qq ), mUpdateOnShow( true ), mPendingChanges( true ), mCustomColumnSetupUsed( false ), mCustomNumberOfColumns( 2 ) { } ~Private() { qDeleteAll( mSelectionSavers ); } void addView( const Akonadi::Collection &collection ); void addView( KCheckableProxyModel *selectionProxy, const QString &title ); AgendaView *createView( const QString &title ); void deleteViews(); void setupViews(); void resizeScrollView( const QSize &size ); MultiAgendaView *q; QList mAgendaViews; QList mAgendaWidgets; KHBox *mTopBox; QScrollArea *mScrollArea; TimeLabelsZone *mTimeLabelsZone; QSplitter *mLeftSplitter, *mRightSplitter; QScrollBar *mScrollBar; QWidget *mLeftBottomSpacer, *mRightBottomSpacer; QDate mStartDate, mEndDate; bool mUpdateOnShow; bool mPendingChanges; bool mCustomColumnSetupUsed; QVector mCollectionSelectionModels; QVector mCustomColumnTitles; int mCustomNumberOfColumns; QLabel *mLabel; QWidget *mRightDummyWidget; QHash* > mSelectionSavers; }; MultiAgendaView::MultiAgendaView( QWidget *parent ) : EventView( parent ), d( new Private( this ) ) { QHBoxLayout *topLevelLayout = new QHBoxLayout( this ); topLevelLayout->setSpacing( 0 ); topLevelLayout->setMargin( 0 ); QFontMetrics fm( font() ); int topLabelHeight = 2 * fm.height() + fm.lineSpacing(); KVBox *topSideBox = new KVBox( this ); QWidget *topSideSpacer = new QWidget( topSideBox ); topSideSpacer->setFixedHeight( topLabelHeight ); d->mLeftSplitter = new QSplitter( Qt::Vertical, topSideBox ); d->mLeftSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() ); d->mLabel = new QLabel( i18n( "All Day" ), d->mLeftSplitter ); d->mLabel->setAlignment( Qt::AlignRight | Qt::AlignVCenter ); d->mLabel->setWordWrap( true ); KVBox *sideBox = new KVBox( d->mLeftSplitter ); // compensate for the frame the agenda views but not the timelabels have QWidget *timeLabelTopAlignmentSpacer = new QWidget( sideBox ); d->mTimeLabelsZone = new TimeLabelsZone( sideBox, PrefsPtr( new Prefs() ) ); QWidget *timeLabelBotAlignmentSpacer = new QWidget( sideBox ); d->mLeftBottomSpacer = new QWidget( topSideBox ); topLevelLayout->addWidget( topSideBox ); d->mScrollArea = new QScrollArea( this ); d->mScrollArea->setWidgetResizable( true ); d->mScrollArea->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); // BUG: timelabels aren't aligned with the agenda's grid, 2 or 3 pixels of offset. // asymetric since the timelabels timeLabelTopAlignmentSpacer->setFixedHeight( d->mScrollArea->frameWidth() - 1 ); // have 25 horizontal lines timeLabelBotAlignmentSpacer->setFixedHeight( d->mScrollArea->frameWidth() - 2 ); d->mScrollArea->setFrameShape( QFrame::NoFrame ); topLevelLayout->addWidget( d->mScrollArea, 100 ); d->mTopBox = new KHBox( d->mScrollArea->viewport() ); d->mScrollArea->setWidget( d->mTopBox ); topSideBox = new KVBox( this ); topSideSpacer = new QWidget( topSideBox ); topSideSpacer->setFixedHeight( topLabelHeight ); d->mRightSplitter = new QSplitter( Qt::Vertical, topSideBox ); d->mRightSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() ); connect( d->mLeftSplitter, SIGNAL(splitterMoved(int,int)), SLOT(resizeSplitters()) ); connect( d->mRightSplitter, SIGNAL(splitterMoved(int,int)), SLOT(resizeSplitters()) ); d->mRightDummyWidget = new QWidget( d->mRightSplitter ); d->mScrollBar = new QScrollBar( Qt::Vertical, d->mRightSplitter ); d->mRightBottomSpacer = new QWidget( topSideBox ); topLevelLayout->addWidget( topSideBox ); } void MultiAgendaView::setCalendar( const Akonadi::ETMCalendar::Ptr &calendar ) { EventView::setCalendar( calendar ); Q_FOREACH ( KCheckableProxyModel *proxy, d->mCollectionSelectionModels ) { proxy->setSourceModel( calendar->entityTreeModel() ); } disconnect( 0, SIGNAL(selectionChanged(Akonadi::Collection::List,Akonadi::Collection::List)), this, SLOT(forceRecreateViews())); connect( collectionSelection(), SIGNAL(selectionChanged(Akonadi::Collection::List,Akonadi::Collection::List)), SLOT(forceRecreateViews()) ); recreateViews(); } void MultiAgendaView::recreateViews() { if ( !d->mPendingChanges ) { return; } d->mPendingChanges = false; d->deleteViews(); if ( d->mCustomColumnSetupUsed ) { Q_ASSERT( d->mCollectionSelectionModels.size() == d->mCustomNumberOfColumns ); for ( int i = 0; i < d->mCustomNumberOfColumns; ++i ) { d->addView( d->mCollectionSelectionModels[i], d->mCustomColumnTitles[i] ); } } else { Q_FOREACH ( const Akonadi::Collection &i, collectionSelection()->selectedCollections() ) { if ( i.contentMimeTypes().contains( KCalCore::Event::eventMimeType() ) ) { d->addView( i ); } } } // no resources activated, so stop here to avoid crashing somewhere down the line // TODO: show a nice message instead if ( d->mAgendaViews.isEmpty() ) { return; } d->setupViews(); QTimer::singleShot( 0, this, SLOT(slotResizeScrollView()) ); d->mTimeLabelsZone->updateAll(); QScrollArea *timeLabel = d->mTimeLabelsZone->timeLabels().first(); connect( timeLabel->verticalScrollBar(), SIGNAL(valueChanged(int)), d->mScrollBar, SLOT(setValue(int)) ); connect( d->mScrollBar, SIGNAL(valueChanged(int)), timeLabel->verticalScrollBar(), SLOT(setValue(int)) ); resizeSplitters(); QTimer::singleShot( 0, this, SLOT(setupScrollBar()) ); d->mTimeLabelsZone->updateTimeLabelsPosition(); } void MultiAgendaView::forceRecreateViews() { d->mPendingChanges = true; recreateViews(); } void MultiAgendaView::Private::deleteViews() { Q_FOREACH ( AgendaView *const i, mAgendaViews ) { KCheckableProxyModel *proxy = i->takeCustomCollectionSelectionProxyModel(); if ( proxy && !mCollectionSelectionModels.contains( proxy ) ) { delete proxy; } delete i; } mAgendaViews.clear(); mTimeLabelsZone->setAgendaView( 0 ); qDeleteAll( mAgendaWidgets ); mAgendaWidgets.clear(); } void MultiAgendaView::Private::setupViews() { foreach ( AgendaView *agenda, mAgendaViews ) { q->connect( agenda, SIGNAL(newEventSignal()), q, SIGNAL(newEventSignal()) ); q->connect( agenda, SIGNAL(newEventSignal(QDate)), q, SIGNAL(newEventSignal(QDate)) ); q->connect( agenda, SIGNAL(newEventSignal(QDateTime)), q, SIGNAL(newEventSignal(QDateTime)) ); q->connect( agenda, SIGNAL(newEventSignal(QDateTime,QDateTime)), q, SIGNAL(newEventSignal(QDateTime,QDateTime)) ); q->connect( agenda, SIGNAL(editIncidenceSignal(Akonadi::Item)), q, SIGNAL(editIncidenceSignal(Akonadi::Item)) ); q->connect( agenda, SIGNAL(showIncidenceSignal(Akonadi::Item)), q, SIGNAL(showIncidenceSignal(Akonadi::Item)) ); q->connect( agenda, SIGNAL(deleteIncidenceSignal(Akonadi::Item)), q, SIGNAL(deleteIncidenceSignal(Akonadi::Item)) ); q->connect( agenda, SIGNAL(incidenceSelected(Akonadi::Item,QDate)), q, SIGNAL(incidenceSelected(Akonadi::Item,QDate)) ); q->connect( agenda, SIGNAL(cutIncidenceSignal(Akonadi::Item)), q, SIGNAL(cutIncidenceSignal(Akonadi::Item)) ); q->connect( agenda, SIGNAL(copyIncidenceSignal(Akonadi::Item)), q, SIGNAL(copyIncidenceSignal(Akonadi::Item)) ); q->connect( agenda, SIGNAL(pasteIncidenceSignal()), q, SIGNAL(pasteIncidenceSignal()) ); q->connect( agenda, SIGNAL(toggleAlarmSignal(Akonadi::Item)), q, SIGNAL(toggleAlarmSignal(Akonadi::Item)) ); q->connect( agenda, SIGNAL(dissociateOccurrencesSignal(Akonadi::Item,QDate)), q, SIGNAL(dissociateOccurrencesSignal(Akonadi::Item,QDate)) ); q->connect( agenda, SIGNAL(newTodoSignal(QDate)), q, SIGNAL(newTodoSignal(QDate)) ); q->connect( agenda, SIGNAL(incidenceSelected(Akonadi::Item,QDate)), q, SLOT(slotSelectionChanged()) ); q->connect( agenda, SIGNAL(timeSpanSelectionChanged()), q, SLOT(slotClearTimeSpanSelection()) ); q->disconnect( agenda->agenda(), SIGNAL(zoomView(int,QPoint,Qt::Orientation)), agenda, 0 ); q->connect( agenda->agenda(), SIGNAL(zoomView(int,QPoint,Qt::Orientation)), q, SLOT(zoomView(int,QPoint,Qt::Orientation)) ); } AgendaView *lastView = mAgendaViews.last(); foreach ( AgendaView *agenda, mAgendaViews ) { if ( agenda != lastView ) { connect( agenda->agenda()->verticalScrollBar(), SIGNAL(valueChanged(int)), lastView->agenda()->verticalScrollBar(), SLOT(setValue(int)) ); } } foreach ( AgendaView *agenda, mAgendaViews ) { agenda->readSettings(); } int minWidth = 0; foreach ( QWidget *widget, mAgendaWidgets ) { minWidth = qMax( minWidth, widget->minimumSizeHint().width() ); } foreach ( QWidget *widget, mAgendaWidgets ) { widget->setMinimumWidth( minWidth ); } } MultiAgendaView::~MultiAgendaView() { delete d; } Akonadi::Item::List MultiAgendaView::selectedIncidences() const { Akonadi::Item::List list; foreach ( AgendaView *agendaView, d->mAgendaViews ) { list += agendaView->selectedIncidences(); } return list; } KCalCore::DateList MultiAgendaView::selectedIncidenceDates() const { KCalCore::DateList list; foreach ( AgendaView *agendaView, d->mAgendaViews ) { list += agendaView->selectedIncidenceDates(); } return list; } int MultiAgendaView::currentDateCount() const { foreach ( AgendaView *agendaView, d->mAgendaViews ) { return agendaView->currentDateCount(); } return 0; } void MultiAgendaView::showDates( const QDate &start, const QDate &end, const QDate &preferredMonth ) { Q_UNUSED( preferredMonth ); d->mStartDate = start; d->mEndDate = end; slotResizeScrollView(); d->mTimeLabelsZone->updateAll(); foreach ( AgendaView *agendaView, d->mAgendaViews ) { agendaView->showDates( start, end ); } } void MultiAgendaView::showIncidences( const Akonadi::Item::List &incidenceList, const QDate &date ) { foreach ( AgendaView *agendaView, d->mAgendaViews ) { agendaView->showIncidences( incidenceList, date ); } } void MultiAgendaView::updateView() { recreateViews(); foreach ( AgendaView *agendaView, d->mAgendaViews ) { agendaView->updateView(); } } int MultiAgendaView::maxDatesHint() const { // these maxDatesHint functions aren't used return AgendaView::MAX_DAY_COUNT; } void MultiAgendaView::slotSelectionChanged() { foreach ( AgendaView *agenda, d->mAgendaViews ) { if ( agenda != sender() ) { agenda->clearSelection(); } } } bool MultiAgendaView::eventDurationHint( QDateTime &startDt, QDateTime &endDt, bool &allDay ) const { foreach ( AgendaView *agenda, d->mAgendaViews ) { bool valid = agenda->eventDurationHint( startDt, endDt, allDay ); if ( valid ) { return true; } } return false; } void MultiAgendaView::slotClearTimeSpanSelection() { foreach ( AgendaView *agenda, d->mAgendaViews ) { if ( agenda != sender() ) { agenda->clearTimeSpanSelection(); } else { setCollectionId( agenda->collectionId() ); } } } AgendaView *MultiAgendaView::Private::createView( const QString &title ) { QWidget *box = new QWidget( mTopBox ); QVBoxLayout *layout = new QVBoxLayout( box ); layout->setMargin( 0 ); QLabel *l = new QLabel( title ); layout->addWidget( l ); l->setAlignment( Qt::AlignVCenter | Qt::AlignHCenter ); AgendaView *av = new AgendaView( q->preferences(), q->startDateTime().date(), q->endDateTime().date(), true, true, q ); layout->addWidget( av ); av->setCalendar( q->calendar() ); av->setIncidenceChanger( q->changer() ); av->agenda()->scrollArea()->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); mAgendaViews.append( av ); mAgendaWidgets.append( box ); box->show(); mTimeLabelsZone->setAgendaView( av ); q->connect( mScrollBar, SIGNAL(valueChanged(int)), av->agenda()->verticalScrollBar(), SLOT(setValue(int)) ); q->connect( av->splitter(), SIGNAL(splitterMoved(int,int)), q, SLOT(resizeSplitters()) ); q->connect( av, SIGNAL(showIncidencePopupSignal(Akonadi::Item,QDate)), q, SIGNAL(showIncidencePopupSignal(Akonadi::Item,QDate)) ); q->connect( av, SIGNAL(showNewEventPopupSignal()), q, SIGNAL(showNewEventPopupSignal()) ); const QSize minHint = av->allDayAgenda()->scrollArea()->minimumSizeHint(); if ( minHint.isValid() ) { mLabel->setMinimumHeight( minHint.height() ); mRightDummyWidget->setMinimumHeight( minHint.height() ); } return av; } void MultiAgendaView::Private::addView( const Akonadi::Collection &collection ) { AgendaView *av = createView( CalendarSupport::displayName( q->calendar().data(), collection ) ); av->setCollectionId( collection.id() ); } void MultiAgendaView::Private::addView( KCheckableProxyModel *sm, const QString &title ) { AgendaView *av = createView( title ); av->setCustomCollectionSelectionProxyModel( sm ); } void MultiAgendaView::resizeEvent( QResizeEvent *ev ) { d->resizeScrollView( ev->size() ); EventView::resizeEvent( ev ); } void MultiAgendaView::Private::resizeScrollView( const QSize &size ) { const int widgetWidth = size.width() - mTimeLabelsZone->width() - mScrollBar->width(); int height = size.height(); if ( mScrollArea->horizontalScrollBar()->isVisible() ) { // this should never happen, you can't get horizontalScrollBars const int sbHeight = mScrollArea->horizontalScrollBar()->height(); height -= sbHeight; mLeftBottomSpacer->setFixedHeight( sbHeight ); mRightBottomSpacer->setFixedHeight( sbHeight ); } else { mLeftBottomSpacer->setFixedHeight( 0 ); mRightBottomSpacer->setFixedHeight( 0 ); } mScrollArea->widget()->setFixedSize( widgetWidth, height ); mTopBox->resize( widgetWidth, height ); } void MultiAgendaView::setIncidenceChanger( Akonadi::IncidenceChanger *changer ) { EventView::setIncidenceChanger( changer ); foreach ( AgendaView *agenda, d->mAgendaViews ) { agenda->setIncidenceChanger( changer ); } } void MultiAgendaView::setPreferences( const PrefsPtr &prefs ) { foreach ( AgendaView *agenda, d->mAgendaViews ) { agenda->setPreferences( prefs ); } EventView::setPreferences( prefs ); } void MultiAgendaView::updateConfig() { EventView::updateConfig(); d->mTimeLabelsZone->setPreferences( preferences() ); d->mTimeLabelsZone->updateAll(); foreach ( AgendaView *agenda, d->mAgendaViews ) { agenda->updateConfig(); } } void MultiAgendaView::resizeSplitters() { if ( d->mAgendaViews.isEmpty() ) { return; } QSplitter *lastMovedSplitter = qobject_cast( sender() ); if ( !lastMovedSplitter ) { lastMovedSplitter = d->mLeftSplitter; } foreach ( AgendaView *agenda, d->mAgendaViews ) { if ( agenda->splitter() == lastMovedSplitter ) { continue; } agenda->splitter()->setSizes( lastMovedSplitter->sizes() ); } if ( lastMovedSplitter != d->mLeftSplitter ) { d->mLeftSplitter->setSizes( lastMovedSplitter->sizes() ); } if ( lastMovedSplitter != d->mRightSplitter ) { d->mRightSplitter->setSizes( lastMovedSplitter->sizes() ); } } void MultiAgendaView::zoomView( const int delta, const QPoint &pos, const Qt::Orientation ori ) { const int hourSz = preferences()->hourSize(); if ( ori == Qt::Vertical ) { if ( delta > 0 ) { if ( hourSz > 4 ) { preferences()->setHourSize( hourSz - 1 ); } } else { preferences()->setHourSize( hourSz + 1 ); } } foreach ( AgendaView *agenda, d->mAgendaViews ) { agenda->zoomView( delta, pos, ori ); } d->mTimeLabelsZone->updateAll(); } void MultiAgendaView::slotResizeScrollView() { d->resizeScrollView( size() ); } void MultiAgendaView::showEvent( QShowEvent *event ) { EventView::showEvent( event ); if ( d->mUpdateOnShow ) { d->mUpdateOnShow = false; d->mPendingChanges = true; // force a full view recreation showDates( d->mStartDate, d->mEndDate ); } } void MultiAgendaView::setChanges( Changes changes ) { EventView::setChanges( changes ); foreach ( AgendaView *agenda, d->mAgendaViews ) { agenda->setChanges( changes ); } } void MultiAgendaView::setupScrollBar() { if ( !d->mAgendaViews.isEmpty() && d->mAgendaViews.first()->agenda() ) { QScrollBar *scrollBar = d->mAgendaViews.first()->agenda()->verticalScrollBar(); d->mScrollBar->setMinimum( scrollBar->minimum() ); d->mScrollBar->setMaximum( scrollBar->maximum() ); d->mScrollBar->setSingleStep( scrollBar->singleStep() ); d->mScrollBar->setPageStep( scrollBar->pageStep() ); d->mScrollBar->setValue( scrollBar->value() ); } } void MultiAgendaView::collectionSelectionChanged() { kDebug(); d->mPendingChanges = true; recreateViews(); } bool MultiAgendaView::hasConfigurationDialog() const { /** The wrapper in korg has the dialog. Too complicated to move to CalendarViews. Depends on korg/AkonadiCollectionView, and will be refactored some day to get rid of CollectionSelectionProxyModel/EntityStateSaver */ return false; } void MultiAgendaView::doRestoreConfig( const KConfigGroup &configGroup ) { if ( !calendar() ) { kError() << "Calendar is not set."; Q_ASSERT( false ); return; } d->mCustomColumnSetupUsed = configGroup.readEntry( "UseCustomColumnSetup", false ); d->mCustomNumberOfColumns = configGroup.readEntry( "CustomNumberOfColumns", 2 ); d->mCustomColumnTitles = configGroup.readEntry( "ColumnTitles", QStringList() ).toVector(); if ( d->mCustomColumnTitles.size() != d->mCustomNumberOfColumns ) { const int orig = d->mCustomColumnTitles.size(); d->mCustomColumnTitles.resize( d->mCustomNumberOfColumns ); for ( int i = orig; i < d->mCustomNumberOfColumns; ++i ) { d->mCustomColumnTitles[i] = generateColumnLabel( i ); } } QVector oldModels = d->mCollectionSelectionModels; d->mCollectionSelectionModels.clear(); if ( d->mCustomColumnSetupUsed ) { d->mCollectionSelectionModels.resize( d->mCustomNumberOfColumns ); for ( int i = 0; i < d->mCustomNumberOfColumns; ++i ) { // Sort the calanders by name QSortFilterProxyModel *sortProxy = new QSortFilterProxyModel( this ); sortProxy->setDynamicSortFilter( true ); sortProxy->setSourceModel( calendar()->entityTreeModel() ); // Only show the first column KColumnFilterProxyModel *columnFilterProxy = new KColumnFilterProxyModel( this ); columnFilterProxy->setVisibleColumn( Akonadi::ETMCalendar::CollectionTitle ); columnFilterProxy->setSourceModel( sortProxy ); // Keep track of selection. QItemSelectionModel *qsm = new QItemSelectionModel( columnFilterProxy ); // Make the model checkable. KCheckableProxyModel *checkableProxy = new KCheckableProxyModel( this ); checkableProxy->setSourceModel( columnFilterProxy ); checkableProxy->setSelectionModel( qsm ); const QString groupName = configGroup.name() + QLatin1String("_subView_") + QString::number( i ); const KConfigGroup group = configGroup.config()->group( groupName ); if ( !d->mSelectionSavers.contains( groupName ) ) { d->mSelectionSavers.insert( groupName, new KViewStateMaintainer( group ) ); d->mSelectionSavers[groupName]->setSelectionModel( checkableProxy->selectionModel() ); } d->mSelectionSavers[groupName]->restoreState(); d->mCollectionSelectionModels[i] = checkableProxy; } } d->mPendingChanges = true; recreateViews(); qDeleteAll( oldModels ); } void MultiAgendaView::doSaveConfig( KConfigGroup &configGroup ) { configGroup.writeEntry( "UseCustomColumnSetup", d->mCustomColumnSetupUsed ); configGroup.writeEntry( "CustomNumberOfColumns", d->mCustomNumberOfColumns ); const QStringList titleList = d->mCustomColumnTitles.toList(); configGroup.writeEntry( "ColumnTitles", titleList ); int idx = 0; foreach ( KCheckableProxyModel *checkableProxyModel, d->mCollectionSelectionModels ) { const QString groupName = configGroup.name() + QLatin1String("_subView_") + QString::number( idx ); KConfigGroup group = configGroup.config()->group( groupName ); ++idx; //TODO never used ? KViewStateMaintainer saver( group ); if ( !d->mSelectionSavers.contains( groupName ) ) { d->mSelectionSavers.insert( groupName, new KViewStateMaintainer( group ) ); d->mSelectionSavers[groupName]->setSelectionModel( checkableProxyModel->selectionModel() ); } d->mSelectionSavers[groupName]->saveState(); } } void MultiAgendaView::customCollectionsChanged( ConfigDialogInterface *dlg ) { if ( !d->mCustomColumnSetupUsed && !dlg->useCustomColumns() ) { // Config didn't change, no need to recreate views return; } d->mCustomColumnSetupUsed = dlg->useCustomColumns(); d->mCustomNumberOfColumns = dlg->numberOfColumns(); QVector newModels; newModels.resize( d->mCustomNumberOfColumns ); d->mCustomColumnTitles.resize( d->mCustomNumberOfColumns ); for ( int i = 0; i < d->mCustomNumberOfColumns; ++i ) { newModels[i] = dlg->takeSelectionModel( i ); d->mCustomColumnTitles[i] = dlg->columnTitle( i ); } d->mCollectionSelectionModels = newModels; d->mPendingChanges = true; recreateViews(); } bool MultiAgendaView::customColumnSetupUsed() const { return d->mCustomColumnSetupUsed; } int MultiAgendaView::customNumberOfColumns() const { return d->mCustomNumberOfColumns; } QVector MultiAgendaView::collectionSelectionModels() const { return d->mCollectionSelectionModels; } QVector MultiAgendaView::customColumnTitles() const { return d->mCustomColumnTitles; }