35 #include <calendarsupport/kcalprefs.h>
36 #include <calendarsupport/utils.h>
38 #include <Akonadi/AgentFilterProxyModel>
39 #include <Akonadi/AgentInstanceCreateJob>
40 #include <Akonadi/AgentManager>
41 #include <Akonadi/AgentTypeDialog>
42 #include <Akonadi/CollectionDeleteJob>
43 #include <Akonadi/CollectionFilterProxyModel>
44 #include <Akonadi/EntityDisplayAttribute>
45 #include <Akonadi/EntityTreeView>
46 #include <Akonadi/EntityTreeModel>
47 #include <Akonadi/ETMViewStateSaver>
48 #include <Akonadi/Calendar/StandardCalendarActionManager>
51 #include <KActionCollection>
52 #include <KCheckableProxyModel>
53 #include <KColorDialog>
54 #include <KMessageBox>
55 #include <KRecursiveFilterProxyModel>
57 #include <QHeaderView>
59 #include <QStyledItemDelegate>
60 #include <QVBoxLayout>
63 : mView( view ), mAkonadiCollectionView( 0 )
69 static bool hasCompatibleMimeTypes(
const Akonadi::Collection &collection )
71 static QStringList goodMimeTypes;
73 if ( goodMimeTypes.isEmpty() ) {
74 goodMimeTypes << QLatin1String(
"text/calendar" )
75 << KCalCore::Event::eventMimeType()
76 << KCalCore::Todo::todoMimeType()
77 << KCalCore::Journal::journalMimeType();
80 for (
int i=0; i<goodMimeTypes.count(); ++i ) {
81 if ( collection.contentMimeTypes().contains( goodMimeTypes.at( i ) ) ) {
89 class ColorDelegate :
public QStyledItemDelegate
92 explicit ColorDelegate(
QObject * parent = 0 ) : QStyledItemDelegate( parent )
96 void paint ( QPainter *painter,
const QStyleOptionViewItem &option,
97 const QModelIndex &index )
const
99 QStyledItemDelegate::paint( painter, option, index );
100 QStyleOptionViewItemV4 v4 = option;
101 initStyleOption( &v4, index );
102 if ( v4.checkState == Qt::Checked ) {
103 const Akonadi::Collection collection = CalendarSupport::collectionFromIndex( index );
105 if ( color.isValid() ) {
107 const int h = r.height() - 4;
108 r.adjust( r.width() - h - 2, 2, - 2, -2 );
110 painter->setRenderHint( QPainter::Antialiasing );
111 QPen pen = painter->pen();
112 pen.setColor( color );
114 path.addRoundedRect( r, 5, 5 );
115 color.setAlpha( 200 );
116 painter->fillPath( path, color );
117 painter->strokePath( path, pen );
124 class ColorProxyModel :
public QSortFilterProxyModel
127 explicit ColorProxyModel(
QObject *parent=0 )
128 : QSortFilterProxyModel( parent ), mInitDefaultCalendar( false )
133 QVariant data(
const QModelIndex &index,
int role )
const
135 if ( !index.isValid() ) {
138 if ( role == Qt::DecorationRole ) {
139 const Akonadi::Collection collection = CalendarSupport::collectionFromIndex( index );
141 if ( hasCompatibleMimeTypes( collection ) ) {
142 if ( collection.hasAttribute<Akonadi::EntityDisplayAttribute>() &&
143 !collection.attribute<Akonadi::EntityDisplayAttribute>()->iconName().isEmpty() ) {
144 return collection.attribute<Akonadi::EntityDisplayAttribute>()->icon();
147 }
else if ( role == Qt::FontRole ) {
148 const Akonadi::Collection collection = CalendarSupport::collectionFromIndex( index );
149 if ( !collection.contentMimeTypes().isEmpty() &&
151 collection.rights() & Akonadi::Collection::CanCreateItem ) {
152 QFont font = qvariant_cast<QFont>( QSortFilterProxyModel::data( index, Qt::FontRole ) );
153 font.setBold(
true );
154 if ( !mInitDefaultCalendar ) {
155 mInitDefaultCalendar =
true;
156 CalendarSupport::KCalPrefs::instance()->setDefaultCalendarId( collection.id() );
162 return QSortFilterProxyModel::data( index, role );
166 Qt::ItemFlags flags(
const QModelIndex &index )
const
168 return Qt::ItemIsSelectable | QSortFilterProxyModel::flags( index );
172 mutable bool mInitDefaultCalendar;
180 QObject::connect( mAkonadiCollectionView, SIGNAL(resourcesChanged(
bool)),
181 mView, SLOT(resourcesChanged()) );
182 QObject::connect( mAkonadiCollectionView, SIGNAL(resourcesChanged(
bool)),
183 mView, SLOT(updateCategories()) );
184 QObject::connect( mAkonadiCollectionView, SIGNAL(resourcesAddedRemoved()),
185 mView, SLOT(resourcesChanged()) );
186 QObject::connect( mAkonadiCollectionView, SIGNAL(resourcesAddedRemoved()),
187 mView, SLOT(updateCategories()) );
188 return mAkonadiCollectionView;
198 return mAkonadiCollectionView;
207 mSelectionProxyModel( 0 ),
208 mNotSendAddRemoveSignal( false ),
209 mWasDefaultCalendar( false ),
210 mHasContextMenu( hasContextMenu )
212 QVBoxLayout *topLayout =
new QVBoxLayout(
this );
213 topLayout->setMargin( 0 );
214 topLayout->setSpacing( KDialog::spacingHint() );
222 ColorProxyModel *colorProxy =
new ColorProxyModel(
this );
223 colorProxy->setObjectName( QLatin1String(
"Show calendar colors") );
224 colorProxy->setDynamicSortFilter(
true );
225 mBaseModel = colorProxy;
227 mCollectionView =
new Akonadi::EntityTreeView(
this );
228 topLayout->addWidget( mCollectionView );
229 mCollectionView->header()->hide();
230 mCollectionView->setRootIsDecorated(
true );
231 mCollectionView->setItemDelegate(
new ColorDelegate(
this ) );
239 mCollectionView->setModel( colorProxy );
240 connect( mCollectionView->selectionModel(),
241 SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
242 SLOT(updateMenu()) );
244 connect( mCollectionView->model(), SIGNAL(rowsInserted(QModelIndex,
int,
int)),
245 SLOT(checkNewCalendar(QModelIndex,
int,
int)) );
250 connect( mBaseModel, SIGNAL(rowsInserted(QModelIndex,
int,
int)),
251 this, SLOT(rowsInserted(QModelIndex,
int,
int)) );
256 mCollectionView->setXmlGuiClient( xmlclient );
259 new Akonadi::StandardCalendarActionManager( xmlclient->actionCollection(), mCollectionView );
261 QList<Akonadi::StandardActionManager::Type> standardActions;
262 standardActions << Akonadi::StandardActionManager::CreateCollection
263 << Akonadi::StandardActionManager::CopyCollections
264 << Akonadi::StandardActionManager::DeleteCollections
265 << Akonadi::StandardActionManager::SynchronizeCollections
266 << Akonadi::StandardActionManager::CollectionProperties
267 << Akonadi::StandardActionManager::CopyItems
268 << Akonadi::StandardActionManager::Paste
269 << Akonadi::StandardActionManager::DeleteItems
270 << Akonadi::StandardActionManager::CutItems
271 << Akonadi::StandardActionManager::CutCollections
272 << Akonadi::StandardActionManager::CreateResource
273 << Akonadi::StandardActionManager::DeleteResources
274 << Akonadi::StandardActionManager::ResourceProperties
275 << Akonadi::StandardActionManager::SynchronizeResources
276 << Akonadi::StandardActionManager::SynchronizeCollectionsRecursive;
278 Q_FOREACH( Akonadi::StandardActionManager::Type standardAction, standardActions ) {
279 mActionManager->createAction( standardAction );
282 QList<Akonadi::StandardCalendarActionManager::Type> calendarActions;
283 calendarActions << Akonadi::StandardCalendarActionManager::CreateEvent
284 << Akonadi::StandardCalendarActionManager::CreateTodo
285 << Akonadi::StandardCalendarActionManager::CreateSubTodo
286 << Akonadi::StandardCalendarActionManager::CreateJournal
287 << Akonadi::StandardCalendarActionManager::EditIncidence;
289 Q_FOREACH( Akonadi::StandardCalendarActionManager::Type calendarAction, calendarActions ) {
290 mActionManager->createAction( calendarAction );
293 mActionManager->setCollectionSelectionModel( mCollectionView->selectionModel() );
295 mActionManager->interceptAction( Akonadi::StandardActionManager::CreateResource );
296 mActionManager->interceptAction( Akonadi::StandardActionManager::DeleteResources );
297 mActionManager->interceptAction( Akonadi::StandardActionManager::DeleteCollections );
299 connect( mActionManager->action( Akonadi::StandardActionManager::CreateResource ),
300 SIGNAL(triggered(
bool)),
301 this, SLOT(newCalendar()) );
302 connect( mActionManager->action( Akonadi::StandardActionManager::DeleteResources ),
303 SIGNAL(triggered(
bool)),
304 this, SLOT(deleteCalendar()) );
305 connect( mActionManager->action( Akonadi::StandardActionManager::DeleteCollections ),
306 SIGNAL(triggered(
bool)),
307 this, SLOT(deleteCalendar()) );
309 mActionManager->setContextText( Akonadi::StandardActionManager::CollectionProperties,
310 Akonadi::StandardActionManager::DialogTitle,
311 ki18nc(
"@title:window",
"Properties of Calendar Folder %1" ) );
313 const QStringList pages =
314 QStringList() << QLatin1String(
"CalendarSupport::CollectionGeneralPage" )
315 << QLatin1String(
"Akonadi::CachePolicyPage" )
316 << QLatin1String(
"PimCommon::CollectionAclPage" );
318 mActionManager->setCollectionPropertiesPageNames( pages );
320 mDisableColor =
new KAction( mCollectionView );
321 mDisableColor->setText( i18n(
"&Disable Color" ) );
322 mDisableColor->setEnabled(
false );
323 xmlclient->actionCollection()->addAction( QString::fromLatin1(
"disable_color" ),
325 connect( mDisableColor, SIGNAL(triggered(
bool)),
this, SLOT(disableColor()) );
327 mAssignColor =
new KAction( mCollectionView );
328 mAssignColor->setText( i18n(
"&Assign Color..." ) );
329 mAssignColor->setEnabled(
false );
330 xmlclient->actionCollection()->addAction( QString::fromLatin1(
"assign_color" ), mAssignColor );
331 connect( mAssignColor, SIGNAL(triggered(
bool)),
this, SLOT(assignColor()) );
333 mDefaultCalendar =
new KAction( mCollectionView );
334 mDefaultCalendar->setText( i18n(
"Use as &Default Calendar" ) );
335 mDefaultCalendar->setEnabled(
false );
336 xmlclient->actionCollection()->addAction( QString::fromLatin1(
"set_standard_calendar" ),
338 connect( mDefaultCalendar, SIGNAL(triggered(
bool)),
this, SLOT(setDefaultCalendar()) );
344 Akonadi::ETMViewStateSaver treeStateSaver;
345 KConfigGroup group(
KOGlobals::self()->config(),
"CollectionTreeView" );
346 treeStateSaver.setView( mCollectionView );
347 treeStateSaver.setSelectionModel( 0 );
348 treeStateSaver.saveState( group );
351 void AkonadiCollectionView::restoreTreeState()
353 static QPointer<Akonadi::ETMViewStateSaver> treeStateRestorer;
354 if ( treeStateRestorer ) {
355 delete treeStateRestorer;
357 treeStateRestorer =
new Akonadi::ETMViewStateSaver();
358 KConfigGroup group(
KOGlobals::self()->config(),
"CollectionTreeView" );
359 treeStateRestorer->setView( mCollectionView );
360 treeStateRestorer->setSelectionModel( 0 );
361 treeStateRestorer->restoreState( group );
364 void AkonadiCollectionView::setDefaultCalendar()
366 QModelIndex index = mCollectionView->selectionModel()->currentIndex();
367 Q_ASSERT( index.isValid() );
368 const Akonadi::Collection collection = CalendarSupport::collectionFromIndex( index );
369 CalendarSupport::KCalPrefs::instance()->setDefaultCalendarId( collection.id() );
370 CalendarSupport::KCalPrefs::instance()->usrWriteConfig();
377 void AkonadiCollectionView::assignColor()
379 QModelIndex index = mCollectionView->selectionModel()->currentIndex();
380 Q_ASSERT( index.isValid() );
381 const Akonadi::Collection collection = CalendarSupport::collectionFromIndex( index );
382 Q_ASSERT( collection.isValid() );
384 const QString identifier = QString::number( collection.id() );
387 const int result = KColorDialog::getColor( myColor, defaultColor );
388 if ( result == KColorDialog::Accepted && myColor != defaultColor ) {
396 void AkonadiCollectionView::disableColor()
398 QModelIndex index = mCollectionView->selectionModel()->currentIndex();
399 Q_ASSERT( index.isValid() );
400 const Akonadi::Collection collection = CalendarSupport::collectionFromIndex( index );
401 Q_ASSERT( collection.isValid() );
402 const QString identifier = QString::number( collection.id() );
411 if ( mSelectionProxyModel == m ) {
415 mSelectionProxyModel = m;
416 if ( !mSelectionProxyModel ) {
420 mBaseModel->setSourceModel( mSelectionProxyModel );
425 return mSelectionProxyModel;
430 return mCollectionView;
433 void AkonadiCollectionView::updateView()
436 mSelectionProxyModel->selectionModel()->hasSelection() :
440 void AkonadiCollectionView::updateMenu()
442 if ( !mHasContextMenu ) {
445 bool enableAction = mCollectionView->selectionModel()->hasSelection();
446 enableAction = enableAction &&
448 mAssignColor->setEnabled( enableAction );
449 QModelIndex index = mCollectionView->selectionModel()->currentIndex();
451 bool disableStuff =
false;
453 if ( index.isValid() ) {
454 const Akonadi::Collection collection = CalendarSupport::collectionFromIndex( index );
455 Q_ASSERT( collection.isValid() );
457 if ( !collection.contentMimeTypes().isEmpty() ) {
458 const QString identifier = QString::number( collection.id() );
460 enableAction = enableAction && defaultColor.isValid();
461 mDisableColor->setEnabled( enableAction );
463 collection.rights() & Akonadi::Collection::CanCreateItem );
471 if ( disableStuff ) {
472 mDisableColor->setEnabled(
false );
473 mDefaultCalendar->setEnabled(
false );
474 mAssignColor->setEnabled(
false );
478 void AkonadiCollectionView::newCalendar()
480 Akonadi::AgentTypeDialog dlg(
this );
481 dlg.setWindowTitle( i18n(
"Add Calendar" ) );
482 dlg.agentFilterProxyModel()->addMimeTypeFilter( QString::fromLatin1(
"text/calendar" ) );
483 dlg.agentFilterProxyModel()->addCapabilityFilter( QLatin1String(
"Resource") );
485 mNotSendAddRemoveSignal =
true;
486 const Akonadi::AgentType agentType = dlg.agentType();
487 if ( agentType.isValid() ) {
488 Akonadi::AgentInstanceCreateJob *job =
new Akonadi::AgentInstanceCreateJob( agentType,
this );
489 job->configure(
this );
490 connect( job, SIGNAL(result(
KJob*)),
this, SLOT(newCalendarDone(
KJob*)) );
496 void AkonadiCollectionView::newCalendarDone(
KJob *job )
498 Akonadi::AgentInstanceCreateJob *createjob =
static_cast<Akonadi::AgentInstanceCreateJob*
>( job );
499 if ( createjob->error() ) {
503 kWarning() <<
"Create calendar failed:" << createjob->errorString();
504 mNotSendAddRemoveSignal =
false;
507 mNotSendAddRemoveSignal =
false;
511 void AkonadiCollectionView::deleteCalendar()
513 QModelIndex index = mCollectionView->selectionModel()->currentIndex();
514 Q_ASSERT( index.isValid() );
515 const Akonadi::Collection collection = CalendarSupport::collectionFromIndex( index );
516 Q_ASSERT( collection.isValid() );
518 const QString displayname = index.model()->data( index, Qt::DisplayRole ).toString();
519 Q_ASSERT( !displayname.isEmpty() );
521 if ( KMessageBox::warningContinueCancel(
523 i18n(
"Do you really want to delete calendar %1?", displayname ),
524 i18n(
"Delete Calendar" ),
525 KStandardGuiItem::del(),
526 KStandardGuiItem::cancel(),
528 KMessageBox::Dangerous ) == KMessageBox::Continue ) {
530 bool isTopLevel = collection.parentCollection() == Akonadi::Collection::root();
532 mNotSendAddRemoveSignal =
true;
537 Akonadi::CollectionDeleteJob *job =
new Akonadi::CollectionDeleteJob( collection,
this );
538 connect( job, SIGNAL(result(
KJob*)),
this, SLOT(deleteCalendarDone(
KJob*)) );
541 const Akonadi::AgentInstance instance =
542 Akonadi::AgentManager::self()->instance( collection.resource() );
543 if ( instance.isValid() ) {
544 Akonadi::AgentManager::self()->removeInstance( instance );
550 void AkonadiCollectionView::deleteCalendarDone(
KJob *job )
552 Akonadi::CollectionDeleteJob *deletejob =
static_cast<Akonadi::CollectionDeleteJob*
>( job );
553 if ( deletejob->error() ) {
554 kWarning() <<
"Delete calendar failed:" << deletejob->errorString();
555 mNotSendAddRemoveSignal =
false;
558 if ( mWasDefaultCalendar ) {
559 CalendarSupport::KCalPrefs::instance()->setDefaultCalendarId( Akonadi::Collection().
id() );
561 mNotSendAddRemoveSignal =
false;
565 void AkonadiCollectionView::rowsInserted(
const QModelIndex &,
int,
int )
567 if ( !mNotSendAddRemoveSignal ) {
575 Akonadi::Collection collection;
576 QItemSelectionModel *selectionModel = mCollectionView->selectionModel();
577 if ( !selectionModel ) {
580 QModelIndexList indexes = selectionModel->selectedIndexes();
581 if ( !indexes.isEmpty() ) {
582 collection = indexes.first().data( Akonadi::EntityTreeModel::CollectionRole ).value<Akonadi::Collection>();
589 Akonadi::Collection::List collections;
590 if ( !mSelectionProxyModel ) {
593 QItemSelectionModel *selectionModel = mSelectionProxyModel->selectionModel();
594 if ( !selectionModel ) {
597 QModelIndexList indexes = selectionModel->selectedIndexes();
598 foreach(
const QModelIndex &index, indexes ) {
599 if ( index.isValid() ) {
600 Akonadi::Collection collection = index.data( Akonadi::EntityTreeModel::CollectionRole ).value<Akonadi::Collection>();
601 if ( collection.isValid() )
602 collections << collection;
610 if (!mSelectionProxyModel)
612 QItemSelectionModel *selectionModel = mSelectionProxyModel->selectionModel();
615 QModelIndexList indexes = selectionModel->selectedIndexes();
616 foreach(
const QModelIndex &index, indexes) {
617 if (index.isValid()) {
618 Akonadi::Collection c = index.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
619 if (c.id() == collection.id()) {
627 Akonadi::EntityTreeModel *AkonadiCollectionView::entityTreeModel()
const
629 QAbstractProxyModel *proxy = qobject_cast<QAbstractProxyModel*>( mCollectionView->model() );
631 Akonadi::EntityTreeModel *etm = qobject_cast<Akonadi::EntityTreeModel*>( proxy->sourceModel() );
635 proxy = qobject_cast<QAbstractProxyModel*>( proxy->sourceModel() );
638 kWarning() <<
"Couldn't find EntityTreeModel";
642 void AkonadiCollectionView::checkNewCalendar(
const QModelIndex &parent,
int begin,
int end )
645 Akonadi::EntityTreeModel *etm = entityTreeModel();
646 if ( etm && entityTreeModel()->isCollectionTreeFetched() ) {
647 for(
int row=begin; row<=end; ++row ) {
648 QModelIndex index = mCollectionView->model()->index( row, 0, parent );
649 if ( index.isValid() )
650 mCollectionView->model()->setData( index, Qt::Checked, Qt::CheckStateRole );
652 if ( parent.isValid() ) {
653 mCollectionView->setExpanded( parent,
true );
658 #include "akonadicollectionview.moc"
int agendaViewColors() const
Get Color Usage.
KCheckableProxyModel * collectionSelectionProxyModel() const
void setResourceColor(const QString &, const QColor &)
AkonadiCollectionView(CalendarView *view, bool hasContextMenu=true, QWidget *parent=0)
KXMLGUIClient * xmlguiClient(QWidget *) const
Akonadi::EntityTreeView * view() const
CalendarViewExtension * create(QWidget *)
AkonadiCollectionView * collectionView() const
This is the main calendar widget.
CalendarView * view() const
Akonadi::Collection::List checkedCollections() const
AkonadiCollectionViewFactory(CalendarView *view)
Akonadi::Collection selectedCollection() const
static KOGlobals * self()
This class provides a view of calendar resources.
void resourcesChanged(bool enabled)
void resourcesAddedRemoved()
KORGANIZERPRIVATE_EXPORT QColor resourceColor(const Akonadi::Item &incidence)
This method returns the proper resource / subresource color for the view.
static KOPrefs * instance()
Get instance of KOPrefs.
bool isChecked(const Akonadi::Collection &) const
void setCollectionSelectionProxyModel(KCheckableProxyModel *)
KORGANIZERPRIVATE_EXPORT bool isStandardCalendar(const Akonadi::Entity::Id &id)
Return true if it's the standard calendar.
QColor resourceColor(const QString &)
void defaultResourceChanged(const Akonadi::Collection &)