28 #include <Akonadi/Collection>
29 #include <Akonadi/CollectionDialog>
30 #include <Akonadi/EntityDisplayAttribute>
31 #include <Akonadi/EntityTreeModel>
32 #include <Akonadi/Item>
33 #include <Akonadi/Calendar/ETMCalendar>
34 #include <akonadi/calendar/publishdialog.h>
35 #include <akonadi/calendar/calendarsettings.h>
37 #include <KHolidays/Holidays>
39 #include <KCalCore/CalFilter>
40 #include <KCalCore/Event>
41 #include <KCalCore/FreeBusy>
42 #include <KCalCore/Incidence>
43 #include <KCalCore/Journal>
44 #include <KCalCore/MemoryCalendar>
45 #include <KCalCore/Todo>
46 #include <KCalCore/ICalFormat>
47 #include <KCalCore/FileStorage>
49 #include <KCalUtils/DndFactory>
50 #include <KCalUtils/ICalDrag>
51 #include <KCalUtils/VCalDrag>
53 #include <Mailtransport/TransportManager>
55 #include <KIconLoader>
58 #include <QAbstractItemModel>
61 #include <QModelIndex>
65 #include <boost/bind.hpp>
66 #include <KMessageBox>
67 #include <KPIMIdentities/IdentityManager>
68 #include <KFileDialog>
69 #include <KIO/NetAccess>
71 using namespace CalendarSupport;
72 using namespace KHolidays;
73 using namespace KCalCore;
79 return item.payload<KCalCore::Incidence::Ptr>();
80 }
catch( Akonadi::PayloadException ) {
81 return KCalCore::Incidence::Ptr();
89 KCalCore::Incidence::Ptr
incidence = item.payload<KCalCore::Incidence::Ptr>();
90 if ( incidence && incidence->type() == KCalCore::Incidence::TypeEvent ) {
91 return item.payload<KCalCore::Event::Ptr>();
93 }
catch( Akonadi::PayloadException ) {
94 return KCalCore::Event::Ptr();
96 return KCalCore::Event::Ptr();
101 KCalCore::Event::List events;
102 Q_FOREACH (
const Akonadi::Item &item, items ) {
104 events.push_back( e );
113 Q_FOREACH (
const Akonadi::Item &item, items ) {
115 incidences.push_back( e );
124 KCalCore::Incidence::Ptr
incidence = item.payload<KCalCore::Incidence::Ptr>();
125 if ( incidence && incidence->type() == KCalCore::Incidence::TypeTodo ) {
126 return item.payload<KCalCore::Todo::Ptr>();
128 }
catch( Akonadi::PayloadException ) {
129 return KCalCore::Todo::Ptr();
131 return KCalCore::Todo::Ptr();
137 KCalCore::Incidence::Ptr
incidence = item.payload<KCalCore::Incidence::Ptr>();
138 if ( incidence && incidence->type() == KCalCore::Incidence::TypeJournal ) {
139 return item.payload<KCalCore::Journal::Ptr>();
141 }
catch( Akonadi::PayloadException ) {
142 return KCalCore::Journal::Ptr();
144 return KCalCore::Journal::Ptr();
149 return item.hasPayload<KCalCore::Incidence::Ptr>();
154 return item.hasPayload<KCalCore::Event::Ptr>();
159 return item.hasPayload<KCalCore::Todo::Ptr>();
164 return item.hasPayload<KCalCore::Journal::Ptr>();
168 const KDateTime::Spec &timeSpec )
170 if ( items.isEmpty() ) {
174 KCalCore::MemoryCalendar::Ptr cal(
new KCalCore::MemoryCalendar( timeSpec ) );
177 int incidencesFound = 0;
178 Q_FOREACH (
const Akonadi::Item &item, items ) {
184 urls.push_back( item.url() );
185 KCalCore::Incidence::Ptr i( incidence->clone() );
186 cal->addIncidence( i );
189 if ( incidencesFound == 0 ) {
193 std::auto_ptr<QMimeData> mimeData(
new QMimeData );
195 mimeData->setUrls( urls );
197 KCalUtils::ICalDrag::populateMimeData( mimeData.get(), cal );
198 KCalUtils::VCalDrag::populateMimeData( mimeData.get(), cal );
200 return mimeData.release();
204 const KDateTime::Spec &timeSpec )
209 #ifndef QT_NO_DRAGANDDROP
211 const KDateTime::Spec &timeSpec,
QWidget *parent )
213 return createDrag( Akonadi::Item::List() << item, timeSpec, parent );
220 if ( items.isEmpty() ) {
224 Q_FOREACH (
const Akonadi::Item &item, items ) {
229 if ( !prev.isEmpty() && type != prev ) {
237 #ifndef QT_NO_DRAGANDDROP
239 const KDateTime::Spec &timeSpec,
QWidget *parent )
241 std::auto_ptr<QDrag> drag(
new QDrag( parent ) );
245 if ( common ==
"Event" ) {
246 drag->setPixmap( BarIcon( QLatin1String(
"view-calendar-day" ) ) );
247 }
else if ( common ==
"Todo" ) {
248 drag->setPixmap( BarIcon( QLatin1String(
"view-calendar-tasks" ) ) );
251 return drag.release();
255 static bool itemMatches(
const Akonadi::Item &item,
const KCalCore::CalFilter *filter )
262 return filter->filterIncidence( inc );
266 const KCalCore::CalFilter *filter )
269 Akonadi::Item::List items( items_ );
270 items.erase( std::remove_if( items.begin(), items.end(),
276 const QStringList &supportedMimeTypes )
278 if ( !url.isValid() ) {
282 if ( url.scheme() != QLatin1String(
"akonadi" ) ) {
286 return supportedMimeTypes.contains( url.queryItem( QLatin1String(
"type" ) ) );
292 QStringList() << KCalCore::Event::eventMimeType()
293 << KCalCore::Todo::todoMimeType()
294 << KCalCore::Journal::journalMimeType()
295 << KCalCore::FreeBusy::freeBusyMimeType() );
301 std::find_if( urls.begin(), urls.end(),
307 if ( !url.isValid() || url.scheme() != QLatin1String(
"akonadi" ) ) {
311 return url.queryItem( QLatin1String(
"type" ) ) == KCalCore::Todo::todoMimeType();
326 Q_FOREACH (
const KUrl &i, mimeData->urls() ) {
338 Q_FOREACH (
const KUrl &i, mimeData->urls() ) {
348 return !
todoItemUrls( mimeData ).isEmpty() || !
todos( mimeData, KDateTime::Spec() ).isEmpty();
354 !
incidences( mimeData, KDateTime::Spec() ).isEmpty();
358 const KDateTime::Spec &spec )
360 KCalCore::Todo::List
todos;
362 #ifndef QT_NO_DRAGANDDROP
363 KCalCore::Calendar::Ptr cal( KCalUtils::DndFactory::createDropCalendar( mimeData, spec ) );
365 Q_FOREACH (
const KCalCore::Todo::Ptr &i, cal->todos() ) {
366 todos.push_back( KCalCore::Todo::Ptr( i->clone() ) );
375 const KDateTime::Spec &spec )
379 #ifndef QT_NO_DRAGANDDROP
380 KCalCore::Calendar::Ptr cal( KCalUtils::DndFactory::createDropCalendar( mimeData, spec ) );
382 KCalCore::Incidence::List calIncidences = cal->incidences();
383 Q_FOREACH (
const KCalCore::Incidence::Ptr &i, calIncidences ) {
384 incidences.push_back( KCalCore::Incidence::Ptr( i->clone() ) );
394 const QStringList &mimeTypes,
395 const Akonadi::Collection &defCollection )
397 QPointer<Akonadi::CollectionDialog> dlg(
new Akonadi::CollectionDialog( parent ) );
398 dlg->setCaption( i18n(
"Select Calendar" ) );
399 dlg->setDescription( i18n(
"Select the calendar where this item will be stored." ) );
400 dlg->changeCollectionDialogOptions( Akonadi::CollectionDialog::KeepTreeExpanded );
401 kDebug() <<
"selecting collections with mimeType in " << mimeTypes;
403 dlg->setMimeTypeFilter( mimeTypes );
404 dlg->setAccessRightsFilter( Akonadi::Collection::CanCreateItem );
405 if ( defCollection.isValid() ) {
406 dlg->setDefaultCollection( defCollection );
408 Akonadi::Collection collection;
411 dialogCode = dlg->exec();
412 if ( dlg && dialogCode == QDialog::Accepted ) {
413 collection = dlg->selectedCollection();
415 if ( !collection.isValid() ) {
416 kWarning() <<
"An invalid collection was selected!";
425 Akonadi::Item item = idx.data( Akonadi::EntityTreeModel::ItemRole ).value<Akonadi::Item>();
426 item.setParentCollection(
427 idx.data( Akonadi::EntityTreeModel::ParentCollectionRole ).value<Akonadi::Collection>() );
432 const QModelIndex &parentIndex,
435 const int endRow = end >= 0 ? end : model->rowCount( parentIndex ) - 1;
436 Akonadi::Collection::List collections;
438 QModelIndex i = model->index( row, 0, parentIndex );
439 while ( row <= endRow ) {
441 if ( collection.isValid() ) {
442 collections << collection;
443 QModelIndex childIndex = i.child( 0, 0 );
444 if ( childIndex.isValid() ) {
449 i = i.sibling( row, 0 );
455 const QModelIndex &parentIndex,
458 const int endRow = end >= 0 ? end : model->rowCount( parentIndex ) - 1;
459 Akonadi::Item::List items;
461 QModelIndex i = model->index( row, 0, parentIndex );
462 while ( row <= endRow ) {
467 QModelIndex childIndex = i.child( 0, 0 );
468 if ( childIndex.isValid() ) {
473 i = i.sibling( row, 0 );
480 return index.data( Akonadi::EntityTreeModel::CollectionRole ).value<Akonadi::Collection>();
485 return index.data( Akonadi::EntityTreeModel::CollectionIdRole ).value<Akonadi::Collection::Id>();
490 Akonadi::Collection::List l;
491 Q_FOREACH (
const QModelIndex &idx, indexes ) {
499 Akonadi::Collection fullCollection;
500 if ( calendar && calendar->collection( c.id() ).isValid() ) {
501 fullCollection = calendar->collection( c.id() );
506 QString cName = fullCollection.name();
507 const QString resourceName = fullCollection.resource();
510 if ( resourceName.contains( QLatin1String(
"kolabproxy" ) ) ) {
511 QString typeStr = cName;
515 Akonadi::Collection p = c.parentCollection();
516 while ( p != Akonadi::Collection::root() ) {
517 Akonadi::Collection tCol = calendar->collection( p.id() );
518 const QString tName = tCol.name();
519 if ( tName.toLower().startsWith( QLatin1String(
"shared.cal" ) ) ) {
520 ownerStr = QLatin1String(
"Shared");
522 typeStr = QLatin1String(
"Calendar");
524 }
else if ( tName.toLower().startsWith( QLatin1String(
"shared.tasks" ) ) ||
525 tName.toLower().startsWith( QLatin1String(
"shared.todo" ) ) ) {
526 ownerStr = QLatin1String(
"Shared");
528 typeStr = QLatin1String(
"Tasks");
530 }
else if ( tName.toLower().startsWith( QLatin1String(
"shared.journal" ) ) ) {
531 ownerStr = QLatin1String(
"Shared");
533 typeStr = QLatin1String(
"Journal");
535 }
else if ( tName.toLower().startsWith( QLatin1String(
"shared.notes" ) ) ) {
536 ownerStr = QLatin1String(
"Shared");
538 typeStr = QLatin1String(
"Notes");
540 }
else if ( tName != i18n(
"Calendar" ) &&
541 tName != i18n(
"Tasks" ) &&
542 tName != i18n(
"Journal" ) &&
543 tName != i18n(
"Notes" ) ) {
550 p = p.parentCollection();
554 if ( !ownerStr.isEmpty() ) {
555 if ( ownerStr.toUpper() == QLatin1String(
"INBOX" ) ) {
556 return i18nc(
"%1 is folder contents",
557 "My Kolab %1", typeStr );
558 }
else if ( ownerStr.toUpper() == QLatin1String(
"SHARED" ) ) {
559 return i18nc(
"%1 is folder name, %2 is folder contents",
560 "Shared Kolab %1 %2", nameStr, typeStr );
562 if ( nameStr.isEmpty() ) {
563 return i18nc(
"%1 is folder owner name, %2 is folder contents",
564 "%1's Kolab %2", ownerStr, typeStr );
566 return i18nc(
"%1 is folder owner name, %2 is folder name, %3 is folder contents",
567 "%1's %2 Kolab %3", ownerStr, nameStr, typeStr );
571 return i18nc(
"%1 is folder contents",
572 "Kolab %1", typeStr );
577 if ( resourceName.contains( QLatin1String(
"davgroupware" ) ) ) {
578 return i18nc(
"%1 is the folder name",
"%1 CalDav Calendar", cName );
582 if ( resourceName.contains( QLatin1String(
"google" ) ) ) {
585 Akonadi::Collection p = c.parentCollection();
586 ownerStr = calendar->collection( p.id() ).
displayName();
589 const QString nameStr = c.displayName();
592 const QString mimeStr = c.contentMimeTypes().join( QLatin1String(
",") );
593 if ( mimeStr.contains( QLatin1String(
".event") ) ) {
594 typeStr = i18n(
"Calendar" );
595 }
else if ( mimeStr.contains( QLatin1String(
".todo") ) ) {
596 typeStr = i18n(
"Tasks" );
597 }
else if ( mimeStr.contains( QLatin1String(
".journal") ) ) {
598 typeStr = i18n(
"Journal" );
599 }
else if ( mimeStr.contains( QLatin1String(
".note") ) ) {
600 typeStr = i18n(
"Notes" );
605 if ( !ownerStr.isEmpty() ) {
606 const int atChar = ownerStr.lastIndexOf( QLatin1Char(
'@') );
607 ownerStr = ownerStr.left( atChar );
608 if ( nameStr.isEmpty() ) {
609 return i18nc(
"%1 is folder owner name, %2 is folder contents",
610 "%1's Google %2", ownerStr, typeStr );
612 return i18nc(
"%1 is folder owner name, %2 is folder name",
613 "%1's %2", ownerStr, nameStr );
616 return i18nc(
"%1 is folder contents",
617 "Google %1", typeStr );
622 const QString dName = fullCollection.displayName();
624 if ( !dName.isEmpty() ) {
625 return fullCollection.name().startsWith( QLatin1String(
"akonadi_" ) ) ? i18n(
"My %1", dName ) : fullCollection.name();
627 return i18nc(
"unknown resource",
"Unknown" );
633 return incidence->mimeType();
637 const QDate &endDate )
642 const int numDays = startDate.daysTo( endDate ) + 1;
644 for (
int i = 0; i < numDays; ++i ) {
645 const QDate date = startDate.addDays( i );
646 if ( !( mask & ( 1 << ( date.dayOfWeek() - 1 ) ) ) ) {
647 result.append( date );
656 const Holiday::List list = holidays.holidays( startDate, endDate );
657 const int listCount( list.count() );
658 for (
int i = 0; i < listCount; ++i ) {
659 const Holiday &h = list.at( i );
660 if ( h.dayType() == Holiday::NonWorkday ) {
661 result.removeAll( h.date() );
674 const Holiday::List list = holidays.holidays( date );
675 const int listCount( list.count() );
676 for (
int i = 0; i < listCount; ++i ) {
677 hdays.append( list.at( i ).text() );
689 i18n(
"No item selected." ) );
693 Attachment::List attachments = incidence->attachments();
695 if ( attachments.empty() ) {
699 QString targetFile, targetDir;
700 if ( attachments.count() > 1 ) {
702 targetDir = KFileDialog::getExistingDirectory( KUrl(
"kfiledialog:///saveAttachment" ),
704 i18n(
"Save Attachments To" ) );
705 if ( targetDir.isEmpty() ) {
710 if ( !targetDir.endsWith( QLatin1Char(
'/') ) ) {
711 targetDir.append( QLatin1Char(
'/') );
715 QString fileName = attachments.first()->label();
716 if ( fileName.isEmpty() ) {
717 fileName = i18nc(
"filename for an unnamed attachment",
"attachment.1" );
719 targetFile = KFileDialog::getSaveFileName( KUrl( QLatin1String(
"kfiledialog:///saveAttachment/") + fileName ),
722 i18n(
"Save Attachment" ) );
723 if ( targetFile.isEmpty() ) {
727 targetDir = QFileInfo( targetFile ).absolutePath() + QLatin1Char(
'/');
730 Q_FOREACH ( Attachment::Ptr attachment, attachments ) {
731 targetFile = targetDir + attachment->label();
733 if ( attachment->isUri() ) {
734 sourceUrl = attachment->uri();
736 sourceUrl = incidence->writeAttachmentToTempFile( attachment );
739 if ( !KIO::NetAccess::file_copy( sourceUrl, KUrl( targetFile ) ) &&
740 KIO::NetAccess::lastError() ) {
741 KMessageBox::error( parentWidget, KIO::NetAccess::lastErrorString() );
748 QStringList cats, thisCats;
751 Q_FOREACH (
const KCalCore::Incidence::Ptr &
incidence, incidences ) {
752 thisCats = incidence->categories();
753 for ( QStringList::ConstIterator si = thisCats.constBegin();
754 si != thisCats.constEnd(); ++si ) {
755 if ( !cats.contains( *si ) ) {
765 if (srcFilename.isEmpty()) {
766 kError() <<
"Empty filename.";
770 if (!QFile::exists(srcFilename)) {
771 kError() <<
"File'" << srcFilename <<
"' doesn't exist.";
774 bool loadedSuccesfully =
true;
777 destCalendar->startBatchAdding();
778 KCalCore::FileStorage storage(destCalendar);
779 storage.setFileName(srcFilename);
780 loadedSuccesfully = storage.load();
781 destCalendar->endBatchAdding();
783 return loadedSuccesfully;
static QByteArray findMostCommonType(const Akonadi::Item::List &items)
CALENDARSUPPORT_EXPORT QMimeData * createMimeData(const Akonadi::Item &item, const KDateTime::Spec &timeSpec)
creates mime data object for dragging an akonadi item containing an incidence
CALENDARSUPPORT_EXPORT QDrag * createDrag(const Akonadi::Item &item, const KDateTime::Spec &timeSpec, QWidget *parent)
creates a drag object for dragging an akonadi item containing an incidence
CALENDARSUPPORT_EXPORT bool isValidIncidenceItemUrl(const KUrl &url, const QStringList &supportedMimeTypes)
returns true if the URL represents an Akonadi item and has one of the given mimetypes.
CALENDARSUPPORT_EXPORT KCalCore::Incidence::Ptr incidence(const Akonadi::Item &item)
returns the incidence from an akonadi item, or a null pointer if the item has no such payload ...
static bool itemMatches(const Akonadi::Item &item, const KCalCore::CalFilter *filter)
CALENDARSUPPORT_EXPORT bool hasIncidence(const Akonadi::Item &item)
returns whether an Akonadi item contains an incidence
CALENDARSUPPORT_EXPORT KCalCore::Todo::Ptr todo(const Akonadi::Item &item)
returns the todo from an akonadi item, or a null pointer if the item has no such payload ...
QList< QModelIndex > QModelIndexList
CALENDARSUPPORT_EXPORT bool mimeDataHasIncidence(const QMimeData *mimeData)
CALENDARSUPPORT_EXPORT Akonadi::Collection selectCollection(QWidget *parent, int &dialogCode, const QStringList &mimeTypes, const Akonadi::Collection &defaultCollection=Akonadi::Collection())
Shows a modal dialog that allows to select a collection.
CALENDARSUPPORT_EXPORT QString subMimeTypeForIncidence(const KCalCore::Incidence::Ptr &incidence)
CALENDARSUPPORT_EXPORT QList< KUrl > todoItemUrls(const QMimeData *mimeData)
CALENDARSUPPORT_EXPORT QStringList categories(const KCalCore::Incidence::List &incidences)
CALENDARSUPPORT_EXPORT KCalCore::Incidence::List incidences(const QMimeData *mimeData, const KDateTime::Spec &timeSpec)
CALENDARSUPPORT_EXPORT KCalCore::Incidence::List incidencesFromItems(const Akonadi::Item::List &items)
returns incidence pointers from an akonadi item.
CALENDARSUPPORT_EXPORT KCalCore::Event::List eventsFromItems(const Akonadi::Item::List &items)
returns event pointers from an akonadi item, or a null pointer if the item has no such payload ...
static KCalPrefs * instance()
Get instance of KCalPrefs.
CALENDARSUPPORT_EXPORT Akonadi::Item::List itemsFromModel(const QAbstractItemModel *model, const QModelIndex &parentIndex=QModelIndex(), int start=0, int end=-1)
CALENDARSUPPORT_EXPORT QString displayName(Akonadi::ETMCalendar *calendar, const Akonadi::Collection &coll)
CALENDARSUPPORT_EXPORT bool hasEvent(const Akonadi::Item &item)
returns whether an Akonadi item contains an event
CALENDARSUPPORT_EXPORT Akonadi::Collection::List collectionsFromIndexes(const QModelIndexList &indexes)
CALENDARSUPPORT_EXPORT Akonadi::Collection collectionFromIndex(const QModelIndex &index)
CALENDARSUPPORT_EXPORT bool hasTodo(const Akonadi::Item &item)
returns whether an Akonadi item contains a todo
CALENDARSUPPORT_EXPORT void saveAttachments(const Akonadi::Item &item, QWidget *parentWidget=0)
CALENDARSUPPORT_EXPORT Akonadi::Collection::Id collectionIdFromIndex(const QModelIndex &index)
CALENDARSUPPORT_EXPORT bool mimeDataHasTodo(const QMimeData *mimeData)
CALENDARSUPPORT_EXPORT QList< QDate > workDays(const QDate &start, const QDate &end)
Returns a list containing work days between start and .
CALENDARSUPPORT_EXPORT KCalCore::Journal::Ptr journal(const Akonadi::Item &item)
returns the journal from an akonadi item, or a null pointer if the item has no such payload ...
CALENDARSUPPORT_EXPORT Akonadi::Item::List applyCalFilter(const Akonadi::Item::List &items, const KCalCore::CalFilter *filter)
Applies a filter to a list of items containing incidences.
CALENDARSUPPORT_EXPORT KCalCore::Event::Ptr event(const Akonadi::Item &item)
returns the event from an akonadi item, or a null pointer if the item has no such payload ...
CALENDARSUPPORT_EXPORT bool canDecode(const QMimeData *mimeData)
returns true if the mime data object contains any of the following:
CALENDARSUPPORT_EXPORT QStringList holiday(const QDate &date)
Returns a list of holidays that occur at.
CALENDARSUPPORT_EXPORT Akonadi::Item itemFromIndex(const QModelIndex &index)
CALENDARSUPPORT_EXPORT KCalCore::Todo::List todos(const QMimeData *mimeData, const KDateTime::Spec &timeSpec)
static bool containsValidIncidenceItemUrl(const QList< QUrl > &urls)
CALENDARSUPPORT_EXPORT bool hasJournal(const Akonadi::Item &item)
returns whether an Akonadi item contains a journal
CALENDARSUPPORT_EXPORT Akonadi::Collection::List collectionsFromModel(const QAbstractItemModel *model, const QModelIndex &parentIndex=QModelIndex(), int start=0, int end=-1)
CALENDARSUPPORT_EXPORT QList< KUrl > incidenceItemUrls(const QMimeData *mimeData)
CALENDARSUPPORT_EXPORT bool mergeCalendar(const QString &srcFilename, const KCalCore::Calendar::Ptr &destCalendar)
CALENDARSUPPORT_EXPORT bool isValidTodoItemUrl(const KUrl &url)
returns true if the URL represents an Akonadi item and has one of the given mimetypes.