• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

kalarm

  • sources
  • kde-4.14
  • kdepim
  • kalarm
resourceselector.cpp
Go to the documentation of this file.
1 /*
2  * resourceselector.cpp - calendar resource selection widget
3  * Program: kalarm
4  * Copyright © 2006-2013 by David Jarvie <djarvie@kde.org>
5  * Based on KOrganizer's ResourceView class and KAddressBook's ResourceSelection class,
6  * Copyright (C) 2003,2004 Cornelius Schumacher <schumacher@kde.org>
7  * Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
8  * Copyright (c) 2004 Tobias Koenig <tokoe@kde.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License along
21  * with this program; if not, write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  */
24 
25 #include "resourceselector.h"
26 
27 #include "kalarm.h"
28 #include "alarmcalendar.h"
29 #include "autoqpointer.h"
30 #ifdef USE_AKONADI
31 #include "akonadiresourcecreator.h"
32 #include "calendarmigrator.h"
33 #include "kalarmapp.h"
34 #else
35 #include "alarmresources.h"
36 #include "eventlistmodel.h"
37 #include "resourcemodelview.h"
38 #endif
39 #include "messagebox.h"
40 #include "packedlayout.h"
41 #include "preferences.h"
42 #include "resourceconfigdialog.h"
43 
44 #ifdef USE_AKONADI
45 #include <akonadi/agentmanager.h>
46 #include <akonadi/agentinstancecreatejob.h>
47 #include <akonadi/agenttype.h>
48 #include <akonadi/collectionpropertiesdialog.h>
49 #include <akonadi/entitydisplayattribute.h>
50 #else
51 #include <kcal/resourcecalendar.h>
52 #endif
53 
54 #include <kdialog.h>
55 #include <klocale.h>
56 #include <kglobal.h>
57 #include <kcombobox.h>
58 #include <kinputdialog.h>
59 #include <kmenu.h>
60 #include <kdebug.h>
61 #include <kicon.h>
62 #include <kactioncollection.h>
63 #include <kaction.h>
64 #include <ktoggleaction.h>
65 #include <kcolordialog.h>
66 
67 #include <QLabel>
68 #include <QPushButton>
69 #include <QTimer>
70 #include <QResizeEvent>
71 #include <QApplication>
72 
73 #ifdef USE_AKONADI
74 using namespace KCalCore;
75 #else
76 using namespace KCal;
77 #endif
78 #ifdef USE_AKONADI
79 using namespace Akonadi;
80 #endif
81 
82 
83 #ifdef USE_AKONADI
84 ResourceSelector::ResourceSelector(QWidget* parent)
85 #else
86 ResourceSelector::ResourceSelector(AlarmResources* calendar, QWidget* parent)
87 #endif
88  : QFrame(parent),
89 #ifndef USE_AKONADI
90  mCalendar(calendar),
91 #endif
92  mContextMenu(0),
93  mActionReload(0),
94  mActionShowDetails(0),
95  mActionSetColour(0),
96  mActionClearColour(0),
97  mActionEdit(0),
98 #ifdef USE_AKONADI
99  mActionUpdate(0),
100 #else
101  mActionSave(0),
102 #endif
103  mActionRemove(0),
104  mActionImport(0),
105  mActionExport(0),
106  mActionSetDefault(0)
107 {
108  QBoxLayout* topLayout = new QVBoxLayout(this);
109  topLayout->setMargin(KDialog::spacingHint()); // use spacingHint for the margin
110 
111  QLabel* label = new QLabel(i18nc("@title:group", "Calendars"), this);
112  topLayout->addWidget(label, 0, Qt::AlignHCenter);
113 
114  mAlarmType = new KComboBox(this);
115  mAlarmType->addItem(i18nc("@item:inlistbox", "Active Alarms"));
116  mAlarmType->addItem(i18nc("@item:inlistbox", "Archived Alarms"));
117  mAlarmType->addItem(i18nc("@item:inlistbox", "Alarm Templates"));
118  mAlarmType->setFixedHeight(mAlarmType->sizeHint().height());
119  mAlarmType->setWhatsThis(i18nc("@info:whatsthis", "Choose which type of data to show alarm calendars for"));
120  topLayout->addWidget(mAlarmType);
121  // No spacing between combo box and listview.
122 
123 #ifdef USE_AKONADI
124  CollectionFilterCheckListModel* model = new CollectionFilterCheckListModel(this);
125  mListView = new CollectionView(model, this);
126 #else
127  ResourceModel* model = ResourceModel::instance();
128  ResourceFilterModel* filterModel = new ResourceFilterModel(model, this);
129  mListView = new ResourceView(this);
130  mListView->setModel(filterModel);
131 #endif
132  connect(mListView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(selectionChanged()));
133  mListView->setContextMenuPolicy(Qt::CustomContextMenu);
134  connect(mListView, SIGNAL(customContextMenuRequested(QPoint)), SLOT(contextMenuRequested(QPoint)));
135  mListView->setWhatsThis(i18nc("@info:whatsthis",
136  "List of available calendars of the selected type. The checked state shows whether a calendar "
137  "is enabled (checked) or disabled (unchecked). The default calendar is shown in bold."));
138  topLayout->addWidget(mListView, 1);
139  topLayout->addSpacing(KDialog::spacingHint());
140 
141  PackedLayout* blayout = new PackedLayout(Qt::AlignHCenter);
142  blayout->setMargin(0);
143  blayout->setSpacing(KDialog::spacingHint());
144  topLayout->addLayout(blayout);
145 
146  mAddButton = new QPushButton(i18nc("@action:button", "Add..."), this);
147  mEditButton = new QPushButton(i18nc("@action:button", "Edit..."), this);
148  mDeleteButton = new QPushButton(i18nc("@action:button", "Remove"), this);
149  blayout->addWidget(mAddButton);
150  blayout->addWidget(mEditButton);
151  blayout->addWidget(mDeleteButton);
152  mEditButton->setWhatsThis(i18nc("@info:whatsthis", "Edit the highlighted calendar"));
153  mDeleteButton->setWhatsThis(i18nc("@info:whatsthis", "<para>Remove the highlighted calendar from the list.</para>"
154  "<para>The calendar itself is left intact, and may subsequently be reinstated in the list if desired.</para>"));
155  mEditButton->setDisabled(true);
156  mDeleteButton->setDisabled(true);
157  connect(mAddButton, SIGNAL(clicked()), SLOT(addResource()));
158  connect(mEditButton, SIGNAL(clicked()), SLOT(editResource()));
159  connect(mDeleteButton, SIGNAL(clicked()), SLOT(removeResource()));
160 
161 #ifdef USE_AKONADI
162  connect(AkonadiModel::instance(), SIGNAL(collectionAdded(Akonadi::Collection)),
163  SLOT(slotCollectionAdded(Akonadi::Collection)));
164 #else
165  connect(mCalendar, SIGNAL(resourceStatusChanged(AlarmResource*,AlarmResources::Change)), SLOT(slotStatusChanged(AlarmResource*,AlarmResources::Change)));
166 #endif
167 
168  connect(mAlarmType, SIGNAL(activated(int)), SLOT(alarmTypeSelected()));
169  QTimer::singleShot(0, this, SLOT(alarmTypeSelected()));
170 
171  Preferences::connect(SIGNAL(archivedKeepDaysChanged(int)), this, SLOT(archiveDaysChanged(int)));
172 }
173 
174 /******************************************************************************
175 * Called when an alarm type has been selected.
176 * Filter the resource list to show resources of the selected alarm type, and
177 * add appropriate whatsThis texts to the list and to the Add button.
178 */
179 void ResourceSelector::alarmTypeSelected()
180 {
181  QString addTip;
182  switch (mAlarmType->currentIndex())
183  {
184  case 0:
185  mCurrentAlarmType = CalEvent::ACTIVE;
186  addTip = i18nc("@info:tooltip", "Add a new active alarm calendar");
187  break;
188  case 1:
189  mCurrentAlarmType = CalEvent::ARCHIVED;
190  addTip = i18nc("@info:tooltip", "Add a new archived alarm calendar");
191  break;
192  case 2:
193  mCurrentAlarmType = CalEvent::TEMPLATE;
194  addTip = i18nc("@info:tooltip", "Add a new alarm template calendar");
195  break;
196  }
197  // WORKAROUND: Switch scroll bars off to avoid crash (see explanation
198  // in reinstateAlarmTypeScrollBars() description).
199  mListView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
200  mListView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
201 #ifdef USE_AKONADI
202  mListView->collectionModel()->setEventTypeFilter(mCurrentAlarmType);
203 #else
204  static_cast<ResourceFilterModel*>(mListView->model())->setFilter(mCurrentAlarmType);
205 #endif
206  mAddButton->setWhatsThis(addTip);
207  mAddButton->setToolTip(addTip);
208  // WORKAROUND: Switch scroll bars back on after allowing geometry to update ...
209  QTimer::singleShot(0, this, SLOT(reinstateAlarmTypeScrollBars()));
210 
211 #ifdef USE_AKONADI
212  selectionChanged(); // enable/disable buttons
213 #endif
214 }
215 
216 /******************************************************************************
217 * WORKAROUND for crash due to presumed Qt bug.
218 * Switch scroll bars off. This is to avoid a crash which can very occasionally
219 * happen when changing from a list of calendars which requires vertical scroll
220 * bars, to a list whose text is very slightly wider but which doesn't require
221 * scroll bars at all. (The suspicion is that the width is such that it would
222 * require horizontal scroll bars if the vertical scroll bars were still
223 * present.) Presumably due to a Qt bug, this can result in a recursive call to
224 * ResourceView::viewportEvent() with a Resize event.
225 *
226 * The crash only occurs if the ResourceSelector happens to have exactly (within
227 * one pixel) the "right" width to create the crash.
228 */
229 void ResourceSelector::reinstateAlarmTypeScrollBars()
230 {
231  mListView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
232  mListView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
233 }
234 
235 /******************************************************************************
236 * Prompt the user for a new resource to add to the list.
237 */
238 void ResourceSelector::addResource()
239 {
240 #ifdef USE_AKONADI
241  AkonadiResourceCreator* creator = new AkonadiResourceCreator(mCurrentAlarmType, this);
242  connect(creator, SIGNAL(finished(AkonadiResourceCreator*,bool)),
243  SLOT(resourceAdded(AkonadiResourceCreator*,bool)));
244  creator->createResource();
245 #else
246  AlarmResourceManager* manager = mCalendar->resourceManager();
247  QStringList descs = manager->resourceTypeDescriptions();
248  bool ok = false;
249  QString desc = KInputDialog::getItem(i18nc("@title:window", "Calendar Configuration"),
250  i18nc("@info", "Select storage type of new calendar:"), descs, 0, false, &ok, this);
251  if (!ok || descs.isEmpty())
252  return;
253  QString type = manager->resourceTypeNames()[descs.indexOf(desc)];
254  AlarmResource* resource = dynamic_cast<AlarmResource*>(manager->createResource(type));
255  if (!resource)
256  {
257  KAMessageBox::error(this, i18nc("@info", "Unable to create calendar of type <resource>%1</resource>.", type));
258  return;
259  }
260  resource->setResourceName(i18nc("@info/plain", "%1 calendar", type));
261  resource->setAlarmType(mCurrentAlarmType);
262  resource->setActive(false); // prevent setReadOnly() declaring it as unwritable before we've tried to load it
263 
264  // Use AutoQPointer to guard against crash on application exit while
265  // the dialogue is still open. It prevents double deletion (both on
266  // deletion of ResourceSelector, and on return from this function).
267  AutoQPointer<ResourceConfigDialog> dlg = new ResourceConfigDialog(this, resource);
268  if (dlg->exec() == QDialog::Accepted)
269  {
270  resource->setEnabled(true);
271  resource->setTimeSpec(Preferences::timeZone());
272  manager->add(resource);
273  manager->writeConfig();
274  mCalendar->resourceAdded(resource); // load the resource and connect in-process change signals
275  }
276  else
277  {
278  delete resource;
279  resource = 0;
280  }
281 #endif
282 }
283 
284 #ifdef USE_AKONADI
285 /******************************************************************************
286 * Called when the job started by AkonadiModel::addCollection() has completed.
287 */
288 void ResourceSelector::resourceAdded(AkonadiResourceCreator* creator, bool success)
289 {
290  if (success)
291  {
292  AgentInstance agent = creator->agentInstance();
293  if (agent.isValid())
294  {
295  // Note that we're expecting the agent's Collection to be added
296  mAddAgents += agent;
297  }
298  }
299  delete creator;
300 }
301 
302 /******************************************************************************
303 * Called when a collection is added to the AkonadiModel.
304 */
305 void ResourceSelector::slotCollectionAdded(const Collection& collection)
306 {
307  if (collection.isValid())
308  {
309  AgentInstance agent = AgentManager::self()->instance(collection.resource());
310  if (agent.isValid())
311  {
312  int i = mAddAgents.indexOf(agent);
313  if (i >= 0)
314  {
315  // The collection belongs to an agent created by addResource()
316  CalEvent::Types types = CalEvent::types(collection.contentMimeTypes());
317  CollectionControlModel::setEnabled(collection, types, true);
318  if (!(types & mCurrentAlarmType))
319  {
320  // The user has selected alarm types for the resource
321  // which don't include the currently displayed type.
322  // Show a collection list which includes a selected type.
323  int index = -1;
324  if (types & CalEvent::ACTIVE)
325  index = 0;
326  else if (types & CalEvent::ARCHIVED)
327  index = 1;
328  else if (types & CalEvent::TEMPLATE)
329  index = 2;
330  if (index >= 0)
331  {
332  mAlarmType->setCurrentIndex(index);
333  alarmTypeSelected();
334  }
335  }
336  mAddAgents.removeAt(i);
337  }
338  }
339  }
340 }
341 #endif
342 
343 /******************************************************************************
344 * Edit the currently selected resource.
345 */
346 void ResourceSelector::editResource()
347 {
348 #ifdef USE_AKONADI
349  Collection collection = currentResource();
350  if (collection.isValid())
351  {
352  AgentInstance instance = AgentManager::self()->instance(collection.resource());
353  if (instance.isValid())
354  instance.configure(this);
355  }
356 #else
357  AlarmResource* resource = currentResource();
358  if (!resource)
359  return;
360  bool readOnly = resource->readOnly();
361  // Use AutoQPointer to guard against crash on application exit while
362  // the dialogue is still open. It prevents double deletion (both on
363  // deletion of ResourceSelector, and on return from this function).
364  AutoQPointer<ResourceConfigDialog> dlg = new ResourceConfigDialog(this, resource);
365  if (dlg->exec() == QDialog::Accepted)
366  {
367  // Act on any changed settings.
368  // Read-only is handled automatically by AlarmResource::setReadOnly().
369  if (!readOnly && resource->readOnly() && resource->standardResource())
370  {
371  // A standard resource is being made read-only.
372  if (resource->alarmType() == CalEvent::ACTIVE)
373  {
374  KAMessageBox::sorry(this, i18nc("@info", "You cannot make your default active alarm calendar read-only."));
375  resource->setReadOnly(false);
376  }
377  else if (resource->alarmType() == CalEvent::ARCHIVED && Preferences::archivedKeepDays())
378  {
379  // Only allow the archived alarms standard resource to be made read-only
380  // if we're not saving archived alarms.
381  KAMessageBox::sorry(this, i18nc("@info", "You cannot make your default archived alarm calendar "
382  "read-only while expired alarms are configured to be kept."));
383  resource->setReadOnly(false);
384  }
385  else if (KAMessageBox::warningContinueCancel(this, i18nc("@info", "Do you really want to make your default calendar read-only?"))
386  == KMessageBox::Cancel)
387  {
388  resource->setReadOnly(false);
389  }
390  }
391  }
392 #endif
393 }
394 
395 #ifdef USE_AKONADI
396 /******************************************************************************
397 * Update the backend storage format for the currently selected resource in the
398 * displayed list.
399 */
400 void ResourceSelector::updateResource()
401 {
402  Collection collection = currentResource();
403  if (!collection.isValid())
404  return;
405  AkonadiModel::instance()->refresh(collection); // update with latest data
406  CalendarMigrator::updateToCurrentFormat(collection, true, this);
407 }
408 #endif
409 
410 /******************************************************************************
411 * Remove the currently selected resource from the displayed list.
412 */
413 void ResourceSelector::removeResource()
414 {
415 #ifdef USE_AKONADI
416  Collection collection = currentResource();
417  if (!collection.isValid())
418  return;
419  QString name = collection.name();
420  // Check if it's the standard or only resource for at least one type.
421  CalEvent::Types allTypes = AkonadiModel::types(collection);
422  CalEvent::Types standardTypes = CollectionControlModel::standardTypes(collection, true);
423  CalEvent::Type currentType = currentResourceType();
424  CalEvent::Type stdType = (standardTypes & CalEvent::ACTIVE) ? CalEvent::ACTIVE
425  : (standardTypes & CalEvent::ARCHIVED) ? CalEvent::ARCHIVED
426  : CalEvent::EMPTY;
427 #else
428  AlarmResource* resource = currentResource();
429  if (!resource)
430  return;
431  QString name = resource->resourceName();
432  bool std = resource->standardResource();
433  // Check if it's the standard resource for its type.
434  CalEvent::Type stdType = std ? resource->alarmType() : CalEvent::EMPTY;
435 #endif
436  if (stdType == CalEvent::ACTIVE)
437  {
438  KAMessageBox::sorry(this, i18nc("@info", "You cannot remove your default active alarm calendar."));
439  return;
440  }
441  if (stdType == CalEvent::ARCHIVED && Preferences::archivedKeepDays())
442  {
443  // Only allow the archived alarms standard resource to be removed if
444  // we're not saving archived alarms.
445  KAMessageBox::sorry(this, i18nc("@info", "You cannot remove your default archived alarm calendar "
446  "while expired alarms are configured to be kept."));
447  return;
448  }
449 #ifdef USE_AKONADI
450  QString text;
451  if (standardTypes)
452  {
453  // It's a standard resource for at least one alarm type
454  if (allTypes != currentType)
455  {
456  // It also contains alarm types other than the currently displayed type
457  QString stdTypes = CollectionControlModel::typeListForDisplay(standardTypes);
458  QString otherTypes;
459  CalEvent::Types nonStandardTypes(allTypes & ~standardTypes);
460  if (nonStandardTypes != currentType)
461  otherTypes = i18nc("@info", "<para>It also contains:%1</para>", CollectionControlModel::typeListForDisplay(nonStandardTypes));
462  text = i18nc("@info", "<para><resource>%1</resource> is the default calendar for:%2</para>%3"
463  "<para>Do you really want to remove it from all calendar lists?</para>", name, stdTypes, otherTypes);
464  }
465  else
466  text = i18nc("@info", "Do you really want to remove your default calendar (<resource>%1</resource>) from the list?", name);
467  }
468  else if (allTypes != currentType)
469  text = i18nc("@info", "<para><resource>%1</resource> contains:%2</para><para>Do you really want to remove it from all calendar lists?</para>",
470  name, CollectionControlModel::typeListForDisplay(allTypes));
471  else
472  text = i18nc("@info", "Do you really want to remove the calendar <resource>%1</resource> from the list?", name);
473 #else
474  QString text = std ? i18nc("@info", "Do you really want to remove your default calendar (<resource>%1</resource>) from the list?", name)
475  : i18nc("@info", "Do you really want to remove the calendar <resource>%1</resource> from the list?", name);
476 #endif
477  if (KAMessageBox::warningContinueCancel(this, text, QString(), KStandardGuiItem::remove()) == KMessageBox::Cancel)
478  return;
479 
480 #ifdef USE_AKONADI
481  AkonadiModel::instance()->removeCollection(collection);
482 #else
483  // Remove resource from alarm and resource lists before deleting it, to avoid
484  // crashes when display updates occur immediately after it is deleted.
485  if (resource->alarmType() == CalEvent::TEMPLATE)
486  EventListModel::templates()->removeResource(resource);
487  else
488  EventListModel::alarms()->removeResource(resource);
489  ResourceModel::instance()->removeResource(resource);
490  AlarmResourceManager* manager = mCalendar->resourceManager();
491  manager->remove(resource);
492  manager->writeConfig();
493 #endif
494 }
495 
496 /******************************************************************************
497 * Called when the current selection changes, to enable/disable the
498 * Delete and Edit buttons accordingly.
499 */
500 void ResourceSelector::selectionChanged()
501 {
502  bool state = mListView->selectionModel()->selectedRows().count();
503  mDeleteButton->setEnabled(state);
504  mEditButton->setEnabled(state);
505 }
506 
507 /******************************************************************************
508 * Initialise the button and context menu actions.
509 */
510 void ResourceSelector::initActions(KActionCollection* actions)
511 {
512  mActionReload = new KAction(KIcon(QLatin1String("view-refresh")), i18nc("@action Reload calendar", "Re&load"), this);
513  actions->addAction(QLatin1String("resReload"), mActionReload);
514  connect(mActionReload, SIGNAL(triggered(bool)), SLOT(reloadResource()));
515 #ifndef USE_AKONADI
516  mActionSave = new KAction(KIcon(QLatin1String("document-save")), i18nc("@action", "&Save"), this);
517  actions->addAction(QLatin1String("resSave"), mActionSave);
518  connect(mActionSave, SIGNAL(triggered(bool)), SLOT(saveResource()));
519 #endif
520  mActionShowDetails = new KAction(KIcon(QLatin1String("help-about")), i18nc("@action", "Show &Details"), this);
521  actions->addAction(QLatin1String("resDetails"), mActionShowDetails);
522  connect(mActionShowDetails, SIGNAL(triggered(bool)), SLOT(showInfo()));
523  mActionSetColour = new KAction(KIcon(QLatin1String("color-picker")), i18nc("@action", "Set &Color..."), this);
524  actions->addAction(QLatin1String("resSetColour"), mActionSetColour);
525  connect(mActionSetColour, SIGNAL(triggered(bool)), SLOT(setColour()));
526  mActionClearColour = new KAction(i18nc("@action", "Clear C&olor"), this);
527  actions->addAction(QLatin1String("resClearColour"), mActionClearColour);
528  connect(mActionClearColour, SIGNAL(triggered(bool)), SLOT(clearColour()));
529  mActionEdit = new KAction(KIcon(QLatin1String("document-properties")), i18nc("@action", "&Edit..."), this);
530  actions->addAction(QLatin1String("resEdit"), mActionEdit);
531  connect(mActionEdit, SIGNAL(triggered(bool)), SLOT(editResource()));
532 #ifdef USE_AKONADI
533  mActionUpdate = new KAction(i18nc("@action", "&Update Calendar Format"), this);
534  actions->addAction(QLatin1String("resUpdate"), mActionUpdate);
535  connect(mActionUpdate, SIGNAL(triggered(bool)), SLOT(updateResource()));
536 #endif
537  mActionRemove = new KAction(KIcon(QLatin1String("edit-delete")), i18nc("@action", "&Remove"), this);
538  actions->addAction(QLatin1String("resRemove"), mActionRemove);
539  connect(mActionRemove, SIGNAL(triggered(bool)), SLOT(removeResource()));
540  mActionSetDefault = new KToggleAction(this);
541  actions->addAction(QLatin1String("resDefault"), mActionSetDefault);
542  connect(mActionSetDefault, SIGNAL(triggered(bool)), SLOT(setStandard()));
543  QAction* action = new KAction(KIcon(QLatin1String("document-new")), i18nc("@action", "&Add..."), this);
544  actions->addAction(QLatin1String("resAdd"), action);
545  connect(action, SIGNAL(triggered(bool)), SLOT(addResource()));
546  mActionImport = new KAction(i18nc("@action", "Im&port..."), this);
547  actions->addAction(QLatin1String("resImport"), mActionImport);
548  connect(mActionImport, SIGNAL(triggered(bool)), SLOT(importCalendar()));
549  mActionExport = new KAction(i18nc("@action", "E&xport..."), this);
550  actions->addAction(QLatin1String("resExport"), mActionExport);
551  connect(mActionExport, SIGNAL(triggered(bool)), SLOT(exportCalendar()));
552 }
553 
554 void ResourceSelector::setContextMenu(KMenu* menu)
555 {
556  mContextMenu = menu;
557 }
558 
559 /******************************************************************************
560 * Display the context menu for the selected calendar.
561 */
562 void ResourceSelector::contextMenuRequested(const QPoint& viewportPos)
563 {
564  if (!mContextMenu)
565  return;
566  bool active = false;
567  bool writable = false;
568 #ifdef USE_AKONADI
569  bool updatable = false;
570  Collection collection;
571 #else
572  AlarmResource* resource = 0;
573 #endif
574  if (mListView->selectionModel()->hasSelection())
575  {
576  QModelIndex index = mListView->indexAt(viewportPos);
577  if (index.isValid())
578 #ifdef USE_AKONADI
579  collection = mListView->collectionModel()->collection(index);
580 #else
581  resource = static_cast<ResourceFilterModel*>(mListView->model())->resource(index);
582 #endif
583  else
584  mListView->clearSelection();
585  }
586  CalEvent::Type type = currentResourceType();
587 #ifdef USE_AKONADI
588  bool haveCalendar = collection.isValid();
589 #else
590  bool haveCalendar = resource;
591 #endif
592  if (haveCalendar)
593  {
594 #ifdef USE_AKONADI
595  // Note: the CollectionControlModel functions call AkonadiModel::refresh(collection)
596  active = CollectionControlModel::isEnabled(collection, type);
597  KACalendar::Compat compatibility;
598  int rw = CollectionControlModel::isWritableEnabled(collection, type, compatibility);
599  writable = (rw > 0);
600  if (!rw
601  && (compatibility & ~KACalendar::Converted)
602  && !(compatibility & ~(KACalendar::Convertible | KACalendar::Converted)))
603  updatable = true; // the calendar format is convertible to the current KAlarm format
604  if (!(AkonadiModel::instance()->types(collection) & type))
605  type = CalEvent::EMPTY;
606 #else
607  active = resource->isEnabled();
608  type = resource->alarmType();
609  writable = resource->writable();
610 #endif
611  }
612  mActionReload->setEnabled(active);
613  mActionShowDetails->setEnabled(haveCalendar);
614  mActionSetColour->setEnabled(haveCalendar);
615  mActionClearColour->setEnabled(haveCalendar);
616 #ifdef USE_AKONADI
617  mActionClearColour->setVisible(AkonadiModel::instance()->backgroundColor(collection).isValid());
618 #else
619  mActionClearColour->setVisible(resource && resource->colour().isValid());
620  mActionSave->setEnabled(active && writable);
621 #endif
622  mActionEdit->setEnabled(haveCalendar);
623 #ifdef USE_AKONADI
624  mActionUpdate->setEnabled(updatable);
625 #endif
626  mActionRemove->setEnabled(haveCalendar);
627  mActionImport->setEnabled(active && writable);
628  mActionExport->setEnabled(active);
629  QString text;
630  switch (type)
631  {
632  case CalEvent::ACTIVE: text = i18nc("@action", "Use as &Default for Active Alarms"); break;
633  case CalEvent::ARCHIVED: text = i18nc("@action", "Use as &Default for Archived Alarms"); break;
634  case CalEvent::TEMPLATE: text = i18nc("@action", "Use as &Default for Alarm Templates"); break;
635  default: break;
636  }
637  mActionSetDefault->setText(text);
638 #ifdef USE_AKONADI
639  bool standard = CollectionControlModel::isStandard(collection, type);
640 #else
641  bool standard = (resource && resource == mCalendar->getStandardResource(static_cast<CalEvent::Type>(type)) && resource->standardResource());
642 #endif
643  mActionSetDefault->setChecked(active && writable && standard);
644  mActionSetDefault->setEnabled(active && writable);
645  mContextMenu->popup(mListView->viewport()->mapToGlobal(viewportPos));
646 }
647 
648 /******************************************************************************
649 * Called from the context menu to reload the selected resource.
650 */
651 void ResourceSelector::reloadResource()
652 {
653 #ifdef USE_AKONADI
654  Collection collection = currentResource();
655  if (collection.isValid())
656  AkonadiModel::instance()->reloadCollection(collection);
657 #else
658  AlarmResource* resource = currentResource();
659  if (resource)
660  AlarmCalendar::resources()->loadResource(resource, this);
661 #endif
662 }
663 
664 /******************************************************************************
665 * Called from the context menu to save the selected resource.
666 */
667 void ResourceSelector::saveResource()
668 {
669 #ifdef USE_AKONADI
670  // Save resource is not applicable to Akonadi
671 #else
672  AlarmResource* resource = currentResource();
673  if (resource)
674  resource->save();
675 #endif
676 }
677 
678 /******************************************************************************
679 * Called when the length of time archived alarms are to be stored changes.
680 * If expired alarms are now to be stored, set any single archived alarm
681 * resource to be the default.
682 */
683 void ResourceSelector::archiveDaysChanged(int days)
684 {
685  if (days)
686  {
687 #ifdef USE_AKONADI
688  if (!CollectionControlModel::getStandard(CalEvent::ARCHIVED).isValid())
689  {
690  Collection::List cols = CollectionControlModel::enabledCollections(CalEvent::ARCHIVED, true);
691  if (cols.count() == 1)
692  {
693  CollectionControlModel::setStandard(cols[0], CalEvent::ARCHIVED);
694  theApp()->purgeNewArchivedDefault(cols[0]);
695  }
696  }
697 #else
698  AlarmResources* resources = AlarmResources::instance();
699  AlarmResource* std = resources->getStandardResource(CalEvent::ARCHIVED);
700  if (std && !std->standardResource())
701  resources->setStandardResource(std);
702 #endif
703  }
704 }
705 
706 /******************************************************************************
707 * Called from the context menu to set the selected resource as the default
708 * for its alarm type. The resource is automatically made active.
709 */
710 void ResourceSelector::setStandard()
711 {
712 #ifdef USE_AKONADI
713  Collection collection = currentResource();
714  if (collection.isValid())
715  {
716  CalEvent::Type alarmType = currentResourceType();
717  bool standard = mActionSetDefault->isChecked();
718  if (standard)
719  CollectionControlModel::setEnabled(collection, alarmType, true);
720  CollectionControlModel::setStandard(collection, alarmType, standard);
721  if (alarmType == CalEvent::ARCHIVED)
722  theApp()->purgeNewArchivedDefault(collection);
723  }
724 #else
725  AlarmResource* resource = currentResource();
726  if (resource)
727  {
728  if (mActionSetDefault->isChecked())
729  {
730  resource->setEnabled(true);
731  mCalendar->setStandardResource(resource);
732  }
733  else
734  resource->setStandardResource(false);
735  }
736 #endif
737 }
738 
739 #ifndef USE_AKONADI
740 /******************************************************************************
741 * Called when a calendar status has changed.
742 */
743 void ResourceSelector::slotStatusChanged(AlarmResource* resource, AlarmResources::Change change)
744 {
745  if (change == AlarmResources::WrongType && resource->isWrongAlarmType())
746  {
747  QString text;
748  switch (resource->alarmType())
749  {
750  case CalEvent::ACTIVE:
751  text = i18nc("@info/plain", "It is not an active alarm calendar.");
752  break;
753  case CalEvent::ARCHIVED:
754  text = i18nc("@info/plain", "It is not an archived alarm calendar.");
755  break;
756  case CalEvent::TEMPLATE:
757  text = i18nc("@info/plain", "It is not an alarm template calendar.");
758  break;
759  default:
760  return;
761  }
762  KAMessageBox::sorry(this, i18nc("@info", "<para>Calendar <resource>%1</resource> has been disabled:</para><para>%2</para>", resource->resourceName(), text));
763  }
764 }
765 #endif
766 
767 /******************************************************************************
768 * Called from the context menu to merge alarms from an external calendar into
769 * the selected resource (if any).
770 */
771 void ResourceSelector::importCalendar()
772 {
773 #ifdef USE_AKONADI
774  Collection collection = currentResource();
775  AlarmCalendar::importAlarms(this, (collection.isValid() ? &collection : 0));
776 #else
777  AlarmCalendar::importAlarms(this, currentResource());
778 #endif
779 }
780 
781 /******************************************************************************
782 * Called from the context menu to copy the selected resource's alarms to an
783 * external calendar.
784 */
785 void ResourceSelector::exportCalendar()
786 {
787 #ifdef USE_AKONADI
788  Collection calendar = currentResource();
789  if (calendar.isValid())
790 #else
791  AlarmResource* calendar = currentResource();
792  if (calendar)
793 #endif
794  AlarmCalendar::exportAlarms(AlarmCalendar::resources()->events(calendar), this);
795 }
796 
797 /******************************************************************************
798 * Called from the context menu to set a colour for the selected resource.
799 */
800 void ResourceSelector::setColour()
801 {
802 #ifdef USE_AKONADI
803  Collection collection = currentResource();
804  if (collection.isValid())
805  {
806  QColor colour = AkonadiModel::instance()->backgroundColor(collection);
807  if (!colour.isValid())
808  colour = QApplication::palette().color(QPalette::Base);
809  if (KColorDialog::getColor(colour, QColor(), this) == KColorDialog::Accepted)
810  AkonadiModel::instance()->setBackgroundColor(collection, colour);
811  }
812 #else
813  AlarmResource* resource = currentResource();
814  if (resource)
815  {
816  QColor colour = resource->colour();
817  if (!colour.isValid())
818  colour = QApplication::palette().color(QPalette::Base);
819  if (KColorDialog::getColor(colour, QColor(), this) == KColorDialog::Accepted)
820  resource->setColour(colour);
821  }
822 #endif
823 }
824 
825 /******************************************************************************
826 * Called from the context menu to clear the display colour for the selected
827 * resource.
828 */
829 void ResourceSelector::clearColour()
830 {
831 #ifdef USE_AKONADI
832  Collection collection = currentResource();
833  if (collection.isValid())
834  AkonadiModel::instance()->setBackgroundColor(collection, QColor());
835 #else
836  AlarmResource* resource = currentResource();
837  if (resource)
838  resource->setColour(QColor());
839 #endif
840 }
841 
842 /******************************************************************************
843 * Called from the context menu to display information for the selected resource.
844 */
845 void ResourceSelector::showInfo()
846 {
847 #ifdef USE_AKONADI
848  Collection collection = currentResource();
849  if (collection.isValid())
850  {
851  const QString name = collection.displayName();
852  QString id = collection.resource(); // resource name
853  CalEvent::Type alarmType = currentResourceType();
854  QString calType = AgentManager::self()->instance(id).type().name();
855  QString storage = AkonadiModel::instance()->storageType(collection);
856  QString location = collection.remoteId();
857  KUrl url(location);
858  if (url.isLocalFile())
859  location = url.path();
860  CalEvent::Types altypes = AkonadiModel::instance()->types(collection);
861  QStringList alarmTypes;
862  if (altypes & CalEvent::ACTIVE)
863  alarmTypes << i18nc("@info/plain", "Active alarms");
864  if (altypes & CalEvent::ARCHIVED)
865  alarmTypes << i18nc("@info/plain", "Archived alarms");
866  if (altypes & CalEvent::TEMPLATE)
867  alarmTypes << i18nc("@info/plain", "Alarm templates");
868  QString alarmTypeString = alarmTypes.join(i18nc("@info/plain List separator", ", "));
869  KACalendar::Compat compat;
870  QString perms = AkonadiModel::readOnlyTooltip(collection);
871  if (perms.isEmpty())
872  perms = i18nc("@info/plain", "Read-write");
873  QString enabled = CollectionControlModel::isEnabled(collection, alarmType)
874  ? i18nc("@info/plain", "Enabled")
875  : i18nc("@info/plain", "Disabled");
876  QString std = CollectionControlModel::isStandard(collection, alarmType)
877  ? i18nc("@info/plain Parameter in 'Default calendar: Yes/No'", "Yes")
878  : i18nc("@info/plain Parameter in 'Default calendar: Yes/No'", "No");
879  QString text = i18nc("@info",
880  "<title>%1</title>"
881  "<para>ID: %2<nl/>"
882  "Calendar type: %3<nl/>"
883  "Contents: %4<nl/>"
884  "%5: <filename>%6</filename><nl/>"
885  "Permissions: %7<nl/>"
886  "Status: %8<nl/>"
887  "Default calendar: %9</para>",
888  name, id, calType, alarmTypeString, storage, location, perms, enabled, std);
889  // Display the collection information. Because the user requested
890  // the information, don't raise a KNotify event.
891  KAMessageBox::information(this, text, QString(), QString(), 0);
892  }
893 #else
894  AlarmResource* resource = currentResource();
895  if (resource)
896  {
897  // Display the collection information. Because the user requested
898  // the information, don't raise a KNotify event.
899  KAMessageBox::information(this, resource->infoText(), QString(), QString(), 0);
900  }
901 #endif
902 }
903 
904 /******************************************************************************
905 * Return the currently selected resource in the list.
906 */
907 #ifdef USE_AKONADI
908 Collection ResourceSelector::currentResource() const
909 {
910  return mListView->collection(mListView->selectionModel()->currentIndex());
911 }
912 #else
913 AlarmResource* ResourceSelector::currentResource() const
914 {
915  return mListView->resource(mListView->selectionModel()->currentIndex());
916 }
917 #endif
918 
919 /******************************************************************************
920 * Return the currently selected resource type.
921 */
922 CalEvent::Type ResourceSelector::currentResourceType() const
923 {
924  switch (mAlarmType->currentIndex())
925  {
926  case 0: return CalEvent::ACTIVE;
927  case 1: return CalEvent::ARCHIVED;
928  case 2: return CalEvent::TEMPLATE;
929  default: return CalEvent::EMPTY;
930  }
931 }
932 
933 void ResourceSelector::resizeEvent(QResizeEvent* re)
934 {
935  emit resized(re->oldSize(), re->size());
936 }
937 
938 // vim: et sw=4:
AkonadiResourceCreator::agentInstance
Akonadi::AgentInstance agentInstance() const
Definition: akonadiresourcecreator.h:43
QModelIndex
QResizeEvent
QWidget
calendarmigrator.h
CollectionControlModel::getStandard
static Akonadi::Collection getStandard(CalEvent::Type, bool useDefault=false)
Return the standard collection for a specified mime type.
Definition: collectionmodel.cpp:993
AkonadiModel::readOnlyTooltip
static QString readOnlyTooltip(const Akonadi::Collection &)
Return the read-only status tooltip for a collection.
Definition: akonadimodel.cpp:963
EventListModel::alarms
static EventListModel * alarms()
Definition: eventlistmodel.cpp:55
AlarmCalendar::importAlarms
static bool importAlarms(QWidget *, AlarmResource *=0)
Definition: alarmcalendar.cpp:875
ResourceSelector::resizeEvent
virtual void resizeEvent(QResizeEvent *)
Definition: resourceselector.cpp:933
CollectionControlModel::setStandard
static void setStandard(Akonadi::Collection &, CalEvent::Type, bool standard)
Set or clear a collection as the standard collection for a specified mime type.
Definition: collectionmodel.cpp:1066
CollectionControlModel::isWritableEnabled
static int isWritableEnabled(const Akonadi::Collection &, CalEvent::Type)
Return whether a collection is both enabled and fully writable for a given alarm type, i.e.
Definition: collectionmodel.cpp:968
ResourceModel::removeResource
void removeResource(AlarmResource *)
Definition: resourcemodelview.cpp:246
text
virtual QByteArray text(quint32 serialNumber) const =0
AlarmCalendar::loadResource
void loadResource(AlarmResource *, QWidget *parent)
Definition: alarmcalendar.cpp:536
AlarmCalendar::resources
static AlarmCalendar * resources()
Definition: alarmcalendar.h:130
QPalette::color
const QColor & color(ColorGroup group, ColorRole role) const
CalendarMigrator::updateToCurrentFormat
static void updateToCurrentFormat(const Akonadi::Collection &, bool ignoreKeepFormat, QWidget *parent)
Definition: calendarmigrator.cpp:375
KAMessageBox::error
static void error(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Options(Notify|WindowModal))
CollectionControlModel::isStandard
static bool isStandard(Akonadi::Collection &, CalEvent::Type)
Return whether a collection is the standard collection for a specified mime type. ...
Definition: collectionmodel.cpp:1018
AkonadiModel::refresh
bool refresh(Akonadi::Collection &) const
Refresh the specified collection instance with up to date data.
Definition: akonadimodel.cpp:1807
alarmcalendar.h
QPoint
QStringList::join
QString join(const QString &separator) const
QBoxLayout::addSpacing
void addSpacing(int size)
ResourceView
Definition: resourcemodelview.h:89
AkonadiModel::storageType
QString storageType(const Akonadi::Collection &) const
Return the storage type (file/directory/URL etc.) for a collection.
Definition: akonadimodel.cpp:918
CollectionControlModel::isEnabled
static bool isEnabled(const Akonadi::Collection &, CalEvent::Type)
Return whether a collection is enabled (and valid).
Definition: collectionmodel.cpp:715
CollectionControlModel::typeListForDisplay
static QString typeListForDisplay(CalEvent::Types)
Return a bulleted list of alarm types for inclusion in an i18n message.
Definition: collectionmodel.cpp:946
kalarmapp.h
the KAlarm application object
QModelIndex::isValid
bool isValid() const
ResourceConfigDialog
Definition: resourceconfigdialog.h:37
QBoxLayout::addWidget
void addWidget(QWidget *widget, int stretch, QFlags< Qt::AlignmentFlag > alignment)
ResourceModel::instance
static ResourceModel * instance(QObject *parent=0)
Definition: resourcemodelview.cpp:41
packedlayout.h
autoqpointer.h
Preferences::timeZone
static KTimeZone timeZone(bool reload=false)
Definition: preferences.cpp:199
QResizeEvent::oldSize
const QSize & oldSize() const
AkonadiModel::instance
static AkonadiModel * instance()
Definition: akonadimodel.cpp:83
QList::isEmpty
bool isEmpty() const
QString::isEmpty
bool isEmpty() const
resourcemodelview.h
eventlistmodel.h
QVBoxLayout
CollectionControlModel::standardTypes
static CalEvent::Types standardTypes(const Akonadi::Collection &, bool useDefault=false)
Return the alarm type(s) for which a collection is the standard collection.
Definition: collectionmodel.cpp:1032
PackedLayout
messagebox.h
QString
QColor
QApplication::palette
QPalette palette()
QLayout::setMargin
void setMargin(int margin)
QLayout::addWidget
void addWidget(QWidget *w)
theApp
KAlarmApp * theApp()
Definition: kalarmapp.h:263
AkonadiModel::removeCollection
bool removeCollection(const Akonadi::Collection &)
Remove a collection from Akonadi.
Definition: akonadimodel.cpp:1081
QStringList
AkonadiModel::reloadCollection
bool reloadCollection(const Akonadi::Collection &)
Reload a collection's data from Akonadi storage (not from the backend).
Definition: akonadimodel.cpp:1139
QResizeEvent::size
const QSize & size() const
AutoQPointer
preferences.h
Preferences::connect
static void connect(const char *signal, const QObject *receiver, const char *member)
Definition: preferences.cpp:369
QFrame
CollectionControlModel::enabledCollections
static Akonadi::Collection::List enabledCollections(CalEvent::Type, bool writable)
Return the enabled collections which contain a specified mime type.
Definition: collectionmodel.cpp:1229
EventListModel::templates
static EventListModel * templates()
Definition: eventlistmodel.cpp:68
ResourceSelector::ResourceSelector
ResourceSelector(AlarmResources *, QWidget *parent=0)
Definition: resourceselector.cpp:86
QItemSelection
AkonadiModel::types
static CalEvent::Types types(const Akonadi::Collection &)
Definition: akonadimodel.cpp:1926
QLatin1String
KAMessageBox::sorry
static void sorry(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Options(Notify|WindowModal))
kalarm.h
QAction
ResourceSelector::initActions
void initActions(KActionCollection *)
Definition: resourceselector.cpp:510
AkonadiModel::setBackgroundColor
void setBackgroundColor(Akonadi::Collection &, const QColor &)
Set the background color for a collection and its alarms.
Definition: akonadimodel.cpp:874
CollectionFilterCheckListModel
Definition: collectionmodel.h:113
KComboBox
resourceselector.h
akonadiresourcecreator.h
KAMessageBox::warningContinueCancel
static int warningContinueCancel(QWidget *parent, const QString &text, const QString &caption=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Options(Notify|WindowModal))
QLayout::setSpacing
void setSpacing(int)
ResourceModel
Definition: resourcemodelview.h:38
QPushButton
QStringList::indexOf
int indexOf(const QRegExp &rx, int from) const
ResourceFilterModel
Definition: resourcemodelview.h:70
EventListModel::removeResource
void removeResource(AlarmResource *)
Definition: eventlistmodel.cpp:640
AlarmCalendar::exportAlarms
static bool exportAlarms(const KAEvent::List &, QWidget *parent)
Definition: alarmcalendar.cpp:1074
CollectionView
Definition: collectionmodel.h:141
QLabel
ResourceSelector::setContextMenu
void setContextMenu(KMenu *)
Definition: resourceselector.cpp:554
AkonadiModel::backgroundColor
QColor backgroundColor(Akonadi::Collection &) const
Get the background color for a collection and its alarms.
Definition: akonadimodel.cpp:885
QBoxLayout
resourceconfigdialog.h
AkonadiResourceCreator::createResource
void createResource()
Definition: akonadiresourcecreator.cpp:53
QColor::isValid
bool isValid() const
AkonadiResourceCreator
Definition: akonadiresourcecreator.h:37
QBoxLayout::addLayout
void addLayout(QLayout *layout, int stretch)
QTimer::singleShot
singleShot
KAMessageBox::information
static void information(QWidget *parent, const QString &text, const QString &caption=QString(), const QString &dontShowAgainName=QString(), Options options=Options(Notify|WindowModal))
CollectionControlModel::setEnabled
static CalEvent::Types setEnabled(const Akonadi::Collection &, CalEvent::Types, bool enabled)
Enable or disable a collection (if it is valid) for specified alarm types.
Definition: collectionmodel.cpp:736
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:34:51 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kalarm

Skip menu "kalarm"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer
  • pimprint

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal