KCalUtils

dndfactory.cpp
Go to the documentation of this file.
1 /*
2  This file is part of the kcalutils library.
3 
4  SPDX-FileCopyrightText: 1998 Preston Brown <[email protected]>
5  SPDX-FileCopyrightText: 2001, 2002 Cornelius Schumacher <[email protected]>
6  SPDX-FileCopyrightText: 2003-2004 Reinhold Kainhofer <[email protected]>
7  SPDX-FileCopyrightText: 2005 Rafal Rzepecki <[email protected]>
8  SPDX-FileCopyrightText: 2008 Thomas Thrainer <[email protected]>
9 
10  SPDX-License-Identifier: LGPL-2.0-or-later
11 */
12 /**
13  @file
14  This file is part of the API for handling calendar data and
15  defines the DndFactory class.
16 
17  @brief
18  vCalendar/iCalendar Drag-and-Drop object factory.
19 
20  @author Preston Brown <[email protected]>
21  @author Cornelius Schumacher <[email protected]>
22  @author Reinhold Kainhofer <[email protected]>
23 */
24 #include "dndfactory.h"
25 #include "icaldrag.h"
26 #include "vcaldrag.h"
27 
28 #include "kcalutils_debug.h"
29 #include <KCalendarCore/MemoryCalendar>
30 #include <KIconLoader>
31 #include <KUrlMimeData>
32 #include <QUrl>
33 
34 #include <QApplication>
35 #include <QClipboard>
36 #include <QDate>
37 #include <QDrag>
38 #include <QDropEvent>
39 #include <QIcon>
40 #include <QMimeData>
41 #include <QTimeZone>
42 
43 using namespace KCalendarCore;
44 using namespace KCalUtils;
45 
46 /**
47  DndFactoryPrivate class that helps to provide binary compatibility between releases.
48  @internal
49 */
50 //@cond PRIVATE
51 class KCalUtils::DndFactoryPrivate
52 {
53 public:
54  DndFactoryPrivate(const Calendar::Ptr &calendar)
55  : mCalendar(calendar)
56  {
57  }
58 
59  Incidence::Ptr pasteIncidence(const Incidence::Ptr &incidence, QDateTime newDateTime, DndFactory::PasteFlags pasteOptions)
60  {
61  Incidence::Ptr inc(incidence);
62 
63  if (inc) {
64  inc = Incidence::Ptr(inc->clone());
65  inc->recreate();
66  }
67 
68  if (inc && newDateTime.isValid()) {
69  if (inc->type() == Incidence::TypeEvent) {
70  Event::Ptr event = inc.staticCast<Event>();
71  if (pasteOptions & DndFactory::FlagPasteAtOriginalTime) {
72  // Set date and preserve time and timezone stuff
73  const QDate date = newDateTime.date();
74  newDateTime = event->dtStart();
75  newDateTime.setDate(date);
76  }
77 
78  // in seconds
79  const qint64 durationInSeconds = event->dtStart().secsTo(event->dtEnd());
80  const qint64 durationInDays = event->dtStart().daysTo(event->dtEnd());
81 
82  if (incidence->allDay()) {
83  event->setDtStart(QDateTime(newDateTime.date(), {}));
84  event->setDtEnd(newDateTime.addDays(durationInDays));
85  } else {
86  event->setDtStart(newDateTime);
87  event->setDtEnd(newDateTime.addSecs(durationInSeconds));
88  }
89  } else if (inc->type() == Incidence::TypeTodo) {
90  Todo::Ptr aTodo = inc.staticCast<Todo>();
91  const bool pasteAtDtStart = (pasteOptions & DndFactory::FlagTodosPasteAtDtStart);
92  if (pasteOptions & DndFactory::FlagPasteAtOriginalTime) {
93  // Set date and preserve time and timezone stuff
94  const QDate date = newDateTime.date();
95  newDateTime = pasteAtDtStart ? aTodo->dtStart() : aTodo->dtDue();
96  newDateTime.setDate(date);
97  }
98  if (pasteAtDtStart) {
99  aTodo->setDtStart(newDateTime);
100  } else {
101  aTodo->setDtDue(newDateTime);
102  }
103  } else if (inc->type() == Incidence::TypeJournal) {
104  if (pasteOptions & DndFactory::FlagPasteAtOriginalTime) {
105  // Set date and preserve time and timezone stuff
106  const QDate date = newDateTime.date();
107  newDateTime = inc->dtStart();
108  newDateTime.setDate(date);
109  }
110  inc->setDtStart(newDateTime);
111  } else {
112  qCDebug(KCALUTILS_LOG) << "Trying to paste unknown incidence of type" << int(inc->type());
113  }
114  }
115 
116  return inc;
117  }
118 
119  const Calendar::Ptr mCalendar;
120 };
121 //@endcond
122 
123 DndFactory::DndFactory(const Calendar::Ptr &calendar)
124  : d(new KCalUtils::DndFactoryPrivate(calendar))
125 {
126 }
127 
128 DndFactory::~DndFactory() = default;
129 
131 {
132  auto mimeData = new QMimeData;
133 
134  ICalDrag::populateMimeData(mimeData, d->mCalendar);
135 
136  return mimeData;
137 }
138 
140 {
141  auto drag = new QDrag(owner);
142  drag->setMimeData(createMimeData());
143 
144  return drag;
145 }
146 
148 {
149  Calendar::Ptr cal(new MemoryCalendar(d->mCalendar->timeZone()));
150  Incidence::Ptr i(incidence->clone());
151  // strip recurrence id's, We don't want to drag the exception but the occurrence.
152  i->setRecurrenceId({});
153  cal->addIncidence(i);
154 
155  auto mimeData = new QMimeData;
156 
157  ICalDrag::populateMimeData(mimeData, cal);
158 
159  QUrl uri = i->uri();
160  if (uri.isValid()) {
161  QMap<QString, QString> metadata;
162  metadata[QStringLiteral("labels")] = QLatin1String(QUrl::toPercentEncoding(i->summary()));
163  mimeData->setUrls(QList<QUrl>() << uri);
164  KUrlMimeData::setMetaData(metadata, mimeData);
165  }
166 
167  return mimeData;
168 }
169 
171 {
172  auto drag = new QDrag(owner);
173  drag->setMimeData(createMimeData(incidence));
174  drag->setPixmap(QIcon::fromTheme(incidence->iconName()).pixmap(KIconLoader::SizeSmallMedium));
175 
176  return drag;
177 }
178 
180 {
181  if (mimeData) {
183 
184  if (ICalDrag::fromMimeData(mimeData, calendar) || VCalDrag::fromMimeData(mimeData, calendar)) {
185  return calendar;
186  }
187  }
188 
189  return Calendar::Ptr();
190 }
191 
193 {
194  Calendar::Ptr calendar(createDropCalendar(dropEvent->mimeData()));
195  if (calendar) {
196  dropEvent->accept();
197  return calendar;
198  }
199  return MemoryCalendar::Ptr();
200 }
201 
203 {
204  // qCDebug(KCALUTILS_LOG);
205  Event::Ptr event;
206  Calendar::Ptr calendar(createDropCalendar(mimeData));
207 
208  if (calendar) {
209  Event::List events = calendar->events();
210  if (!events.isEmpty()) {
211  event = Event::Ptr(new Event(*events.first()));
212  }
213  }
214  return event;
215 }
216 
218 {
219  Event::Ptr event = createDropEvent(dropEvent->mimeData());
220 
221  if (event) {
222  dropEvent->accept();
223  }
224 
225  return event;
226 }
227 
229 {
230  // qCDebug(KCALUTILS_LOG);
231  Todo::Ptr todo;
232  Calendar::Ptr calendar(createDropCalendar(mimeData));
233 
234  if (calendar) {
235  Todo::List todos = calendar->todos();
236  if (!todos.isEmpty()) {
237  todo = Todo::Ptr(new Todo(*todos.first()));
238  }
239  }
240 
241  return todo;
242 }
243 
245 {
246  Todo::Ptr todo = createDropTodo(dropEvent->mimeData());
247 
248  if (todo) {
249  dropEvent->accept();
250  }
251 
252  return todo;
253 }
254 
255 void DndFactory::cutIncidence(const Incidence::Ptr &selectedIncidence)
256 {
257  Incidence::List list;
258  list.append(selectedIncidence);
259  cutIncidences(list);
260 }
261 
263 {
264  if (copyIncidences(incidences)) {
265  Incidence::List::ConstIterator it;
266  const Incidence::List::ConstIterator end(incidences.constEnd());
267  for (it = incidences.constBegin(); it != end; ++it) {
268  d->mCalendar->deleteIncidence(*it);
269  }
270  return true;
271  } else {
272  return false;
273  }
274 }
275 
277 {
278  QClipboard *clipboard = QApplication::clipboard();
279  Q_ASSERT(clipboard);
280  Calendar::Ptr calendar(new MemoryCalendar(d->mCalendar->timeZone()));
281 
282  Incidence::List::ConstIterator it;
283  const Incidence::List::ConstIterator end(incidences.constEnd());
284  for (it = incidences.constBegin(); it != end; ++it) {
285  if (*it) {
286  calendar->addIncidence(Incidence::Ptr((*it)->clone()));
287  }
288  }
289 
290  auto mimeData = new QMimeData;
291 
292  ICalDrag::populateMimeData(mimeData, calendar);
293 
294  if (calendar->incidences().isEmpty()) {
295  return false;
296  } else {
297  clipboard->setMimeData(mimeData);
298  return true;
299  }
300 }
301 
303 {
304  Incidence::List list;
305  list.append(selectedInc);
306  return copyIncidences(list);
307 }
308 
310 {
311  QClipboard *clipboard = QApplication::clipboard();
312  Q_ASSERT(clipboard);
313  Calendar::Ptr calendar(createDropCalendar(clipboard->mimeData()));
314  Incidence::List list;
315 
316  if (!calendar) {
317  qCDebug(KCALUTILS_LOG) << "Can't parse clipboard";
318  return list;
319  }
320 
321  // All pasted incidences get new uids, must keep track of old uids,
322  // so we can update child's parents
323  QHash<QString, Incidence::Ptr> oldUidToNewInc;
324 
325  Incidence::List::ConstIterator it;
326  const Incidence::List incidences = calendar->incidences();
327  Incidence::List::ConstIterator end(incidences.constEnd());
328  for (it = incidences.constBegin(); it != end; ++it) {
329  Incidence::Ptr incidence = d->pasteIncidence(*it, newDateTime, pasteOptions);
330  if (incidence) {
331  list.append(incidence);
332  oldUidToNewInc[(*it)->uid()] = *it;
333  }
334  }
335 
336  // update relations
337  end = list.constEnd();
338  for (it = list.constBegin(); it != end; ++it) {
339  Incidence::Ptr incidence = *it;
340  if (oldUidToNewInc.contains(incidence->relatedTo())) {
341  Incidence::Ptr parentInc = oldUidToNewInc[incidence->relatedTo()];
342  incidence->setRelatedTo(parentInc->uid());
343  } else {
344  // not related to anything in the clipboard
345  incidence->setRelatedTo(QString());
346  }
347  }
348 
349  return list;
350 }
351 
353 {
354  QClipboard *clipboard = QApplication::clipboard();
355  Calendar::Ptr calendar(createDropCalendar(clipboard->mimeData()));
356 
357  if (!calendar) {
358  qCDebug(KCALUTILS_LOG) << "Can't parse clipboard";
359  return Incidence::Ptr();
360  }
361 
362  Incidence::List incidenceList = calendar->incidences();
363  Incidence::Ptr incidence = incidenceList.isEmpty() ? Incidence::Ptr() : incidenceList.first();
364 
365  return d->pasteIncidence(incidence, newDateTime, pasteOptions);
366 }
void append(const T &value)
QDateTime addSecs(qint64 s) const const
bool isEmpty() const const
KCalendarCore::Incidence::Ptr pasteIncidence(const QDateTime &newDateTime=QDateTime(), PasteFlags pasteOptions=PasteFlags())
This function clones the incidence that's in the clipboard and sets the clone's date/time to the spec...
Definition: dndfactory.cpp:352
KCALUTILS_EXPORT bool fromMimeData(const QMimeData *e, const KCalendarCore::Calendar::Ptr &cal)
Decode drag&drop object to vCalendar component vcal.
Definition: vcaldrag.cpp:34
KCALUTILS_EXPORT bool populateMimeData(QMimeData *e, const KCalendarCore::Calendar::Ptr &cal)
Sets the iCalendar representation as data of the drag object.
Definition: icaldrag.cpp:25
KCOREADDONS_EXPORT void setMetaData(const MetaDataMap &metaData, QMimeData *mimeData)
KCALUTILS_EXPORT bool fromMimeData(const QMimeData *e, const KCalendarCore::Calendar::Ptr &cal)
Decode drag&drop object to iCalendar component cal.
Definition: icaldrag.cpp:49
QDateTime addDays(qint64 ndays) const const
QIcon fromTheme(const QString &name)
void cutIncidence(const KCalendarCore::Incidence::Ptr &)
Cut the incidence to the clipboard.
Definition: dndfactory.cpp:255
KCalendarCore::Event::Ptr createDropEvent(const QMimeData *md)
Create Event object from mime data.
Definition: dndfactory.cpp:202
QVector::const_iterator constEnd() const const
QList::const_iterator constBegin() const const
const QMimeData * mimeData() const const
T & first()
AKONADI_CALENDAR_EXPORT KCalendarCore::Incidence::Ptr incidence(const Akonadi::Item &item)
QDrag * createDrag(QObject *owner)
Create a drag object for the whole calendar.
Definition: dndfactory.cpp:139
void setDate(const QDate &date)
bool isValid() const const
QClipboard * clipboard()
QSharedPointer< Incidence > Ptr
KCalendarCore::Incidence::List pasteIncidences(const QDateTime &newDateTime=QDateTime(), PasteFlags pasteOptions=PasteFlags())
This function clones the incidences that are in the clipboard and sets the clone's date/time to the s...
Definition: dndfactory.cpp:309
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
QByteArray toPercentEncoding(const QString &input, const QByteArray &exclude, const QByteArray &include)
bool copyIncidences(const KCalendarCore::Incidence::List &incidences)
Copies a list of incidences to the clipboard.
Definition: dndfactory.cpp:276
const QMimeData * mimeData(QClipboard::Mode mode) const const
QList::const_iterator constEnd() const const
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) const const
QTimeZone systemTimeZone()
QDate date() const const
QMimeData * createMimeData()
Create the mime data for the whole calendar.
Definition: dndfactory.cpp:130
bool copyIncidence(const KCalendarCore::Incidence::Ptr &)
Copy the incidence to clipboard/.
Definition: dndfactory.cpp:302
bool isValid() const const
void setMimeData(QMimeData *src, QClipboard::Mode mode)
bool cutIncidences(const KCalendarCore::Incidence::List &incidences)
Cuts a list of incidences to the clipboard.
Definition: dndfactory.cpp:262
QSharedPointer< X > staticCast() const const
QVector::const_iterator constBegin() const const
bool contains(const Key &key) const const
KCalendarCore::Calendar::Ptr createDropCalendar(QDropEvent *de)
Create the calendar that is contained in the drop event's data.
Definition: dndfactory.cpp:192
KCalendarCore::Todo::Ptr createDropTodo(const QMimeData *md)
Create Todo object from mime data.
Definition: dndfactory.cpp:228
void accept()
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 6 2023 04:09:39 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.