28 #include <QDomElement>
34 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
37 #include <QTextStream>
41 #include "../util/btassert.h"
42 #include "../util/btconnect.h"
43 #include "../util/cresmgr.h"
44 #include "../util/directory.h"
45 #include "../util/tool.h"
53 #define CURRENT_SYNTAX_VERSION 1
58 inline QString
toHeader(QString
const & key, QString
const & moduleName)
59 {
return QStringLiteral(
"%1 (%2)").arg(key).arg(moduleName); }
70 : m_parent(other.m_parent)
71 , m_text(other.m_text)
76 void setText(QString
const & text) { m_text = text; }
78 QString
const &
text()
const {
return m_text; }
80 virtual QString
toolTip()
const {
return {}; }
82 virtual Qt::ItemFlags
flags() const noexcept {
return Qt::NoItemFlags; }
84 virtual QIcon
const &
icon() const noexcept {
85 static QIcon
const noIcon;
110 const QString &
description,
const QString & title);
115 Qt::ItemFlags
flags() const noexcept final
override {
116 return Qt::ItemIsSelectable
117 | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled
121 QIcon
const &
icon() const noexcept final
override
122 {
return CResMgr::mainIndex::bookmark::icon(); }
139 QString toolTip()
const override;
163 Qt::ItemFlags
flags() const noexcept final
override {
164 return Qt::ItemIsSelectable | Qt::ItemIsEditable
165 | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled
169 QIcon
const &
icon() const noexcept final
override
170 {
return CResMgr::mainIndex::closedFolder::icon(); }
176 m_children.append(child);
181 {
return m_children; }
186 m_children.insert(index, child);
190 for (
auto *
const c : children)
191 insertChild(index++, c);
195 delete m_children[index];
196 m_children.removeAt(index);
232 : m_rootItem(new BookmarkFolder(QStringLiteral(
"Root")))
235 m_saveTimer.setInterval(30 * 1000);
236 m_saveTimer.setSingleShot(
true);
242 + QStringLiteral(
"/bookmarks.xml");
245 BookmarkItemBase *
item(
const QModelIndex & index)
const {
247 return static_cast<BookmarkItemBase *
>(index.internalPointer());
251 template <
typename T>
253 {
return dynamic_cast<T *
>(item(index)); }
256 if(m_defaultModel == q_ptr){
257 if(!m_saveTimer.isActive())
268 QString bookmarksFile = loadXmlFromFile(fileName);
269 if (bookmarksFile.isNull())
272 doc.setContent(bookmarksFile);
273 QDomElement document = doc.documentElement();
274 if (document.tagName() != QStringLiteral(
"SwordBookmarks")) {
275 qWarning(
"Not a BibleTime Bookmark XML file");
279 QDomElement child = document.firstChild().toElement();
281 while ( !child.isNull() && child.parentNode() == document) {
282 BookmarkItemBase* i = handleXmlElement(child,
nullptr);
284 if (!child.nextSibling().isNull()) {
285 child = child.nextSibling().toElement();
288 child = QDomElement();
298 if (element.tagName() == QStringLiteral(
"Folder")) {
299 BookmarkFolder* newFolder =
new BookmarkFolder(QString(), parent);
300 if (element.hasAttribute(QStringLiteral(
"caption"))) {
301 newFolder->setText(element.attribute(
302 QStringLiteral(
"caption")));
304 QDomNodeList childList = element.childNodes();
305 for (
int i = 0; i < childList.length(); i++) {
306 QDomElement newElement = childList.at(i).toElement();
307 handleXmlElement(newElement, newFolder);
311 if (element.tagName() == QStringLiteral(
"Bookmark")) {
313 if (element.hasAttribute(QStringLiteral(
"modulename"))) {
315 newBookmarkItem->setModule(
316 element.attribute(QStringLiteral(
"modulename")));
318 if (element.hasAttribute(QStringLiteral(
"key"))) {
319 newBookmarkItem->setKey(
320 element.attribute(QStringLiteral(
"key")));
322 if (element.hasAttribute(QStringLiteral(
"description"))) {
323 newBookmarkItem->setDescription(
324 element.attribute(QStringLiteral(
"description")));
326 if (element.hasAttribute(QStringLiteral(
"title"))) {
327 newBookmarkItem->setText(
328 element.attribute(QStringLiteral(
"title")));
330 return newBookmarkItem;
337 if (fileName.isEmpty())
338 fileName = defaultBookmarksFile();
341 t.setAutoDetectUnicode(
false);
342 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
343 t.setCodec(QTextCodec::codecForName(QByteArrayLiteral(
"UTF-8")));
345 t.setEncoding(QStringConverter::Utf8);
348 QFile file(fileName);
349 if (!file.open(QIODevice::ReadOnly))
361 QDomDocument doc(QStringLiteral(
"DOC"));
363 doc.createProcessingInstruction(
364 QStringLiteral(
"xml"),
365 QStringLiteral(
"version=\"1.0\" encoding=\"UTF-8\"")));
368 doc.createElement(QStringLiteral(
"SwordBookmarks"));
369 content.setAttribute(QStringLiteral(
"syntaxVersion"),
371 doc.appendChild(content);
375 for (
auto const *
const itemPtr : rootItem->children())
376 saveItem(itemPtr, content);
377 return doc.toString();
381 void saveItem(BookmarkItemBase
const * item, QDomElement & parentElement) {
382 BookmarkFolder
const * folderItem =
nullptr;
385 if ((folderItem =
dynamic_cast<BookmarkFolder
const *
>(item))) {
387 parentElement.ownerDocument().createElement(
388 QStringLiteral(
"Folder"));
389 elem.setAttribute(QStringLiteral(
"caption"), folderItem->text());
391 parentElement.appendChild(elem);
393 for (
auto const *
const itemPtr : folderItem->children())
394 saveItem(itemPtr, elem);
396 else if ((bookmarkItem =
dynamic_cast<BookmarkItem const *
>(item))) {
398 parentElement.ownerDocument().createElement(
399 QStringLiteral(
"Bookmark"));
401 elem.setAttribute(QStringLiteral(
"key"),
402 bookmarkItem->englishKey());
403 elem.setAttribute(QStringLiteral(
"description"),
405 elem.setAttribute(QStringLiteral(
"modulename"),
406 bookmarkItem->moduleName());
407 elem.setAttribute(QStringLiteral(
"moduledescription"),
409 ? bookmarkItem->
module()->config(
412 if (!bookmarkItem->text().isEmpty()) {
413 elem.setAttribute(QStringLiteral(
"title"), bookmarkItem->text());
415 parentElement.appendChild(elem);
443 for (
auto const *
const childItem : children())
446 if (folder->hasDescendant(childItem))
453 for (
auto const *
const subitem : children()) {
461 newFolder->
addChild(bmFolder->deepCopy());
469 const QString & description,
470 const QString & title)
471 : m_description(description)
472 , m_moduleName(module.name())
478 sword::VerseKey vk(key.toUtf8().constData(), key.toUtf8().constData(),
479 static_cast<sword::VerseKey *
>(module.
swordModule().getKey())->getVersificationSystem());
499 , m_description(other.m_description)
500 , m_moduleName(other.m_moduleName)
511 return englishKeyName;
514 QString returnKeyName = englishKeyName;
517 sword::VerseKey vk(englishKeyName.toUtf8().constData(), englishKeyName.toUtf8().constData(),
518 static_cast<sword::VerseKey *
>(
module()->swordModule().getKey())->getVersificationSystem());
521 returnKeyName = k.key();
524 return returnKeyName;
528 auto const *
const m =
module();
537 std::unique_ptr<CSwordKey> k(m->createKey());
545 auto const & txt =
text();
547 return QStringLiteral(
"<b>%1)</b><hr>%2").arg(header,
description());
548 return QStringLiteral(
"<b>%1)</b><br>%2<hr>%3")
568 if(d->m_saveTimer.isActive())
577 if (
auto const *
const f =
dynamic_cast<BookmarkFolder *
>(d->item(
parent)))
578 return f->children().size();
593 auto const *
const f =
dynamic_cast<BookmarkFolder *
>(d->item(
parent));
594 if (f && f->children().size() > row && row >= 0)
595 return createIndex(row, column, f->children()[row]);
596 return QModelIndex();
602 const BookmarkItemBase * i = d->item(
index);
603 return (i->parent() ==
nullptr || i->parent()->parent() ==
nullptr) ?
604 QModelIndex() : createIndex(i->parent()->index(), 0, i->parent());
610 const BookmarkItemBase * i = d->item(
index);
614 case Qt::DisplayRole:
617 case Qt::ToolTipRole:
619 case Qt::DecorationRole:
624 return QStringLiteral(
"bookmark");
626 return QStringLiteral(
"folder");
635 return d->item(
index)->flags();
640 Q_UNUSED(orientation)
649 BookmarkItemBase * i = d->item(
index);
650 if (role == Qt::DisplayRole || role == Qt::EditRole) {
651 i->setText(val.toString());
652 if(
dynamic_cast<BookmarkFolder *
>(i) ||
dynamic_cast<BookmarkItem *
>(i))
662 if (
auto *
const f =
dynamic_cast<BookmarkFolder *
>(d->item(
parent))) {
663 BT_ASSERT(row + count <= f->children().size());
664 beginRemoveRows(
parent, row, row + count - 1);
665 for(
int i = 0; i < count; ++i)
677 if (
auto *
const f =
dynamic_cast<BookmarkFolder *
>(d->item(
parent))) {
679 beginInsertRows(
parent, row, row + count - 1);
680 for(
int i = 0; i < count; ++i)
681 f->insertChild(row,
new BookmarkItemBase);
690 BT_ASSERT(
dynamic_cast<BookmarkFolder *
>(d->item(rootItem)));
691 auto const serializedTree =
692 d->serializeTreeFromRootItem(
693 static_cast<BookmarkFolder *
>(d->item(rootItem)));
694 if (fileName.isEmpty())
699 if(d->m_saveTimer.isActive())
700 d->m_saveTimer.stop();
707 BT_ASSERT(
dynamic_cast<BookmarkFolder *
>(d->item(rootItem)));
708 auto *
const i =
static_cast<BookmarkFolder *
>(d->item(rootItem));
711 if(!rootItem.isValid() && fileName.isEmpty()) {
712 BT_ASSERT(!d->m_defaultModel &&
"Only one default model allowed!");
715 d->m_defaultModel =
this;
718 if(items.size() == 0)
721 auto const numChildren = i->children().size();
722 beginInsertRows(rootItem, numChildren, numChildren + items.size() - 1);
723 i->insertChildren(numChildren, items);
731 return d->itemAs<BookmarkFolder
const>(
index);
744 auto *
const targetFolder =
static_cast<BookmarkFolder *
>(d->item(
parent));
746 bool bookmarksOnly =
true;
747 bool targetIncluded =
false;
748 bool moreThanOneFolder =
false;
752 for (
auto const &
index : toCopy) {
753 if (BookmarkFolder
const *
const folder =
754 d->itemAs<BookmarkFolder
const>(
index))
756 bookmarksOnly =
false;
757 if (toCopy.count() > 1) {
758 moreThanOneFolder =
true;
761 if (folder->hasDescendant(d->item(
parent))) {
762 targetIncluded =
true;
771 if (!bookmarksOnly && toCopy.count() == 1)
772 newList.append(d->itemAs<BookmarkFolder
const>(toCopy[0])->deepCopy());
773 if (!bookmarksOnly && toCopy.count() > 1) {
775 moreThanOneFolder =
true;
778 if (moreThanOneFolder || targetIncluded) {
783 beginInsertRows(
parent, row, row + newList.size() - 1);
785 targetFolder->insertChildren(row, newList);
815 return i->description();
830 QModelIndex
const & parent,
833 QString
const & description,
834 QString
const & title)
838 if (BookmarkFolder *
const i = d->itemAs<BookmarkFolder>(
parent)) {
844 i->insertChild(
r, c);
850 return createIndex(c->index(), 0, c);
852 return QModelIndex();
859 if (BookmarkFolder *
const i = d->itemAs<BookmarkFolder>(
parent)) {
860 beginInsertRows(
parent, row, row);
862 BookmarkFolder * c =
new BookmarkFolder(name.isEmpty() ? QObject::tr(
"New folder") : name);
863 i->insertChild(row, c);
869 return createIndex(c->index(), 0, c);
871 return QModelIndex();
878 if (BookmarkFolder
const *
const f =
879 d->itemAs<BookmarkFolder
const>(baseIndex))
880 return f->hasDescendant(d->item(testIndex));
886 return i1->text().localeAwareCompare(i2->text()) < 0;
891 return i1->text().localeAwareCompare(i2->text()) > 0;
895 Qt::SortOrder
const order)
899 if(BookmarkFolder *
const f = d->itemAs<BookmarkFolder>(
parent)) {
901 if(f == d->m_rootItem) {
904 for(
int i = 0; i < items.size(); ++i) {
905 if (
auto *
const ff =
dynamic_cast<BookmarkFolder *
>(items[i])){
906 items.append(ff->children());
914 for (
auto *
const f : parents) {
915 Q_EMIT layoutAboutToBeChanged();
917 QModelIndexList indexes;
918 for(
int i = 0; i < f->children().size(); ++i)
919 indexes.append(createIndex(i, 0, f->children()[i]));
921 std::sort(f->children().begin(),
923 order == Qt::AscendingOrder
927 for(
int i = 0; i < f->children().size(); ++i) {
928 BookmarkItemBase * iii = f->children()[i];
929 for(
int ii = 0; ii < indexes.size(); ++ii)
930 if(iii == indexes[ii].internalPointer())
931 changePersistentIndex(createIndex(ii, 0, iii), createIndex(i, 0, iii));
933 Q_EMIT layoutChanged();
941 static auto const staticRoleNames = {
942 std::make_pair(
static_cast<int>(Qt::DisplayRole),
943 QByteArrayLiteral(
"display")),
944 std::make_pair(
static_cast<int>(Qt::DecorationRole),
945 QByteArrayLiteral(
"icon")),
946 std::make_pair(
static_cast<int>(Qt::EditRole),
947 QByteArrayLiteral(
"edit")),
948 std::make_pair(
static_cast<int>(
TypeRole),
949 QByteArrayLiteral(
"itemtype"))
951 return staticRoleNames;
bool BtBookmarksModelSortAscending(BookmarkItemBase *i1, BookmarkItemBase *i2)
#define CURRENT_SYNTAX_VERSION
bool BtBookmarksModelSortDescending(BookmarkItemBase *i1, BookmarkItemBase *i2)
BtConfig & btConfig()
This is a shortchand for BtConfig::getInstance().
QString const & key() const noexcept
BookmarkItem(QString module, QString key, QString description)
QString const & description() const noexcept
QString const & module() const noexcept
BookmarkItemBase * item(const QModelIndex &index) const
BtBookmarksModelPrivate(BtBookmarksModel *parent)
static QString defaultBookmarksFile()
QString loadXmlFromFile(QString fileName=QString())
void saveItem(BookmarkItemBase const *item, QDomElement &parentElement)
BookmarkFolder * m_rootItem
QString serializeTreeFromRootItem(BookmarkFolder *rootItem)
BookmarkItemBase * handleXmlElement(QDomElement &element, BookmarkFolder *parent)
QList< BookmarkItemBase * > loadTree(QString fileName=QString())
static BtBookmarksModel * m_defaultModel
~BtBookmarksModelPrivate()
T * itemAs(QModelIndex const &index) const
int rowCount(const QModelIndex &parent=QModelIndex()) const override
void copyItems(int row, const QModelIndex &parent, const QModelIndexList &toCopy)
Copies item to target position.
bool isBookmark(const QModelIndex &index) const
bool hasDescendant(const QModelIndex &baseIndex, const QModelIndex &testIndex) const
bool isFolder(const QModelIndex &index) const
void sortItems(QModelIndex const &parent=QModelIndex(), Qt::SortOrder const order=Qt::AscendingOrder)
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QString description(const QModelIndex &index) const
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
Qt::ItemFlags flags(const QModelIndex &index) const override
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
QHash< int, QByteArray > roleNames() const override
~BtBookmarksModel() override
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
void setDescription(const QModelIndex &index, const QString &description)
set descritpion for index.
QModelIndex parent(const QModelIndex &index) const override
bool load(QString fileName=QString(), const QModelIndex &rootItem=QModelIndex())
Import bookmarks from file.
BtBookmarksModel(QObject *parent=nullptr)
bool hasChildren(const QModelIndex &parent=QModelIndex()) const override
CSwordModuleInfo * module(const QModelIndex &index) const
bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
QModelIndex addFolder(int row, const QModelIndex &parent, const QString &name=QString())
add new folder.
bool save(QString fileName=QString(), const QModelIndex &rootItem=QModelIndex())
Save bookmarks or specified branch to file.
BtBookmarksModelPrivate *const d_ptr
QModelIndex addBookmark(int const row, QModelIndex const &parent, CSwordModuleInfo const &module, QString const &key, QString const &description=QString(), QString const &title=QString())
add new item with given parameters
int columnCount(const QModelIndex &parent=QModelIndex()) const override
QString key(const QModelIndex &index) const
FilterOptions getFilterOptions() const
CSwordModuleInfo * findModuleByName(const QString &name) const
Searches for a module with the given name.
static CSwordBackend & instance() noexcept
void setFilterOptions(const FilterOptions &options)
QString const & name() const
sword::SWModule & swordModule() const
CSwordKey implementation for Sword's VerseKey.
void insertChild(int index, BookmarkItemBase *child)
BookmarkFolder * deepCopy() const
bool hasDescendant(BookmarkItemBase const *item) const
QList< BookmarkItemBase * > m_children
QList< BookmarkItemBase * > const & children() const noexcept
void insertChildren(int index, QList< BookmarkItemBase * > children)
void removeChild(int index)
Qt::ItemFlags flags() const noexcept final override
QIcon const & icon() const noexcept final override
QList< BookmarkItemBase * > & children() noexcept
void addChild(BookmarkItemBase *child)
~BookmarkFolder() final override
void setText(QString const &text)
virtual Qt::ItemFlags flags() const noexcept
BookmarkItemBase(const BookmarkItemBase &other)
virtual QString toolTip() const
virtual QIcon const & icon() const noexcept
virtual ~BookmarkItemBase()
void setParent(BookmarkFolder *parent)
QString const & text() const
BookmarkFolder * m_parent
BookmarkFolder * parent() const
Qt::ItemFlags flags() const noexcept final override
BookmarkItem(const CSwordModuleInfo &module, const QString &key, const QString &description, const QString &title)
void setModule(QString const &moduleName)
QString const & moduleName() const
BookmarkItem(BookmarkFolder *parent)
void setKey(QString const &key)
CSwordModuleInfo * module() const
QString const & englishKey() const
void setDescription(QString const &description)
QString const & description() const
QIcon const & icon() const noexcept final override
QString toolTip() const override
QStringList r(content.left(bodyIndex))
QString toHeader(QString const &key, QString const &moduleName)
const QDir & getUserBaseDir()