File indexing completed on 2025-01-19 03:58:03
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2017-05-15 0007 * Description : low level manager for bookmarks 0008 * 0009 * SPDX-FileCopyrightText: 2017-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * 0011 * SPDX-License-Identifier: GPL-2.0-or-later 0012 * 0013 * ============================================================ */ 0014 0015 #include "bookmarksmngr.h" 0016 0017 // Qt includes 0018 0019 #include <QBuffer> 0020 #include <QFile> 0021 #include <QMimeData> 0022 #include <QDragEnterEvent> 0023 #include <QIcon> 0024 #include <QHeaderView> 0025 #include <QMessageBox> 0026 #include <QToolButton> 0027 #include <QDebug> 0028 #include <QApplication> 0029 0030 // KDE includes 0031 0032 #include <klocalizedstring.h> 0033 0034 // Local includes 0035 0036 #include "dfiledialog.h" 0037 #include "bookmarknode.h" 0038 #include "digikam_debug.h" 0039 0040 namespace Digikam 0041 { 0042 0043 RemoveBookmarksCommand::RemoveBookmarksCommand(BookmarksManager* const mngr, 0044 BookmarkNode* const parent, 0045 int row) 0046 : QUndoCommand(i18n("Remove Bookmark")), 0047 m_row (row), 0048 m_bookmarkManager(mngr), 0049 m_node (parent->children().value(row)), 0050 m_parent (parent), 0051 m_done (false) 0052 { 0053 } 0054 0055 RemoveBookmarksCommand::~RemoveBookmarksCommand() 0056 { 0057 if (m_done && !m_node->parent()) 0058 { 0059 delete m_node; 0060 } 0061 } 0062 0063 void RemoveBookmarksCommand::undo() 0064 { 0065 m_parent->add(m_node, m_row); 0066 Q_EMIT m_bookmarkManager->entryAdded(m_node); 0067 m_done = false; 0068 } 0069 0070 void RemoveBookmarksCommand::redo() 0071 { 0072 m_parent->remove(m_node); 0073 Q_EMIT m_bookmarkManager->entryRemoved(m_parent, m_row, m_node); 0074 m_done = true; 0075 } 0076 0077 // -------------------------------------------------------------- 0078 0079 InsertBookmarksCommand::InsertBookmarksCommand(BookmarksManager* const mngr, 0080 BookmarkNode* const parent, 0081 BookmarkNode* const node, 0082 int row) 0083 : RemoveBookmarksCommand(mngr, parent, row) 0084 { 0085 setText(i18n("Insert Bookmark")); 0086 m_node = node; 0087 } 0088 0089 void InsertBookmarksCommand::undo() 0090 { 0091 RemoveBookmarksCommand::redo(); 0092 } 0093 0094 void InsertBookmarksCommand::redo() 0095 { 0096 RemoveBookmarksCommand::undo(); 0097 } 0098 0099 // -------------------------------------------------------------- 0100 0101 class Q_DECL_HIDDEN ChangeBookmarkCommand::Private 0102 { 0103 public: 0104 0105 explicit Private() 0106 : manager (nullptr), 0107 type (Url), 0108 node (nullptr) 0109 { 0110 } 0111 0112 BookmarksManager* manager; 0113 BookmarkData type; 0114 QString oldValue; 0115 QString newValue; 0116 BookmarkNode* node; 0117 }; 0118 0119 ChangeBookmarkCommand::ChangeBookmarkCommand(BookmarksManager* const mngr, 0120 BookmarkNode* const node, 0121 const QString& newValue, 0122 BookmarkData type) 0123 : QUndoCommand(), 0124 d (new Private) 0125 { 0126 d->manager = mngr; 0127 d->type = type; 0128 d->newValue = newValue; 0129 d->node = node; 0130 0131 switch (d->type) 0132 { 0133 case Title: 0134 { 0135 d->oldValue = d->node->title; 0136 setText(i18n("Title Change")); 0137 break; 0138 } 0139 0140 case Desc: 0141 { 0142 d->oldValue = d->node->desc; 0143 setText(i18n("Comment Change")); 0144 break; 0145 } 0146 0147 default: // Url 0148 { 0149 d->oldValue = d->node->url; 0150 setText(i18n("Address Change")); 0151 break; 0152 } 0153 } 0154 } 0155 0156 ChangeBookmarkCommand::~ChangeBookmarkCommand() 0157 { 0158 delete d; 0159 } 0160 0161 void ChangeBookmarkCommand::undo() 0162 { 0163 switch (d->type) 0164 { 0165 case Title: 0166 { 0167 d->node->title = d->oldValue; 0168 break; 0169 } 0170 0171 case Desc: 0172 { 0173 d->node->desc = d->oldValue; 0174 break; 0175 } 0176 0177 default: // Url 0178 { 0179 d->node->url = d->oldValue; 0180 break; 0181 } 0182 } 0183 0184 Q_EMIT d->manager->entryChanged(d->node); 0185 } 0186 0187 void ChangeBookmarkCommand::redo() 0188 { 0189 switch (d->type) 0190 { 0191 case Title: 0192 { 0193 d->node->title = d->newValue; 0194 break; 0195 } 0196 0197 case Desc: 0198 { 0199 d->node->desc = d->newValue; 0200 break; 0201 } 0202 0203 default: // Url 0204 { 0205 d->node->url = d->newValue; 0206 break; 0207 } 0208 } 0209 0210 Q_EMIT d->manager->entryChanged(d->node); 0211 } 0212 0213 // -------------------------------------------------------------- 0214 0215 class Q_DECL_HIDDEN BookmarksModel::Private 0216 { 0217 public: 0218 0219 explicit Private() 0220 : manager (nullptr), 0221 endMacro(false) 0222 { 0223 } 0224 0225 BookmarksManager* manager; 0226 bool endMacro; 0227 }; 0228 0229 BookmarksModel::BookmarksModel(BookmarksManager* const mngr, QObject* const parent) 0230 : QAbstractItemModel(parent), 0231 d (new Private) 0232 { 0233 d->manager = mngr; 0234 0235 connect(d->manager, SIGNAL(entryAdded(BookmarkNode*)), 0236 this, SLOT(entryAdded(BookmarkNode*))); 0237 0238 connect(d->manager, SIGNAL(entryRemoved(BookmarkNode*,int,BookmarkNode*)), 0239 this, SLOT(entryRemoved(BookmarkNode*,int,BookmarkNode*))); 0240 0241 connect(d->manager, SIGNAL(entryChanged(BookmarkNode*)), 0242 this, SLOT(entryChanged(BookmarkNode*))); 0243 } 0244 0245 BookmarksModel::~BookmarksModel() 0246 { 0247 delete d; 0248 } 0249 0250 BookmarksManager* BookmarksModel::bookmarksManager() const 0251 { 0252 return d->manager; 0253 } 0254 0255 QModelIndex BookmarksModel::index(BookmarkNode* node) const 0256 { 0257 BookmarkNode* const parent = node->parent(); 0258 0259 if (!parent) 0260 { 0261 return QModelIndex(); 0262 } 0263 0264 return createIndex(parent->children().indexOf(node), 0, node); 0265 } 0266 0267 void BookmarksModel::entryAdded(BookmarkNode* item) 0268 { 0269 Q_ASSERT(item && item->parent()); 0270 0271 int row = item->parent()->children().indexOf(item); 0272 BookmarkNode* const parent = item->parent(); 0273 0274 // item was already added so remove before beginInsertRows is called 0275 0276 parent->remove(item); 0277 beginInsertRows(index(parent), row, row); 0278 parent->add(item, row); 0279 endInsertRows(); 0280 } 0281 0282 void BookmarksModel::entryRemoved(BookmarkNode* parent, int row, BookmarkNode* item) 0283 { 0284 // item was already removed, re-add so beginRemoveRows works 0285 0286 parent->add(item, row); 0287 beginRemoveRows(index(parent), row, row); 0288 parent->remove(item); 0289 endRemoveRows(); 0290 } 0291 0292 void BookmarksModel::entryChanged(BookmarkNode* item) 0293 { 0294 QModelIndex idx = index(item); 0295 Q_EMIT dataChanged(idx, idx); 0296 } 0297 0298 bool BookmarksModel::removeRows(int row, int count, const QModelIndex& parent) 0299 { 0300 if ((row < 0) || (count <= 0) || ((row + count) > rowCount(parent))) 0301 { 0302 return false; 0303 } 0304 0305 BookmarkNode* const bookmarkNode = node(parent); 0306 0307 for (int i = (row + count - 1) ; i >= row ; --i) 0308 { 0309 BookmarkNode* const node = bookmarkNode->children().at(i); 0310 d->manager->removeBookmark(node); 0311 } 0312 0313 if (d->endMacro) 0314 { 0315 d->manager->undoRedoStack()->endMacro(); 0316 d->endMacro = false; 0317 } 0318 0319 return true; 0320 } 0321 0322 QVariant BookmarksModel::headerData(int section, Qt::Orientation orientation, int role) const 0323 { 0324 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) 0325 { 0326 switch (section) 0327 { 0328 case 0: 0329 { 0330 return i18nc("@title: bookmark header", "Title"); 0331 } 0332 0333 case 1: 0334 { 0335 return i18nc("@title: bookmark header", "Comment"); 0336 } 0337 } 0338 } 0339 0340 return QAbstractItemModel::headerData(section, orientation, role); 0341 } 0342 0343 QVariant BookmarksModel::data(const QModelIndex& index, int role) const 0344 { 0345 if (!index.isValid() || (index.model() != this)) 0346 { 0347 return QVariant(); 0348 } 0349 0350 const BookmarkNode* const bookmarkNode = node(index); 0351 0352 switch (role) 0353 { 0354 case Qt::EditRole: 0355 case Qt::DisplayRole: 0356 { 0357 if (bookmarkNode->type() == BookmarkNode::Separator) 0358 { 0359 switch (index.column()) 0360 { 0361 case 0: 0362 { 0363 return QString(50, QChar(0xB7)); 0364 } 0365 0366 case 1: 0367 { 0368 return QString(); 0369 } 0370 } 0371 } 0372 0373 switch (index.column()) 0374 { 0375 case 0: 0376 { 0377 return bookmarkNode->title; 0378 } 0379 0380 case 1: 0381 { 0382 return bookmarkNode->desc; 0383 } 0384 } 0385 0386 break; 0387 } 0388 0389 case BookmarksModel::UrlRole: 0390 { 0391 return QUrl(bookmarkNode->url); 0392 } 0393 0394 case BookmarksModel::UrlStringRole: 0395 { 0396 return bookmarkNode->url; 0397 } 0398 0399 case BookmarksModel::DateAddedRole: 0400 { 0401 return bookmarkNode->dateAdded; 0402 } 0403 0404 case BookmarksModel::TypeRole: 0405 { 0406 return bookmarkNode->type(); 0407 } 0408 0409 case BookmarksModel::SeparatorRole: 0410 { 0411 return (bookmarkNode->type() == BookmarkNode::Separator); 0412 } 0413 0414 case Qt::DecorationRole: 0415 { 0416 if (index.column() == 0) 0417 { 0418 if (bookmarkNode->type() == BookmarkNode::Bookmark) 0419 { 0420 return QIcon::fromTheme(QLatin1String("globe")); 0421 } 0422 else 0423 { 0424 return QIcon::fromTheme(QLatin1String("folder")); 0425 } 0426 } 0427 } 0428 } 0429 0430 return QVariant(); 0431 } 0432 0433 int BookmarksModel::columnCount(const QModelIndex& parent) const 0434 { 0435 return ((parent.column() > 0) ? 0 : 2); 0436 } 0437 0438 int BookmarksModel::rowCount(const QModelIndex& parent) const 0439 { 0440 if (parent.column() > 0) 0441 { 0442 return 0; 0443 } 0444 0445 if (!parent.isValid()) 0446 { 0447 return d->manager->bookmarks()->children().count(); 0448 } 0449 0450 const BookmarkNode* const item = static_cast<BookmarkNode*>(parent.internalPointer()); 0451 0452 return item->children().count(); 0453 } 0454 0455 QModelIndex BookmarksModel::index(int row, int column, const QModelIndex& parent) const 0456 { 0457 if ((row < 0) || (column < 0) || (row >= rowCount(parent)) || (column >= columnCount(parent))) 0458 { 0459 return QModelIndex(); 0460 } 0461 0462 // get the parent node 0463 0464 BookmarkNode* const parentNode = node(parent); 0465 0466 return createIndex(row, column, parentNode->children().at(row)); 0467 } 0468 0469 QModelIndex BookmarksModel::parent(const QModelIndex& index) const 0470 { 0471 if (!index.isValid()) 0472 { 0473 return QModelIndex(); 0474 } 0475 0476 BookmarkNode* const itemNode = node(index); 0477 BookmarkNode* const parentNode = (itemNode ? itemNode->parent() : nullptr); 0478 0479 if (!parentNode || (parentNode == d->manager->bookmarks())) 0480 { 0481 return QModelIndex(); 0482 } 0483 0484 // get the parent's row 0485 0486 BookmarkNode* const grandParentNode = parentNode->parent(); 0487 int parentRow = grandParentNode->children().indexOf(parentNode); 0488 0489 Q_ASSERT(parentRow >= 0); 0490 0491 return createIndex(parentRow, 0, parentNode); 0492 } 0493 0494 bool BookmarksModel::hasChildren(const QModelIndex& parent) const 0495 { 0496 if (!parent.isValid()) 0497 { 0498 return true; 0499 } 0500 0501 const BookmarkNode* const parentNode = node(parent); 0502 0503 return ((parentNode->type() == BookmarkNode::Folder) || 0504 (parentNode->type() == BookmarkNode::RootFolder)); 0505 } 0506 0507 Qt::ItemFlags BookmarksModel::flags(const QModelIndex& index) const 0508 { 0509 if (!index.isValid()) 0510 { 0511 return Qt::NoItemFlags; 0512 } 0513 0514 Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; 0515 BookmarkNode* const bookmarkNode = node(index); 0516 0517 if (bookmarkNode->type() != BookmarkNode::RootFolder) 0518 { 0519 flags |= Qt::ItemIsDragEnabled; 0520 } 0521 0522 if ((bookmarkNode->type() != BookmarkNode::Separator) && 0523 (bookmarkNode->type() != BookmarkNode::RootFolder)) 0524 { 0525 flags |= Qt::ItemIsEditable; 0526 } 0527 0528 if (hasChildren(index)) 0529 { 0530 flags |= Qt::ItemIsDropEnabled; 0531 } 0532 0533 return flags; 0534 } 0535 0536 Qt::DropActions BookmarksModel::supportedDropActions() const 0537 { 0538 return (Qt::CopyAction | Qt::MoveAction); 0539 } 0540 0541 QStringList BookmarksModel::mimeTypes() const 0542 { 0543 QStringList types; 0544 types << QLatin1String("application/bookmarks.xbel"); 0545 0546 return types; 0547 } 0548 0549 QMimeData* BookmarksModel::mimeData(const QModelIndexList& indexes) const 0550 { 0551 QMimeData* const mimeData = new QMimeData(); 0552 QByteArray data; 0553 QDataStream stream(&data, QIODevice::WriteOnly); 0554 0555 Q_FOREACH (QModelIndex index, indexes) 0556 { 0557 if ((index.column() != 0) || !index.isValid()) 0558 { 0559 continue; 0560 } 0561 0562 QByteArray encodedData; 0563 QBuffer buffer(&encodedData); 0564 buffer.open(QBuffer::ReadWrite); 0565 XbelWriter writer; 0566 const BookmarkNode* const parentNode = node(index); 0567 writer.write(&buffer, parentNode); 0568 stream << encodedData; 0569 } 0570 0571 mimeData->setData(QLatin1String("application/bookmarks.xbel"), data); 0572 0573 return mimeData; 0574 } 0575 0576 bool BookmarksModel::dropMimeData(const QMimeData* data, 0577 Qt::DropAction action, 0578 int row, int column, 0579 const QModelIndex& parent) 0580 { 0581 if (action == Qt::IgnoreAction) 0582 { 0583 return true; 0584 } 0585 0586 if (!data->hasFormat(QLatin1String("application/bookmarks.xbel")) || column > 0) 0587 { 0588 return false; 0589 } 0590 0591 QByteArray ba = data->data(QLatin1String("application/bookmarks.xbel")); 0592 QDataStream stream(&ba, QIODevice::ReadOnly); 0593 0594 if (stream.atEnd()) 0595 { 0596 return false; 0597 } 0598 0599 QUndoStack* const undoStack = d->manager->undoRedoStack(); 0600 undoStack->beginMacro(QLatin1String("Move Bookmarks")); 0601 0602 while (!stream.atEnd()) 0603 { 0604 QByteArray encodedData; 0605 stream >> encodedData; 0606 QBuffer buffer(&encodedData); 0607 buffer.open(QBuffer::ReadOnly); 0608 0609 XbelReader reader; 0610 BookmarkNode* const rootNode = reader.read(&buffer); 0611 QList<BookmarkNode*> children = rootNode->children(); 0612 0613 for (int i = 0 ; i < children.count() ; ++i) 0614 { 0615 BookmarkNode* const bookmarkNode = children.at(i); 0616 rootNode->remove(bookmarkNode); 0617 row = qMax(0, row); 0618 BookmarkNode* const parentNode = node(parent); 0619 d->manager->addBookmark(parentNode, bookmarkNode, row); 0620 d->endMacro = true; 0621 } 0622 0623 delete rootNode; 0624 } 0625 0626 return true; 0627 } 0628 0629 bool BookmarksModel::setData(const QModelIndex& index, const QVariant& value, int role) 0630 { 0631 if (!index.isValid() || (flags(index) & Qt::ItemIsEditable) == 0) 0632 { 0633 return false; 0634 } 0635 0636 BookmarkNode* const item = node(index); 0637 0638 switch (role) 0639 { 0640 case Qt::EditRole: 0641 case Qt::DisplayRole: 0642 { 0643 if (index.column() == 0) 0644 { 0645 d->manager->setTitle(item, value.toString()); 0646 break; 0647 } 0648 0649 if (index.column() == 1) 0650 { 0651 d->manager->setComment(item, value.toString()); 0652 break; 0653 } 0654 0655 return false; 0656 } 0657 0658 case BookmarksModel::UrlRole: 0659 { 0660 d->manager->setUrl(item, value.toUrl().toString()); 0661 break; 0662 } 0663 0664 case BookmarksModel::UrlStringRole: 0665 { 0666 d->manager->setUrl(item, value.toString()); 0667 break; 0668 } 0669 0670 default: 0671 { 0672 return false; 0673 } 0674 } 0675 0676 return true; 0677 } 0678 0679 BookmarkNode* BookmarksModel::node(const QModelIndex& index) const 0680 { 0681 BookmarkNode* const itemNode = static_cast<BookmarkNode*>(index.internalPointer()); 0682 0683 if (!itemNode) 0684 { 0685 return d->manager->bookmarks(); 0686 } 0687 0688 return itemNode; 0689 } 0690 0691 // -------------------------------------------------------------- 0692 0693 AddBookmarkProxyModel::AddBookmarkProxyModel(QObject* const parent) 0694 : QSortFilterProxyModel(parent) 0695 { 0696 } 0697 0698 int AddBookmarkProxyModel::columnCount(const QModelIndex& parent) const 0699 { 0700 return qMin(1, QSortFilterProxyModel::columnCount(parent)); 0701 } 0702 0703 bool AddBookmarkProxyModel::filterAcceptsRow(int srow, const QModelIndex& sparent) const 0704 { 0705 QModelIndex idx = sourceModel()->index(srow, 0, sparent); 0706 0707 return sourceModel()->hasChildren(idx); 0708 } 0709 0710 // -------------------------------------------------------------- 0711 0712 TreeProxyModel::TreeProxyModel(QObject* const parent) 0713 : QSortFilterProxyModel(parent) 0714 { 0715 setFilterCaseSensitivity(Qt::CaseInsensitive); 0716 } 0717 0718 int TreeProxyModel::columnCount(const QModelIndex&) const 0719 { 0720 // 1th column : Title 0721 // 2th column : Comment 0722 0723 return 2; 0724 } 0725 0726 bool TreeProxyModel::filterAcceptsRow(int srow, const QModelIndex& sparent) const 0727 { 0728 QModelIndex index = sourceModel()->index(srow, 0, sparent); 0729 0730 if (!index.isValid()) 0731 { 0732 return false; 0733 } 0734 0735 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0736 0737 if (index.data().toString().contains(filterRegularExpression())) 0738 0739 #else 0740 0741 if (index.data().toString().contains(filterRegExp())) 0742 0743 #endif 0744 0745 { 0746 return true; 0747 } 0748 0749 for (int i = 0 ; i < sourceModel()->rowCount(index) ; ++i) 0750 { 0751 if (filterAcceptsRow(i, index)) 0752 { 0753 return true; 0754 } 0755 } 0756 0757 return false; 0758 } 0759 0760 void TreeProxyModel::emitResult(bool v) 0761 { 0762 Q_EMIT signalFilterAccepts(v); 0763 } 0764 0765 // -------------------------------------------------------------- 0766 0767 class Q_DECL_HIDDEN BookmarksManager::Private 0768 { 0769 public: 0770 0771 explicit Private() 0772 : loaded (false), 0773 bookmarkRootNode(nullptr), 0774 bookmarkModel (nullptr) 0775 { 0776 } 0777 0778 bool loaded; 0779 BookmarkNode* bookmarkRootNode; 0780 BookmarksModel* bookmarkModel; 0781 QUndoStack commands; 0782 QString bookmarksFile; 0783 }; 0784 0785 BookmarksManager::BookmarksManager(const QString& bookmarksFile, QObject* const parent) 0786 : QObject(parent), 0787 d (new Private) 0788 { 0789 d->bookmarksFile = bookmarksFile; 0790 load(); 0791 } 0792 0793 BookmarksManager::~BookmarksManager() 0794 { 0795 delete d->bookmarkRootNode; 0796 delete d; 0797 } 0798 0799 void BookmarksManager::changeExpanded() 0800 { 0801 } 0802 0803 void BookmarksManager::load() 0804 { 0805 if (d->loaded) 0806 { 0807 return; 0808 } 0809 0810 qCDebug(DIGIKAM_GEOIFACE_LOG) << "Loading GPS bookmarks from" << d->bookmarksFile; 0811 d->loaded = true; 0812 0813 XbelReader reader; 0814 d->bookmarkRootNode = reader.read(d->bookmarksFile); 0815 0816 if (reader.error() != QXmlStreamReader::NoError) 0817 { 0818 QMessageBox::warning(nullptr, i18nc("@title:window", "Loading Bookmark"), 0819 i18n("Error when loading bookmarks on line %1, column %2:\n%3", 0820 reader.lineNumber(), 0821 reader.columnNumber(), 0822 reader.errorString())); 0823 } 0824 } 0825 0826 void BookmarksManager::save() 0827 { 0828 if (!d->loaded) 0829 { 0830 return; 0831 } 0832 0833 qCDebug(DIGIKAM_GEOIFACE_LOG) << "Saving GPS bookmarks to" << d->bookmarksFile; 0834 0835 XbelWriter writer; 0836 0837 if (!writer.write(d->bookmarksFile, d->bookmarkRootNode)) 0838 { 0839 qCWarning(DIGIKAM_GEOIFACE_LOG) << "BookmarkManager: error saving to" << d->bookmarksFile; 0840 } 0841 } 0842 0843 void BookmarksManager::addBookmark(BookmarkNode* const parent, BookmarkNode* const node, int row) 0844 { 0845 if (!d->loaded) 0846 { 0847 return; 0848 } 0849 0850 Q_ASSERT(parent); 0851 0852 InsertBookmarksCommand* const command = new InsertBookmarksCommand(this, parent, node, row); 0853 d->commands.push(command); 0854 } 0855 0856 void BookmarksManager::removeBookmark(BookmarkNode* const node) 0857 { 0858 if (!d->loaded) 0859 { 0860 return; 0861 } 0862 0863 Q_ASSERT(node); 0864 0865 BookmarkNode* const parent = node->parent(); 0866 int row = parent->children().indexOf(node); 0867 RemoveBookmarksCommand* const command = new RemoveBookmarksCommand(this, parent, row); 0868 d->commands.push(command); 0869 } 0870 0871 void BookmarksManager::setTitle(BookmarkNode* const node, const QString& newTitle) 0872 { 0873 if (!d->loaded) 0874 { 0875 return; 0876 } 0877 0878 Q_ASSERT(node); 0879 0880 ChangeBookmarkCommand* const command = new ChangeBookmarkCommand(this, node, newTitle, 0881 ChangeBookmarkCommand::Title); 0882 d->commands.push(command); 0883 } 0884 0885 void BookmarksManager::setUrl(BookmarkNode* const node, const QString& newUrl) 0886 { 0887 if (!d->loaded) 0888 { 0889 return; 0890 } 0891 0892 Q_ASSERT(node); 0893 0894 ChangeBookmarkCommand* const command = new ChangeBookmarkCommand(this, node, newUrl, 0895 ChangeBookmarkCommand::Url); 0896 d->commands.push(command); 0897 } 0898 0899 void BookmarksManager::setComment(BookmarkNode* const node, const QString& newDesc) 0900 { 0901 if (!d->loaded) 0902 { 0903 return; 0904 } 0905 0906 Q_ASSERT(node); 0907 0908 ChangeBookmarkCommand* const command = new ChangeBookmarkCommand(this, node, newDesc, 0909 ChangeBookmarkCommand::Desc); 0910 d->commands.push(command); 0911 } 0912 0913 BookmarkNode* BookmarksManager::bookmarks() 0914 { 0915 if (!d->loaded) 0916 { 0917 load(); 0918 } 0919 0920 return d->bookmarkRootNode; 0921 } 0922 0923 BookmarksModel* BookmarksManager::bookmarksModel() 0924 { 0925 if (!d->bookmarkModel) 0926 { 0927 d->bookmarkModel = new BookmarksModel(this, this); 0928 } 0929 0930 return d->bookmarkModel; 0931 } 0932 0933 QUndoStack* BookmarksManager::undoRedoStack() const 0934 { 0935 return &d->commands; 0936 } 0937 0938 void BookmarksManager::importBookmarks() 0939 { 0940 QString fileName = DFileDialog::getOpenFileName(nullptr, i18nc("@title:window", "Open File"), 0941 QString(), 0942 i18n("XBEL (*.xbel *.xml)")); 0943 if (fileName.isEmpty()) 0944 { 0945 return; 0946 } 0947 0948 XbelReader reader; 0949 BookmarkNode* const importRootNode = reader.read(fileName); 0950 0951 if (reader.error() != QXmlStreamReader::NoError) 0952 { 0953 QMessageBox::warning(nullptr, i18nc("@title:window", "Loading Bookmark"), 0954 i18n("Error when loading bookmarks on line %1, column %2:\n%3", 0955 reader.lineNumber(), 0956 reader.columnNumber(), 0957 reader.errorString())); 0958 } 0959 0960 importRootNode->setType(BookmarkNode::Folder); 0961 importRootNode->title = i18n("Imported %1", QLocale().toString(QDate::currentDate(), QLocale::ShortFormat)); 0962 addBookmark(bookmarks(), importRootNode); 0963 } 0964 0965 void BookmarksManager::exportBookmarks() 0966 { 0967 QString fileName = DFileDialog::getSaveFileName(nullptr, i18nc("@title:window", "Save File"), 0968 i18n("%1 Bookmarks.xbel", QCoreApplication::applicationName()), 0969 i18n("XBEL (*.xbel *.xml)")); 0970 if (fileName.isEmpty()) 0971 { 0972 return; 0973 } 0974 0975 XbelWriter writer; 0976 0977 if (!writer.write(fileName, d->bookmarkRootNode)) 0978 { 0979 QMessageBox::critical(nullptr, i18nc("@title:window", "Export Bookmark"), i18n("Error saving bookmarks")); 0980 } 0981 } 0982 0983 } // namespace Digikam 0984 0985 #include "moc_bookmarksmngr.cpp"