File indexing completed on 2024-04-21 03:52:37

0001 // -*- c-basic-offset:4; indent-tabs-mode:nil -*-
0002 /*
0003     This file is part of the KDE libraries
0004     SPDX-FileCopyrightText: 2000 David Faure <faure@kde.org>
0005     SPDX-FileCopyrightText: 2003 Alexander Kellett <lypanov@kde.org>
0006     SPDX-FileCopyrightText: 2008 Norbert Frese <nf2@scheinwelt.at>
0007 
0008     SPDX-License-Identifier: LGPL-2.0-only
0009 */
0010 
0011 #include "kbookmark.h"
0012 
0013 #include <KStringHandler>
0014 #include <kurlmimedata.h>
0015 
0016 #include <QCoreApplication>
0017 #include <QMimeDatabase>
0018 #include <QStack>
0019 #include <QDateTime>
0020 #include <QMimeData>
0021 
0022 namespace
0023 {
0024 namespace Strings
0025 {
0026 QString metaDataKDEOwner()
0027 {
0028     return QStringLiteral("http://www.kde.org");
0029 }
0030 QString metaDataFreedesktopOwner()
0031 {
0032     return QStringLiteral("http://freedesktop.org");
0033 }
0034 QString metaDataMimeOwner()
0035 {
0036     return QStringLiteral("http://www.freedesktop.org/standards/shared-mime-info");
0037 }
0038 
0039 QString xbelMimeType()
0040 {
0041     return QStringLiteral("application/x-xbel");
0042 }
0043 }
0044 }
0045 
0046 ////// utility functions
0047 
0048 static QDomNode cd(QDomNode node, const QString &name, bool create)
0049 {
0050     QDomNode subnode = node.namedItem(name);
0051     if (create && subnode.isNull()) {
0052         subnode = node.ownerDocument().createElement(name);
0053         node.appendChild(subnode);
0054     }
0055     return subnode;
0056 }
0057 
0058 static QDomNode cd_or_create(const QDomNode &node, const QString &name)
0059 {
0060     return cd(node, name, true);
0061 }
0062 
0063 static QDomText get_or_create_text(QDomNode node)
0064 {
0065     QDomNode subnode = node.firstChild();
0066     if (subnode.isNull()) {
0067         subnode = node.ownerDocument().createTextNode(QLatin1String(""));
0068         node.appendChild(subnode);
0069     }
0070     return subnode.toText();
0071 }
0072 
0073 static QDomNode findMetadata(const QString &forOwner, QDomNode &parent, bool create)
0074 {
0075     const bool forOwnerIsKDE = (forOwner == Strings::metaDataKDEOwner());
0076 
0077     QDomElement metadataElement;
0078     for (QDomNode _node = parent.firstChild(); !_node.isNull(); _node = _node.nextSibling()) {
0079         QDomElement elem = _node.toElement();
0080         if (!elem.isNull() && elem.tagName() == QLatin1String("metadata")) {
0081             const QString owner = elem.attribute(QStringLiteral("owner"));
0082             if (owner == forOwner) {
0083                 return elem;
0084             }
0085             if (owner.isEmpty() && forOwnerIsKDE) {
0086                 metadataElement = elem;
0087             }
0088         }
0089     }
0090     if (create && metadataElement.isNull()) {
0091         metadataElement = parent.ownerDocument().createElement(QStringLiteral("metadata"));
0092         parent.appendChild(metadataElement);
0093         metadataElement.setAttribute(QStringLiteral("owner"), forOwner);
0094 
0095     } else if (!metadataElement.isNull() && forOwnerIsKDE) {
0096         // i'm not sure if this is good, we shouldn't take over foreign metadata
0097         metadataElement.setAttribute(QStringLiteral("owner"), Strings::metaDataKDEOwner());
0098     }
0099     return metadataElement;
0100 }
0101 
0102 //////
0103 
0104 KBookmarkGroup::KBookmarkGroup()
0105     : KBookmark(QDomElement())
0106 {
0107 }
0108 
0109 KBookmarkGroup::KBookmarkGroup(const QDomElement &elem)
0110     : KBookmark(elem)
0111 {
0112 }
0113 
0114 bool KBookmarkGroup::isOpen() const
0115 {
0116     return element.attribute(QStringLiteral("folded")) == QLatin1String("no"); // default is: folded
0117 }
0118 
0119 KBookmark KBookmarkGroup::first() const
0120 {
0121     return KBookmark(nextKnownTag(element.firstChildElement(), true));
0122 }
0123 
0124 KBookmark KBookmarkGroup::previous(const KBookmark &current) const
0125 {
0126     return KBookmark(nextKnownTag(current.element.previousSiblingElement(), false));
0127 }
0128 
0129 KBookmark KBookmarkGroup::next(const KBookmark &current) const
0130 {
0131     return KBookmark(nextKnownTag(current.element.nextSiblingElement(), true));
0132 }
0133 
0134 int KBookmarkGroup::indexOf(const KBookmark &child) const
0135 {
0136     int counter = 0;
0137     for (KBookmark bk = first(); !bk.isNull(); bk = next(bk), ++counter) {
0138         if (bk.element == child.element) {
0139             return counter;
0140         }
0141     }
0142     return -1;
0143 }
0144 
0145 QDomElement KBookmarkGroup::nextKnownTag(const QDomElement &start, bool goNext) const
0146 {
0147     for (QDomElement elem = start; !elem.isNull();) {
0148         QString tag = elem.tagName();
0149         if (tag == QLatin1String("folder") || tag == QLatin1String("bookmark") || tag == QLatin1String("separator")) {
0150             return elem;
0151         }
0152         if (goNext) {
0153             elem = elem.nextSiblingElement();
0154         } else {
0155             elem = elem.previousSiblingElement();
0156         }
0157     }
0158     return QDomElement();
0159 }
0160 
0161 KBookmarkGroup KBookmarkGroup::createNewFolder(const QString &text)
0162 {
0163     if (isNull()) {
0164         return KBookmarkGroup();
0165     }
0166     QDomDocument doc = element.ownerDocument();
0167     QDomElement groupElem = doc.createElement(QStringLiteral("folder"));
0168     element.appendChild(groupElem);
0169     QDomElement textElem = doc.createElement(QStringLiteral("title"));
0170     groupElem.appendChild(textElem);
0171     textElem.appendChild(doc.createTextNode(text));
0172     return KBookmarkGroup(groupElem);
0173 }
0174 
0175 KBookmark KBookmarkGroup::createNewSeparator()
0176 {
0177     if (isNull()) {
0178         return KBookmark();
0179     }
0180     QDomDocument doc = element.ownerDocument();
0181     Q_ASSERT(!doc.isNull());
0182     QDomElement sepElem = doc.createElement(QStringLiteral("separator"));
0183     element.appendChild(sepElem);
0184     return KBookmark(sepElem);
0185 }
0186 
0187 bool KBookmarkGroup::moveBookmark(const KBookmark &item, const KBookmark &after)
0188 {
0189     QDomNode n;
0190     if (!after.isNull()) {
0191         n = element.insertAfter(item.element, after.element);
0192     } else { // first child
0193         if (element.firstChild().isNull()) { // Empty element -> set as real first child
0194             n = element.insertBefore(item.element, QDomElement());
0195         }
0196 
0197         // we have to skip everything up to the first valid child
0198         QDomElement firstChild = nextKnownTag(element.firstChild().toElement(), true);
0199         if (!firstChild.isNull()) {
0200             if (firstChild == item.element) { // item is already the first child, done
0201                 return true;
0202             }
0203             n = element.insertBefore(item.element, firstChild);
0204         } else {
0205             // No real first child -> append after the <title> etc.
0206             n = element.appendChild(item.element);
0207         }
0208     }
0209     return (!n.isNull());
0210 }
0211 
0212 KBookmark KBookmarkGroup::addBookmark(const KBookmark &bm)
0213 {
0214     element.appendChild(bm.internalElement());
0215     return bm;
0216 }
0217 
0218 KBookmark KBookmarkGroup::addBookmark(const QString &text, const QUrl &url, const QString &icon)
0219 {
0220     if (isNull()) {
0221         return KBookmark();
0222     }
0223     QDomDocument doc = element.ownerDocument();
0224     QDomElement elem = doc.createElement(QStringLiteral("bookmark"));
0225     elem.setAttribute(QStringLiteral("href"), url.toString(QUrl::FullyEncoded));
0226 
0227     QDomElement textElem = doc.createElement(QStringLiteral("title"));
0228     elem.appendChild(textElem);
0229     textElem.appendChild(doc.createTextNode(text));
0230 
0231     KBookmark newBookmark = addBookmark(KBookmark(elem));
0232 
0233     // as icons are moved to metadata, we have to use the KBookmark API for this
0234     newBookmark.setIcon(icon);
0235     return newBookmark;
0236 }
0237 
0238 void KBookmarkGroup::deleteBookmark(const KBookmark &bk)
0239 {
0240     element.removeChild(bk.element);
0241 }
0242 
0243 bool KBookmarkGroup::isToolbarGroup() const
0244 {
0245     return (element.attribute(QStringLiteral("toolbar")) == QLatin1String("yes"));
0246 }
0247 
0248 QDomElement KBookmarkGroup::findToolbar() const
0249 {
0250     if (element.attribute(QStringLiteral("toolbar")) == QLatin1String("yes")) {
0251         return element;
0252     }
0253     for (QDomElement e = element.firstChildElement(QStringLiteral("folder")); !e.isNull(); e = e.nextSiblingElement(QStringLiteral("folder"))) {
0254         QDomElement result = KBookmarkGroup(e).findToolbar();
0255         if (!result.isNull()) {
0256             return result;
0257         }
0258     }
0259     return QDomElement();
0260 }
0261 
0262 QList<QUrl> KBookmarkGroup::groupUrlList() const
0263 {
0264     QList<QUrl> urlList;
0265     for (KBookmark bm = first(); !bm.isNull(); bm = next(bm)) {
0266         if (bm.isSeparator() || bm.isGroup()) {
0267             continue;
0268         }
0269         urlList << bm.url();
0270     }
0271     return urlList;
0272 }
0273 
0274 //////
0275 
0276 KBookmark::KBookmark()
0277 {
0278 }
0279 
0280 KBookmark::KBookmark(const QDomElement &elem)
0281     : element(elem)
0282 {
0283 }
0284 
0285 bool KBookmark::isGroup() const
0286 {
0287     QString tag = element.tagName();
0288     return tag == QLatin1String("folder") //
0289         || tag == QLatin1String("xbel"); // don't forget the toplevel group
0290 }
0291 
0292 bool KBookmark::isSeparator() const
0293 {
0294     return (element.tagName() == QLatin1String("separator"));
0295 }
0296 
0297 bool KBookmark::isNull() const
0298 {
0299     return element.isNull();
0300 }
0301 
0302 bool KBookmark::hasParent() const
0303 {
0304     QDomElement parent = element.parentNode().toElement();
0305     return !parent.isNull();
0306 }
0307 
0308 QString KBookmark::text() const
0309 {
0310     return KStringHandler::csqueeze(fullText());
0311 }
0312 
0313 QString KBookmark::fullText() const
0314 {
0315     if (isSeparator()) {
0316         return QCoreApplication::translate("KBookmark", "--- separator ---", "Bookmark separator");
0317     }
0318 
0319     QString text = element.namedItem(QStringLiteral("title")).toElement().text();
0320     text.replace(QLatin1Char('\n'), QLatin1Char(' ')); // #140673
0321     return text;
0322 }
0323 
0324 void KBookmark::setFullText(const QString &fullText)
0325 {
0326     QDomNode titleNode = element.namedItem(QStringLiteral("title"));
0327     if (titleNode.isNull()) {
0328         titleNode = element.ownerDocument().createElement(QStringLiteral("title"));
0329         element.appendChild(titleNode);
0330     }
0331 
0332     if (titleNode.firstChild().isNull()) {
0333         QDomText domtext = titleNode.ownerDocument().createTextNode(QLatin1String(""));
0334         titleNode.appendChild(domtext);
0335     }
0336 
0337     QDomText domtext = titleNode.firstChild().toText();
0338     domtext.setData(fullText);
0339 }
0340 
0341 QUrl KBookmark::url() const
0342 {
0343     return QUrl(element.attribute(QStringLiteral("href")));
0344 }
0345 
0346 void KBookmark::setUrl(const QUrl &url)
0347 {
0348     element.setAttribute(QStringLiteral("href"), url.toString());
0349 }
0350 
0351 QString KBookmark::icon() const
0352 {
0353     QDomNode metaDataNode = metaData(Strings::metaDataFreedesktopOwner(), false);
0354     QDomElement iconElement = cd(metaDataNode, QStringLiteral("bookmark:icon"), false).toElement();
0355 
0356     QString icon = iconElement.attribute(QStringLiteral("name"));
0357 
0358     // migration code
0359     if (icon.isEmpty()) {
0360         icon = element.attribute(QStringLiteral("icon"));
0361     }
0362     if (icon == QLatin1String("www")) { // common icon for kde3 bookmarks
0363         return QStringLiteral("internet-web-browser");
0364     }
0365     // end migration code
0366 
0367     if (icon == QLatin1String("bookmark_folder")) {
0368         return QStringLiteral("folder-bookmarks");
0369     }
0370     if (icon.isEmpty()) {
0371         // Default icon depends on URL for bookmarks, and is default directory
0372         // icon for groups.
0373         if (isGroup()) {
0374             icon = QStringLiteral("folder-bookmarks");
0375         } else {
0376             if (isSeparator()) {
0377                 icon = QStringLiteral("edit-clear"); // whatever
0378             } else {
0379                 // get icon from mimeType
0380                 QMimeDatabase db;
0381                 QMimeType mime;
0382                 QString _mimeType = mimeType();
0383                 if (!_mimeType.isEmpty()) {
0384                     mime = db.mimeTypeForName(_mimeType);
0385                 } else {
0386                     mime = db.mimeTypeForUrl(url());
0387                 }
0388                 if (mime.isValid()) {
0389                     icon = mime.iconName();
0390                 }
0391             }
0392         }
0393     }
0394     return icon;
0395 }
0396 
0397 void KBookmark::setIcon(const QString &icon)
0398 {
0399     QDomNode metaDataNode = metaData(Strings::metaDataFreedesktopOwner(), true);
0400     QDomElement iconElement = cd_or_create(metaDataNode, QStringLiteral("bookmark:icon")).toElement();
0401     iconElement.setAttribute(QStringLiteral("name"), icon);
0402 
0403     // migration code
0404     if (!element.attribute(QStringLiteral("icon")).isEmpty()) {
0405         element.removeAttribute(QStringLiteral("icon"));
0406     }
0407 }
0408 
0409 QString KBookmark::description() const
0410 {
0411     if (isSeparator()) {
0412         return QString();
0413     }
0414 
0415     QString description = element.namedItem(QStringLiteral("desc")).toElement().text();
0416     description.replace(QLatin1Char('\n'), QLatin1Char(' ')); // #140673
0417     return description;
0418 }
0419 
0420 void KBookmark::setDescription(const QString &description)
0421 {
0422     QDomNode descNode = element.namedItem(QStringLiteral("desc"));
0423     if (descNode.isNull()) {
0424         descNode = element.ownerDocument().createElement(QStringLiteral("desc"));
0425         element.appendChild(descNode);
0426     }
0427 
0428     if (descNode.firstChild().isNull()) {
0429         QDomText domtext = descNode.ownerDocument().createTextNode(QString());
0430         descNode.appendChild(domtext);
0431     }
0432 
0433     QDomText domtext = descNode.firstChild().toText();
0434     domtext.setData(description);
0435 }
0436 
0437 QString KBookmark::mimeType() const
0438 {
0439     QDomNode metaDataNode = metaData(Strings::metaDataMimeOwner(), false);
0440     QDomElement mimeTypeElement = cd(metaDataNode, QStringLiteral("mime:mime-type"), false).toElement();
0441     return mimeTypeElement.attribute(QStringLiteral("type"));
0442 }
0443 
0444 void KBookmark::setMimeType(const QString &mimeType)
0445 {
0446     QDomNode metaDataNode = metaData(Strings::metaDataMimeOwner(), true);
0447     QDomElement iconElement = cd_or_create(metaDataNode, QStringLiteral("mime:mime-type")).toElement();
0448     iconElement.setAttribute(QStringLiteral("type"), mimeType);
0449 }
0450 
0451 bool KBookmark::showInToolbar() const
0452 {
0453     if (element.hasAttribute(QStringLiteral("showintoolbar"))) {
0454         bool show = element.attribute(QStringLiteral("showintoolbar")) == QLatin1String("yes");
0455         const_cast<QDomElement *>(&element)->removeAttribute(QStringLiteral("showintoolbar"));
0456         const_cast<KBookmark *>(this)->setShowInToolbar(show);
0457     }
0458     return metaDataItem(QStringLiteral("showintoolbar")) == QLatin1String("yes");
0459 }
0460 
0461 void KBookmark::setShowInToolbar(bool show)
0462 {
0463     setMetaDataItem(QStringLiteral("showintoolbar"), show ? QStringLiteral("yes") : QStringLiteral("no"));
0464 }
0465 
0466 KBookmarkGroup KBookmark::parentGroup() const
0467 {
0468     return KBookmarkGroup(element.parentNode().toElement());
0469 }
0470 
0471 KBookmarkGroup KBookmark::toGroup() const
0472 {
0473     Q_ASSERT(isGroup());
0474     return KBookmarkGroup(element);
0475 }
0476 
0477 QString KBookmark::address() const
0478 {
0479     if (element.tagName() == QLatin1String("xbel")) {
0480         return QLatin1String(""); // not QString() !
0481     } else {
0482         // Use keditbookmarks's DEBUG_ADDRESSES flag to debug this code :)
0483         if (element.parentNode().isNull()) {
0484             Q_ASSERT(false);
0485             return QStringLiteral("ERROR"); // Avoid an infinite loop
0486         }
0487         KBookmarkGroup group = parentGroup();
0488         QString parentAddress = group.address();
0489         int pos = group.indexOf(*this);
0490         Q_ASSERT(pos != -1);
0491         return parentAddress + QLatin1Char('/') + QString::number(pos);
0492     }
0493 }
0494 
0495 int KBookmark::positionInParent() const
0496 {
0497     return parentGroup().indexOf(*this);
0498 }
0499 
0500 QDomElement KBookmark::internalElement() const
0501 {
0502     return element;
0503 }
0504 
0505 KBookmark KBookmark::standaloneBookmark(const QString &text, const QUrl &url, const QString &icon)
0506 {
0507     QDomDocument doc(QStringLiteral("xbel"));
0508     QDomElement elem = doc.createElement(QStringLiteral("xbel"));
0509     doc.appendChild(elem);
0510     KBookmarkGroup grp(elem);
0511     grp.addBookmark(text, url, icon);
0512     return grp.first();
0513 }
0514 
0515 QString KBookmark::commonParent(const QString &first, const QString &second)
0516 {
0517     QString A = first;
0518     QString B = second;
0519     QString error(QStringLiteral("ERROR"));
0520     if (A == error || B == error) {
0521         return error;
0522     }
0523 
0524     A += QLatin1Char('/');
0525     B += QLatin1Char('/');
0526 
0527     int lastCommonSlash = 0;
0528     int lastPos = A.length() < B.length() ? A.length() : B.length();
0529     for (int i = 0; i < lastPos; ++i) {
0530         if (A[i] != B[i]) {
0531             return A.left(lastCommonSlash);
0532         }
0533         if (A[i] == QLatin1Char('/')) {
0534             lastCommonSlash = i;
0535         }
0536     }
0537     return A.left(lastCommonSlash);
0538 }
0539 
0540 void KBookmark::updateAccessMetadata()
0541 {
0542     // qCDebug(KBOOKMARKS_LOG) << "KBookmark::updateAccessMetadata " << address() << " " << url();
0543 
0544     const uint timet = QDateTime::currentDateTimeUtc().toSecsSinceEpoch();
0545     setMetaDataItem(QStringLiteral("time_added"), QString::number(timet), DontOverwriteMetaData);
0546     setMetaDataItem(QStringLiteral("time_visited"), QString::number(timet));
0547 
0548     QString countStr = metaDataItem(QStringLiteral("visit_count")); // TODO use spec'ed name
0549     bool ok;
0550     int currentCount = countStr.toInt(&ok);
0551     if (!ok) {
0552         currentCount = 0;
0553     }
0554     currentCount++;
0555     setMetaDataItem(QStringLiteral("visit_count"), QString::number(currentCount));
0556 
0557     // TODO - time_modified
0558 }
0559 
0560 QString KBookmark::parentAddress(const QString &address)
0561 {
0562     return address.left(address.lastIndexOf(QLatin1Char('/')));
0563 }
0564 
0565 uint KBookmark::positionInParent(const QString &address)
0566 {
0567     return QStringView(address).mid(address.lastIndexOf(QLatin1Char('/')) + 1).toInt();
0568 }
0569 
0570 QString KBookmark::previousAddress(const QString &address)
0571 {
0572     uint pp = positionInParent(address);
0573     return pp > 0 ? parentAddress(address) + QLatin1Char('/') + QString::number(pp - 1) : QString();
0574 }
0575 
0576 QString KBookmark::nextAddress(const QString &address)
0577 {
0578     return parentAddress(address) + QLatin1Char('/') + QString::number(positionInParent(address) + 1);
0579 }
0580 
0581 QDomNode KBookmark::metaData(const QString &owner, bool create) const
0582 {
0583     QDomNode infoNode = cd(internalElement(), QStringLiteral("info"), create);
0584     if (infoNode.isNull()) {
0585         return QDomNode();
0586     }
0587     return findMetadata(owner, infoNode, create);
0588 }
0589 
0590 QString KBookmark::metaDataItem(const QString &key) const
0591 {
0592     QDomNode metaDataNode = metaData(Strings::metaDataKDEOwner(), false);
0593     for (QDomElement e = metaDataNode.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) {
0594         if (e.tagName() == key) {
0595             return e.text();
0596         }
0597     }
0598     return QString();
0599 }
0600 
0601 void KBookmark::setMetaDataItem(const QString &key, const QString &value, MetaDataOverwriteMode mode)
0602 {
0603     QDomNode metaDataNode = metaData(Strings::metaDataKDEOwner(), true);
0604     QDomNode item = cd_or_create(metaDataNode, key);
0605     QDomText text = get_or_create_text(item);
0606     if (mode == DontOverwriteMetaData && !text.data().isEmpty()) {
0607         return;
0608     }
0609 
0610     text.setData(value);
0611 }
0612 
0613 bool KBookmark::operator==(const KBookmark &rhs) const
0614 {
0615     return element == rhs.element;
0616 }
0617 
0618 ////
0619 
0620 KBookmarkGroupTraverser::~KBookmarkGroupTraverser()
0621 {
0622 }
0623 
0624 void KBookmarkGroupTraverser::traverse(const KBookmarkGroup &root)
0625 {
0626     QStack<KBookmarkGroup> stack;
0627     stack.push(root);
0628     KBookmark bk = root.first();
0629     for (;;) {
0630         if (bk.isNull()) {
0631             if (stack.count() == 1) { // only root is on the stack
0632                 return;
0633             }
0634             if (!stack.isEmpty()) {
0635                 visitLeave(stack.top());
0636                 bk = stack.pop();
0637             }
0638             bk = stack.top().next(bk);
0639         } else if (bk.isGroup()) {
0640             KBookmarkGroup gp = bk.toGroup();
0641             visitEnter(gp);
0642             bk = gp.first();
0643             stack.push(gp);
0644         } else {
0645             visit(bk);
0646             bk = stack.top().next(bk);
0647         }
0648     }
0649 }
0650 
0651 void KBookmarkGroupTraverser::visit(const KBookmark &)
0652 {
0653 }
0654 
0655 void KBookmarkGroupTraverser::visitEnter(const KBookmarkGroup &)
0656 {
0657 }
0658 
0659 void KBookmarkGroupTraverser::visitLeave(const KBookmarkGroup &)
0660 {
0661 }
0662 
0663 void KBookmark::populateMimeData(QMimeData *mimeData) const
0664 {
0665     KBookmark::List bookmarkList;
0666     bookmarkList.append(*this);
0667     bookmarkList.populateMimeData(mimeData);
0668 }
0669 
0670 KBookmark::List::List()
0671     : QList<KBookmark>()
0672 {
0673 }
0674 
0675 void KBookmark::List::populateMimeData(QMimeData *mimeData) const
0676 {
0677     QList<QUrl> urls;
0678 
0679     QDomDocument doc(QStringLiteral("xbel"));
0680     QDomElement elem = doc.createElement(QStringLiteral("xbel"));
0681     doc.appendChild(elem);
0682 
0683     for (const_iterator it = begin(), end = this->end(); it != end; ++it) {
0684         urls.append((*it).url());
0685         elem.appendChild((*it).internalElement().cloneNode(true /* deep */));
0686     }
0687 
0688     // This sets text/uri-list and text/plain into the mimedata
0689     mimeData->setUrls(urls);
0690 
0691     mimeData->setData(Strings::xbelMimeType(), doc.toByteArray());
0692 }
0693 
0694 bool KBookmark::List::canDecode(const QMimeData *mimeData)
0695 {
0696     return mimeData->hasFormat(Strings::xbelMimeType()) || mimeData->hasUrls();
0697 }
0698 
0699 QStringList KBookmark::List::mimeDataTypes()
0700 {
0701     return QStringList() << Strings::xbelMimeType() << KUrlMimeData::mimeDataTypes();
0702 }
0703 
0704 KBookmark::List KBookmark::List::fromMimeData(const QMimeData *mimeData, QDomDocument &doc)
0705 {
0706     KBookmark::List bookmarks;
0707     const QByteArray payload = mimeData->data(Strings::xbelMimeType());
0708     if (!payload.isEmpty()) {
0709         doc.setContent(payload);
0710         QDomElement elem = doc.documentElement();
0711         const QDomNodeList children = elem.childNodes();
0712         bookmarks.reserve(children.count());
0713         for (int childno = 0; childno < children.count(); childno++) {
0714             bookmarks.append(KBookmark(children.item(childno).toElement()));
0715         }
0716         return bookmarks;
0717     }
0718     const QList<QUrl> urls = KUrlMimeData::urlsFromMimeData(mimeData);
0719     bookmarks.reserve(urls.size());
0720     for (int i = 0; i < urls.size(); ++i) {
0721         const QUrl url = urls.at(i);
0722         bookmarks.append(KBookmark::standaloneBookmark(url.toDisplayString(), url, QString() /*TODO icon*/));
0723     }
0724     return bookmarks;
0725 }