summaryrefslogtreecommitdiff
path: root/src/frontend/bookmarks
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/bookmarks')
-rw-r--r--src/frontend/bookmarks/btbookmarkfolder.cpp140
-rw-r--r--src/frontend/bookmarks/btbookmarkfolder.h50
-rw-r--r--src/frontend/bookmarks/btbookmarkitem.cpp149
-rw-r--r--src/frontend/bookmarks/btbookmarkitem.h76
-rw-r--r--src/frontend/bookmarks/btbookmarkitembase.cpp21
-rw-r--r--src/frontend/bookmarks/btbookmarkitembase.h62
-rw-r--r--src/frontend/bookmarks/btbookmarkloader.cpp177
-rw-r--r--src/frontend/bookmarks/btbookmarkloader.h46
-rw-r--r--src/frontend/bookmarks/bteditbookmarkdialog.cpp78
-rw-r--r--src/frontend/bookmarks/bteditbookmarkdialog.h62
-rw-r--r--src/frontend/bookmarks/cbookmarkindex.cpp937
-rw-r--r--src/frontend/bookmarks/cbookmarkindex.h214
12 files changed, 2012 insertions, 0 deletions
diff --git a/src/frontend/bookmarks/btbookmarkfolder.cpp b/src/frontend/bookmarks/btbookmarkfolder.cpp
new file mode 100644
index 0000000..1cc2583
--- /dev/null
+++ b/src/frontend/bookmarks/btbookmarkfolder.cpp
@@ -0,0 +1,140 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2011 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "frontend/bookmarks/btbookmarkfolder.h"
+
+#include <QDebug>
+#include <QFileDialog>
+#include "frontend/bookmarks/btbookmarkitembase.h"
+#include "frontend/bookmarks/btbookmarkitem.h"
+#include "frontend/bookmarks/btbookmarkloader.h"
+#include "util/cresmgr.h"
+#include "util/directory.h"
+
+
+BtBookmarkFolder::BtBookmarkFolder(const QString &name, QTreeWidgetItem *parent)
+ : BtBookmarkItemBase(parent) {
+ setText(0, name);
+ setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEnabled);
+}
+
+bool BtBookmarkFolder::enableAction(MenuAction action) {
+ if (action == ChangeFolder || action == NewFolder || action == DeleteEntries || action == ImportBookmarks )
+ return true;
+ if (action == SortFolderBookmarks || action == ExportBookmarks || action == ImportBookmarks )
+ return true;
+ if ((action == PrintBookmarks) && childCount())
+ return true;
+ return false;
+}
+
+void BtBookmarkFolder::exportBookmarks() {
+ QString filter = QObject::tr("BibleTime bookmark files") + QString(" (*.btb);;") + QObject::tr("All files") + QString(" (*.*)");
+ QString fileName = QFileDialog::getSaveFileName(0, QObject::tr("Export Bookmarks"), "", filter);
+
+ if (!fileName.isEmpty()) {
+ qDebug() << "exportBookmarks()";
+ BtBookmarkLoader loader;
+ loader.saveTreeFromRootItem(this, fileName, false ); //false: don't overwrite without asking
+ };
+
+}
+
+void BtBookmarkFolder::importBookmarks() {
+ QString filter = QObject::tr("BibleTime bookmark files") + QString(" (*.btb);;") + QObject::tr("All files") + QString(" (*.*)");
+ QString fileName = QFileDialog::getOpenFileName(0, QObject::tr("Import bookmarks"), "", filter);
+ if (!fileName.isEmpty()) {
+ qDebug() << "import bookmarks";
+ BtBookmarkLoader loader;
+ QList<QTreeWidgetItem*> itemList = loader.loadTree(fileName);
+ this->insertChildren(0, itemList);
+ };
+}
+
+QString BtBookmarkFolder::toolTip() const {
+ return QString::null;
+}
+
+void BtBookmarkFolder::newSubFolder() {
+ if (dynamic_cast<BtBookmarkFolder*>(this)) {
+ BtBookmarkFolder* f = new BtBookmarkFolder(QObject::tr("New folder"), this);
+
+ treeWidget()->setCurrentItem(f);
+ f->update();
+ f->rename();
+ }
+}
+
+QList<QTreeWidgetItem*> BtBookmarkFolder::getChildList() const {
+ QList<QTreeWidgetItem*> list;
+ for (int i = 0; i < childCount(); i++) {
+ list.append(child(i));
+ }
+ return list;
+}
+
+void BtBookmarkFolder::rename() {
+ treeWidget()->editItem(this);
+}
+
+void BtBookmarkFolder::update() {
+ namespace DU = util::directory;
+
+ qDebug() << "BtBookmarkFolder::update()";
+ BtBookmarkItemBase::update();
+ if (isExpanded() && childCount())
+ setIcon(0, DU::getIcon(CResMgr::mainIndex::openedFolder::icon));
+ else
+ setIcon(0, DU::getIcon(CResMgr::mainIndex::closedFolder::icon));
+}
+
+bool BtBookmarkFolder::hasDescendant(QTreeWidgetItem* item) const {
+ qDebug() << "BtBookmarkFolder::hasDescendant, this:" << this << "possible descendant:" << item;
+
+ if (this == item) {
+ qDebug() << "it's this, return true";
+ return true;
+ }
+ if (getChildList().indexOf(item) > -1) {
+ qDebug() << "direct child, return true";
+ return true;
+ }
+ foreach(QTreeWidgetItem* childItem, getChildList()) {
+ bool subresult = false;
+ BtBookmarkFolder* folder = 0;
+ if ( (folder = dynamic_cast<BtBookmarkFolder*>(childItem)) ) {
+ subresult = folder->hasDescendant(childItem);
+ }
+
+ if (subresult == true) {
+ qDebug() << "descendand child, return true";
+ return true;
+ }
+ }
+ qDebug() << "no child, return false";
+ return false;
+}
+
+BtBookmarkFolder* BtBookmarkFolder::deepCopy() {
+ qDebug() << "BtBookmarkFolder::deepCopy";
+ BtBookmarkFolder* newFolder = new BtBookmarkFolder(this->text(0));
+ foreach(QTreeWidgetItem* subitem, getChildList()) {
+ if (BtBookmarkItem* bmItem = dynamic_cast<BtBookmarkItem*>(subitem)) {
+ newFolder->addChild(new BtBookmarkItem(*bmItem));
+ }
+ else {
+ if (BtBookmarkFolder* bmFolder = dynamic_cast<BtBookmarkFolder*>(subitem)) {
+ newFolder->addChild(bmFolder->deepCopy());
+ }
+ }
+ }
+ newFolder->update();
+ return newFolder;
+}
+
diff --git a/src/frontend/bookmarks/btbookmarkfolder.h b/src/frontend/bookmarks/btbookmarkfolder.h
new file mode 100644
index 0000000..90021f8
--- /dev/null
+++ b/src/frontend/bookmarks/btbookmarkfolder.h
@@ -0,0 +1,50 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2011 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTBOOKMARKFOLDER_H
+#define BTBOOKMARKFOLDER_H
+
+#include "frontend/bookmarks/btbookmarkitembase.h"
+
+
+#define CURRENT_SYNTAX_VERSION 1
+
+class BtBookmarkFolder : public BtBookmarkItemBase {
+ public:
+ friend class BtBookmarkLoader;
+ BtBookmarkFolder(const QString &name, QTreeWidgetItem *parent = 0);
+ ~BtBookmarkFolder() {}
+
+ /** See the base class. */
+ virtual bool enableAction(const MenuAction action);
+
+ /** User gives a file from which to load items into this folder. */
+ virtual void exportBookmarks();
+ /** User gives a file to which items from this folder are saved. */
+ virtual void importBookmarks();
+
+ /** Creates a new folder under this. */
+ void newSubFolder();
+
+ /** Returns a list of direct childs of this item. */
+ QList<QTreeWidgetItem*> getChildList() const;
+
+ /** Returns true if the given item is this or a direct or indirect subitem of this. */
+ bool hasDescendant(QTreeWidgetItem* item) const;
+
+ /** Creates a deep copy of this item. */
+ BtBookmarkFolder* deepCopy();
+
+ void rename();
+ void update();
+
+ QString toolTip() const;
+};
+
+#endif
diff --git a/src/frontend/bookmarks/btbookmarkitem.cpp b/src/frontend/bookmarks/btbookmarkitem.cpp
new file mode 100644
index 0000000..fff3d2c
--- /dev/null
+++ b/src/frontend/bookmarks/btbookmarkitem.cpp
@@ -0,0 +1,149 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2011 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "frontend/bookmarks/btbookmarkitem.h"
+
+#include <QSharedPointer>
+#include <QDebug>
+#include "backend/config/cbtconfig.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/keys/cswordversekey.h"
+#include "btglobal.h"
+#include "frontend/bookmarks/btbookmarkfolder.h"
+#include "frontend/bookmarks/bteditbookmarkdialog.h"
+#include "util/cresmgr.h"
+#include "util/directory.h"
+
+
+BtBookmarkItem::BtBookmarkItem(const CSwordModuleInfo *module,
+ const QString &key,
+ const QString &description,
+ const QString &title)
+ : m_description(description),
+ m_moduleName(module ? module->name() : QString::null),
+ m_title(title)
+{
+ if (((module && (module->type() == CSwordModuleInfo::Bible)) || (module->type() == CSwordModuleInfo::Commentary)) ) {
+ CSwordVerseKey vk(0);
+ vk.setKey(key);
+ vk.setLocale("en");
+ m_key = vk.key(); //the m_key member is always the english key!
+ }
+ else {
+ m_key = key;
+ };
+
+ update();
+}
+
+BtBookmarkItem::BtBookmarkItem(QTreeWidgetItem* parent)
+ : BtBookmarkItemBase(parent) {}
+
+BtBookmarkItem::BtBookmarkItem(const BtBookmarkItem& other)
+ : BtBookmarkItemBase(0),
+ m_key(other.m_key),
+ m_description(other.m_description),
+ m_moduleName(other.m_moduleName),
+ m_title(other.m_title)
+{
+ update();
+}
+
+CSwordModuleInfo *BtBookmarkItem::module() const {
+ return CSwordBackend::instance()->findModuleByName(m_moduleName);
+}
+
+QString BtBookmarkItem::key() const {
+ const QString englishKeyName = englishKey();
+ if (!module()) {
+ return englishKeyName;
+ }
+
+ QString returnKeyName = englishKeyName;
+ if ((module()->type() == CSwordModuleInfo::Bible) || (module()->type() == CSwordModuleInfo::Commentary)) {
+ CSwordVerseKey vk(0);
+ vk.setKey(englishKeyName);
+ vk.setLocale(CSwordBackend::instance()->booknameLanguage().toLatin1() );
+
+ returnKeyName = vk.key(); //the returned key is always in the currently set bookname language
+ }
+
+ return returnKeyName;
+}
+
+QString BtBookmarkItem::toolTip() const {
+ if (!module()) {
+ return QString::null;
+ }
+
+ FilterOptions filterOptions = CBTConfig::getFilterOptionDefaults();
+ filterOptions.footnotes = false;
+ filterOptions.scriptureReferences = false;
+ CSwordBackend::instance()->setFilterOptions(filterOptions);
+
+ QString ret;
+ QSharedPointer<CSwordKey> k( CSwordKey::createInstance(module()) );
+ k->setKey(key());
+
+ // const CLanguageMgr::Language* lang = module()->language();
+ // CBTConfig::FontSettingsPair fontPair = CBTConfig::get(lang);
+
+ Q_ASSERT(k.data());
+ QString header = QString::fromLatin1("%1 (%2)")
+ .arg(key())
+ .arg(module()->name());
+ if (title() != header) {
+ ret = QString::fromLatin1("<b>%1</b><br>%2<hr>%3")
+ .arg(header)
+ .arg(title())
+ .arg(description())
+ ;
+ }
+ else {
+ ret = QString::fromLatin1("<b>%1</b><hr>%2")
+ .arg(header)
+ .arg(description())
+ ;
+ }
+
+ return ret;
+}
+
+bool BtBookmarkItem::enableAction(MenuAction action) {
+ if (action == EditBookmark || (module() && (action == PrintBookmarks)) || action == DeleteEntries)
+ return true;
+
+ return false;
+}
+
+void BtBookmarkItem::rename() {
+ BtEditBookmarkDialog d(QString::fromLatin1("%1 (%2)").arg(key()).arg(module() ? module()->name() : QObject::tr("unknown")),
+ m_title,
+ m_description, treeWidget());
+
+ if (d.exec() == QDialog::Accepted) {
+ m_title = d.titleText();
+ m_description = d.descriptionText();
+ update();
+ }
+}
+
+void BtBookmarkItem::update() {
+ namespace DU = util::directory;
+
+ qDebug() << "BtBookmarkItem::update";
+ setIcon(0, DU::getIcon(CResMgr::mainIndex::bookmark::icon));
+
+ if (m_title.isEmpty()) {
+ m_title = QString::fromLatin1("%1 (%2)").arg(key()).arg(module() ? module()->name() : QObject::tr("unknown"));
+ }
+ setText(0,m_title);
+ setToolTip(0, toolTip());
+}
+
diff --git a/src/frontend/bookmarks/btbookmarkitem.h b/src/frontend/bookmarks/btbookmarkitem.h
new file mode 100644
index 0000000..3166e61
--- /dev/null
+++ b/src/frontend/bookmarks/btbookmarkitem.h
@@ -0,0 +1,76 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2011 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTBOOKMARKITEM_H
+#define BTBOOKMARKITEM_H
+
+#include "frontend/bookmarks/btbookmarkitembase.h"
+
+#include <QString>
+
+
+class BtBookmarkFolder;
+class CSwordModuleInfo;
+
+class BtBookmarkItem : public BtBookmarkItemBase {
+ public:
+ friend class BtBookmarkLoader;
+
+ BtBookmarkItem(QTreeWidgetItem* parent);
+
+ /** Creates a bookmark with module, key and description. */
+ BtBookmarkItem(const CSwordModuleInfo *module, const QString &key,
+ const QString &description, const QString &title);
+
+ /** Creates a copy. */
+ BtBookmarkItem(const BtBookmarkItem& other);
+
+ ~BtBookmarkItem() {}
+
+ /** Returns the used module, 0 if there is no such module. */
+ CSwordModuleInfo *module() const;
+
+ /** Returns the used key. */
+ QString key() const;
+
+ /** Returns the used description. */
+ inline const QString &description() const {
+ return m_description;
+ }
+
+ /** Returns the title. */
+ inline const QString &title() const {
+ return m_title;
+ }
+
+ /** Returns a tooltip for this bookmark. */
+ virtual QString toolTip() const;
+
+ /** Returns whether the action is supported by this item. */
+ virtual bool enableAction(MenuAction action);
+
+ /** Changes this bookmark. */
+ virtual void rename();
+
+ void update();
+
+ private:
+ /** Returns the english key.*/
+ inline const QString &englishKey() const {
+ return m_key;
+ }
+
+ private:
+ QString m_key;
+ QString m_description;
+ QString m_moduleName;
+ QString m_title;
+};
+
+#endif
diff --git a/src/frontend/bookmarks/btbookmarkitembase.cpp b/src/frontend/bookmarks/btbookmarkitembase.cpp
new file mode 100644
index 0000000..1a80f7d
--- /dev/null
+++ b/src/frontend/bookmarks/btbookmarkitembase.cpp
@@ -0,0 +1,21 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2011 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "frontend/bookmarks/btbookmarkitembase.h"
+
+
+BtBookmarkItemBase::BtBookmarkItemBase() {
+ // Intentionally empty
+}
+
+BtBookmarkItemBase::BtBookmarkItemBase(QTreeWidgetItem *parent)
+ : QTreeWidgetItem(parent)
+{
+ // Intentionally empty
+}
diff --git a/src/frontend/bookmarks/btbookmarkitembase.h b/src/frontend/bookmarks/btbookmarkitembase.h
new file mode 100644
index 0000000..8452473
--- /dev/null
+++ b/src/frontend/bookmarks/btbookmarkitembase.h
@@ -0,0 +1,62 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2011 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTBOOKMARKITEMBASE_H
+#define BTBOOKMARKITEMBASE_H
+
+#include <QTreeWidgetItem>
+
+#include <QDropEvent>
+#include <QMimeData>
+#include <QString>
+
+
+class CBookmarkIndex;
+
+class BtBookmarkItemBase : public QTreeWidgetItem {
+ public:
+ enum MenuAction {
+ NewFolder = 0,
+ ChangeFolder,
+
+ EditBookmark,
+ SortFolderBookmarks,
+ SortAllBookmarks,
+ ImportBookmarks,
+ ExportBookmarks,
+ PrintBookmarks,
+
+ DeleteEntries,
+
+ ActionBegin = NewFolder,
+ ActionEnd = DeleteEntries
+ };
+
+ /** Where to drop/create item(s): above, below or inside an item.*/
+ enum Location {Above, Below, Inside};
+
+ BtBookmarkItemBase();
+ BtBookmarkItemBase(QTreeWidgetItem* parent);
+ virtual ~BtBookmarkItemBase() {}
+
+ virtual QString toolTip() const = 0;
+
+ /** Returns true if the given action should be enabled in the popup menu. */
+ virtual bool enableAction( MenuAction action ) = 0;
+
+ /** Rename the item. */
+ virtual void rename() = 0;
+
+ /** Update the item (icon etc.) after creating or changing it. */
+ virtual void update() {}
+
+};
+
+#endif
+
diff --git a/src/frontend/bookmarks/btbookmarkloader.cpp b/src/frontend/bookmarks/btbookmarkloader.cpp
new file mode 100644
index 0000000..ed1dd29
--- /dev/null
+++ b/src/frontend/bookmarks/btbookmarkloader.cpp
@@ -0,0 +1,177 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2011 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "frontend/bookmarks/btbookmarkloader.h"
+
+#include <QDebug>
+#include <QDomElement>
+#include <QDomNode>
+#include <QDomDocument>
+#include <QFile>
+#include <QIODevice>
+#include <QTextCodec>
+#include <QTextStream>
+#include <QTreeWidgetItem>
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "frontend/bookmarks/btbookmarkitem.h"
+#include "frontend/bookmarks/btbookmarkfolder.h"
+#include "util/tool.h"
+
+
+#define CURRENT_SYNTAX_VERSION 1
+
+QList<QTreeWidgetItem*> BtBookmarkLoader::loadTree(QString fileName) {
+ qDebug() << "BtBookmarkLoader::loadTree";
+ QList<QTreeWidgetItem*> itemList;
+
+ QDomDocument doc;
+ doc.setContent(loadXmlFromFile(fileName));
+
+ //bookmarkfolder::loadBookmarksFromXML()
+
+ QDomElement document = doc.documentElement();
+ if ( document.tagName() != "SwordBookmarks" ) {
+ qWarning("Not a BibleTime Bookmark XML file");
+ return QList<QTreeWidgetItem*>();
+ }
+
+ QDomElement child = document.firstChild().toElement();
+
+ while ( !child.isNull() && child.parentNode() == document) {
+ qDebug() << "BtBookmarkLoader::loadTree while start";
+ QTreeWidgetItem* i = handleXmlElement(child, 0);
+ itemList.append(i);
+ if (!child.nextSibling().isNull()) {
+ child = child.nextSibling().toElement();
+ }
+ else {
+ child = QDomElement(); //null
+ }
+
+ }
+
+ return itemList;
+}
+
+QTreeWidgetItem* BtBookmarkLoader::handleXmlElement(QDomElement& element, QTreeWidgetItem* parent) {
+ qDebug() << "BtBookmarkLoader::handleXmlElement";
+ QTreeWidgetItem* newItem = 0;
+ if (element.tagName() == "Folder") {
+ qDebug() << "BtBookmarkLoader::handleXmlElement: found folder";
+ BtBookmarkFolder* newFolder = new BtBookmarkFolder(QString::null, parent);
+ if (element.hasAttribute("caption")) {
+ newFolder->setText(0, element.attribute("caption"));
+ }
+ QDomNodeList childList = element.childNodes();
+ for (unsigned int i = 0; i < childList.length(); i++) {
+ qDebug() << "BtBookmarkLoader::handleXmlElement: go through child list of folder";
+ QDomElement newElement = childList.at(i).toElement();
+ QTreeWidgetItem* newChildItem = handleXmlElement(newElement, newFolder);
+ newFolder->addChild(newChildItem);
+ }
+ newFolder->update();
+ newItem = newFolder;
+ }
+ else if (element.tagName() == "Bookmark") {
+ qDebug() << "BtBookmarkLoader::handleXmlElement: found bookmark";
+ BtBookmarkItem* newBookmarkItem = new BtBookmarkItem(parent);
+ if (element.hasAttribute("modulename")) {
+ //we use the name in all cases, even if the module isn't installed anymore
+ newBookmarkItem->m_moduleName = element.attribute("modulename");
+ }
+ if (element.hasAttribute("key")) {
+ newBookmarkItem->m_key = element.attribute("key");
+ }
+ if (element.hasAttribute("description")) {
+ newBookmarkItem->m_description = element.attribute("description");
+ }
+ if (element.hasAttribute("title")) {
+ newBookmarkItem->m_title = element.attribute("title");
+ }
+ newBookmarkItem->update();
+ newItem = newBookmarkItem;
+ }
+ qDebug() << "BtBookmarkLoader::handleXmlElement: return new item";
+ return newItem;
+}
+
+
+QString BtBookmarkLoader::loadXmlFromFile(QString fileName) {
+ namespace DU = util::directory;
+
+ if (fileName.isNull()) {
+ fileName = DU::getUserBaseDir().absolutePath() + "/bookmarks.xml";
+ }
+ QFile file(fileName);
+ if (!file.exists())
+ return QString::null;
+
+ QString xml;
+ if (file.open(QIODevice::ReadOnly)) {
+ QTextStream t;
+ t.setAutoDetectUnicode(false);
+ t.setCodec(QTextCodec::codecForName("UTF-8"));
+ t.setDevice(&file);
+ xml = t.readAll();
+ file.close();
+ }
+ return xml;
+}
+
+void BtBookmarkLoader::saveTreeFromRootItem(QTreeWidgetItem* rootItem, QString fileName, bool forceOverwrite) {
+ namespace DU = util::directory;
+
+ Q_ASSERT(rootItem);
+ if (fileName.isNull()) {
+ fileName = DU::getUserBaseDir().absolutePath() + "/bookmarks.xml";
+ }
+
+ QDomDocument doc("DOC");
+ doc.appendChild( doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
+
+ QDomElement content = doc.createElement("SwordBookmarks");
+ content.setAttribute("syntaxVersion", CURRENT_SYNTAX_VERSION);
+ doc.appendChild(content);
+
+ //append the XML nodes of all child items
+
+ for (int i = 0; i < rootItem->childCount(); i++) {
+ saveItem(rootItem->child(i), content);
+ }
+ util::tool::savePlainFile(fileName, doc.toString(), forceOverwrite, QTextCodec::codecForName("UTF-8"));
+
+}
+
+void BtBookmarkLoader::saveItem(QTreeWidgetItem* item, QDomElement& parentElement) {
+ BtBookmarkFolder* folderItem = 0;
+ BtBookmarkItem* bookmarkItem = 0;
+
+ if ((folderItem = dynamic_cast<BtBookmarkFolder*>(item))) {
+ QDomElement elem = parentElement.ownerDocument().createElement("Folder");
+ elem.setAttribute("caption", folderItem->text(0));
+
+ parentElement.appendChild(elem);
+
+ for (int i = 0; i < folderItem->childCount(); i++) {
+ saveItem(folderItem->child(i), elem);
+ }
+ }
+ else if ((bookmarkItem = dynamic_cast<BtBookmarkItem*>(item))) {
+ QDomElement elem = parentElement.ownerDocument().createElement("Bookmark");
+
+ elem.setAttribute("key", bookmarkItem->englishKey());
+ elem.setAttribute("description", bookmarkItem->description());
+ elem.setAttribute("modulename", bookmarkItem->m_moduleName);
+ elem.setAttribute("moduledescription", bookmarkItem->module() ? bookmarkItem->module()->config(CSwordModuleInfo::Description) : QString::null);
+ if ( ! bookmarkItem->title().isEmpty()) {
+ elem.setAttribute("title", bookmarkItem->m_title);
+ }
+ parentElement.appendChild(elem);
+ }
+}
diff --git a/src/frontend/bookmarks/btbookmarkloader.h b/src/frontend/bookmarks/btbookmarkloader.h
new file mode 100644
index 0000000..8b819ce
--- /dev/null
+++ b/src/frontend/bookmarks/btbookmarkloader.h
@@ -0,0 +1,46 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2011 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTBOOKMARKLOADER_H
+#define BTBOOKMARKLOADER_H
+
+#include "util/directory.h"
+
+#include <QDomElement>
+#include <QList>
+#include <QString>
+
+
+class QTreeWidgetItem;
+
+/**
+* Class for loading and saving bookmarks.
+*/
+class BtBookmarkLoader {
+ public:
+ /** Loads a list of items (with subitem trees) from a named file
+ * or from the default bookmarks file. */
+ QList<QTreeWidgetItem*> loadTree(QString fileName = QString::null);
+
+ /** Takes one item and saves the tree which is under it to a named file
+ * or to the default bookmarks file, asking the user about overwriting if necessary. */
+ void saveTreeFromRootItem(QTreeWidgetItem* rootItem, QString fileName = QString::null, bool forceOverwrite = true);
+
+ private:
+ /** Create a new item from a document element. */
+ QTreeWidgetItem* handleXmlElement(QDomElement& element, QTreeWidgetItem* parent);
+
+ /** Writes one item to a document element. */
+ void saveItem(QTreeWidgetItem* item, QDomElement& parentElement);
+
+ /** Loads a bookmark XML document from a named file or from the default bookmarks file. */
+ QString loadXmlFromFile(QString fileName = QString::null);
+};
+
+#endif
diff --git a/src/frontend/bookmarks/bteditbookmarkdialog.cpp b/src/frontend/bookmarks/bteditbookmarkdialog.cpp
new file mode 100644
index 0000000..614498f
--- /dev/null
+++ b/src/frontend/bookmarks/bteditbookmarkdialog.cpp
@@ -0,0 +1,78 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2011 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "bteditbookmarkdialog.h"
+
+#include <QDialogButtonBox>
+#include <QVBoxLayout>
+#include <QFormLayout>
+#include <QLabel>
+#include <QLineEdit>
+#include <QTextEdit>
+#include <QWidget>
+#include "util/cresmgr.h"
+#include "util/dialogutil.h"
+#include "util/directory.h"
+
+
+BtEditBookmarkDialog::BtEditBookmarkDialog(const QString &key,
+ const QString &title,
+ const QString &description,
+ QWidget *parent,
+ Qt::WindowFlags wflags)
+ : QDialog(parent, wflags)
+{
+ namespace DU = util::directory;
+
+ QVBoxLayout *mainLayout = new QVBoxLayout(this);
+
+ resize(400, 300);
+ setWindowIcon(DU::getIcon(CResMgr::mainIndex::bookmark::icon));
+
+ m_layout = new QFormLayout;
+
+ m_keyLabel = new QLabel(this);
+ m_keyTextLabel = new QLabel(key, this);
+ m_layout->addRow(m_keyLabel, m_keyTextLabel);
+
+ m_titleLabel = new QLabel(this);
+ m_titleEdit = new QLineEdit(title, this);
+ m_layout->addRow(m_titleLabel, m_titleEdit);
+
+ m_descriptionLabel = new QLabel(this);
+ m_descriptionEdit = new QTextEdit(description, this);
+ m_descriptionEdit->setWordWrapMode(QTextOption::WordWrap);
+ m_layout->addRow(m_descriptionLabel, m_descriptionEdit);
+
+ mainLayout->addLayout(m_layout);
+
+ m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel
+ | QDialogButtonBox::NoButton
+ | QDialogButtonBox::Ok,
+ Qt::Horizontal,
+ this);
+ util::prepareDialogBox(m_buttonBox);
+ mainLayout->addWidget(m_buttonBox);
+
+ QObject::connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ QObject::connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+ retranslateUi();
+
+ m_titleEdit->setFocus();
+}
+
+void BtEditBookmarkDialog::retranslateUi() {
+ setWindowTitle(tr("Edit Bookmark"));
+ m_keyLabel->setText(tr("Location:"));
+ m_titleLabel->setText(tr("Title:"));
+ m_descriptionLabel->setText(tr("Description:"));
+
+ /// \todo Add tooltips and what's this texts etc.
+}
diff --git a/src/frontend/bookmarks/bteditbookmarkdialog.h b/src/frontend/bookmarks/bteditbookmarkdialog.h
new file mode 100644
index 0000000..c3455e2
--- /dev/null
+++ b/src/frontend/bookmarks/bteditbookmarkdialog.h
@@ -0,0 +1,62 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2011 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTEDITBOOKMARKDIALOG_H
+#define BTEDITBOOKMARKDIALOG_H
+
+#include <QDialog>
+#include <QLineEdit>
+#include <QTextEdit>
+
+class QDialogButtonBox;
+class QFormLayout;
+class QLabel;
+class QWidget;
+
+/**
+ \brief A dialog box for editing bookmarks.
+*/
+class BtEditBookmarkDialog : public QDialog {
+ Q_OBJECT
+
+ public: /* Methods: */
+ BtEditBookmarkDialog(const QString &key,
+ const QString &title,
+ const QString &description,
+ QWidget *parent = 0,
+ Qt::WindowFlags wflags = Qt::Dialog);
+
+ /**
+ * Returns the description written in the description box.
+ */
+ inline const QString descriptionText() {
+ return m_descriptionEdit->toPlainText();
+ }
+
+ /**
+ * Returns the title written in the title box.
+ */
+ inline const QString titleText() { return m_titleEdit->text(); }
+
+ protected: /* Methods: */
+ void retranslateUi();
+
+ private: /* Fields: */
+ QFormLayout *m_layout;
+ QLabel *m_keyLabel;
+ QLabel *m_keyTextLabel;
+ QLabel *m_titleLabel;
+ QLineEdit *m_titleEdit;
+ QLabel *m_descriptionLabel;
+ QTextEdit *m_descriptionEdit;
+ QDialogButtonBox *m_buttonBox;
+
+};
+
+#endif
diff --git a/src/frontend/bookmarks/cbookmarkindex.cpp b/src/frontend/bookmarks/cbookmarkindex.cpp
new file mode 100644
index 0000000..b6adbfa
--- /dev/null
+++ b/src/frontend/bookmarks/cbookmarkindex.cpp
@@ -0,0 +1,937 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2011 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "frontend/bookmarks/cbookmarkindex.h"
+
+#include <QSharedPointer>
+#include <QAction>
+#include <QApplication>
+#include <QCursor>
+#include <QDebug>
+#include <QDrag>
+#include <QDragLeaveEvent>
+#include <QDragMoveEvent>
+#include <QDropEvent>
+#include <QInputDialog>
+#include <QList>
+#include <QMenu>
+#include <QMouseEvent>
+#include <QPainter>
+#include <QPaintEvent>
+#include <QTimer>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+#include <QToolTip>
+#include "backend/config/cbtconfig.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/referencemanager.h"
+#include "frontend/cdragdrop.h"
+#include "frontend/cinfodisplay.h"
+#include "frontend/cprinter.h"
+#include "frontend/bookmarks/btbookmarkitembase.h"
+#include "frontend/bookmarks/btbookmarkitem.h"
+#include "frontend/bookmarks/btbookmarkfolder.h"
+#include "frontend/bookmarks/btbookmarkloader.h"
+#include "frontend/searchdialog/csearchdialog.h"
+#include "util/cresmgr.h"
+#include "util/tool.h"
+#include "util/directory.h"
+#include "util/dialogutil.h"
+#include "bibletime.h"
+
+
+CBookmarkIndex::CBookmarkIndex(QWidget *parent)
+ : QTreeWidget(parent),
+ m_magTimer(this),
+ m_previousEventItem(0) {
+ setMouseTracking(true);
+ m_magTimer.setSingleShot(true);
+ m_magTimer.setInterval(CBTConfig::get(CBTConfig::magDelay));
+ setContextMenuPolicy(Qt::CustomContextMenu);
+ initView();
+ initConnections();
+ initTree();
+}
+
+CBookmarkIndex::~CBookmarkIndex() {
+ saveBookmarks();
+}
+
+
+/** Initializes the view. */
+void CBookmarkIndex::initView() {
+ //qDebug() << "CBookmarkIndex::initView";
+
+ setHeaderHidden(true);
+
+ setFocusPolicy(Qt::WheelFocus);
+
+ //d'n'd related settings
+ setDragEnabled( true );
+ setAcceptDrops( true );
+ setDragDropMode(QAbstractItemView::DragDrop);
+ viewport()->setAcceptDrops(true);
+ setAutoScroll(true);
+ setAutoExpandDelay(800);
+
+ setItemsExpandable(true);
+ setRootIsDecorated(true);
+ setAllColumnsShowFocus(true);
+ setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+ //setup the popup menu
+ m_popup = new QMenu(viewport());
+ m_popup->setTitle(tr("Bookmarks"));
+
+ m_actions.newFolder = newQAction(tr("New folder"), CResMgr::mainIndex::newFolder::icon, 0, this, SLOT(createNewFolder()), this);
+ m_actions.changeFolder = newQAction(tr("Rename folder"), CResMgr::mainIndex::changeFolder::icon, 0, this, SLOT(changeFolder()), this);
+
+ m_actions.editBookmark = newQAction(tr("Edit bookmark..."), CResMgr::mainIndex::editBookmark::icon, 0, this, SLOT(editBookmark()), this);
+ /// \todo Add icons for sorting bookmarks
+ m_actions.sortFolderBookmarks = newQAction(tr("Sort folder bookmarks..."), QString::null, 0, this, SLOT(sortFolderBookmarks()), this);
+ m_actions.sortAllBookmarks = newQAction(tr("Sort all bookmarks..."), QString::null, 0, this, SLOT(sortAllBookmarks()), this);
+ m_actions.importBookmarks = newQAction(tr("Import to folder..."), CResMgr::mainIndex::importBookmarks::icon, 0, this, SLOT(importBookmarks()), this);
+ m_actions.exportBookmarks = newQAction(tr("Export from folder..."), CResMgr::mainIndex::exportBookmarks::icon, 0, this, SLOT(exportBookmarks()), this);
+ m_actions.printBookmarks = newQAction(tr("Print bookmarks..."), CResMgr::mainIndex::printBookmarks::icon, 0, this, SLOT(printBookmarks()), this);
+
+ m_actions.deleteEntries = newQAction(tr("Remove selected items..."), CResMgr::mainIndex::deleteItems::icon, 0, this, SLOT(deleteEntries()), this);
+
+
+ //fill the popup menu itself
+ m_popup->addAction(m_actions.newFolder);
+ m_popup->addAction(m_actions.changeFolder);
+ QAction* separator = new QAction(this);
+ separator->setSeparator(true);
+ m_popup->addAction(separator);
+ m_popup->addAction(m_actions.editBookmark);
+ m_popup->addAction(m_actions.sortFolderBookmarks);
+ m_popup->addAction(m_actions.sortAllBookmarks);
+ m_popup->addAction(m_actions.importBookmarks);
+ m_popup->addAction(m_actions.exportBookmarks);
+ m_popup->addAction(m_actions.printBookmarks);
+ separator = new QAction(this);
+ separator->setSeparator(true);
+ m_popup->addAction(separator);
+ m_popup->addAction(m_actions.deleteEntries);
+
+ m_bookmarksModified = false;
+ //qDebug() << "CBookmarkIndex::initView end";
+}
+
+/** Convenience function for creating a new QAction.
+* Should be replaced with something better; it was easier to make a new function
+* than to modify all QAction constructors.
+*/
+QAction* CBookmarkIndex::newQAction(const QString& text, const QString& pix, const int /*shortcut*/, const QObject* receiver, const char* slot, QObject* parent) {
+ namespace DU = util::directory;
+ QAction *action;
+ if (pix.isEmpty()) {
+ action = new QAction(text, parent);
+ } else {
+ action = new QAction(DU::getIcon(pix), text, parent);
+ }
+ QObject::connect(action, SIGNAL(triggered()), receiver, slot);
+ return action;
+}
+
+/** Initialize the SIGNAL<->SLOT connections */
+void CBookmarkIndex::initConnections() {
+ //qDebug() << "CBookmarkIndex::initConnections";
+ bool ok;
+ ok = connect(this, SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SLOT(slotExecuted(QTreeWidgetItem*)));
+ Q_ASSERT(ok);
+ ok = connect(this, SIGNAL(customContextMenuRequested(const QPoint&)),
+ SLOT(contextMenu(const QPoint&)));
+ Q_ASSERT(ok);
+ ok = connect(&m_magTimer, SIGNAL(timeout()), this, SLOT(magTimeout()));
+ Q_ASSERT(ok);
+ ok = connect(this, SIGNAL(itemEntered(QTreeWidgetItem*, int)), this, SLOT(slotItemEntered(QTreeWidgetItem*, int)) );
+ Q_ASSERT(ok);
+
+ // Connection to detect changes in the items themselves (e.g. renames,
+ // description changes) so that we can consider saving the bookmarks.
+ connect(this, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(needToSaveBookmarks(QTreeWidgetItem*)) );
+
+ // Connect the bookmark saving timer.
+ bookmarkSaveTimer.setSingleShot(true);
+ connect(&bookmarkSaveTimer, SIGNAL(timeout()), this, SLOT(considerSavingBookmarks()) );
+}
+
+
+/**
+* Hack to get single click and selection working. See slotExecuted.
+*/
+void CBookmarkIndex::mouseReleaseEvent(QMouseEvent* event) {
+ //qDebug() << "CBookmarkIndex::mouseReleaseEvent";
+ m_mouseReleaseEventModifiers = event->modifiers();
+ QTreeWidget::mouseReleaseEvent(event);
+}
+
+/** Called when an item is clicked with mouse or activated with keyboard. */
+void CBookmarkIndex::slotExecuted( QTreeWidgetItem* i ) {
+ qDebug() << "CBookmarkIndex::slotExecuted";
+
+ //HACK: checking the modifier keys from the last mouseReleaseEvent
+ //depends on executing order: mouseReleaseEvent first, then itemClicked signal
+ int modifiers = m_mouseReleaseEventModifiers;
+ m_mouseReleaseEventModifiers = Qt::NoModifier;
+ if (modifiers != Qt::NoModifier) {
+ return;
+ }
+
+ BtBookmarkItemBase* btItem = dynamic_cast<BtBookmarkItemBase*>(i);
+ if (!btItem) {
+ return;
+ }
+
+ BtBookmarkFolder* folderItem = 0;
+ BtBookmarkItem* bookmarkItem = 0;
+ if ((folderItem = dynamic_cast<BtBookmarkFolder*>(btItem))) {
+ i->setExpanded( !i->isExpanded() );
+ }
+ else if (( bookmarkItem = dynamic_cast<BtBookmarkItem*>(btItem) )) { //clicked on a bookmark
+ if (CSwordModuleInfo* mod = bookmarkItem->module()) {
+ QList<CSwordModuleInfo*> modules;
+ modules.append(mod);
+ emit createReadDisplayWindow(modules, bookmarkItem->key());
+ }
+ }
+}
+
+/** Creates a drag mime data object for the current selection. */
+QMimeData* CBookmarkIndex::dragObject() {
+ BTMimeData::ItemList dndItems;
+ BTMimeData* mimeData = new BTMimeData;
+
+ foreach( QTreeWidgetItem* widgetItem, selectedItems() ) {
+ if (!widgetItem)
+ break;
+ if (dynamic_cast<BtBookmarkItemBase*>(widgetItem)) {
+ if (BtBookmarkItem* bookmark = dynamic_cast<BtBookmarkItem*>( widgetItem )) {
+ //take care of bookmarks which have no valid module any more, e.g. if it was uninstalled
+ const QString moduleName = bookmark->module() ? bookmark->module()->name() : QString::null;
+ mimeData->appendBookmark(moduleName, bookmark->key(), bookmark->description());
+ }
+ }
+ }
+ return mimeData;
+}
+
+void CBookmarkIndex::dragEnterEvent( QDragEnterEvent* event ) {
+ //qDebug() << "CBookmarkIndex::dragEnterEvent";
+ setState(QAbstractItemView::DraggingState);
+ QTreeWidget::dragEnterEvent(event);
+ if (event->source() == this || event->mimeData()->hasFormat("BibleTime/Bookmark")) {
+ event->acceptProposedAction();
+ }
+}
+
+
+void CBookmarkIndex::dragMoveEvent( QDragMoveEvent* event ) {
+ //qDebug() << "CBookmarkIndex::dragMoveEvent";
+
+ // do this first, otherwise the event may be ignored
+ QTreeWidget::dragMoveEvent(event);
+
+ event->acceptProposedAction();
+ event->accept();
+
+ // do this to paint the arrow
+ m_dragMovementPosition = event->pos();
+ viewport()->update();
+
+}
+
+void CBookmarkIndex::dragLeaveEvent( QDragLeaveEvent* ) {
+ qDebug() << "CBookmarkIndex::dragLeaveEvent";
+ setState(QAbstractItemView::NoState); // not dragging anymore
+ viewport()->update(); // clear the arrow
+}
+
+
+void CBookmarkIndex::paintEvent(QPaintEvent* event) {
+ namespace DU = util::directory;
+
+ static QPixmap pix;
+ static int halfPixHeight;
+ static bool arrowInitialized = false;
+
+ // Initialize the static variables, including the arrow pixmap
+ if (!arrowInitialized) {
+ arrowInitialized = true;
+ int arrowSize = util::tool::mWidth(this, 1);
+ QString fileName;
+ if (DU::getIconDir().exists("pointing_arrow.svg")) {
+ fileName = DU::getIconDir().filePath("pointing_arrow.svg");
+ }
+ else {
+ if (DU::getIconDir().exists("pointing_arrow.png")) {
+ fileName = DU::getIconDir().filePath("pointing_arrow.png");
+ }
+ else {
+ qWarning() << "Picture file pointing_arrow.svg or .png not found!";
+ }
+ }
+
+ pix = QPixmap(fileName);
+ pix = pix.scaled(arrowSize, arrowSize, Qt::KeepAspectRatioByExpanding);
+ halfPixHeight = pix.height() / 2;
+ }
+
+ // Do the normal painting first
+ QTreeWidget::paintEvent(event);
+
+ // Paint the arrow if the drag is going on
+ if (QAbstractItemView::DraggingState == state()) {
+ bool rtol = QApplication::isRightToLeft();
+
+ QPainter painter(this->viewport());
+ QTreeWidgetItem* item = itemAt(m_dragMovementPosition);
+ bool isFolder = dynamic_cast<BtBookmarkFolder*>(item);
+ bool isBookmark = dynamic_cast<BtBookmarkItem*>(item);
+
+ // Find the place for the arrow
+ QRect rect = visualItemRect(item);
+ int xCoord = rtol ? rect.right() : rect.left();
+ int yCoord;
+ if (isFolder) {
+ if (m_dragMovementPosition.y() > rect.bottom() - (2* rect.height() / 3) ) {
+ yCoord = rect.bottom() - halfPixHeight; // bottom
+ xCoord = rtol ? (xCoord - indentation()) : (xCoord + indentation());
+ }
+ else {
+ yCoord = rect.top() - halfPixHeight - 1; // top
+ }
+
+ }
+ else {
+ if (isBookmark) {
+ if (m_dragMovementPosition.y() > rect.bottom() - rect.height() / 2) {
+ yCoord = rect.bottom() - halfPixHeight; // bottom
+ }
+ else {
+ yCoord = rect.top() - halfPixHeight - 1; // top
+ }
+ }
+ else {
+ if (item) { // the extra item
+ yCoord = rect.top() - halfPixHeight - 1;
+ }
+ else { // empty area
+ rect = visualItemRect(m_extraItem);
+ yCoord = rect.top() - halfPixHeight - 1;
+ xCoord = rtol ? rect.right() : rect.left();
+ }
+ }
+ }
+
+ painter.drawPixmap(xCoord, yCoord, pix);
+ }
+}
+
+
+void CBookmarkIndex::dropEvent( QDropEvent* event ) {
+ qDebug() << "CBookmarkIndex::dropEvent";
+
+ //setState(QAbstractItemView::NoState);
+ // Try to prevent annoying timed autocollapsing. Remember to disconnect before return.
+ QObject::connect(this, SIGNAL(itemCollapsed(QTreeWidgetItem*)), this, SLOT(expandAutoCollapsedItem(QTreeWidgetItem*)));
+ QTreeWidgetItem* item = itemAt(event->pos());
+ QTreeWidgetItem* parentItem = 0;
+ int indexUnderParent = 0;
+
+ // Find the place where the drag is dropped
+ if (item) {
+ qDebug() << "there was item";
+
+ QRect rect = visualItemRect(item);
+ bool isFolder = dynamic_cast<BtBookmarkFolder*>(item);
+ bool isBookmark = dynamic_cast<BtBookmarkItem*>(item);
+
+ if (isFolder) { // item is a folder
+ qDebug() << "item was folder";
+ if (event->pos().y() > rect.bottom() - (2* rect.height() / 3) ) {
+ parentItem = item;
+ }
+ else {
+ parentItem = item->parent();
+ if (!parentItem) {
+ parentItem = invisibleRootItem();
+ }
+ qDebug() << "item:" << item << "parent:" << parentItem;
+ indexUnderParent = parentItem->indexOfChild(item); // before the current folder
+ }
+ }
+ else {
+ if (isBookmark) { // item is a bookmark
+ qDebug() << "item was bookmark";
+ parentItem = item->parent();
+ if (!parentItem) {
+ parentItem = invisibleRootItem();
+ }
+ indexUnderParent = parentItem->indexOfChild(item); // before the current bookmark
+ if (event->pos().y() > rect.bottom() - rect.height() / 2) {
+ indexUnderParent++; // after the current bookmark
+ }
+ }
+ else { // item is the extra item
+ parentItem = item->parent();
+ if (!parentItem) {
+ parentItem = invisibleRootItem();
+ }
+ indexUnderParent = parentItem->indexOfChild(item); // before the current bookmark
+ }
+ }
+
+ }
+ else { // no item under event point: drop to the end
+ qDebug() << "there was no item";
+ parentItem = invisibleRootItem();
+ indexUnderParent = parentItem->childCount() - 1;
+ }
+
+
+ if ( event->source() == this ) {
+ qDebug() << "dropping internal drag";
+ event->accept();
+
+ bool bookmarksOnly = true;
+ bool targetIncluded = false;
+ bool moreThanOneFolder = false;
+
+ QList<QTreeWidgetItem*> newItems = addItemsToDropTree(parentItem, bookmarksOnly, targetIncluded, moreThanOneFolder);
+
+ if (moreThanOneFolder) {
+ QToolTip::showText(QCursor::pos(), tr("Can drop only bookmarks or one folder"));
+ QObject::disconnect(this, SIGNAL(itemCollapsed(QTreeWidgetItem*)), this, SLOT(expandAutoCollapsedItem(QTreeWidgetItem*)));
+ return;
+ }
+ if (targetIncluded) {
+ QToolTip::showText(QCursor::pos(), tr("Can't drop folder into the folder itself or into its subfolder"));
+ QObject::disconnect(this, SIGNAL(itemCollapsed(QTreeWidgetItem*)), this, SLOT(expandAutoCollapsedItem(QTreeWidgetItem*)));
+ return;
+ }
+ // Ask whether to copy or move with a popup menu
+
+ QMenu* dropPopupMenu = new QMenu(this);
+ QAction* copy = dropPopupMenu->addAction(tr("Copy"));
+ QAction* move = dropPopupMenu->addAction(tr("Move"));
+ QAction* dropAction = dropPopupMenu->exec(QCursor::pos());
+ if (dropAction == copy) {
+ qDebug() << "copy";
+ parentItem->insertChildren(indexUnderParent, newItems);
+ // Need this here because the "move" case goes through
+ // "deleteEntries" which has a save call.
+ needToSaveBookmarks();
+ }
+ else {
+ if (dropAction == move) {
+ qDebug() << "move";
+ parentItem->insertChildren(indexUnderParent, newItems);
+ deleteEntries(false);
+ }
+ else {
+ QObject::disconnect(this, SIGNAL(itemCollapsed(QTreeWidgetItem*)),
+ this, SLOT(expandAutoCollapsedItem(QTreeWidgetItem*)));
+ return; // user canceled
+ }
+ }
+ }
+ else {
+ qDebug() << "the source was outside this";
+ createBookmarkFromDrop(event, parentItem, indexUnderParent);
+ }
+ QObject::disconnect(this, SIGNAL(itemCollapsed(QTreeWidgetItem*)), this, SLOT(expandAutoCollapsedItem(QTreeWidgetItem*)));
+ setState(QAbstractItemView::NoState);
+}
+
+
+void CBookmarkIndex::createBookmarkFromDrop(QDropEvent* event, QTreeWidgetItem* parentItem, int indexInParent) {
+ //qDebug() << "CBookmarkIndex::createBookmarkFromDrop";
+ //take the bookmark data from the mime source
+ const BTMimeData* mdata = dynamic_cast<const BTMimeData*>(event->mimeData());
+ if (mdata) {
+ //create the new bookmark
+ QString moduleName = mdata->bookmark().module();
+ QString keyText = mdata->bookmark().key();
+ QString description = mdata->bookmark().description();
+ CSwordModuleInfo *minfo = CSwordBackend::instance()->findModuleByName(moduleName);
+ QString title; // TODO
+
+ QTreeWidgetItem* newItem = new BtBookmarkItem(minfo, keyText, description, title);
+ // connect(newItem, SIGNAL(bookmarkModified()), this, SLOT(needToSaveBookmarks()) );
+ parentItem->insertChild(indexInParent, newItem);
+
+ qDebug() << "Saving in...CBookmarkIndex::createBookmarkFromDrop";
+ needToSaveBookmarks();
+ }
+}
+
+
+/** Load the tree from file */
+void CBookmarkIndex::initTree() {
+ qDebug() << "CBookmarkIndex::initTree";
+ BtBookmarkLoader loader;
+ addTopLevelItems(loader.loadTree());
+
+ // add the invisible extra item at the end
+ m_extraItem = new QTreeWidgetItem();
+ m_extraItem->setFlags(Qt::ItemIsDropEnabled);
+ addTopLevelItem(m_extraItem);
+}
+
+void CBookmarkIndex::slotItemEntered(QTreeWidgetItem* item, int) {
+ qDebug() << "CBookmarkIndex::slotItemEntered";
+ if (item == m_extraItem) {
+ m_extraItem->setText(0, tr("Drag references from text views to this view"));
+ }
+ else {
+ m_extraItem->setText(0, QString::null);
+ }
+}
+
+
+/** Returns the correct QAction object for the given type of action. */
+QAction* CBookmarkIndex::action( BtBookmarkItemBase::MenuAction type ) const {
+ switch (type) {
+ case BtBookmarkItemBase::NewFolder:
+ return m_actions.newFolder;
+ case BtBookmarkItemBase::ChangeFolder:
+ return m_actions.changeFolder;
+
+ case BtBookmarkItemBase::EditBookmark:
+ return m_actions.editBookmark;
+ case BtBookmarkItemBase::SortFolderBookmarks:
+ return m_actions.sortFolderBookmarks;
+ case BtBookmarkItemBase::SortAllBookmarks:
+ return m_actions.sortAllBookmarks;
+ case BtBookmarkItemBase::ImportBookmarks:
+ return m_actions.importBookmarks;
+ case BtBookmarkItemBase::ExportBookmarks:
+ return m_actions.exportBookmarks;
+ case BtBookmarkItemBase::PrintBookmarks:
+ return m_actions.printBookmarks;
+
+ case BtBookmarkItemBase::DeleteEntries:
+ return m_actions.deleteEntries;
+
+ default:
+ return 0;
+ }
+}
+
+/** Shows the context menu at the given position. */
+void CBookmarkIndex::contextMenu(const QPoint& p) {
+ //qDebug() << "CBookmarkIndex::contextMenu";
+ //setup menu entries depending on current selection
+ QTreeWidgetItem* i = itemAt(p);
+ QList<QTreeWidgetItem *> items = selectedItems();
+ //The item which was clicked may not be selected
+ if (i && !items.contains(i) && i != m_extraItem)
+ items.append(i);
+
+ if (items.count() == 0) {
+ //special handling for no selection
+ BtBookmarkItemBase::MenuAction actionType;
+ for (int index = BtBookmarkItemBase::ActionBegin; index <= BtBookmarkItemBase::ActionEnd; ++index) {
+ actionType = static_cast<BtBookmarkItemBase::MenuAction>(index);
+ if (QAction* a = action(actionType)) {
+ switch (index) {
+ //case BtBookmarkItemBase::ExportBookmarks:
+ //case BtBookmarkItemBase::ImportBookmarks:
+ case BtBookmarkItemBase::NewFolder:
+ case BtBookmarkItemBase::SortAllBookmarks:
+ //case BtBookmarkItemBase::PrintBookmarks:
+ a->setEnabled(true);
+ break;
+ default:
+ a->setEnabled(false);
+ }
+ }
+ }
+ }
+ else if (items.count() == 1) {
+ //special handling for one selected item
+
+ BtBookmarkItemBase* item = dynamic_cast<BtBookmarkItemBase*>(items.at(0));
+ BtBookmarkItemBase::MenuAction actionType;
+ for (int index = BtBookmarkItemBase::ActionBegin; index <= BtBookmarkItemBase::ActionEnd; ++index) {
+ actionType = static_cast<BtBookmarkItemBase::MenuAction>(index);
+ if (QAction* a = action(actionType))
+ a->setEnabled( item->enableAction(actionType) );
+ }
+ }
+ else {
+ //first disable all actions
+ BtBookmarkItemBase::MenuAction actionType;
+ for (int index = BtBookmarkItemBase::ActionBegin; index <= BtBookmarkItemBase::ActionEnd; ++index) {
+ actionType = static_cast<BtBookmarkItemBase::MenuAction>(index);
+ if (QAction* a = action(actionType))
+ a->setEnabled(false);
+ }
+ //enable the menu items depending on the types of the selected items.
+ for (int index = BtBookmarkItemBase::ActionBegin; index <= BtBookmarkItemBase::ActionEnd; ++index) {
+ actionType = static_cast<BtBookmarkItemBase::MenuAction>(index);
+ bool enableAction = isMultiAction(actionType);
+ QListIterator<QTreeWidgetItem *> it(items);
+ while (it.hasNext()) {
+ BtBookmarkItemBase* i = dynamic_cast<BtBookmarkItemBase*>(it.next());
+ enableAction = enableAction && i->enableAction(actionType);
+ }
+ if (enableAction) {
+ QAction* a = action(actionType) ;
+ if (i && a)
+ a->setEnabled(enableAction);
+ }
+ }
+ }
+ //finally, open the popup
+ m_popup->exec(mapToGlobal(p));
+ //qDebug() << "CBookmarkIndex::contextMenu end";
+}
+
+/** Adds a new subfolder to the current item. */
+void CBookmarkIndex::createNewFolder() {
+ //qDebug() << "CBookmarkIndex::createNewFolder";
+ QList<QTreeWidgetItem*> selected = selectedItems();
+ if (selected.count() > 0) {
+ BtBookmarkFolder* i = dynamic_cast<BtBookmarkFolder*>(currentItem());
+ if (i) {
+ i->newSubFolder();
+ }
+ }
+ else {
+ // create a top level folder
+ BtBookmarkFolder* newFolder = new BtBookmarkFolder(tr("New folder"));
+ //parentFolder->addChild(newFolder);
+ insertTopLevelItem(topLevelItemCount() - 1, newFolder);
+ newFolder->update();
+ newFolder->rename();
+ }
+ needToSaveBookmarks();
+}
+
+/** Opens a dialog to change the current folder. */
+void CBookmarkIndex::changeFolder() {
+ BtBookmarkFolder* i = dynamic_cast<BtBookmarkFolder*>(currentItem());
+ Q_ASSERT(i);
+ if (i) {
+ i->rename();
+ }
+}
+
+/** Edits the current bookmark. */
+void CBookmarkIndex::editBookmark() {
+ BtBookmarkItem* i = dynamic_cast<BtBookmarkItem*>(currentItem());
+ Q_ASSERT(i);
+
+ if (i) {
+ i->rename();
+ }
+}
+
+/** Sorts the current folder bookmarks. */
+void CBookmarkIndex::sortFolderBookmarks() {
+ BtBookmarkFolder* i = dynamic_cast<BtBookmarkFolder*>(currentItem());
+ Q_ASSERT(i);
+
+ if (i) {
+ i->sortChildren(0, Qt::AscendingOrder);
+ }
+}
+
+/** Sorts all bookmarks. */
+void CBookmarkIndex::sortAllBookmarks() {
+ sortItems(0, Qt::AscendingOrder);
+ int index = indexOfTopLevelItem(m_extraItem);
+ if (index >= 0) {
+ QTreeWidgetItem* item = takeTopLevelItem(index);
+ if (item != 0) {
+ addTopLevelItem(m_extraItem);
+ }
+ }
+}
+
+/** Exports the bookmarks being in the selected folder. */
+void CBookmarkIndex::exportBookmarks() {
+ BtBookmarkFolder* i = dynamic_cast<BtBookmarkFolder*>(currentItem());
+ Q_ASSERT(i);
+
+ if (i) {
+ i->exportBookmarks();
+ }
+}
+
+/** Import bookmarks from a file and add them to the selected folder. */
+void CBookmarkIndex::importBookmarks() {
+ BtBookmarkFolder* i = dynamic_cast<BtBookmarkFolder*>(currentItem());
+ Q_ASSERT(i);
+
+ if (i) {
+ i->importBookmarks();
+ }
+ needToSaveBookmarks();
+}
+
+/** Prints the selected bookmarks. */
+void CBookmarkIndex::printBookmarks() {
+ Printing::CPrinter::KeyTree tree;
+ Printing::CPrinter::KeyTreeItem::Settings settings;
+ settings.keyRenderingFace = Printing::CPrinter::KeyTreeItem::Settings::CompleteShort;
+
+ QList<QTreeWidgetItem*> items;
+ BtBookmarkFolder* bf = dynamic_cast<BtBookmarkFolder*>(currentItem());
+
+ if (bf) {
+ items = bf->getChildList();
+ }
+ else {
+ items = selectedItems();
+ }
+
+ //create a tree of keytreeitems using the bookmark hierarchy.
+ QListIterator<QTreeWidgetItem*> it(items);
+ while (it.hasNext()) {
+ BtBookmarkItem* i = dynamic_cast<BtBookmarkItem*>(it.next());
+ if (i) {
+ qDebug() << "printBookmarks: add to list" << i->key();
+ tree.append( new Printing::CPrinter::KeyTreeItem( i->key(), i->module(), settings ) );
+ }
+ }
+
+ if (items.count() == 0) {
+ qWarning("Tried to print empty bookmark list.");
+ return;
+ }
+ QSharedPointer<Printing::CPrinter> printer(
+ new Printing::CPrinter( this, CBTConfig::getDisplayOptionDefaults(), CBTConfig::getFilterOptionDefaults() )
+ );
+ printer->printKeyTree(tree);
+}
+
+/** Deletes the selected entries. */
+void CBookmarkIndex::deleteEntries(bool confirm) {
+ if (confirm) {
+ if (!selectedItems().count()) {
+ BtBookmarkItemBase* f = dynamic_cast<BtBookmarkItemBase*>(currentItem());
+ if (f) {
+ currentItem()->setSelected(true);
+ }
+ else {
+ return;
+ }
+ }
+
+ if (util::showQuestion(this, tr("Delete Items"),
+ tr("Do you really want to delete the selected items and child-items?"),
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::No )
+ != QMessageBox::Yes) {
+ return;
+ }
+ }
+
+ while (selectedItems().size() > 0) {
+ delete selectedItems().at(0); // deleting all does not work because it may cause double deletion
+ }
+ // Save the bookmarks. One way would be to signal that the bookmarks have
+ // changed emit a signal so that a number of changes may be saved at once.
+ // Another way is to simply save the bookmarks after each change, which can
+ // be inefficient.
+ needToSaveBookmarks();
+}
+
+
+/*
+Reimplementation from QAbstractItemView/QTreeWidget. Takes care of movable items.
+It's easier to use this than to start drag with mouse event handlers.
+The default implementation would drag items, but we don't call it. Instead we create
+a BibleTime mimedata object. It can be dragged and dropped to a text view or somewhere else.
+The internal drag is handled differently, it doesn't use the mimedata (see dropEvent()).
+*/
+void CBookmarkIndex::startDrag(Qt::DropActions) {
+ qDebug() << "CBookmarkIndex::startDrag";
+
+ QMimeData* mData = dragObject(); // create the data which can be used in other widgets
+ QDrag* drag = new QDrag(this);
+ drag->setMimeData(mData);
+ drag->exec();
+
+ viewport()->update(); // because of the arrow
+}
+
+
+
+
+
+
+/* Returns true if more than one entry is supported by this action type. Returns false for actions which support only one entry, e.g. about module etc. */
+bool CBookmarkIndex::isMultiAction( const BtBookmarkItemBase::MenuAction type ) const {
+ switch (type) {
+ case BtBookmarkItemBase::NewFolder:
+ return false;
+ case BtBookmarkItemBase::ChangeFolder:
+ return false;
+
+ case BtBookmarkItemBase::EditBookmark:
+ return false;
+ case BtBookmarkItemBase::SortFolderBookmarks:
+ return false;
+ case BtBookmarkItemBase::SortAllBookmarks:
+ return false;
+ case BtBookmarkItemBase::ImportBookmarks:
+ return false;
+ case BtBookmarkItemBase::ExportBookmarks:
+ return false;
+ case BtBookmarkItemBase::PrintBookmarks:
+ return true;
+
+ case BtBookmarkItemBase::DeleteEntries:
+ return true;
+ }
+
+ return false;
+}
+
+/* Saves the bookmarks to the default bookmarks file. */
+void CBookmarkIndex::saveBookmarks() {
+
+ qDebug() << "CBookmarkIndex::saveBookmarks()";
+ BtBookmarkLoader loader;
+ loader.saveTreeFromRootItem(invisibleRootItem());
+}
+
+void CBookmarkIndex::mouseMoveEvent(QMouseEvent* event) {
+ //qDebug() << "CBookmarkIndex::mouseMoveEvent";
+
+ // Restart the mag timer if we have moved to another item and shift was not pressed.
+ QTreeWidgetItem* itemUnderPointer = itemAt(event->pos());
+ if (itemUnderPointer && (itemUnderPointer != m_previousEventItem) ) {
+ //qDebug() << "CBookmarkIndex::mouseMoveEvent, moved onto another item";
+ if ( !(event->modifiers() & Qt::ShiftModifier)) {
+ m_magTimer.start(); // see the ctor for the timer properties
+ }
+ }
+ m_previousEventItem = itemUnderPointer;
+
+ // Clear the extra item text unless we are on top of it
+ if ( (itemUnderPointer != m_extraItem) && !m_extraItem->text(0).isNull()) {
+ m_extraItem->setText(0, QString::null);
+ }
+
+ QTreeWidget::mouseMoveEvent(event);
+}
+
+void CBookmarkIndex::magTimeout() {
+ //qDebug() << "CBookmarkIndex::magTimeout";
+
+ QTreeWidgetItem* itemUnderPointer = 0;
+ if (underMouse()) {
+ itemUnderPointer = itemAt(mapFromGlobal(QCursor::pos()));
+ }
+ // if the mouse pointer have been over the same item since the timer was started
+ if (itemUnderPointer && (m_previousEventItem == itemUnderPointer)) {
+ BtBookmarkItem* bitem = dynamic_cast<BtBookmarkItem*>(itemUnderPointer);
+ if (bitem) {
+ //qDebug() << "CBookmarkIndex::timerEvent: update the infodisplay";
+ // Update the mag
+ if (bitem->module()) {
+ (BibleTime::instance()->infoDisplay())->setInfo(
+ InfoDisplay::CInfoDisplay::CrossReference,
+ bitem->module()->name() + ":" + bitem->key()
+ );
+ }
+ else {
+ (BibleTime::instance()->infoDisplay())->setInfo(InfoDisplay::CInfoDisplay::Text, tr("The work to which the bookmark points to is not installed."));
+ }
+
+ }
+ }
+}
+
+/*
+Creates a list of new items based on the current selection.
+If there are only bookmarks in the selection they are all included.
+If there is one folder it's included as a deep copy.
+Sets bookmarksOnly=false if it finds a folder.
+Sets targetIncluded=true if the target is in the list.
+Sets moreThanOneFolder=true if selection includes one folder and something more.
+If moreThanOneFolder or targetIncluded is detected the creation of list is stopped
+and the list is incomplete.
+*/
+QList<QTreeWidgetItem*> CBookmarkIndex::addItemsToDropTree(
+ QTreeWidgetItem* target, bool& bookmarksOnly, bool& targetIncluded, bool& moreThanOneFolder) {
+ qDebug() << "CBookmarkIndex::addItemsToDropTree";
+ QList<QTreeWidgetItem*> selectedList = selectedItems();
+ QList<QTreeWidgetItem*> newList;
+
+ foreach(QTreeWidgetItem* item, selectedList) {
+ qDebug() << "go through all items:" << item;
+ if ( BtBookmarkFolder* folder = dynamic_cast<BtBookmarkFolder*>(item)) {
+ bookmarksOnly = false;
+ if (selectedList.count() > 1) { // only one item allowed if a folder is selected
+ qDebug() << "one folder and something else is selected";
+ moreThanOneFolder = true;
+ break;
+ }
+ if (folder->hasDescendant(target)) { // dropping to self or descendand not allowed
+ qDebug() << "addItemsToDropTree: target is included";
+ targetIncluded = true;
+ break;
+ }
+ }
+ else {
+ qDebug() << "append new QTreeWidget item (should be BtBookmarkItem?)";
+ newList.append(new BtBookmarkItem( *(dynamic_cast<BtBookmarkItem*>(item)) ));
+ }
+ }
+ if (!bookmarksOnly && selectedList.count() == 1) {
+ qDebug() << "exactly one folder";
+ BtBookmarkFolder* folder = dynamic_cast<BtBookmarkFolder*>(selectedList.value(0));
+ BtBookmarkFolder* copy = folder->deepCopy();
+ newList.append(copy);
+ }
+ if (!bookmarksOnly && selectedList.count() > 1) {
+ // wrong amount of items
+ qDebug() << "one folder and something else is selected 2";
+ moreThanOneFolder = true;
+ }
+ qDebug() << "return the new list" << newList;
+ return newList;
+}
+
+/// Bookmark saving code. To avoid many saves during a short period of time,
+/// bookmark modification is first noted. Then, after a wait (1.5s), if no more
+/// modifications are made, the bookmarks are saved. The timer is reset when a
+/// new modification is made. The timer bookmarkSaveTimer is set to be oneshot.
+void CBookmarkIndex::needToSaveBookmarks() {
+ qDebug() << "Got signal to save bookmarks!";
+ m_bookmarksModified = true;
+ bookmarkSaveTimer.start(1500); // Only save after 1.5s.
+}
+void CBookmarkIndex::needToSaveBookmarks(QTreeWidgetItem* treeItem) {
+ // Need to test whether the item that changed is not just a display item,
+ // but actually a folder or bookmark.
+ BtBookmarkItemBase* bookmark = dynamic_cast<BtBookmarkItemBase*>(treeItem);
+ if (bookmark) {
+ qDebug() << "Got signal to save bookmarks!";
+ m_bookmarksModified = true;
+ bookmarkSaveTimer.start(1500); // Only save after 1.5s.
+ }
+}
+
+/// Considers saving bookmarks only if they have been modified. This procedure
+/// should be called by the qtimer bookmarkTimer.
+void CBookmarkIndex::considerSavingBookmarks() {
+ qDebug() << "Considering to save bookmarks!";
+ if (m_bookmarksModified) {
+ saveBookmarks();
+ m_bookmarksModified = false;
+ }
+}
+
diff --git a/src/frontend/bookmarks/cbookmarkindex.h b/src/frontend/bookmarks/cbookmarkindex.h
new file mode 100644
index 0000000..2875a5d
--- /dev/null
+++ b/src/frontend/bookmarks/cbookmarkindex.h
@@ -0,0 +1,214 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2011 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CBOOKMARKINDEX_H
+#define CBOOKMARKINDEX_H
+
+#include "frontend/bookmarks/btbookmarkitembase.h"
+
+#include <QList>
+#include <QTimer>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+#include <QToolTip>
+#include "frontend/displaywindow/cdisplaywindow.h"
+
+
+class BTMimeData;
+class CSearchDialog;
+class CSwordModuleInfo;
+class QAction;
+class QDragLeaveEvent;
+class QDragMoveEvent;
+class QDropEvent;
+class QMenu;
+class QMouseEvent;
+class QPaintEvent;
+class QWidget;
+
+/**
+* The widget which manages all bookmarks.
+* @author The BibleTime team
+*/
+class CBookmarkIndex : public QTreeWidget {
+ Q_OBJECT
+ public:
+ CBookmarkIndex(QWidget *parent);
+ virtual ~CBookmarkIndex();
+
+ void initTree();
+
+ /**
+ * Saves the bookmarks to disk
+ */
+ void saveBookmarks();
+
+ signals:
+ /**
+ * Is emitted when a module should be opened,
+ */
+ void createReadDisplayWindow( QList<CSwordModuleInfo*>, const QString& );
+
+ public slots:
+
+ /**
+ * Indicates a need to save the bookmarks.
+ * This is needed to provide a way for a bookmarkitem stored in the
+ * treeWidget to inform us that it has been modified, namely its
+ * description text. It only sets a dirty-bit so we don't execute many
+ * consecutive saves.
+ */
+ void needToSaveBookmarks();
+ void needToSaveBookmarks(QTreeWidgetItem* treeItem);
+
+
+ protected: // Protected methods
+
+ /** A hack to get the modifiers. */
+ virtual void mouseReleaseEvent(QMouseEvent* event);
+
+ /** Needed to paint an drag pointer arrow. */
+ virtual void paintEvent(QPaintEvent* event);
+
+ /** Initialize the SIGNAL<->SLOT connections. */
+ void initConnections();
+
+ /** Returns the drag object for the current selection. */
+ virtual QMimeData* dragObject();
+
+ /**
+ * D'n'd methods are reimplementations from QTreeWidget or its ancestors.
+ * In these we handle creating, moving and copying bookmarks with d'n'd.
+ */
+ virtual void dragEnterEvent( QDragEnterEvent* event );
+ virtual void dragMoveEvent( QDragMoveEvent* event );
+ virtual void dropEvent( QDropEvent* event );
+ virtual void dragLeaveEvent( QDragLeaveEvent* event );
+
+ /** Returns the correct action object for the given type of action. */
+ QAction* action( BtBookmarkItemBase::MenuAction type ) const;
+
+ /** Reimplementation from QAbstractItemView. Takes care of movable items. */
+ virtual void startDrag(Qt::DropActions supportedActions);
+
+
+ /** Handle mouse moving (mag updates) */
+ virtual void mouseMoveEvent(QMouseEvent* event);
+
+
+ protected slots:
+
+ /** Prevents annoying folder collapsing while dropping. */
+ void expandAutoCollapsedItem(QTreeWidgetItem* i) {
+ expandItem(i);
+ }
+
+ /** Is called when an item was clicked or activated. */
+ void slotExecuted( QTreeWidgetItem* );
+
+ /** Shows the context menu at the given position. */
+ void contextMenu(const QPoint&);
+
+ /** Adds a new subfolder to the current item. */
+ void createNewFolder();
+
+ /** Opens a dialog to change the current folder. */
+ void changeFolder();
+
+ /** Exports the bookmarks from the selected folder. */
+ void exportBookmarks();
+
+ /** Changes the current bookmark. */
+ void editBookmark();
+
+ /** Sorts the current folder bookmarks. */
+ void sortFolderBookmarks();
+
+ /** Sorts all bookmarks. */
+ void sortAllBookmarks();
+
+ /** Helps with the extra item. */
+ void slotItemEntered(QTreeWidgetItem*, int);
+
+ /** Import bookmarks from a file and add them to the selected folder. */
+ void importBookmarks();
+
+ /** Deletes the selected entries. */
+ void deleteEntries(bool confirm = true);
+
+ /** Prints the selected bookmarks. */
+ void printBookmarks();
+
+ /** Slot for the mag update timer. */
+ void magTimeout();
+
+ private:
+
+ /** Initializes the view. */
+ void initView();
+
+ /** Convenience function for creating a new action. */
+ QAction* newQAction(const QString& text, const QString& pix, int shortcut, const QObject* receiver, const char* slot, QObject* parent);
+
+ /**
+ * Returns true if more than one entry is supported by this action type.
+ * Returns false for actions which support only one entry.
+ */
+ bool isMultiAction( const BtBookmarkItemBase::MenuAction type ) const;
+
+ /** A helper function for d'n'd which creates a new bookmark item when drop happens. */
+ void createBookmarkFromDrop(QDropEvent* event, QTreeWidgetItem* parentItem, int indexInParent);
+
+ /**
+ * Returns a list of new items created from the selection.
+ * Sets flags which indicate whether the selection was legal for dropping.
+ */
+ QList<QTreeWidgetItem*> addItemsToDropTree(QTreeWidgetItem* target, bool& bookmarksOnly, bool& targetIncluded, bool& moreThanOneFolder);
+
+ struct Actions {
+ QAction* newFolder;
+ QAction* changeFolder;
+
+ QAction* editBookmark;
+ QAction* sortFolderBookmarks;
+ QAction* sortAllBookmarks;
+ QAction* importBookmarks;
+ QAction* exportBookmarks;
+ QAction* printBookmarks;
+
+ QAction* deleteEntries;
+ }
+ m_actions;
+
+ QMenu* m_popup;
+ QTimer m_magTimer;
+ int m_mouseReleaseEventModifiers;
+ QTreeWidgetItem* m_previousEventItem;
+ QPoint m_dragMovementPosition;
+ QPoint m_dragStartPosition;
+ QTreeWidgetItem* m_extraItem;
+
+ // The following is for managing saving bookmarks. It uses a QTimer to
+ // determine whether the bookmarks should be saved. This may seem like
+ // a hassle, but it is to prevent many saves from being executed at a
+ // time.
+
+ /** Flag indicating that bookmarks have been modified. */
+ bool m_bookmarksModified;
+ QTimer bookmarkSaveTimer;
+
+ private slots:
+ /**
+ * Saves the bookmarks.
+ * It checks m_bookmarksModified and resets it at the end. It should be
+ * connected to a timer that periodically calls this. */
+ void considerSavingBookmarks();
+};
+
+#endif