1 // -*- c-basic-offset:4; indent-tabs-mode:nil -*-
2 /*
3 This file is part of the KDE libraries
4 SPDX-FileCopyrightText: 2000 David Faure <faure@kde.org>
5 SPDX-FileCopyrightText: 2003 Alexander Kellett <lypanov@kde.org>
6 SPDX-FileCopyrightText: 2008 Norbert Frese <nf2@scheinwelt.at>
7
8 SPDX-License-Identifier: LGPL-2.0-only
9 */
10
11 #include "kbookmark.h"
12 #include "kbookmarks_debug.h"
13 #include <kbookmarkmanager.h>
14
15 #include <KStringHandler>
16 #include <kurlmimedata.h>
17
18 #include <QCoreApplication>
19 #include <QMimeDatabase>
20 #include <QStack>
21 #include <QDateTime>
22 #include <QMimeData>
23
24 namespace
25 {
26 namespace Strings
27 {
metaDataKDEOwner()28 QString metaDataKDEOwner()
29 {
30 return QStringLiteral("http://www.kde.org");
31 }
metaDataFreedesktopOwner()32 QString metaDataFreedesktopOwner()
33 {
34 return QStringLiteral("http://freedesktop.org");
35 }
metaDataMimeOwner()36 QString metaDataMimeOwner()
37 {
38 return QStringLiteral("http://www.freedesktop.org/standards/shared-mime-info");
39 }
40
xbelMimeType()41 QString xbelMimeType()
42 {
43 return QStringLiteral("application/x-xbel");
44 }
45 }
46 }
47
48 ////// utility functions
49
cd(QDomNode node,const QString & name,bool create)50 static QDomNode cd(QDomNode node, const QString &name, bool create)
51 {
52 QDomNode subnode = node.namedItem(name);
53 if (create && subnode.isNull()) {
54 subnode = node.ownerDocument().createElement(name);
55 node.appendChild(subnode);
56 }
57 return subnode;
58 }
59
cd_or_create(const QDomNode & node,const QString & name)60 static QDomNode cd_or_create(const QDomNode &node, const QString &name)
61 {
62 return cd(node, name, true);
63 }
64
get_or_create_text(QDomNode node)65 static QDomText get_or_create_text(QDomNode node)
66 {
67 QDomNode subnode = node.firstChild();
68 if (subnode.isNull()) {
69 subnode = node.ownerDocument().createTextNode(QLatin1String(""));
70 node.appendChild(subnode);
71 }
72 return subnode.toText();
73 }
74
findMetadata(const QString & forOwner,QDomNode & parent,bool create)75 static QDomNode findMetadata(const QString &forOwner, QDomNode &parent, bool create)
76 {
77 const bool forOwnerIsKDE = (forOwner == Strings::metaDataKDEOwner());
78
79 QDomElement metadataElement;
80 for (QDomNode _node = parent.firstChild(); !_node.isNull(); _node = _node.nextSibling()) {
81 QDomElement elem = _node.toElement();
82 if (!elem.isNull() && elem.tagName() == QLatin1String("metadata")) {
83 const QString owner = elem.attribute(QStringLiteral("owner"));
84 if (owner == forOwner) {
85 return elem;
86 }
87 if (owner.isEmpty() && forOwnerIsKDE) {
88 metadataElement = elem;
89 }
90 }
91 }
92 if (create && metadataElement.isNull()) {
93 metadataElement = parent.ownerDocument().createElement(QStringLiteral("metadata"));
94 parent.appendChild(metadataElement);
95 metadataElement.setAttribute(QStringLiteral("owner"), forOwner);
96
97 } else if (!metadataElement.isNull() && forOwnerIsKDE) {
98 // i'm not sure if this is good, we shouldn't take over foreign metadata
99 metadataElement.setAttribute(QStringLiteral("owner"), Strings::metaDataKDEOwner());
100 }
101 return metadataElement;
102 }
103
104 //////
105
KBookmarkGroup()106 KBookmarkGroup::KBookmarkGroup()
107 : KBookmark(QDomElement())
108 {
109 }
110
KBookmarkGroup(const QDomElement & elem)111 KBookmarkGroup::KBookmarkGroup(const QDomElement &elem)
112 : KBookmark(elem)
113 {
114 }
115
isOpen() const116 bool KBookmarkGroup::isOpen() const
117 {
118 return element.attribute(QStringLiteral("folded")) == QLatin1String("no"); // default is: folded
119 }
120
first() const121 KBookmark KBookmarkGroup::first() const
122 {
123 return KBookmark(nextKnownTag(element.firstChildElement(), true));
124 }
125
previous(const KBookmark & current) const126 KBookmark KBookmarkGroup::previous(const KBookmark ¤t) const
127 {
128 return KBookmark(nextKnownTag(current.element.previousSiblingElement(), false));
129 }
130
next(const KBookmark & current) const131 KBookmark KBookmarkGroup::next(const KBookmark ¤t) const
132 {
133 return KBookmark(nextKnownTag(current.element.nextSiblingElement(), true));
134 }
135
indexOf(const KBookmark & child) const136 int KBookmarkGroup::indexOf(const KBookmark &child) const
137 {
138 int counter = 0;
139 for (KBookmark bk = first(); !bk.isNull(); bk = next(bk), ++counter) {
140 if (bk.element == child.element) {
141 return counter;
142 }
143 }
144 return -1;
145 }
146
nextKnownTag(const QDomElement & start,bool goNext) const147 QDomElement KBookmarkGroup::nextKnownTag(const QDomElement &start, bool goNext) const
148 {
149 for (QDomElement elem = start; !elem.isNull();) {
150 QString tag = elem.tagName();
151 if (tag == QLatin1String("folder") || tag == QLatin1String("bookmark") || tag == QLatin1String("separator")) {
152 return elem;
153 }
154 if (goNext) {
155 elem = elem.nextSiblingElement();
156 } else {
157 elem = elem.previousSiblingElement();
158 }
159 }
160 return QDomElement();
161 }
162
createNewFolder(const QString & text)163 KBookmarkGroup KBookmarkGroup::createNewFolder(const QString &text)
164 {
165 if (isNull()) {
166 return KBookmarkGroup();
167 }
168 QDomDocument doc = element.ownerDocument();
169 QDomElement groupElem = doc.createElement(QStringLiteral("folder"));
170 element.appendChild(groupElem);
171 QDomElement textElem = doc.createElement(QStringLiteral("title"));
172 groupElem.appendChild(textElem);
173 textElem.appendChild(doc.createTextNode(text));
174 return KBookmarkGroup(groupElem);
175 }
176
createNewSeparator()177 KBookmark KBookmarkGroup::createNewSeparator()
178 {
179 if (isNull()) {
180 return KBookmark();
181 }
182 QDomDocument doc = element.ownerDocument();
183 Q_ASSERT(!doc.isNull());
184 QDomElement sepElem = doc.createElement(QStringLiteral("separator"));
185 element.appendChild(sepElem);
186 return KBookmark(sepElem);
187 }
188
moveBookmark(const KBookmark & item,const KBookmark & after)189 bool KBookmarkGroup::moveBookmark(const KBookmark &item, const KBookmark &after)
190 {
191 QDomNode n;
192 if (!after.isNull()) {
193 n = element.insertAfter(item.element, after.element);
194 } else { // first child
195 if (element.firstChild().isNull()) { // Empty element -> set as real first child
196 n = element.insertBefore(item.element, QDomElement());
197 }
198
199 // we have to skip everything up to the first valid child
200 QDomElement firstChild = nextKnownTag(element.firstChild().toElement(), true);
201 if (!firstChild.isNull()) {
202 if (firstChild == item.element) { // item is already the first child, done
203 return true;
204 }
205 n = element.insertBefore(item.element, firstChild);
206 } else {
207 // No real first child -> append after the <title> etc.
208 n = element.appendChild(item.element);
209 }
210 }
211 return (!n.isNull());
212 }
213
addBookmark(const KBookmark & bm)214 KBookmark KBookmarkGroup::addBookmark(const KBookmark &bm)
215 {
216 element.appendChild(bm.internalElement());
217 return bm;
218 }
219
addBookmark(const QString & text,const QUrl & url,const QString & icon)220 KBookmark KBookmarkGroup::addBookmark(const QString &text, const QUrl &url, const QString &icon)
221 {
222 if (isNull()) {
223 return KBookmark();
224 }
225 QDomDocument doc = element.ownerDocument();
226 QDomElement elem = doc.createElement(QStringLiteral("bookmark"));
227 elem.setAttribute(QStringLiteral("href"), url.toString(QUrl::FullyEncoded));
228
229 QDomElement textElem = doc.createElement(QStringLiteral("title"));
230 elem.appendChild(textElem);
231 textElem.appendChild(doc.createTextNode(text));
232
233 KBookmark newBookmark = addBookmark(KBookmark(elem));
234
235 // as icons are moved to metadata, we have to use the KBookmark API for this
236 newBookmark.setIcon(icon);
237 return newBookmark;
238 }
239
deleteBookmark(const KBookmark & bk)240 void KBookmarkGroup::deleteBookmark(const KBookmark &bk)
241 {
242 element.removeChild(bk.element);
243 }
244
isToolbarGroup() const245 bool KBookmarkGroup::isToolbarGroup() const
246 {
247 return (element.attribute(QStringLiteral("toolbar")) == QLatin1String("yes"));
248 }
249
findToolbar() const250 QDomElement KBookmarkGroup::findToolbar() const
251 {
252 if (element.attribute(QStringLiteral("toolbar")) == QLatin1String("yes")) {
253 return element;
254 }
255 for (QDomElement e = element.firstChildElement(QStringLiteral("folder")); !e.isNull(); e = e.nextSiblingElement(QStringLiteral("folder"))) {
256 QDomElement result = KBookmarkGroup(e).findToolbar();
257 if (!result.isNull()) {
258 return result;
259 }
260 }
261 return QDomElement();
262 }
263
groupUrlList() const264 QList<QUrl> KBookmarkGroup::groupUrlList() const
265 {
266 QList<QUrl> urlList;
267 for (KBookmark bm = first(); !bm.isNull(); bm = next(bm)) {
268 if (bm.isSeparator() || bm.isGroup()) {
269 continue;
270 }
271 urlList << bm.url();
272 }
273 return urlList;
274 }
275
276 //////
277
KBookmark()278 KBookmark::KBookmark()
279 {
280 }
281
KBookmark(const QDomElement & elem)282 KBookmark::KBookmark(const QDomElement &elem)
283 : element(elem)
284 {
285 }
286
isGroup() const287 bool KBookmark::isGroup() const
288 {
289 QString tag = element.tagName();
290 return tag == QLatin1String("folder") //
291 || tag == QLatin1String("xbel"); // don't forget the toplevel group
292 }
293
isSeparator() const294 bool KBookmark::isSeparator() const
295 {
296 return (element.tagName() == QLatin1String("separator"));
297 }
298
isNull() const299 bool KBookmark::isNull() const
300 {
301 return element.isNull();
302 }
303
hasParent() const304 bool KBookmark::hasParent() const
305 {
306 QDomElement parent = element.parentNode().toElement();
307 return !parent.isNull();
308 }
309
text() const310 QString KBookmark::text() const
311 {
312 return KStringHandler::csqueeze(fullText());
313 }
314
fullText() const315 QString KBookmark::fullText() const
316 {
317 if (isSeparator()) {
318 return QCoreApplication::translate("KBookmark", "--- separator ---", "Bookmark separator");
319 }
320
321 QString text = element.namedItem(QStringLiteral("title")).toElement().text();
322 text.replace(QLatin1Char('\n'), QLatin1Char(' ')); // #140673
323 return text;
324 }
325
setFullText(const QString & fullText)326 void KBookmark::setFullText(const QString &fullText)
327 {
328 QDomNode titleNode = element.namedItem(QStringLiteral("title"));
329 if (titleNode.isNull()) {
330 titleNode = element.ownerDocument().createElement(QStringLiteral("title"));
331 element.appendChild(titleNode);
332 }
333
334 if (titleNode.firstChild().isNull()) {
335 QDomText domtext = titleNode.ownerDocument().createTextNode(QLatin1String(""));
336 titleNode.appendChild(domtext);
337 }
338
339 QDomText domtext = titleNode.firstChild().toText();
340 domtext.setData(fullText);
341 }
342
url() const343 QUrl KBookmark::url() const
344 {
345 return QUrl(element.attribute(QStringLiteral("href")));
346 }
347
setUrl(const QUrl & url)348 void KBookmark::setUrl(const QUrl &url)
349 {
350 element.setAttribute(QStringLiteral("href"), url.toString());
351 }
352
icon() const353 QString KBookmark::icon() const
354 {
355 QDomNode metaDataNode = metaData(Strings::metaDataFreedesktopOwner(), false);
356 QDomElement iconElement = cd(metaDataNode, QStringLiteral("bookmark:icon"), false).toElement();
357
358 QString icon = iconElement.attribute(QStringLiteral("name"));
359
360 // migration code
361 if (icon.isEmpty()) {
362 icon = element.attribute(QStringLiteral("icon"));
363 }
364 if (icon == QLatin1String("www")) { // common icon for kde3 bookmarks
365 return QStringLiteral("internet-web-browser");
366 }
367 // end migration code
368
369 if (icon == QLatin1String("bookmark_folder")) {
370 return QStringLiteral("folder-bookmarks");
371 }
372 if (icon.isEmpty()) {
373 // Default icon depends on URL for bookmarks, and is default directory
374 // icon for groups.
375 if (isGroup()) {
376 icon = QStringLiteral("folder-bookmarks");
377 } else {
378 if (isSeparator()) {
379 icon = QStringLiteral("edit-clear"); // whatever
380 } else {
381 // get icon from mimeType
382 QMimeDatabase db;
383 QMimeType mime;
384 QString _mimeType = mimeType();
385 if (!_mimeType.isEmpty()) {
386 mime = db.mimeTypeForName(_mimeType);
387 } else {
388 mime = db.mimeTypeForUrl(url());
389 }
390 if (mime.isValid()) {
391 icon = mime.iconName();
392 }
393 }
394 }
395 }
396 return icon;
397 }
398
setIcon(const QString & icon)399 void KBookmark::setIcon(const QString &icon)
400 {
401 QDomNode metaDataNode = metaData(Strings::metaDataFreedesktopOwner(), true);
402 QDomElement iconElement = cd_or_create(metaDataNode, QStringLiteral("bookmark:icon")).toElement();
403 iconElement.setAttribute(QStringLiteral("name"), icon);
404
405 // migration code
406 if (!element.attribute(QStringLiteral("icon")).isEmpty()) {
407 element.removeAttribute(QStringLiteral("icon"));
408 }
409 }
410
description() const411 QString KBookmark::description() const
412 {
413 if (isSeparator()) {
414 return QString();
415 }
416
417 QString description = element.namedItem(QStringLiteral("desc")).toElement().text();
418 description.replace(QLatin1Char('\n'), QLatin1Char(' ')); // #140673
419 return description;
420 }
421
setDescription(const QString & description)422 void KBookmark::setDescription(const QString &description)
423 {
424 QDomNode descNode = element.namedItem(QStringLiteral("desc"));
425 if (descNode.isNull()) {
426 descNode = element.ownerDocument().createElement(QStringLiteral("desc"));
427 element.appendChild(descNode);
428 }
429
430 if (descNode.firstChild().isNull()) {
431 QDomText domtext = descNode.ownerDocument().createTextNode(QString());
432 descNode.appendChild(domtext);
433 }
434
435 QDomText domtext = descNode.firstChild().toText();
436 domtext.setData(description);
437 }
438
mimeType() const439 QString KBookmark::mimeType() const
440 {
441 QDomNode metaDataNode = metaData(Strings::metaDataMimeOwner(), false);
442 QDomElement mimeTypeElement = cd(metaDataNode, QStringLiteral("mime:mime-type"), false).toElement();
443 return mimeTypeElement.attribute(QStringLiteral("type"));
444 }
445
setMimeType(const QString & mimeType)446 void KBookmark::setMimeType(const QString &mimeType)
447 {
448 QDomNode metaDataNode = metaData(Strings::metaDataMimeOwner(), true);
449 QDomElement iconElement = cd_or_create(metaDataNode, QStringLiteral("mime:mime-type")).toElement();
450 iconElement.setAttribute(QStringLiteral("type"), mimeType);
451 }
452
showInToolbar() const453 bool KBookmark::showInToolbar() const
454 {
455 if (element.hasAttribute(QStringLiteral("showintoolbar"))) {
456 bool show = element.attribute(QStringLiteral("showintoolbar")) == QLatin1String("yes");
457 const_cast<QDomElement *>(&element)->removeAttribute(QStringLiteral("showintoolbar"));
458 const_cast<KBookmark *>(this)->setShowInToolbar(show);
459 }
460 return metaDataItem(QStringLiteral("showintoolbar")) == QLatin1String("yes");
461 }
462
setShowInToolbar(bool show)463 void KBookmark::setShowInToolbar(bool show)
464 {
465 setMetaDataItem(QStringLiteral("showintoolbar"), show ? QStringLiteral("yes") : QStringLiteral("no"));
466 }
467
parentGroup() const468 KBookmarkGroup KBookmark::parentGroup() const
469 {
470 return KBookmarkGroup(element.parentNode().toElement());
471 }
472
toGroup() const473 KBookmarkGroup KBookmark::toGroup() const
474 {
475 Q_ASSERT(isGroup());
476 return KBookmarkGroup(element);
477 }
478
address() const479 QString KBookmark::address() const
480 {
481 if (element.tagName() == QLatin1String("xbel")) {
482 return QLatin1String(""); // not QString() !
483 } else {
484 // Use keditbookmarks's DEBUG_ADDRESSES flag to debug this code :)
485 if (element.parentNode().isNull()) {
486 Q_ASSERT(false);
487 return QStringLiteral("ERROR"); // Avoid an infinite loop
488 }
489 KBookmarkGroup group = parentGroup();
490 QString parentAddress = group.address();
491 int pos = group.indexOf(*this);
492 Q_ASSERT(pos != -1);
493 return parentAddress + QLatin1Char('/') + QString::number(pos);
494 }
495 }
496
positionInParent() const497 int KBookmark::positionInParent() const
498 {
499 return parentGroup().indexOf(*this);
500 }
501
internalElement() const502 QDomElement KBookmark::internalElement() const
503 {
504 return element;
505 }
506
standaloneBookmark(const QString & text,const QUrl & url,const QString & icon)507 KBookmark KBookmark::standaloneBookmark(const QString &text, const QUrl &url, const QString &icon)
508 {
509 QDomDocument doc(QStringLiteral("xbel"));
510 QDomElement elem = doc.createElement(QStringLiteral("xbel"));
511 doc.appendChild(elem);
512 KBookmarkGroup grp(elem);
513 grp.addBookmark(text, url, icon);
514 return grp.first();
515 }
516
commonParent(const QString & first,const QString & second)517 QString KBookmark::commonParent(const QString &first, const QString &second)
518 {
519 QString A = first;
520 QString B = second;
521 QString error(QStringLiteral("ERROR"));
522 if (A == error || B == error) {
523 return error;
524 }
525
526 A += QLatin1Char('/');
527 B += QLatin1Char('/');
528
529 int lastCommonSlash = 0;
530 int lastPos = A.length() < B.length() ? A.length() : B.length();
531 for (int i = 0; i < lastPos; ++i) {
532 if (A[i] != B[i]) {
533 return A.left(lastCommonSlash);
534 }
535 if (A[i] == QLatin1Char('/')) {
536 lastCommonSlash = i;
537 }
538 }
539 return A.left(lastCommonSlash);
540 }
541
updateAccessMetadata()542 void KBookmark::updateAccessMetadata()
543 {
544 // qCDebug(KBOOKMARKS_LOG) << "KBookmark::updateAccessMetadata " << address() << " " << url();
545
546 const uint timet = QDateTime::currentDateTimeUtc().toSecsSinceEpoch();
547 setMetaDataItem(QStringLiteral("time_added"), QString::number(timet), DontOverwriteMetaData);
548 setMetaDataItem(QStringLiteral("time_visited"), QString::number(timet));
549
550 QString countStr = metaDataItem(QStringLiteral("visit_count")); // TODO use spec'ed name
551 bool ok;
552 int currentCount = countStr.toInt(&ok);
553 if (!ok) {
554 currentCount = 0;
555 }
556 currentCount++;
557 setMetaDataItem(QStringLiteral("visit_count"), QString::number(currentCount));
558
559 // TODO - time_modified
560 }
561
parentAddress(const QString & address)562 QString KBookmark::parentAddress(const QString &address)
563 {
564 return address.left(address.lastIndexOf(QLatin1Char('/')));
565 }
566
positionInParent(const QString & address)567 uint KBookmark::positionInParent(const QString &address)
568 {
569 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
570 return QStringView(address).mid(address.lastIndexOf(QLatin1Char('/')) + 1).toInt();
571 #else
572 return address.midRef(address.lastIndexOf(QLatin1Char('/')) + 1).toInt();
573 #endif
574 }
575
previousAddress(const QString & address)576 QString KBookmark::previousAddress(const QString &address)
577 {
578 uint pp = positionInParent(address);
579 return pp > 0 ? parentAddress(address) + QLatin1Char('/') + QString::number(pp - 1) : QString();
580 }
581
nextAddress(const QString & address)582 QString KBookmark::nextAddress(const QString &address)
583 {
584 return parentAddress(address) + QLatin1Char('/') + QString::number(positionInParent(address) + 1);
585 }
586
metaData(const QString & owner,bool create) const587 QDomNode KBookmark::metaData(const QString &owner, bool create) const
588 {
589 QDomNode infoNode = cd(internalElement(), QStringLiteral("info"), create);
590 if (infoNode.isNull()) {
591 return QDomNode();
592 }
593 return findMetadata(owner, infoNode, create);
594 }
595
metaDataItem(const QString & key) const596 QString KBookmark::metaDataItem(const QString &key) const
597 {
598 QDomNode metaDataNode = metaData(Strings::metaDataKDEOwner(), false);
599 for (QDomElement e = metaDataNode.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) {
600 if (e.tagName() == key) {
601 return e.text();
602 }
603 }
604 return QString();
605 }
606
setMetaDataItem(const QString & key,const QString & value,MetaDataOverwriteMode mode)607 void KBookmark::setMetaDataItem(const QString &key, const QString &value, MetaDataOverwriteMode mode)
608 {
609 QDomNode metaDataNode = metaData(Strings::metaDataKDEOwner(), true);
610 QDomNode item = cd_or_create(metaDataNode, key);
611 QDomText text = get_or_create_text(item);
612 if (mode == DontOverwriteMetaData && !text.data().isEmpty()) {
613 return;
614 }
615
616 text.setData(value);
617 }
618
operator ==(const KBookmark & rhs) const619 bool KBookmark::operator==(const KBookmark &rhs) const
620 {
621 return element == rhs.element;
622 }
623
624 ////
625
~KBookmarkGroupTraverser()626 KBookmarkGroupTraverser::~KBookmarkGroupTraverser()
627 {
628 }
629
traverse(const KBookmarkGroup & root)630 void KBookmarkGroupTraverser::traverse(const KBookmarkGroup &root)
631 {
632 QStack<KBookmarkGroup> stack;
633 stack.push(root);
634 KBookmark bk = root.first();
635 for (;;) {
636 if (bk.isNull()) {
637 if (stack.count() == 1) { // only root is on the stack
638 return;
639 }
640 if (!stack.isEmpty()) {
641 visitLeave(stack.top());
642 bk = stack.pop();
643 }
644 bk = stack.top().next(bk);
645 } else if (bk.isGroup()) {
646 KBookmarkGroup gp = bk.toGroup();
647 visitEnter(gp);
648 bk = gp.first();
649 stack.push(gp);
650 } else {
651 visit(bk);
652 bk = stack.top().next(bk);
653 }
654 }
655 }
656
visit(const KBookmark &)657 void KBookmarkGroupTraverser::visit(const KBookmark &)
658 {
659 }
660
visitEnter(const KBookmarkGroup &)661 void KBookmarkGroupTraverser::visitEnter(const KBookmarkGroup &)
662 {
663 }
664
visitLeave(const KBookmarkGroup &)665 void KBookmarkGroupTraverser::visitLeave(const KBookmarkGroup &)
666 {
667 }
668
populateMimeData(QMimeData * mimeData) const669 void KBookmark::populateMimeData(QMimeData *mimeData) const
670 {
671 KBookmark::List bookmarkList;
672 bookmarkList.append(*this);
673 bookmarkList.populateMimeData(mimeData);
674 }
675
List()676 KBookmark::List::List()
677 : QList<KBookmark>()
678 {
679 }
680
populateMimeData(QMimeData * mimeData) const681 void KBookmark::List::populateMimeData(QMimeData *mimeData) const
682 {
683 QList<QUrl> urls;
684
685 QDomDocument doc(QStringLiteral("xbel"));
686 QDomElement elem = doc.createElement(QStringLiteral("xbel"));
687 doc.appendChild(elem);
688
689 for (const_iterator it = begin(), end = this->end(); it != end; ++it) {
690 urls.append((*it).url());
691 elem.appendChild((*it).internalElement().cloneNode(true /* deep */));
692 }
693
694 // This sets text/uri-list and text/plain into the mimedata
695 mimeData->setUrls(urls);
696
697 mimeData->setData(Strings::xbelMimeType(), doc.toByteArray());
698 }
699
canDecode(const QMimeData * mimeData)700 bool KBookmark::List::canDecode(const QMimeData *mimeData)
701 {
702 return mimeData->hasFormat(Strings::xbelMimeType()) || mimeData->hasUrls();
703 }
704
mimeDataTypes()705 QStringList KBookmark::List::mimeDataTypes()
706 {
707 return QStringList() << Strings::xbelMimeType() << KUrlMimeData::mimeDataTypes();
708 }
709
fromMimeData(const QMimeData * mimeData,QDomDocument & doc)710 KBookmark::List KBookmark::List::fromMimeData(const QMimeData *mimeData, QDomDocument &doc)
711 {
712 KBookmark::List bookmarks;
713 const QByteArray payload = mimeData->data(Strings::xbelMimeType());
714 if (!payload.isEmpty()) {
715 doc.setContent(payload);
716 QDomElement elem = doc.documentElement();
717 const QDomNodeList children = elem.childNodes();
718 bookmarks.reserve(children.count());
719 for (int childno = 0; childno < children.count(); childno++) {
720 bookmarks.append(KBookmark(children.item(childno).toElement()));
721 }
722 return bookmarks;
723 }
724 const QList<QUrl> urls = KUrlMimeData::urlsFromMimeData(mimeData);
725 bookmarks.reserve(urls.size());
726 for (int i = 0; i < urls.size(); ++i) {
727 const QUrl url = urls.at(i);
728 bookmarks.append(KBookmark::standaloneBookmark(url.toDisplayString(), url, QString() /*TODO icon*/));
729 }
730 return bookmarks;
731 }
732