kde-playground/kdepim/calendarviews/multiagenda/multiagendaview.cpp
2015-04-14 21:49:29 +00:00

790 lines
25 KiB
C++

/*
Copyright (c) 2007 Volker Krause <vkrause@kde.org>
Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
Author: Sergio Martins <sergio.martins@kdab.com>
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 <Akonadi/EntityTreeModel>
#include <Akonadi/Calendar/ETMCalendar>
#include <calendarsupport/collectionselection.h>
#include <calendarsupport/utils.h>
#include <Akonadi/ETMViewStateSaver>
#include <akonadi_next/kcolumnfilterproxymodel.h>
using namespace Future;
#include <KCalCore/Event>
#include <KCheckableProxyModel>
#include <KGlobalSettings>
#include <KLocalizedString>
#include <KVBox>
#include <KViewStateMaintainer>
#include <QHBoxLayout>
#include <QItemSelectionModel>
#include <QLabel>
#include <QResizeEvent>
#include <QScrollArea>
#include <QScrollBar>
#include <QSplitter>
#include <QSortFilterProxyModel>
#include <QTimer>
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<int,QString> 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<QWidget*>( 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<AgendaView*> mAgendaViews;
QList<QWidget*> 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<KCheckableProxyModel*> mCollectionSelectionModels;
QVector<QString> mCustomColumnTitles;
int mCustomNumberOfColumns;
QLabel *mLabel;
QWidget *mRightDummyWidget;
QHash<QString, KViewStateMaintainer<ETMViewStateSaver>* > 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<QSplitter*>( 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<KCheckableProxyModel*> 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<ETMViewStateSaver>( 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<ETMViewStateSaver> saver( group );
if ( !d->mSelectionSavers.contains( groupName ) ) {
d->mSelectionSavers.insert( groupName, new KViewStateMaintainer<ETMViewStateSaver>( 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<KCheckableProxyModel *> 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<KCheckableProxyModel *> MultiAgendaView::collectionSelectionModels() const
{
return d->mCollectionSelectionModels;
}
QVector<QString> MultiAgendaView::customColumnTitles() const
{
return d->mCustomColumnTitles;
}