summaryrefslogtreecommitdiff
path: root/src/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend')
-rw-r--r--src/frontend/bookshelfmanager/btconfigdialog.cpp122
-rw-r--r--src/frontend/bookshelfmanager/btconfigdialog.h90
-rw-r--r--src/frontend/bookshelfmanager/btinstallmgr.cpp94
-rw-r--r--src/frontend/bookshelfmanager/btinstallmgr.h75
-rw-r--r--src/frontend/bookshelfmanager/btmodulemanagerdialog.cpp73
-rw-r--r--src/frontend/bookshelfmanager/btmodulemanagerdialog.h43
-rw-r--r--src/frontend/bookshelfmanager/cswordsetupinstallsourcesdialog.cpp184
-rw-r--r--src/frontend/bookshelfmanager/cswordsetupinstallsourcesdialog.h46
-rw-r--r--src/frontend/bookshelfmanager/indexpage/btindexpage.cpp216
-rw-r--r--src/frontend/bookshelfmanager/indexpage/btindexpage.h87
-rw-r--r--src/frontend/bookshelfmanager/installpage/btinstallmodulechooserdialog.cpp232
-rw-r--r--src/frontend/bookshelfmanager/installpage/btinstallmodulechooserdialog.h53
-rw-r--r--src/frontend/bookshelfmanager/installpage/btinstallpage.cpp207
-rw-r--r--src/frontend/bookshelfmanager/installpage/btinstallpage.h66
-rw-r--r--src/frontend/bookshelfmanager/installpage/btinstallpathdialog.cpp170
-rw-r--r--src/frontend/bookshelfmanager/installpage/btinstallpathdialog.h44
-rw-r--r--src/frontend/bookshelfmanager/installpage/btinstallprogressdialog.cpp261
-rw-r--r--src/frontend/bookshelfmanager/installpage/btinstallprogressdialog.h70
-rw-r--r--src/frontend/bookshelfmanager/installpage/btinstallthread.cpp199
-rw-r--r--src/frontend/bookshelfmanager/installpage/btinstallthread.h99
-rw-r--r--src/frontend/bookshelfmanager/installpage/btsourcearea.cpp298
-rw-r--r--src/frontend/bookshelfmanager/installpage/btsourcearea.h97
-rw-r--r--src/frontend/bookshelfmanager/installpage/btsourcewidget.cpp403
-rw-r--r--src/frontend/bookshelfmanager/installpage/btsourcewidget.h86
-rw-r--r--src/frontend/bookshelfmanager/instbackend.cpp280
-rw-r--r--src/frontend/bookshelfmanager/instbackend.h74
-rw-r--r--src/frontend/bookshelfmanager/removepage/btremovepage.cpp229
-rw-r--r--src/frontend/bookshelfmanager/removepage/btremovepage.h67
-rw-r--r--src/frontend/btaboutmoduledialog.cpp45
-rw-r--r--src/frontend/btaboutmoduledialog.h30
-rw-r--r--src/frontend/cdragdrop.cpp57
-rw-r--r--src/frontend/cdragdrop.h85
-rw-r--r--src/frontend/cdragdropmgr.cpp262
-rw-r--r--src/frontend/cdragdropmgr.h160
-rw-r--r--src/frontend/cexportmanager.cpp546
-rw-r--r--src/frontend/cexportmanager.h95
-rw-r--r--src/frontend/cinfodisplay.cpp466
-rw-r--r--src/frontend/cinfodisplay.h71
-rw-r--r--src/frontend/cinputdialog.cpp95
-rw-r--r--src/frontend/cinputdialog.h43
-rw-r--r--src/frontend/cmdiarea.cpp244
-rw-r--r--src/frontend/cmdiarea.h116
-rw-r--r--src/frontend/cmodulechooserdialog.cpp156
-rw-r--r--src/frontend/cmodulechooserdialog.h103
-rw-r--r--src/frontend/cmoduleindexdialog.cpp104
-rw-r--r--src/frontend/cmoduleindexdialog.h61
-rw-r--r--src/frontend/cprinter.cpp136
-rw-r--r--src/frontend/cprinter.h45
-rw-r--r--src/frontend/crossrefrendering.cpp90
-rw-r--r--src/frontend/crossrefrendering.h37
-rw-r--r--src/frontend/display/btcolorwidget.cpp65
-rw-r--r--src/frontend/display/btcolorwidget.h44
-rw-r--r--src/frontend/display/btfontsizewidget.cpp51
-rw-r--r--src/frontend/display/btfontsizewidget.h36
-rw-r--r--src/frontend/display/bthtml.js146
-rw-r--r--src/frontend/display/bthtmlfindtext.cpp106
-rw-r--r--src/frontend/display/bthtmlfindtext.h35
-rw-r--r--src/frontend/display/bthtmlfindtext.ui145
-rw-r--r--src/frontend/display/bthtmljsobject.cpp175
-rw-r--r--src/frontend/display/bthtmljsobject.h60
-rw-r--r--src/frontend/display/bthtmlreaddisplay.cpp364
-rw-r--r--src/frontend/display/bthtmlreaddisplay.h118
-rw-r--r--src/frontend/display/cdisplay.cpp208
-rw-r--r--src/frontend/display/cdisplay.h186
-rw-r--r--src/frontend/display/chtmlwritedisplay.cpp285
-rw-r--r--src/frontend/display/chtmlwritedisplay.h106
-rw-r--r--src/frontend/display/cplainwritedisplay.cpp160
-rw-r--r--src/frontend/display/cplainwritedisplay.h100
-rw-r--r--src/frontend/display/creaddisplay.cpp112
-rw-r--r--src/frontend/display/creaddisplay.h73
-rw-r--r--src/frontend/display/cwritedisplay.cpp21
-rw-r--r--src/frontend/display/cwritedisplay.h51
-rw-r--r--src/frontend/displaywindow/btactioncollection.cpp38
-rw-r--r--src/frontend/displaywindow/btactioncollection.h32
-rw-r--r--src/frontend/displaywindow/bttoolbarpopupaction.cpp51
-rw-r--r--src/frontend/displaywindow/bttoolbarpopupaction.h45
-rw-r--r--src/frontend/displaywindow/cbiblereadwindow.cpp480
-rw-r--r--src/frontend/displaywindow/cbiblereadwindow.h144
-rw-r--r--src/frontend/displaywindow/cbookreadwindow.cpp195
-rw-r--r--src/frontend/displaywindow/cbookreadwindow.h69
-rw-r--r--src/frontend/displaywindow/cbuttons.cpp191
-rw-r--r--src/frontend/displaywindow/cbuttons.h77
-rw-r--r--src/frontend/displaywindow/ccommentaryreadwindow.cpp198
-rw-r--r--src/frontend/displaywindow/ccommentaryreadwindow.h72
-rw-r--r--src/frontend/displaywindow/cdisplaywindow.cpp497
-rw-r--r--src/frontend/displaywindow/cdisplaywindow.h264
-rw-r--r--src/frontend/displaywindow/cdisplaywindowfactory.cpp57
-rw-r--r--src/frontend/displaywindow/cdisplaywindowfactory.h34
-rw-r--r--src/frontend/displaywindow/chtmlwritewindow.cpp163
-rw-r--r--src/frontend/displaywindow/chtmlwritewindow.h75
-rw-r--r--src/frontend/displaywindow/clexiconreadwindow.cpp367
-rw-r--r--src/frontend/displaywindow/clexiconreadwindow.h118
-rw-r--r--src/frontend/displaywindow/cmodulechooserbar.cpp127
-rw-r--r--src/frontend/displaywindow/cmodulechooserbar.h77
-rw-r--r--src/frontend/displaywindow/cmodulechooserbutton.cpp211
-rw-r--r--src/frontend/displaywindow/cmodulechooserbutton.h82
-rw-r--r--src/frontend/displaywindow/cplainwritewindow.cpp183
-rw-r--r--src/frontend/displaywindow/cplainwritewindow.h96
-rw-r--r--src/frontend/displaywindow/creadwindow.cpp205
-rw-r--r--src/frontend/displaywindow/creadwindow.h79
-rw-r--r--src/frontend/displaywindow/cwritewindow.cpp161
-rw-r--r--src/frontend/displaywindow/cwritewindow.h72
-rw-r--r--src/frontend/htmldialogs/btaboutdialog.cpp251
-rw-r--r--src/frontend/htmldialogs/btaboutdialog.h29
-rw-r--r--src/frontend/htmldialogs/bttabhtmldialog.cpp140
-rw-r--r--src/frontend/htmldialogs/bttabhtmldialog.h87
-rw-r--r--src/frontend/keychooser/bthistory.cpp130
-rw-r--r--src/frontend/keychooser/bthistory.h80
-rw-r--r--src/frontend/keychooser/cbookkeychooser.cpp278
-rw-r--r--src/frontend/keychooser/cbookkeychooser.h86
-rw-r--r--src/frontend/keychooser/cbooktreechooser.cpp200
-rw-r--r--src/frontend/keychooser/cbooktreechooser.h87
-rw-r--r--src/frontend/keychooser/ckeychooser.cpp64
-rw-r--r--src/frontend/keychooser/ckeychooser.h115
-rw-r--r--src/frontend/keychooser/ckeychooserwidget.cpp304
-rw-r--r--src/frontend/keychooser/ckeychooserwidget.h171
-rw-r--r--src/frontend/keychooser/clexiconkeychooser.cpp180
-rw-r--r--src/frontend/keychooser/clexiconkeychooser.h86
-rw-r--r--src/frontend/keychooser/cscrollbutton.cpp85
-rw-r--r--src/frontend/keychooser/cscrollbutton.h85
-rw-r--r--src/frontend/keychooser/cscrollerwidgetset.cpp87
-rw-r--r--src/frontend/keychooser/cscrollerwidgetset.h76
-rw-r--r--src/frontend/keychooser/versekeychooser/btdropdownchooserbutton.cpp134
-rw-r--r--src/frontend/keychooser/versekeychooser/btdropdownchooserbutton.h79
-rw-r--r--src/frontend/keychooser/versekeychooser/btversekeymenu.cpp52
-rw-r--r--src/frontend/keychooser/versekeychooser/btversekeymenu.h43
-rw-r--r--src/frontend/keychooser/versekeychooser/cbiblekeychooser.cpp108
-rw-r--r--src/frontend/keychooser/versekeychooser/cbiblekeychooser.h78
-rw-r--r--src/frontend/keychooser/versekeychooser/ckeyreferencewidget.cpp229
-rw-r--r--src/frontend/keychooser/versekeychooser/ckeyreferencewidget.h86
-rw-r--r--src/frontend/mainindex/bookmarks/btbookmarkfolder.cpp150
-rw-r--r--src/frontend/mainindex/bookmarks/btbookmarkfolder.h51
-rw-r--r--src/frontend/mainindex/bookmarks/btbookmarkitem.cpp163
-rw-r--r--src/frontend/mainindex/bookmarks/btbookmarkitem.h67
-rw-r--r--src/frontend/mainindex/bookmarks/btbookmarkitembase.cpp41
-rw-r--r--src/frontend/mainindex/bookmarks/btbookmarkitembase.h63
-rw-r--r--src/frontend/mainindex/bookmarks/btbookmarkloader.cpp174
-rw-r--r--src/frontend/mainindex/bookmarks/btbookmarkloader.h47
-rw-r--r--src/frontend/mainindex/bookmarks/cbookmarkindex.cpp850
-rw-r--r--src/frontend/mainindex/bookmarks/cbookmarkindex.h182
-rw-r--r--src/frontend/mainindex/bookshelf/actionenum.h24
-rw-r--r--src/frontend/mainindex/bookshelf/btindexfolder.cpp19
-rw-r--r--src/frontend/mainindex/bookshelf/btindexfolder.h30
-rw-r--r--src/frontend/mainindex/bookshelf/btindexitem.cpp19
-rw-r--r--src/frontend/mainindex/bookshelf/btindexitem.h45
-rw-r--r--src/frontend/mainindex/bookshelf/btindexmodule.cpp93
-rw-r--r--src/frontend/mainindex/bookshelf/btindexmodule.h39
-rw-r--r--src/frontend/mainindex/bookshelf/cbookshelfindex.cpp722
-rw-r--r--src/frontend/mainindex/bookshelf/cbookshelfindex.h207
-rw-r--r--src/frontend/mainindex/bookshelf/chidemodulechooserdialog.cpp70
-rw-r--r--src/frontend/mainindex/bookshelf/chidemodulechooserdialog.h43
-rw-r--r--src/frontend/mainindex/cmainindex.cpp36
-rw-r--r--src/frontend/mainindex/cmainindex.h57
-rw-r--r--src/frontend/profile/cprofile.cpp433
-rw-r--r--src/frontend/profile/cprofile.h120
-rw-r--r--src/frontend/profile/cprofilemgr.cpp130
-rw-r--r--src/frontend/profile/cprofilemgr.h68
-rw-r--r--src/frontend/profile/cprofilewindow.cpp134
-rw-r--r--src/frontend/profile/cprofilewindow.h126
-rw-r--r--src/frontend/searchdialog/analysis/csearchanalysisdialog.cpp84
-rw-r--r--src/frontend/searchdialog/analysis/csearchanalysisdialog.h58
-rw-r--r--src/frontend/searchdialog/analysis/csearchanalysisitem.cpp169
-rw-r--r--src/frontend/searchdialog/analysis/csearchanalysisitem.h65
-rw-r--r--src/frontend/searchdialog/analysis/csearchanalysislegenditem.cpp84
-rw-r--r--src/frontend/searchdialog/analysis/csearchanalysislegenditem.h35
-rw-r--r--src/frontend/searchdialog/analysis/csearchanalysisscene.cpp292
-rw-r--r--src/frontend/searchdialog/analysis/csearchanalysisscene.h88
-rw-r--r--src/frontend/searchdialog/analysis/csearchanalysisview.cpp50
-rw-r--r--src/frontend/searchdialog/analysis/csearchanalysisview.h54
-rw-r--r--src/frontend/searchdialog/btsearchoptionsarea.cpp530
-rw-r--r--src/frontend/searchdialog/btsearchoptionsarea.h150
-rw-r--r--src/frontend/searchdialog/btsearchresultarea.cpp659
-rw-r--r--src/frontend/searchdialog/btsearchresultarea.h201
-rw-r--r--src/frontend/searchdialog/chistorycombobox.cpp48
-rw-r--r--src/frontend/searchdialog/chistorycombobox.h33
-rw-r--r--src/frontend/searchdialog/cmoduleresultview.cpp297
-rw-r--r--src/frontend/searchdialog/cmoduleresultview.h136
-rw-r--r--src/frontend/searchdialog/crangechooserdialog.cpp330
-rw-r--r--src/frontend/searchdialog/crangechooserdialog.h89
-rw-r--r--src/frontend/searchdialog/csearchdialog.cpp304
-rw-r--r--src/frontend/searchdialog/csearchdialog.h134
-rw-r--r--src/frontend/searchdialog/csearchmodulechooserdialog.cpp61
-rw-r--r--src/frontend/searchdialog/csearchmodulechooserdialog.h44
-rw-r--r--src/frontend/searchdialog/csearchresultview.cpp295
-rw-r--r--src/frontend/searchdialog/csearchresultview.h101
-rw-r--r--src/frontend/settingsdialogs/cacceleratorsettings.cpp.OFF268
-rw-r--r--src/frontend/settingsdialogs/cacceleratorsettings.h.OFF72
-rw-r--r--src/frontend/settingsdialogs/cconfigurationdialog.cpp93
-rw-r--r--src/frontend/settingsdialogs/cconfigurationdialog.h49
-rw-r--r--src/frontend/settingsdialogs/cdisplaysettings.cpp199
-rw-r--r--src/frontend/settingsdialogs/cdisplaysettings.h43
-rw-r--r--src/frontend/settingsdialogs/cfontchooser.cpp359
-rw-r--r--src/frontend/settingsdialogs/cfontchooser.h74
-rw-r--r--src/frontend/settingsdialogs/clanguagesettings.cpp302
-rw-r--r--src/frontend/settingsdialogs/clanguagesettings.h65
-rw-r--r--src/frontend/settingsdialogs/clistwidget.cpp30
-rw-r--r--src/frontend/settingsdialogs/clistwidget.h28
-rw-r--r--src/frontend/settingsdialogs/cswordsettings.cpp423
-rw-r--r--src/frontend/settingsdialogs/cswordsettings.h86
199 files changed, 28234 insertions, 0 deletions
diff --git a/src/frontend/bookshelfmanager/btconfigdialog.cpp b/src/frontend/bookshelfmanager/btconfigdialog.cpp
new file mode 100644
index 0000000..87cb12e
--- /dev/null
+++ b/src/frontend/bookshelfmanager/btconfigdialog.cpp
@@ -0,0 +1,122 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+#include "btconfigdialog.h"
+
+#include "util/directoryutil.h"
+#include "util/ctoolclass.h"
+
+#include <QDialog>
+#include <QStackedWidget>
+#include <QListWidget>
+#include <QListView>
+#include <QListWidgetItem>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QDialogButtonBox>
+#include <QFrame>
+#include <QEvent>
+
+BtConfigDialog::BtConfigDialog(QWidget* parent)
+ : QDialog(parent),
+ m_maxItemWidth(0),
+ m_previousPageIndex(-2)
+{
+ setWindowFlags(Qt::Window);
+ m_contentsList = new QListWidget(this);
+ m_contentsList->setViewMode(QListView::IconMode);
+ m_contentsList->setMovement(QListView::Static);
+
+ m_pageWidget = new QStackedWidget(this);
+ m_pageWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
+
+ QHBoxLayout *mainLayout = new QHBoxLayout;
+ setLayout(mainLayout);
+ mainLayout->addWidget(m_contentsList);
+ m_pageLayout = new QVBoxLayout;
+ mainLayout->addLayout(m_pageLayout);
+
+ m_pageLayout->addWidget(m_pageWidget);
+
+ // Horizontal line
+ QFrame* line = new QFrame();
+ line->setGeometry(QRect(1, 1, 1, 3));
+ line->setFrameShape(QFrame::HLine);
+ line->setFrameShadow(QFrame::Sunken);
+ line->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ m_pageLayout->addWidget(line);
+
+ connect(m_contentsList,
+ SIGNAL(currentRowChanged(int)),
+ this, SLOT(slotChangePage(int))
+ );
+
+}
+
+BtConfigDialog::~BtConfigDialog() {}
+
+void BtConfigDialog::addPage(BtConfigPage* pageWidget)
+{
+ // this is a friend
+ pageWidget->m_parentDialog = this;
+
+ QVBoxLayout* containerLayout = new QVBoxLayout;
+ QLabel* headerLabel = CToolClass::explanationLabel(pageWidget, pageWidget->header(), pageWidget->label());
+ containerLayout->addWidget(headerLabel);
+ containerLayout->addWidget(pageWidget);
+ QWidget* containerWidget = new QWidget(m_pageWidget);
+ containerWidget->setLayout(containerLayout);
+ m_pageWidget->addWidget(containerWidget);
+
+
+ QListWidgetItem* item = new QListWidgetItem(m_contentsList);
+ item->setIcon(util::filesystem::DirectoryUtil::getIcon(pageWidget->iconName()));
+ item->setText(pageWidget->header());
+ item->setTextAlignment(Qt::AlignHCenter);
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+
+ //set the list width - it may bee too wide (if there were no pages) or too narrow
+ if (m_maxItemWidth < m_contentsList->visualItemRect(item).width()) {
+ m_maxItemWidth = m_contentsList->visualItemRect(item).width();
+ m_contentsList->setFixedWidth( m_maxItemWidth + (m_contentsList->frameWidth()*2) );
+ }
+ // all items should has the same width
+ for(int i = 0; i < m_contentsList->count(); ++i) {
+ m_contentsList->item(i)->setSizeHint(QSize(m_maxItemWidth, m_contentsList->visualItemRect(m_contentsList->item(i)).height()) );
+ }
+
+ slotChangePage(m_contentsList->row(item));
+}
+
+void BtConfigDialog::addButtonBox(QDialogButtonBox* box)
+{
+ m_pageLayout->addWidget(box);
+}
+
+BtConfigPage* BtConfigDialog::currentPage()
+{
+ return dynamic_cast<BtConfigPage*>(m_pageWidget->currentWidget());
+}
+
+void BtConfigDialog::slotChangePage(int newIndex)
+{
+ if (m_previousPageIndex != newIndex) {
+ m_previousPageIndex = newIndex;
+ m_contentsList->setCurrentRow(newIndex);
+ m_pageWidget->setCurrentIndex(newIndex);
+ }
+}
+
+
+
+BtConfigPage::BtConfigPage() {}
+
+BtConfigPage::~BtConfigPage() {}
diff --git a/src/frontend/bookshelfmanager/btconfigdialog.h b/src/frontend/bookshelfmanager/btconfigdialog.h
new file mode 100644
index 0000000..7fb3482
--- /dev/null
+++ b/src/frontend/bookshelfmanager/btconfigdialog.h
@@ -0,0 +1,90 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTCONFIGDIALOG_H
+#define BTCONFIGDIALOG_H
+
+
+#include <QDialog>
+#include <QWidget>
+
+#include <QDebug>
+
+class BtConfigPage;
+
+class QListWidgetItem;
+class QListWidget;
+class QStackedWidget;
+class QDialogButtonBox;
+class QVBoxLayout;
+
+/**
+* Base class for configuration dialogs. A dialog which has a page chooser (icons
+* + text) at the left, widget pages and a buttonbox.
+*
+* Usage: add BtConfigPage pages with addPage(), add a button box with addButtonBox().
+* Connect the button box signals. Use setAttribute(Qt::WA_DeleteOnClose) if you want
+* an auto-destroying window.
+*/
+class BtConfigDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ BtConfigDialog(QWidget* parent);
+ virtual ~BtConfigDialog();
+
+ /** Adds a BtConfigPage to the paged widget stack. The new page will be the current page.*/
+ void addPage(BtConfigPage* pageWidget);
+ /** Adds a button box to the lower edge of the dialog. */
+ void addButtonBox(QDialogButtonBox* buttonBox);
+
+ /** Returns the currently selected page. */
+ BtConfigPage* currentPage();
+
+public slots:
+ /** Changes the current page using the given index number. */
+ void slotChangePage(int newIndex);
+
+private:
+ QListWidget* m_contentsList;
+ QStackedWidget* m_pageWidget;
+ QVBoxLayout* m_pageLayout;
+ int m_maxItemWidth;
+ int m_previousPageIndex;
+};
+
+
+
+/**
+* Base class for configuration dialog pages.
+*/
+class BtConfigPage : public QWidget
+{
+ Q_OBJECT
+public:
+ BtConfigPage();
+ virtual ~BtConfigPage();
+
+ /** Implement these to return the correct values.
+ * For example: header(){return tr("General");}
+ */
+ virtual QString iconName() = 0;
+ virtual QString label() = 0;
+ virtual QString header() = 0;
+ BtConfigDialog* parentDialog() {return m_parentDialog;}
+
+private:
+ friend class BtConfigDialog;
+ BtConfigDialog* m_parentDialog;
+
+};
+
+
+#endif
+
diff --git a/src/frontend/bookshelfmanager/btinstallmgr.cpp b/src/frontend/bookshelfmanager/btinstallmgr.cpp
new file mode 100644
index 0000000..d0bc760
--- /dev/null
+++ b/src/frontend/bookshelfmanager/btinstallmgr.cpp
@@ -0,0 +1,94 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//BibleTime includes
+#include "btinstallmgr.h"
+
+#include "frontend/bookshelfmanager/instbackend.h"
+#include "backend/managers/cswordbackend.h"
+
+//Qt includes
+#include <QObject>
+#include <QList>
+#include <QString>
+#include <QStringList>
+
+#include <QDebug>
+
+//sword includes
+#include <installmgr.h>
+#include <ftptrans.h>
+
+using namespace sword;
+
+
+BtInstallMgr::BtInstallMgr()
+ : InstallMgr(instbackend::configPath().toLatin1(), this),
+ m_firstCallOfPreStatus(true)
+{ //use this class also as status reporter
+ qDebug("BtInstallMgr::BtInstallMgr");
+ this->setFTPPassive(true);
+#ifdef SWORD_INTERNET_WARNING
+ // this was in 1.6RC1, removed in RC2. To be removed from here soon - uncomment this and comment out the isUserDisclaimerConfirmed if you need to use RC1.
+ //setUserDisclaimerConfirmed(true);
+#endif
+}
+
+BtInstallMgr::~BtInstallMgr() {
+ //doesn't really help because it only sets a flag
+ terminate(); //make sure to close the connection
+}
+
+#ifdef SWORD_INTERNET_WARNING
+bool BtInstallMgr::isUserDisclaimerConfirmed() const
+{
+ // TODO: Check from config if it's been confirmed with "don't show this anymore" checked.
+ // Create a dialog with the message, checkbox and Continue/Cancel, Cancel as default.
+ return true;
+}
+#endif
+
+void BtInstallMgr::statusUpdate(double dltotal, double dlnow)
+{
+ //qDebug("BtInstallMgr::statusUpdate");
+ if (dlnow > dltotal)
+ dlnow = dltotal;
+
+ int totalPercent = (int)((float)(dlnow + m_completedBytes) / (float)(m_totalBytes) * 100.0);
+
+ if (totalPercent > 100) {
+ totalPercent = 100;
+ }
+ else if (totalPercent < 0) {
+ totalPercent = 0;
+ }
+
+ int filePercent = (int)((float)(dlnow) / (float)(dltotal+1) * 100.0);
+ if (filePercent > 100) {
+ filePercent = 100;
+ }
+ else if (filePercent < 0) {
+ filePercent = 0;
+ }
+ //qApp->processEvents();
+ //qDebug() << "status: total"<<totalPercent<<"file"<<filePercent;
+ emit percentCompleted(totalPercent, filePercent);
+}
+
+
+void BtInstallMgr::preStatus(long totalBytes, long completedBytes, const char* message)
+{
+ if (m_firstCallOfPreStatus) {
+ m_firstCallOfPreStatus = false;
+ emit downloadStarted();
+ }
+ qDebug() << "BtInstallMgr::preStatus:" << (int)totalBytes << "/" << (int)completedBytes << QString(message);
+ m_completedBytes = completedBytes;
+ m_totalBytes = (totalBytes > 0) ? totalBytes : 1; //avoid division by zero
+}
diff --git a/src/frontend/bookshelfmanager/btinstallmgr.h b/src/frontend/bookshelfmanager/btinstallmgr.h
new file mode 100644
index 0000000..5607981
--- /dev/null
+++ b/src/frontend/bookshelfmanager/btinstallmgr.h
@@ -0,0 +1,75 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef NEWBTINSTALLMGR_H
+#define NEWBTINSTALLMGR_H
+
+//sword includes
+#include <installmgr.h>
+#include <ftptrans.h>
+
+//Qt includes
+#include <QObject>
+#include <QList>
+#include <QString>
+#include <QStringList>
+
+class CSwordBackend;
+
+
+typedef QList<sword::InstallSource*> InstallSourceList;
+
+/**
+* Our own reimplementation to provide installation and status bar updates.
+*/
+class BtInstallMgr : public QObject, public sword::InstallMgr, public sword::StatusReporter {
+ Q_OBJECT
+public:
+
+ BtInstallMgr();
+ virtual ~BtInstallMgr();
+
+ /**
+ * Refreshing the source should be cancellable (othewise it might freeze the app if there is
+ * for example something wrong with the network).
+ */
+ void slotRefreshCanceled();
+
+#ifdef SWORD_INTERNET_WARNING
+ /** Re-implemented from sword::InstallMgr. */
+ virtual bool isUserDisclaimerConfirmed() const;
+#endif
+
+protected:
+ /* Reimplementations of methods in StatusReporter */
+ /**
+ * Gets the total and current file status, emits the signal with those values as percents.
+ */
+ virtual void statusUpdate(double dltotal, double dlnow);
+ /**
+ * Called before starting to download each file of the module package.
+ * The sword message is not i18n'ed, it's in the form "Downloading (1 of 6): nt.bzs".
+ * This function is not utilized in the UI ATM.
+ */
+ virtual void preStatus(long totalBytes, long completedBytes, const char *message);
+
+ long m_totalBytes;
+ long m_completedBytes;
+
+private:
+ bool m_firstCallOfPreStatus;
+
+signals:
+ /** Download status. Percent of total and file.*/
+ void percentCompleted( const int, const int);
+ void downloadStarted();
+};
+
+
+#endif
diff --git a/src/frontend/bookshelfmanager/btmodulemanagerdialog.cpp b/src/frontend/bookshelfmanager/btmodulemanagerdialog.cpp
new file mode 100644
index 0000000..5e3dc41
--- /dev/null
+++ b/src/frontend/bookshelfmanager/btmodulemanagerdialog.cpp
@@ -0,0 +1,73 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btmodulemanagerdialog.h"
+
+#include "installpage/btinstallpage.h"
+#include "removepage/btremovepage.h"
+#include "indexpage/btindexpage.h"
+
+#include "util/cpointers.h"
+#include "util/dialogutil.h"
+#include "backend/managers/cswordbackend.h"
+
+#include <QDialogButtonBox>
+
+
+static BtModuleManagerDialog* m_staticModuleManagerDialog = 0;
+
+BtModuleManagerDialog* BtModuleManagerDialog::getInstance(QWidget* parent)
+{
+ if (!m_staticModuleManagerDialog) {
+ m_staticModuleManagerDialog = new BtModuleManagerDialog(parent);
+ };
+ Q_ASSERT(m_staticModuleManagerDialog);
+ return m_staticModuleManagerDialog;
+}
+
+BtModuleManagerDialog::BtModuleManagerDialog(QWidget* parent)
+ : BtConfigDialog(parent)
+{
+ setAttribute(Qt::WA_DeleteOnClose);
+ setWindowTitle(tr("Bookshelf Manager"));
+
+ // Install page
+ BtInstallPage* installPage = new BtInstallPage();
+ addPage(installPage);
+
+ //Uninstall page
+ BtRemovePage* removePage = new BtRemovePage();
+ addPage(removePage);
+
+ //Index page
+ BtIndexPage* indexPage = new BtIndexPage();
+ addPage(indexPage);
+
+ slotChangePage(0);
+
+ // Dialog button (Close)
+ QDialogButtonBox* bbox = new QDialogButtonBox(this);
+ bbox->addButton(QDialogButtonBox::Close);
+ util::prepareDialogBox(bbox);
+ addButtonBox(bbox);
+ connect(bbox, SIGNAL(rejected()), SLOT(close()));
+}
+
+BtModuleManagerDialog::~BtModuleManagerDialog()
+{
+ m_staticModuleManagerDialog = 0;
+}
+
+// The QWidget close() sends close event, so does closing by the window X button.
+void BtModuleManagerDialog::closeEvent(QCloseEvent*)
+{
+ qDebug("BtModuleManagerDialog::closeEvent");
+}
+
+
diff --git a/src/frontend/bookshelfmanager/btmodulemanagerdialog.h b/src/frontend/bookshelfmanager/btmodulemanagerdialog.h
new file mode 100644
index 0000000..52c3e71
--- /dev/null
+++ b/src/frontend/bookshelfmanager/btmodulemanagerdialog.h
@@ -0,0 +1,43 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+#ifndef BTMODULEMANAGERDIALOG_H
+#define BTMODULEMANAGERDIALOG_H
+
+#include "btconfigdialog.h"
+
+class QWidget;
+
+/**
+* The Bookshelf Manager dialog. Includes pages for Install, Remove, Indexes.
+*/
+class BtModuleManagerDialog : public BtConfigDialog
+{
+ Q_OBJECT
+
+public:
+ static BtModuleManagerDialog* getInstance(QWidget* parent);
+
+ ~BtModuleManagerDialog();
+
+
+ //void slotClose();
+protected:
+ /** Reimplementation from QWidget. */
+ virtual void closeEvent(QCloseEvent* event);
+ /** Adds the pages and the button box. */
+ BtModuleManagerDialog(QWidget* parent);
+
+//signals:
+// void swordSetupChanged();
+};
+
+
+#endif
diff --git a/src/frontend/bookshelfmanager/cswordsetupinstallsourcesdialog.cpp b/src/frontend/bookshelfmanager/cswordsetupinstallsourcesdialog.cpp
new file mode 100644
index 0000000..bca32fa
--- /dev/null
+++ b/src/frontend/bookshelfmanager/cswordsetupinstallsourcesdialog.cpp
@@ -0,0 +1,184 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//BT includes
+#include "cswordsetupinstallsourcesdialog.h"
+
+#include "frontend/bookshelfmanager/instbackend.h"
+
+#include <boost/scoped_ptr.hpp>
+
+//Qt includes
+#include <QLayout>
+#include <QLabel>
+#include <QComboBox>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QMessageBox>
+#include <QFileInfo>
+#include <QGridLayout>
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QFileDialog>
+#include <QDir>
+
+
+
+const QString PROTO_FILE( QObject::tr("Local") ); //Local path
+const QString PROTO_FTP( QObject::tr("Remote") ); //Remote path
+
+
+CSwordSetupInstallSourcesDialog::CSwordSetupInstallSourcesDialog(/*QWidget *parent*/)
+ : QDialog()
+{
+ setWindowTitle(tr("New Installation Source"));
+
+ QVBoxLayout* mainLayout = new QVBoxLayout( this );
+ mainLayout->setMargin( 10 );
+ mainLayout->setSpacing( 5 );
+
+ QHBoxLayout *captionLayout = new QHBoxLayout( this );
+ mainLayout->addLayout(captionLayout);
+ QLabel *label = new QLabel( tr("Caption"), this );
+ captionLayout->addWidget( label );
+
+ m_captionEdit = new QLineEdit( this );
+ m_captionEdit->setText("Crosswire Bible Society");
+ captionLayout->addWidget( m_captionEdit );
+
+ mainLayout->addSpacing( 10 );
+
+ QGridLayout* layout = new QGridLayout( this );
+ layout->setSpacing(3);
+ layout->setMargin(3);
+ mainLayout->addLayout(layout);
+ layout->setSpacing( 5 );
+
+ label = new QLabel(tr("Type"), this);
+ layout->addWidget( label, 0, 0);
+
+ m_serverLabel = new QLabel(tr("Server"), this);
+ layout->addWidget( m_serverLabel, 0, 1);
+
+ label = new QLabel(tr("Path"), this);
+ layout->addWidget( label, 0, 2 );
+
+ m_protocolCombo = new QComboBox( this );
+ layout->addWidget(m_protocolCombo, 1, 0);
+ m_protocolCombo->addItem( PROTO_FTP );
+ m_protocolCombo->addItem( PROTO_FILE );
+
+ m_serverEdit = new QLineEdit( this );
+ layout->addWidget( m_serverEdit, 1, 1 );
+ m_serverEdit->setText("ftp.crosswire.org");
+
+ m_pathEdit = new QLineEdit( this );
+ layout->addWidget( m_pathEdit, 1, 2 );
+ m_pathEdit->setText("/pub/sword/raw");
+
+ mainLayout->addSpacing( 10 );
+
+ QHBoxLayout* buttonLayout = new QHBoxLayout( this );
+ mainLayout->addLayout(buttonLayout);
+ buttonLayout->addStretch();
+ QPushButton* okButton = new QPushButton( tr("Ok"), this);
+ QPushButton* discardButton = new QPushButton( tr("Discard"), this);
+ buttonLayout->addWidget( discardButton);
+ buttonLayout->addWidget( okButton);
+ buttonLayout->addStretch();
+
+ connect( okButton, SIGNAL( clicked() ), this, SLOT( slotOk() ) );
+ connect( discardButton, SIGNAL( clicked() ), this, SLOT( reject() ) );
+ connect( m_protocolCombo, SIGNAL( activated(int) ), this, SLOT( slotProtocolChanged() ) );
+
+}
+void CSwordSetupInstallSourcesDialog::slotOk() {
+ //run a few tests to validate the input first
+ if ( m_captionEdit->text().trimmed().isEmpty() ) { //no caption
+ QMessageBox::information( this, tr( "Error" ), tr("Please provide a caption."), QMessageBox::Retry);
+ return;
+ }
+
+ //BTInstallMgr iMgr;
+ //sword::InstallSource is = BTInstallMgr::Tool::RemoteConfig::source( &iMgr, m_captionEdit->text() );
+ sword::InstallSource is = instbackend::source(m_captionEdit->text());
+ if ( (QString)is.caption.c_str() == m_captionEdit->text() ) { //source already exists
+ QMessageBox::information( this, tr( "Error" ),
+ tr("A source with this caption already exists.<br>Please provide a different caption."), QMessageBox::Retry);
+ return;
+ }
+
+ if ( m_protocolCombo->currentText() == PROTO_FTP &&
+ m_serverEdit->text().trimmed().isEmpty() ) { //no server name
+ QMessageBox::information( this, tr( "Error" ), tr("Please provide a server name."), QMessageBox::Retry);
+ return;
+ }
+
+ if ( m_protocolCombo->currentText() == PROTO_FILE) {
+ const QFileInfo fi( m_pathEdit->text() );
+ if (!fi.exists() || !fi.isReadable()) { //no valid and readable path
+ QMessageBox::information( this, tr( "Error" ), tr("Please provide a valid, readable path."), QMessageBox::Retry);
+ return;
+ }
+ else if ( m_pathEdit->text().isEmpty() ) {
+ QMessageBox::information( this, tr( "Error" ), tr("Please provide a path."), QMessageBox::Retry);
+
+ }
+ }
+
+ accept(); //only if nothing else failed
+}
+
+void CSwordSetupInstallSourcesDialog::slotProtocolChanged() {
+ if (m_protocolCombo->currentText() == PROTO_FTP) { //REMOTE
+ m_serverLabel->setEnabled(true);
+ m_serverEdit->setEnabled(true);
+ }
+ else { //LOCAL, no server needed
+ m_serverLabel->setEnabled(false);
+ m_serverEdit->setEnabled(false);
+
+ QString dirname = QFileDialog::getExistingDirectory(this);
+ if (dirname.isEmpty()) {
+ return; // user cancelled
+ }
+ QDir dir(dirname);
+ if (dir.exists()) {
+ m_pathEdit->setText( dir.canonicalPath() );
+ }
+ }
+
+}
+
+sword::InstallSource CSwordSetupInstallSourcesDialog::getSource() {
+
+ boost::scoped_ptr<CSwordSetupInstallSourcesDialog> dlg( new CSwordSetupInstallSourcesDialog() );
+ sword::InstallSource newSource(""); //empty, invalid Source
+
+ if (dlg->exec() == QDialog::Accepted) {
+ if (dlg->m_protocolCombo->currentText() == PROTO_FTP) {
+ newSource.type = "FTP";
+ newSource.source = dlg->m_serverEdit->text().toUtf8();
+
+ //a message to the user would be nice, but we're in message freeze right now (1.5.1)
+ if (dlg->m_serverEdit->text().right(1) == "/") { //remove a trailing slash
+ newSource.source = dlg->m_serverEdit->text().mid(0, dlg->m_serverEdit->text().length()-1).toUtf8();
+ }
+ }
+ else {
+ newSource.type = "DIR";
+ newSource.source = "local";
+ }
+ newSource.caption = dlg->m_captionEdit->text().toUtf8();
+ newSource.directory = dlg->m_pathEdit->text().toUtf8();
+ }
+ return newSource;
+}
+
+
diff --git a/src/frontend/bookshelfmanager/cswordsetupinstallsourcesdialog.h b/src/frontend/bookshelfmanager/cswordsetupinstallsourcesdialog.h
new file mode 100644
index 0000000..47f1973
--- /dev/null
+++ b/src/frontend/bookshelfmanager/cswordsetupinstallsourcesdialog.h
@@ -0,0 +1,46 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+#ifndef CSWORDSETUPINSTALLSOURCESDIALOG_H
+#define CSWORDSETUPINSTALLSOURCESDIALOG_H
+
+#include "frontend/bookshelfmanager/btinstallmgr.h"
+
+#include <QDialog>
+
+#include <installmgr.h>
+
+class QLabel;
+class QComboBox;
+class QLineEdit;
+
+
+
+class CSwordSetupInstallSourcesDialog : public QDialog {
+ Q_OBJECT
+
+public:
+ static sword::InstallSource getSource();
+
+protected:
+ CSwordSetupInstallSourcesDialog();
+
+protected slots:
+ void slotOk();
+ void slotProtocolChanged();
+
+private:
+ QLabel *m_serverLabel;
+ QLineEdit *m_captionEdit, *m_serverEdit, *m_pathEdit;
+ QComboBox *m_protocolCombo;
+};
+
+
+#endif //CSWORDSETUPINSTALLSOURCESDIALOG_H
diff --git a/src/frontend/bookshelfmanager/indexpage/btindexpage.cpp b/src/frontend/bookshelfmanager/indexpage/btindexpage.cpp
new file mode 100644
index 0000000..6c45f9c
--- /dev/null
+++ b/src/frontend/bookshelfmanager/indexpage/btindexpage.cpp
@@ -0,0 +1,216 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btindexpage.h"
+
+#include "frontend/cmoduleindexdialog.h"
+#include "backend/config/cbtconfig.h"
+
+#include "util/ctoolclass.h"
+#include "util/cresmgr.h"
+#include "util/cpointers.h"
+#include "util/directoryutil.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/cswordbackend.h"
+
+//Qt includes
+#include <QString>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+#include <QCheckBox>
+#include <QDir>
+#include <QPushButton>
+
+
+BtIndexPage::BtIndexPage()
+ : BtConfigPage()
+{
+
+ QVBoxLayout *vboxLayout;
+ QHBoxLayout *hboxLayout;
+ vboxLayout = new QVBoxLayout(this);
+
+ m_autoDeleteOrphanedIndicesBox = new QCheckBox(this);
+ m_autoDeleteOrphanedIndicesBox->setToolTip(tr("If selected, those indexes which have no corresponding work will be deleted when BibleTime starts"));
+ m_autoDeleteOrphanedIndicesBox->setText(tr("Automatically delete orphaned indexes when BibleTime starts"));
+ vboxLayout->addWidget(m_autoDeleteOrphanedIndicesBox);
+
+ m_moduleList = new QTreeWidget(this);
+ vboxLayout->addWidget(m_moduleList);
+
+ hboxLayout = new QHBoxLayout();
+
+ QSpacerItem *spacerItem = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ hboxLayout->addItem(spacerItem);
+
+ m_deleteButton = new QPushButton(this);
+ m_deleteButton->setToolTip(tr("Delete the selected indexes"));
+ m_deleteButton->setText(tr("Delete"));
+ hboxLayout->addWidget(m_deleteButton);
+
+ m_createButton = new QPushButton(this);
+ m_createButton->setToolTip(tr("Create new indexes for the selected works"));
+ m_createButton->setText(tr("Create..."));
+ hboxLayout->addWidget(m_createButton);
+
+ vboxLayout->addLayout(hboxLayout);
+
+ // configure the list view
+ m_moduleList->setHeaderLabels( (QStringList(tr("Work")) << tr("Index size")) );
+ m_moduleList->setRootIsDecorated(true);
+ m_moduleList->setColumnWidth(0, CToolClass::mWidth(m_moduleList, 20) );
+ //m_moduleList->setTextAlignment(1, Qt::AlignRight); see doc...
+ m_moduleList->setSortingEnabled(false);
+
+ m_autoDeleteOrphanedIndicesBox->setChecked( CBTConfig::get( CBTConfig::autoDeleteOrphanedIndices ) );
+
+ // icons for our buttons
+ m_createButton->setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::bookshelfmgr::indexpage::create_icon));
+ m_deleteButton->setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::bookshelfmgr::indexpage::delete_icon));
+
+ // connect our signals/slots
+ connect(m_createButton, SIGNAL(clicked()), this, SLOT(createIndices()));
+ connect(m_deleteButton, SIGNAL(clicked()), this, SLOT(deleteIndices()));
+ connect(CPointers::backend(), SIGNAL(sigSwordSetupChanged(CSwordBackend::SetupChangedReason)), SLOT(slotSwordSetupChanged()));
+
+ populateModuleList();
+}
+
+BtIndexPage::~BtIndexPage()
+{
+ CBTConfig::set( CBTConfig::autoDeleteOrphanedIndices, m_autoDeleteOrphanedIndicesBox->isChecked() );
+
+}
+QString BtIndexPage::label()
+{
+ return tr("Create new search indexes and delete created indexes for the installed works.");
+}
+QString BtIndexPage::iconName()
+{
+ return CResMgr::bookshelfmgr::indexpage::icon;
+}
+QString BtIndexPage::header()
+{
+ return tr("Search Indexes");
+}
+
+
+/** Populates the module list with installed modules and orphaned indices */
+void BtIndexPage::populateModuleList() {
+ m_moduleList->clear();
+
+ // populate installed modules
+ m_modsWithIndices = new QTreeWidgetItem(m_moduleList);
+ m_modsWithIndices->setText(0, tr("Works with indexes"));
+ m_modsWithIndices->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate);
+ m_modsWithIndices->setExpanded(true);
+
+ m_modsWithoutIndices = new QTreeWidgetItem(m_moduleList);
+ m_modsWithoutIndices->setText(0, tr("Works without indexes"));
+ m_modsWithoutIndices->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate);
+ m_modsWithoutIndices->setExpanded(true);
+
+
+
+ QList<CSwordModuleInfo*>& modules = CPointers::backend()->moduleList();
+ QList<CSwordModuleInfo*>::iterator end_it = modules.end();
+ for (QList<CSwordModuleInfo*>::iterator it = modules.begin(); it != end_it; ++it) {
+ QTreeWidgetItem* item = 0;
+
+ if ((*it)->hasIndex()) {
+ item = new QTreeWidgetItem(m_modsWithIndices);
+ item->setText(0, (*it)->name());
+ item->setText(1, QString("%1 ").arg((*it)->indexSize() / 1024) + tr("KiB"));
+ item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
+ item->setCheckState(0, Qt::Unchecked);
+ }
+ else {
+ item = new QTreeWidgetItem(m_modsWithoutIndices);
+ item->setText(0, (*it)->name());
+ item->setText(1, QString("0 ") + tr("KiB"));
+ item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
+ item->setCheckState(0, Qt::Checked);
+ }
+ }
+}
+
+/** Creates indices for selected modules if no index currently exists */
+void BtIndexPage::createIndices()
+{
+ bool indicesCreated = false;
+ QList<CSwordModuleInfo*> moduleList;
+
+ for (int i = 0; i < m_modsWithoutIndices->childCount(); i++) {
+ if (m_modsWithoutIndices->child(i)->checkState(0) == Qt::Checked) {
+ CSwordModuleInfo* module = CPointers::backend()->findModuleByName(m_modsWithoutIndices->child(i)->text(0).toUtf8());
+ if (module) {
+ moduleList.append( module );
+ indicesCreated = true;
+ }
+ }
+ }
+
+ //Shows the progress dialog
+ if (indicesCreated) {
+ CModuleIndexDialog::getInstance()->indexAllModules( moduleList );
+ populateModuleList();
+ }
+}
+
+/** Deletes indices for selected modules */
+void BtIndexPage::deleteIndices()
+{
+ bool indicesDeleted = false;
+
+ for (int i = 0; i < m_modsWithIndices->childCount(); i++) {
+ if (m_modsWithIndices->child(i)->checkState(0) == Qt::Checked) {
+ CSwordModuleInfo* module = CPointers::backend()->findModuleByName(m_modsWithIndices->child(i)->text(0).toUtf8());
+ if (module) {
+ CSwordModuleInfo::deleteIndexForModule( module->name() );
+ indicesDeleted = true;
+ }
+ }
+ }
+
+ // repopulate the list if an action was taken
+ if (indicesDeleted) {
+ populateModuleList();
+ }
+}
+
+void BtIndexPage::deleteOrphanedIndices()
+{
+ QDir dir(CSwordModuleInfo::getGlobalBaseIndexLocation());
+ dir.setFilter(QDir::Dirs);
+ CSwordModuleInfo* module;
+
+ for (unsigned int i = 0; i < dir.count(); i++) {
+ if (dir[i] != "." && dir[i] != "..") {
+ if ( (module = CPointers::backend()->findModuleByName(dir[i])) ) { //mod exists
+ if (!module->hasIndex()){ //index files found, but wrong version etc.
+ CSwordModuleInfo::deleteIndexForModule( dir[i] );
+ }
+ }
+ else{ //no module exists
+ if (CBTConfig::get( CBTConfig::autoDeleteOrphanedIndices ) ){
+ CSwordModuleInfo::deleteIndexForModule( dir[i] );
+ }
+ }
+ }
+ }
+}
+
+void BtIndexPage::slotSwordSetupChanged()
+{
+ populateModuleList();
+}
+
diff --git a/src/frontend/bookshelfmanager/indexpage/btindexpage.h b/src/frontend/bookshelfmanager/indexpage/btindexpage.h
new file mode 100644
index 0000000..d8b49c4
--- /dev/null
+++ b/src/frontend/bookshelfmanager/indexpage/btindexpage.h
@@ -0,0 +1,87 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+#ifndef BTINDEXPAGE_H
+#define BTINDEXPAGE_H
+
+#include "frontend/bookshelfmanager/btconfigdialog.h"
+#include "backend/btmoduletreeitem.h"
+
+class QCheckBox;
+class QTreeWidget;
+class QTreeWidgetItem;
+
+/**
+* This class encapsulates the "Manage search indices" page of the Bookshelf
+* Manager. It allows for creation and deletion of search indicies for each
+* installed module. It also allows for deletion of orphaned indices.
+*/
+class BtIndexPage : public BtConfigPage
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor
+ */
+ BtIndexPage();
+
+ /**
+ * Destructor
+ */
+ ~BtIndexPage();
+
+ // BtConfigPage methods
+ QString header();
+ QString iconName();
+ QString label();
+
+public slots:
+ void slotSwordSetupChanged();
+
+protected:
+
+ /**
+ * Populates the module list with installed modules and orphaned indices
+ */
+ void populateModuleList();
+
+
+
+public slots:
+ /**
+ * Creates indices for selected modules if no index currently exists
+ */
+ void createIndices();
+ /**
+ * Deletes indices for selected modules
+ */
+ void deleteIndices();
+
+public:
+ /**
+ * Deletes orphaned indices if the autoDeleteOrphanedIndices is true
+ * Always deletes indices of existing modules where hasIndex() returns false
+ */
+ static void deleteOrphanedIndices();
+
+private:
+
+ QCheckBox *m_autoDeleteOrphanedIndicesBox;
+ QTreeWidget *m_moduleList;
+ QPushButton *m_deleteButton;
+ QPushButton *m_createButton;
+
+ QTreeWidgetItem* m_modsWithIndices;
+ QTreeWidgetItem* m_modsWithoutIndices;
+};
+
+
+#endif
diff --git a/src/frontend/bookshelfmanager/installpage/btinstallmodulechooserdialog.cpp b/src/frontend/bookshelfmanager/installpage/btinstallmodulechooserdialog.cpp
new file mode 100644
index 0000000..739d2ea
--- /dev/null
+++ b/src/frontend/bookshelfmanager/installpage/btinstallmodulechooserdialog.cpp
@@ -0,0 +1,232 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btinstallmodulechooserdialog.h"
+
+#include "frontend/cmodulechooserdialog.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/btmoduletreeitem.h"
+
+#include <QString>
+#include <QList>
+#include <QWidget>
+#include <QString>
+#include <QTreeWidgetItem>
+#include <QBrush>
+#include <QPushButton>
+
+#include <QDebug>
+
+
+BtInstallModuleChooserDialog::BtInstallModuleChooserDialog(QWidget* parent, QString title, QString label, QList<CSwordModuleInfo*>* empty)
+ : CModuleChooserDialog(parent, title, label, empty)
+{
+ qDebug("BtInstallModuleChooserDialog::BtInstallModuleChooserDialog start");
+ init();
+ okButton()->setText(tr("Install"));
+ m_nameList = QStringList();
+}
+
+// Do nothing, the tree is initialized outside this class.
+void BtInstallModuleChooserDialog::initModuleItem(BTModuleTreeItem*, QTreeWidgetItem*)
+{}
+
+void BtInstallModuleChooserDialog::initModuleItem(QString name, QTreeWidgetItem* sourceItem)
+{
+ QTreeWidgetItem* moduleItem = new QTreeWidgetItem(sourceItem);
+ moduleItem->setText(0, name);
+ moduleItem->setFlags(Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);
+ moduleItem->setCheckState(0, Qt::Checked);
+
+ // prevent double items
+ if (m_nameList.contains(name)) {
+ qDebug() << "item already in list:" << name;
+ //moduleItem->setCheckState(0, Qt::Unchecked);
+ QBrush bg(Qt::red);
+ moduleItem->setBackground(0, bg);
+ //find and change the other offending items
+ foreach (QTreeWidgetItem* doubleItem, treeWidget()->findItems(name, Qt::MatchFixedString|Qt::MatchCaseSensitive|Qt::MatchRecursive, 0)) {
+ //doubleItem->setCheckState(0, Qt::Unchecked);
+ //qDebug() << "CInstallModuleChooserDialog::initModuleItem" << doubleItem;
+ doubleItem->setBackground(0, bg);
+ }
+ m_doubleCheckedModules[name] = true;
+ enableOk(false);
+ }
+ m_nameList << name;
+}
+
+void BtInstallModuleChooserDialog::slotItemChecked(QTreeWidgetItem* item, int column)
+{
+ QString moduleName = item->text(0);
+ qDebug("BtInstallModuleChooserDialog::slotItemChecked start");
+ // handle only non-toplevel items which has duplicates and where the first column was changed
+ if (item->parent() && column == 0 && (findModuleItemsByName(moduleName).count() > 1)) {
+ //prevent handling when the color is changed
+ if (item->data(1, Qt::UserRole).toBool() == false) {
+ qDebug("was not updating");
+ item->setData(1, Qt::UserRole, true);
+ } else {
+ qDebug("was updating");
+ item->setData(1, Qt::UserRole, false);
+ return;
+ }
+
+ QList<QTreeWidgetItem*> doubleNameItems = findModuleItemsByName(moduleName);
+ QList<QTreeWidgetItem*> doubleCheckedItems;
+ foreach (QTreeWidgetItem* nItem, doubleNameItems) {
+ if (nItem->checkState(0) == Qt::Checked) {
+ doubleCheckedItems << nItem;
+ }
+ }
+
+ if (doubleCheckedItems.count() > 1) {
+ enableOk(false);
+ // color the items
+ qDebug() << "there were more than 1 item of the name" << moduleName;
+ foreach (QTreeWidgetItem* i, doubleNameItems) {
+ QBrush bg(Qt::red);
+ i->setBackground(0, bg);
+ }
+ m_doubleCheckedModules[moduleName] = true;
+ } else if (doubleCheckedItems.count() == 1) {
+ qDebug() << "there were 1 checked items of the name" << moduleName;
+ // uncolor the items
+ foreach (QTreeWidgetItem* i, doubleNameItems) {
+ i->setBackground(0, i->parent()->background(0));
+ }
+ m_doubleCheckedModules.remove(moduleName);
+ if (m_doubleCheckedModules.count() == 0) {
+ enableOk(true);
+ }
+ }
+ }
+}
+
+QList<QTreeWidgetItem*> BtInstallModuleChooserDialog::findModuleItemsByName(QString name)
+{
+ qDebug() << "BtInstallModuleChooserDialog::findModuleItemsByName:" << name << treeWidget()->topLevelItemCount();
+ QList<QTreeWidgetItem*> doubleNamedAllItems = treeWidget()->findItems(name, Qt::MatchFixedString|Qt::MatchCaseSensitive|Qt::MatchRecursive);
+ //qDebug() << "doubleNamedAllItems: " << doubleNamedAllItems.count();
+ QList<QTreeWidgetItem*> doubleNamedModuleItems;
+ foreach (QTreeWidgetItem* item, doubleNamedAllItems) {
+ //qDebug() << "item:" << item;
+ if (item->parent()) {
+ doubleNamedModuleItems << item;
+ }
+ }
+ //qDebug() << "module items:" << doubleNamedModuleItems.count();
+ return doubleNamedModuleItems;
+}
+
+void BtInstallModuleChooserDialog::enableOk(bool enabled)
+{
+ qDebug() << "BtInstallModuleChooserDialog::enableOk" << enabled;
+ okButton()->setEnabled(enabled);
+}
diff --git a/src/frontend/bookshelfmanager/installpage/btinstallmodulechooserdialog.h b/src/frontend/bookshelfmanager/installpage/btinstallmodulechooserdialog.h
new file mode 100644
index 0000000..39b8a96
--- /dev/null
+++ b/src/frontend/bookshelfmanager/installpage/btinstallmodulechooserdialog.h
@@ -0,0 +1,53 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTINSTALLMODULECHOOSERDIALOG_H
+#define BTINSTALLMODULECHOOSERDIALOG_H
+
+#include "frontend/cmodulechooserdialog.h"
+
+#include <QObject>
+#include <QString>
+#include <QMap>
+#include <QList>
+
+class BTModuleTreeItem;
+
+class QWidget;
+class QTreeWidgetItem;
+
+
+/**
+* Confirmation dialog for installation. Lets the user
+* uncheck modules from the list.
+*/
+class BtInstallModuleChooserDialog : public CModuleChooserDialog
+{
+ Q_OBJECT
+
+public:
+ BtInstallModuleChooserDialog(QWidget* parent, QString title, QString label, QList<CSwordModuleInfo*>* empty);
+
+ void initModuleItem(QString name, QTreeWidgetItem* sourceItem);
+ void enableOk(bool enabled);
+
+public slots:
+ void slotItemChecked(QTreeWidgetItem* item, int column);
+
+protected:
+ virtual void initModuleItem(BTModuleTreeItem*, QTreeWidgetItem*);
+
+ QList<QTreeWidgetItem*> findModuleItemsByName(QString name);
+private:
+ QStringList m_nameList;
+ QMap<QString, bool> m_doubleCheckedModules;
+
+};
+
+#endif
diff --git a/src/frontend/bookshelfmanager/installpage/btinstallpage.cpp b/src/frontend/bookshelfmanager/installpage/btinstallpage.cpp
new file mode 100644
index 0000000..9f8e6b9
--- /dev/null
+++ b/src/frontend/bookshelfmanager/installpage/btinstallpage.cpp
@@ -0,0 +1,207 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+#include "btinstallpage.h"
+
+#include "btinstallpathdialog.h"
+#include "btinstallprogressdialog.h"
+#include "btsourcewidget.h"
+#include "btsourcearea.h"
+
+#include "frontend/bookshelfmanager/btinstallmgr.h"
+#include "frontend/bookshelfmanager/cswordsetupinstallsourcesdialog.h"
+#include "frontend/bookshelfmanager/btconfigdialog.h"
+#include "frontend/bookshelfmanager/instbackend.h"
+#include "frontend/bookshelfmanager/btmodulemanagerdialog.h"
+
+#include "frontend/cmodulechooserdialog.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/cswordbackend.h"
+#include "backend/config/cbtconfig.h"
+
+#include "util/cpointers.h"
+#include "util/ctoolclass.h"
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+
+#include <boost/scoped_ptr.hpp>
+
+
+#include <QAction>
+#include <QApplication>
+#include <QWidget>
+#include <QButtonGroup>
+#include <QComboBox>
+#include <QDialog>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QPushButton>
+#include <QToolButton>
+#include <QSpacerItem>
+#include <QTabBar>
+#include <QStackedWidget>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+#include <QVBoxLayout>
+#include <QFileInfo>
+#include <QMessageBox>
+#include <QProgressDialog>
+#include <QTimer>
+#include <QProgressBar>
+
+#include <QHeaderView>
+
+#include <swversion.h>
+
+
+// *********************************************************
+// *********** Config dialog page: Install/Update **********
+// *********************************************************
+
+BtInstallPage::BtInstallPage()
+ : BtConfigPage()
+{
+ qDebug("BtInstallPage::BtInstallPage() start");
+ initView();
+ initConnections();
+}
+
+void BtInstallPage::setInstallEnabled(bool b)
+{
+ qDebug("void BtInstallPage::setInstallEnabled(bool b) start");
+ m_installButton->setEnabled(b);
+}
+
+QString BtInstallPage::selectedInstallPath()
+{
+ return m_pathCombo->currentText();
+}
+
+void BtInstallPage::initView()
+{
+ qDebug("void BtInstallPage::initView() start");
+ QVBoxLayout *mainLayout = new QVBoxLayout(this);
+
+ // installation path chooser
+ QHBoxLayout* pathLayout = new QHBoxLayout();
+ // beautify the layout
+ int top; int bottom; int left; int right;
+ pathLayout->getContentsMargins(&left, &top, &right, &bottom);
+ pathLayout->setContentsMargins(left, top + 7, right, bottom + 7 );
+ QSpacerItem *pathSpacer= new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ QLabel* pathLabel = new QLabel(tr("Install path:"));
+ m_pathCombo = new QComboBox();
+ m_pathCombo->setToolTip(tr("The path where the new works will be installed"));
+ initPathCombo(); // set the paths and the current path
+ //m_configurePathButton = new QPushButton(tr("Configure...")); //TODO: icon only?
+ m_configurePathButton = new QToolButton(this);
+ m_configurePathButton->setToolTip(tr("Configure paths where works are installed"));
+ m_configurePathButton->setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::bookshelfmgr::installpage::path_icon));
+
+ pathLayout->addItem(pathSpacer);
+ pathLayout->addWidget(pathLabel);
+ pathLayout->addWidget(m_pathCombo);
+ pathLayout->addWidget(m_configurePathButton);
+ mainLayout->addLayout(pathLayout);
+
+ // Source widget
+ //QTabWidget* m_sourcesTabWidget;
+ m_sourceWidget = new BtSourceWidget(this);
+ mainLayout->addWidget(m_sourceWidget);
+ // Install button
+ QHBoxLayout *installButtonLayout = new QHBoxLayout();
+ installButtonLayout->setContentsMargins(0,5,0,5);
+ QSpacerItem *installButtonSpacer = new QSpacerItem(371, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ installButtonLayout->addItem(installButtonSpacer);
+ m_installButton = new QPushButton(tr("Install..."), this);
+ m_installButton->setToolTip(tr("Install or update selected works"));
+ m_installButton->setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::bookshelfmgr::installpage::install_icon));
+ m_installButton->setEnabled(false);
+ installButtonLayout->addWidget(m_installButton);
+
+ mainLayout->addLayout(installButtonLayout);
+}
+
+void BtInstallPage::initConnections()
+{
+ qDebug("void BtInstallPage::initConnections() start");
+ QObject::connect(m_pathCombo, SIGNAL(activated(const QString&)), this , SLOT(slotPathChanged(const QString&)));
+ QObject::connect(m_configurePathButton, SIGNAL(clicked()), this, SLOT(slotEditPaths()));
+ QObject::connect(m_installButton, SIGNAL(clicked()), m_sourceWidget, SLOT(slotInstall()) );
+
+ QObject::connect(CPointers::backend(), SIGNAL(sigSwordSetupChanged(CSwordBackend::SetupChangedReason)), this, SLOT(slotSwordSetupChanged()));
+ //source widget has its own connections, not here
+}
+
+void BtInstallPage::initPathCombo()
+{
+ qDebug("void BtInstallPage::initPathCombo() start");
+ //populate the combo list
+ m_pathCombo->clear();
+
+ QStringList targets = instbackend::targetList();
+ for (QStringList::iterator it = targets.begin(); it != targets.end(); ++it) {
+ if ((*it).isEmpty()) continue;
+ m_pathCombo->addItem(*it);
+ }
+
+ // choose the current value from config but check whether we have so many items
+ int configValue = CBTConfig::get(CBTConfig::installPathIndex);
+ int index = configValue > (m_pathCombo->count()-1) ? m_pathCombo->count()-1 : configValue;
+ m_pathCombo->setCurrentIndex(index);
+}
+
+void BtInstallPage::slotPathChanged(const QString& /*pathText*/)
+{
+ CBTConfig::set(CBTConfig::installPathIndex, m_pathCombo->currentIndex( ) );
+}
+
+void BtInstallPage::slotEditPaths()
+{
+ qDebug("void BtInstallPage::slotEditPaths() start");
+
+ BtInstallPathDialog* dlg = new BtInstallPathDialog();
+ int result = dlg->exec();
+ if (result == QDialog::Accepted) {
+ //dynamic_cast<BtModuleManagerDialog*>(parentDialog())->slotSwordSetupChanged();
+ CPointers::backend()->reloadModules(CSwordBackend::PathChanged);
+ }
+}
+
+// implement the BtConfigPage methods
+
+QString BtInstallPage::iconName()
+{
+ return CResMgr::bookshelfmgr::installpage::icon;
+}
+QString BtInstallPage::label()
+{
+ // TODO: move the warning to a dialog which is shown when adding a source.
+ return tr("Install and update works. Add remote or local sources, refresh them, select the works to be installed/updated and click Install.<br/><b>WARNING:</b> If you live in a persecuted country and don't want to risk detection don't use remote sources.");
+}
+QString BtInstallPage::header()
+{
+ return tr("Install/Update");
+}
+
+void BtInstallPage::slotSwordSetupChanged()
+{
+ qDebug() << "BtInstallPage::slotSwordSetupChanged";
+ initPathCombo();
+// for (int i = 0; i < m_sourceWidget->count(); i++ ) {
+// BtSourceArea* sourceArea = dynamic_cast<BtSourceArea*>(m_sourceWidget->widget(i));
+// Q_ASSERT(sourceArea);
+// sourceArea->createModuleTree();
+// }
+}
+
+
+
diff --git a/src/frontend/bookshelfmanager/installpage/btinstallpage.h b/src/frontend/bookshelfmanager/installpage/btinstallpage.h
new file mode 100644
index 0000000..4d05577
--- /dev/null
+++ b/src/frontend/bookshelfmanager/installpage/btinstallpage.h
@@ -0,0 +1,66 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTINSTALLPAGE_H
+#define BTINSTALLPAGE_H
+
+
+#include "frontend/bookshelfmanager/btconfigdialog.h"
+
+#include <QString>
+
+#include <installmgr.h>
+
+
+class BtSourceWidget;
+
+class QComboBox;
+class QPushButton;
+class QToolButton;
+
+/**
+* The Install page includes module path chooser, source/module handler and install button.
+*/
+class BtInstallPage : public BtConfigPage
+{
+ Q_OBJECT
+public:
+ BtInstallPage();
+
+ // reimplemented from btinstallpage
+ QString iconName();
+ QString label();
+ QString header();
+
+ void setInstallEnabled(bool b);
+
+ QString selectedInstallPath();
+
+public slots:
+ void slotSwordSetupChanged();
+
+private:
+ void initView();
+ void initConnections();
+ void initPathCombo();
+
+private slots:
+ void slotPathChanged(const QString& pathText);
+ void slotEditPaths();
+
+private:
+
+ QComboBox* m_pathCombo;
+ //QPushButton* m_configurePathButton;
+ QToolButton* m_configurePathButton;
+ BtSourceWidget* m_sourceWidget;
+ QPushButton* m_installButton;
+};
+
+#endif
diff --git a/src/frontend/bookshelfmanager/installpage/btinstallpathdialog.cpp b/src/frontend/bookshelfmanager/installpage/btinstallpathdialog.cpp
new file mode 100644
index 0000000..82b8362
--- /dev/null
+++ b/src/frontend/bookshelfmanager/installpage/btinstallpathdialog.cpp
@@ -0,0 +1,170 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btinstallpathdialog.h"
+
+#include "frontend/bookshelfmanager/instbackend.h"
+
+#include "util/ctoolclass.h"
+#include "util/dialogutil.h"
+#include "util/directoryutil.h"
+#include "util/cresmgr.h"
+
+#include <QString>
+#include <QDialog>
+#include <QDir>
+#include <QGridLayout>
+#include <QLabel>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+#include <QPushButton>
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QHeaderView>
+#include <QDialogButtonBox>
+
+#include <QDebug>
+
+BtInstallPathDialog::BtInstallPathDialog()
+{
+ setWindowTitle(tr("Bookshelf Paths"));
+
+ QVBoxLayout *mainLayout;
+ QHBoxLayout *viewLayout;
+
+ mainLayout = new QVBoxLayout(this);
+ viewLayout = new QHBoxLayout();
+
+ QString l1 = tr("Works can be installed in one or more directories. After setting up directories here you can choose one of them in Install page.");
+ QString l2 = tr("BibleTime and the Sword library find the modules from all of these directories. If the directory is removed here it still exists in the system with all the works in it. \".sword\" directory in your home directory is always used automatically and can't be removed or added.");
+
+ QLabel* mainLabel = CToolClass::explanationLabel(this,
+ tr("Configure bookshelf paths"), l1 + QString("<small><br><br>") + l2 + QString("</small>"));
+ mainLayout->addWidget(mainLabel);
+
+ QString swordConfPath = instbackend::swordConfigFilename();
+ QLabel* confPathLabel = new QLabel(tr("Configuration file for the paths is: ").append("<b>%1</b>").arg(swordConfPath), this);
+ confPathLabel->setWordWrap(true);
+ mainLayout->addWidget(confPathLabel);
+
+
+ m_swordPathListBox = new QTreeWidget(this);
+ m_swordPathListBox->header()->hide();
+
+ QDir swordDir = instbackend::swordDir();
+ QStringList targets = instbackend::targetList();
+ foreach (QString pathname, targets) {
+ if (pathname.isEmpty() || QDir(pathname) == swordDir) continue;
+ new QTreeWidgetItem(m_swordPathListBox, QStringList(pathname) );
+ }
+
+ viewLayout->addWidget(m_swordPathListBox);
+
+ QVBoxLayout* buttonLayout = new QVBoxLayout();
+
+ m_addButton = new QPushButton(tr("Add..."), this);
+ m_addButton->setToolTip(tr("Add new path"));
+ m_addButton->setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::bookshelfmgr::paths::add_icon));
+ connect(m_addButton, SIGNAL(clicked()), this, SLOT(slotAddClicked()));
+ buttonLayout->addWidget(m_addButton);
+
+ m_editButton = new QPushButton(tr("Edit..."), this);
+ m_editButton->setToolTip(tr("Edit the selected path"));
+ m_editButton->setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::bookshelfmgr::paths::edit_icon));
+ connect(m_editButton, SIGNAL(clicked()), this, SLOT(slotEditClicked()));
+ buttonLayout->addWidget(m_editButton);
+
+ m_removeButton = new QPushButton(tr("Remove"), this);
+ m_removeButton->setToolTip(tr("Remove the selected path"));
+ m_removeButton->setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::bookshelfmgr::paths::remove_icon));
+ connect(m_removeButton, SIGNAL(clicked()), this, SLOT(slotRemoveClicked()));
+ buttonLayout->addWidget(m_removeButton);
+
+ QSpacerItem* spacerItem = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
+ buttonLayout->addItem(spacerItem);
+
+ viewLayout->addLayout(buttonLayout);
+ mainLayout->addLayout(viewLayout);
+
+ QDialogButtonBox* buttonBox = new QDialogButtonBox(this);
+ buttonBox->setOrientation(Qt::Horizontal);
+ buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok);
+ util::prepareDialogBox(buttonBox);
+ mainLayout->addWidget(buttonBox);
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+}
+
+void BtInstallPathDialog::slotEditClicked() {
+ if (QTreeWidgetItem* i = m_swordPathListBox->currentItem()) {
+ QString dirname = QFileDialog::getExistingDirectory(this, tr("Choose directory"), i->text(0), QFileDialog::ShowDirsOnly|QFileDialog::DontResolveSymlinks);
+
+ if (dirname.isEmpty()) { // if user cancelled the dialog
+ return;
+ }
+ QDir dir = QDir(dirname);
+ if (dir.isReadable()) {
+ const QFileInfo fi( dir.canonicalPath() );
+ if (!fi.exists() || !fi.isWritable()) {
+ const int result = QMessageBox::warning(this, tr("Use Directory?"), tr("This directory is not writable, so works can not be installed here using BibleTime. Do you want to use this directory instead of the previous value?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
+ if (result != QMessageBox::Yes) return;
+ }
+ i->setText(0, dir.absolutePath()); // absolute, not canonical
+ }
+ }
+}
+
+void BtInstallPathDialog::slotAddClicked() {
+ QString dirname = QFileDialog::getExistingDirectory(this, tr("Choose directory"), "", QFileDialog::ShowDirsOnly|QFileDialog::DontResolveSymlinks);
+ if (dirname.isEmpty()) { // if user cancelled the dialog
+ return;
+ }
+ QDir dir = QDir(dirname);
+ if (dir.isReadable()) {
+ const QFileInfo fi( dir.canonicalPath() );
+ if (!fi.exists() || !fi.isWritable()) {
+ const int result = QMessageBox::warning(this, tr("Warning"), tr("This directory is not writable, so works can not be installed here using BibleTime. Do you still want to add it to the list of bookshelf directories?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
+ if (result != QMessageBox::Yes) {
+ return;
+ }
+ }
+ new QTreeWidgetItem(m_swordPathListBox, QStringList(dir.canonicalPath()) );
+ }
+}
+
+void BtInstallPathDialog::slotRemoveClicked() {
+ QTreeWidgetItem* i = m_swordPathListBox->currentItem();
+ if (i) {
+ delete i;
+ }
+}
+
+void BtInstallPathDialog::writeSwordConfig()
+{
+ qDebug("BtInstallPathDialog::writeSwordConfig");
+ if (m_swordPathListBox->topLevelItemCount() >= 0) {
+ QStringList targets;
+ QTreeWidgetItemIterator it(m_swordPathListBox);
+ while (*it) {
+ if (!(*it)->text(0).isEmpty()) {
+ targets << (*it)->text(0);
+ }
+ ++it;
+ }
+ qDebug() << "save the target list" << targets;
+ instbackend::setTargetList(targets); //creates new Sword config
+ }
+}
+
+void BtInstallPathDialog::accept()
+{
+ writeSwordConfig();
+ QDialog::accept();
+}
diff --git a/src/frontend/bookshelfmanager/installpage/btinstallpathdialog.h b/src/frontend/bookshelfmanager/installpage/btinstallpathdialog.h
new file mode 100644
index 0000000..c3b56ac
--- /dev/null
+++ b/src/frontend/bookshelfmanager/installpage/btinstallpathdialog.h
@@ -0,0 +1,44 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTINSTALLPATHDIALOG_H
+#define BTINSTALLPATHDIALOG_H
+
+#include <QDialog>
+
+class QPushButton;
+class QTreeWidget;
+
+
+class BtInstallPathDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ BtInstallPathDialog();
+
+public slots:
+ virtual void accept();
+
+private slots:
+ void slotAddClicked();
+ void slotRemoveClicked();
+ void slotEditClicked();
+
+private:
+ void writeSwordConfig();
+
+private:
+ QPushButton* m_editButton;
+ QPushButton* m_addButton;
+ QPushButton* m_removeButton;
+ QTreeWidget* m_swordPathListBox;
+
+};
+
+#endif
diff --git a/src/frontend/bookshelfmanager/installpage/btinstallprogressdialog.cpp b/src/frontend/bookshelfmanager/installpage/btinstallprogressdialog.cpp
new file mode 100644
index 0000000..2f60fc9
--- /dev/null
+++ b/src/frontend/bookshelfmanager/installpage/btinstallprogressdialog.cpp
@@ -0,0 +1,261 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btinstallprogressdialog.h"
+
+#include "btinstallthread.h"
+
+#include "util/ctoolclass.h"
+#include "util/cpointers.h"
+#include "backend/managers/cswordbackend.h"
+
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+#include <QDialog>
+#include <QHeaderView>
+#include <QProgressBar>
+#include <QPushButton>
+#include <QVBoxLayout>
+#include <QApplication>
+#include <QCloseEvent>
+#include <QMultiMap>
+
+#include <QDebug>
+
+
+BtInstallProgressDialog::BtInstallProgressDialog(QWidget* parent, QTreeWidget* selectedModulesTreeWidget, QString destination)
+ : QDialog(parent)
+{
+ // we want this dialog to be deleted when user closes it or the downloads are completed
+ setAttribute(Qt::WA_DeleteOnClose, true);
+ setWindowTitle(tr("Install Progress"));
+ //create the dialog which shows the status and lets the user stop installation
+ m_statusWidget = new QTreeWidget();
+ m_statusWidget->setRootIsDecorated(false);
+ m_statusWidget->setHeaderLabels(QStringList(tr("Work")) << tr("Progress") << QString::null);
+ m_statusWidget->header()->setStretchLastSection(false);
+ m_statusWidget->header()->setResizeMode(1, QHeaderView::Stretch);
+ m_statusWidget->header()->setMovable(false);
+ //m_statusWidget->setColumnWidth(1, CToolClass::mWidth(m_statusWidget, 2));
+
+ foreach (QTreeWidgetItem* sourceItem, selectedModulesTreeWidget->invisibleRootItem()->takeChildren()) {
+ // create items and threads for modules under this source
+ foreach (QTreeWidgetItem* moduleItem, sourceItem->takeChildren()) {
+ if (moduleItem->checkState(0) == Qt::Checked) {
+ // create a thread for this module
+ BtInstallThread* thread = new BtInstallThread(this, moduleItem->text(0), sourceItem->text(0), destination);
+ m_waitingThreads.insert(sourceItem->text(0), thread);
+ m_threadsByModule.insert(moduleItem->text(0), thread);
+ // progress widget/item
+ QPushButton* stopButton = new QPushButton(tr("Stop"), m_statusWidget);
+ stopButton->setFixedSize(stopButton->sizeHint());
+
+ // the item
+ QTreeWidgetItem* progressItem = new QTreeWidgetItem(m_statusWidget);
+ m_statusWidget->setColumnWidth(2, stopButton->sizeHint().width());
+ progressItem->setSizeHint(2, stopButton->sizeHint());
+ progressItem->setText(0, moduleItem->text(0));
+ progressItem->setFlags(Qt::ItemIsEnabled);
+ m_statusWidget->setItemWidget(progressItem, 2, stopButton);
+ progressItem->setText(1, tr("Waiting for turn..."));
+
+ //connect the signals between the dialog, items and threads
+ QObject::connect(stopButton, SIGNAL(clicked()), thread, SLOT(slotStopInstall()), Qt::QueuedConnection);
+ QObject::connect(thread, SIGNAL(installStopped(QString, QString)), this, SLOT(slotOneItemStopped(QString, QString)), Qt::QueuedConnection);
+ //is this needed or is statusUpdated enough?
+ QObject::connect(thread, SIGNAL(installCompleted(QString, QString, int)), this, SLOT(slotOneItemCompleted(QString, QString, int)), Qt::QueuedConnection);
+ QObject::connect(thread, SIGNAL(statusUpdated(QString, int)), this, SLOT(slotStatusUpdated(QString, int)), Qt::QueuedConnection);
+ QObject::connect(thread, SIGNAL(downloadStarted(QString)), this, SLOT(slotDownloadStarted(QString)), Qt::QueuedConnection);
+
+ QObject::connect(thread, SIGNAL(preparingInstall(QString, QString)), this, SLOT(slotInstallStarted(QString, QString)), Qt::QueuedConnection);
+
+ }
+ }
+ }
+
+ m_statusWidget->setMinimumWidth(m_statusWidget->size().width());
+ QPushButton* stopAllButton = new QPushButton(tr("Stop All"), this);
+
+ QVBoxLayout* layout = new QVBoxLayout(this);
+ layout->addWidget(m_statusWidget);
+ layout->addWidget(stopAllButton);
+
+ connect(stopAllButton, SIGNAL(clicked()), SLOT(slotStopInstall()) );
+
+ qApp->processEvents();
+
+ startThreads();
+
+}
+
+void BtInstallProgressDialog::startThreads()
+{
+ // remove all the updated modules from the backend module list at once
+ //foreach (QString mName, m_threadsByModule.keys()) {
+ //}
+ //QList<CSwordModuleInfo*> CPointers::backend()->takeModulesFromList(m_threadsByModule.keys());
+ qDebug() << "start threads...";
+ //loop through the multimap of the waiting threads, start at most 3 threads for each source
+ QMultiMap<QString, BtInstallThread*>::iterator threadIterator = m_waitingThreads.end();
+// concurrency is disabled for now
+// while (threadIterator != m_waitingThreads.end()) {
+// QString sourceName = threadIterator.key();
+// qDebug() << sourceName;
+// if (m_runningThreads.values(sourceName).count() < 3) {
+// BtInstallThread* t = threadIterator.value();
+// m_runningThreads.insert(sourceName, t);
+// threadIterator = m_waitingThreads.erase(threadIterator);
+// t->start();
+// }
+// else ++threadIterator;
+// }
+ //non-concurrent
+ if (threadIterator != m_waitingThreads.begin()) {
+ // go to the last item which is actually the first in the visible list
+ // because the iterator is reversed compared to insert order
+ threadIterator--;
+ QString sourceName = threadIterator.key();
+ BtInstallThread* t = threadIterator.value();
+ m_runningThreads.insert(sourceName, t);
+ threadIterator = m_waitingThreads.erase(threadIterator);
+ t->start();
+ }
+
+ qDebug("BtInstallProgressDialog::startThreads end");
+}
+
+BtInstallProgressDialog::~BtInstallProgressDialog()
+{}
+
+
+void BtInstallProgressDialog::slotOneItemCompleted(QString module, QString source, int status)
+{
+ QString message;
+ //status comes from the sword installer. TODO: Additionally we should check that there are files really installed.
+ if (status != 0) {
+ message = tr("Failed");
+ }
+ else {
+ message = tr("Completed");
+ }
+ oneItemStoppedOrCompleted(module, source, message);
+}
+
+void BtInstallProgressDialog::slotOneItemStopped(QString module, QString source)
+{
+ oneItemStoppedOrCompleted(module, source, tr("Cancelled"));
+}
+
+void BtInstallProgressDialog::oneItemStoppedOrCompleted(QString module, QString source, QString statusMessage)
+{
+ qDebug() << "\n**********************************\nBtInstallProgressDialog::oneItemStoppedOrCompleted" << module << statusMessage << "\n******************************************";
+ // update the list item
+ m_statusWidget->setItemWidget(getItem(module), 1, 0);
+ getItem(module)->setText(1, statusMessage);
+ m_statusWidget->itemWidget(getItem(module), 2)->setEnabled(false);
+ getItem(module)->setDisabled(true);
+
+ qDebug() << "remove from threads maps" << source << m_threadsByModule.value(module);
+ m_runningThreads.remove(source, m_threadsByModule.value(module));
+ m_waitingThreads.remove(source, m_threadsByModule.value(module));
+
+//concurrency is disabled for now
+// //start a waiting thread if there are any
+// QList<BtInstallThread*> threadsForSource = m_waitingThreads.values(source);
+// qDebug() << threadsForSource;
+// if (!threadsForSource.isEmpty()) {
+// qDebug() << "Threads are waiting for turn";
+// BtInstallThread* thread = threadsForSource.at(0);
+// m_waitingThreads.remove(source, thread);
+// m_runningThreads.insert(source, thread);
+// thread->start();
+// }
+
+ //non-concurrent
+ QMultiMap<QString, BtInstallThread*>::iterator threadIterator = m_waitingThreads.end();
+ if (m_runningThreads.size() == 0 && threadIterator != m_waitingThreads.begin()) {
+ threadIterator--; // the last item
+ QString sourceName = threadIterator.key();
+ BtInstallThread* t = threadIterator.value();
+ m_runningThreads.insert(sourceName, t);
+ threadIterator = m_waitingThreads.erase(threadIterator);
+ t->start();
+ }
+
+ if (threadsDone()) {
+ qDebug() << "close the dialog";
+ close();
+ }
+}
+
+void BtInstallProgressDialog::slotStopInstall()
+{
+ qDebug("BtInstallProgressDialog::slotStopInstall");
+
+ // Clear the waiting threads map, stop all running threads.
+
+ m_waitingThreads.clear();
+ if (m_runningThreads.count() > 0) {
+ foreach(BtInstallThread* thread, m_runningThreads) {
+ thread->slotStopInstall();
+ }
+ } else {
+ close();
+ }
+}
+
+void BtInstallProgressDialog::slotStatusUpdated(QString module, int status)
+{
+ //qDebug("BtInstallProgressDialog::slotStatusUpdated");
+ //qDebug() << "module:" << module << "status:" << status;
+ // find the progress bar for this module and update the value
+ QWidget* itemWidget = m_statusWidget->itemWidget(getItem(module) , 1);
+ QProgressBar* bar = dynamic_cast<QProgressBar*>(itemWidget);
+ if (bar) bar->setValue(status);
+}
+
+void BtInstallProgressDialog::slotInstallStarted(QString module, QString)
+{
+ getItem(module)->setText(1, tr("Preparing install..."));
+}
+
+void BtInstallProgressDialog::slotDownloadStarted(QString module)
+{
+ qDebug() << "BtInstallProgressDialog::slotDownloadStarted" << module;
+ getItem(module)->setText(1, QString::null);
+ //m_statusWidget->itemWidget(getItem(module), 1)->setVisible(true);
+
+ QProgressBar* bar = new QProgressBar(m_statusWidget);
+ bar->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed);
+ bar->setValue(0);
+ m_statusWidget->setItemWidget(getItem(module), 1, bar);
+}
+
+QTreeWidgetItem* BtInstallProgressDialog::getItem(QString moduleName)
+{
+ //qDebug() << "BtInstallProgressDialog::getItem" << moduleName;
+ return m_statusWidget->findItems(moduleName, Qt::MatchExactly).at(0);
+}
+
+void BtInstallProgressDialog::closeEvent(QCloseEvent* event)
+{
+ qDebug("BtInstallProgressDialog::closeEvent");
+
+ if (event->spontaneous()) {
+ event->ignore();
+ return;
+ }
+ // other parts of the UI/engine must be updated
+ CPointers::backend()->reloadModules(CSwordBackend::AddedModules);
+}
+
+bool BtInstallProgressDialog::threadsDone()
+{
+ return (m_waitingThreads.count() == 0 && m_runningThreads.count() == 0);
+}
diff --git a/src/frontend/bookshelfmanager/installpage/btinstallprogressdialog.h b/src/frontend/bookshelfmanager/installpage/btinstallprogressdialog.h
new file mode 100644
index 0000000..67aa8fb
--- /dev/null
+++ b/src/frontend/bookshelfmanager/installpage/btinstallprogressdialog.h
@@ -0,0 +1,70 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTINSTALLPROGRESSDIALOG_H
+#define BTINSTALLPROGRESSDIALOG_H
+
+#include <QDialog>
+#include <QString>
+#include <QMultiMap>
+
+class QTreeWidget;
+class QTreeWidgetItem;
+
+class BtInstallThread;
+
+
+/**
+
+*/
+class BtInstallProgressDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ BtInstallProgressDialog(QWidget* parent, QTreeWidget* selectedModulesTreeWidget, QString destination);
+
+ ~BtInstallProgressDialog();
+
+public slots:
+ void slotOneItemCompleted(QString module, QString source, int status);
+ void slotOneItemStopped(QString module, QString source);
+ void slotStopInstall();
+ void slotStatusUpdated(QString module, int status);
+ void slotDownloadStarted(QString module);
+ void slotInstallStarted(QString module, QString);
+
+protected:
+ /**
+ * Handles closing by the window close button, Cancel (Stop) All button, or completing
+ * the downloads.
+ */
+ virtual void closeEvent(QCloseEvent* event);
+
+//signals:
+// void swordSetupChanged();
+
+private:
+
+ //TODO: using maps is tedious and error prone. Find better solution for handling the modules
+ // and their states.
+ QMultiMap<QString, BtInstallThread*> m_waitingThreads;
+ QMultiMap<QString, BtInstallThread*> m_runningThreads;
+ QMap<QString, BtInstallThread*> m_threadsByModule;
+ //QList<BtInstallThread*> m_doneThreads;
+
+ QTreeWidget* m_statusWidget;
+
+private:
+ QTreeWidgetItem* getItem(QString moduleName);
+ bool threadsDone();
+ void startThreads();
+ void oneItemStoppedOrCompleted(QString module, QString source, QString message);
+};
+
+#endif
diff --git a/src/frontend/bookshelfmanager/installpage/btinstallthread.cpp b/src/frontend/bookshelfmanager/installpage/btinstallthread.cpp
new file mode 100644
index 0000000..adab4fa
--- /dev/null
+++ b/src/frontend/bookshelfmanager/installpage/btinstallthread.cpp
@@ -0,0 +1,199 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btinstallthread.h"
+
+#include "frontend/bookshelfmanager/btinstallmgr.h"
+#include "frontend/bookshelfmanager/instbackend.h"
+#include "util/cpointers.h"
+#include "backend/managers/cswordbackend.h"
+
+#include <QApplication>
+#include <QString>
+#include <QThread>
+#include <QDir>
+
+#include <QDebug>
+
+// sword
+#include <filemgr.h>
+
+BtInstallThread::BtInstallThread(QObject* parent, QString moduleName, QString sourceName, QString destinationName)
+ : QThread(parent),
+ done(false),
+ m_module(moduleName),
+ m_destination(destinationName),
+ m_source(sourceName),
+ m_cancelled(false),
+ m_installSource(instbackend::source(sourceName)),
+ m_backendForSource(instbackend::backend(m_installSource))
+{
+ m_iMgr = new BtInstallMgr();
+}
+
+
+BtInstallThread::~BtInstallThread()
+{
+ delete m_iMgr;
+}
+
+void BtInstallThread::run()
+{
+ qDebug() << "****************************************\nBtInstallThread::run, mod:" << m_module << "\n************************************";
+
+
+ emit preparingInstall(m_module, m_source);
+
+ //make sure target/mods.d and target/modules exist
+ //TODO: move this to some common precondition
+ QDir dir(m_destination);
+ if (!dir.exists()) {
+ dir.mkdir(m_destination);
+ qDebug() << "made directory" << m_destination;
+ }
+ if (!dir.exists("modules")) {
+ dir.mkdir("modules");
+ qDebug() << "made directory" << m_destination << "/modules";
+ }
+ if (!dir.exists("mods.d")) {
+ dir.mkdir("mods.d");
+ qDebug() << "made directory" << m_destination << "/mods.d";
+ }
+
+ QObject::connect(m_iMgr, SIGNAL(percentCompleted(int, int)), this, SLOT(slotManagerStatusUpdated(int, int)), Qt::QueuedConnection);
+ QObject::connect(m_iMgr, SIGNAL(downloadStarted()), this, SLOT(slotDownloadStarted()), Qt::QueuedConnection);
+
+ //check whether it's an update. If yes, remove existing module first
+ //TODO: silently removing without undo if the user cancels the update is WRONG!!!
+ removeModule();
+
+ // manager for the destination path
+ sword::SWMgr lMgr( m_destination.toLatin1() );
+
+ if (instbackend::isRemote(m_installSource)) {
+ qDebug() << "calling install";
+ int status = m_iMgr->installModule(&lMgr, 0, m_module.toLatin1(), &m_installSource);
+ if (status != 0) {
+ qWarning() << "Error with install: " << status << "module:" << m_module;
+ }
+ else {
+ done = true;
+ emit installCompleted(m_module, m_source, status);
+ }
+ }
+ else { //local source
+ emit statusUpdated(m_module, 0);
+ int status = m_iMgr->installModule(&lMgr, m_installSource.directory.c_str(), m_module.toLatin1());
+ if (status > 0) {
+ qWarning() << "Error with install: " << status << "module:" << m_module;
+ }
+ else if (status == -1) {
+ // it was terminated, do nothing
+ }
+ else {
+ emit statusUpdated(m_module, 100);
+ done = true;
+ emit installCompleted(m_module, m_source, status);
+ }
+ }
+}
+
+void BtInstallThread::slotStopInstall()
+{
+ qDebug() << "*************************************\nBtInstallThread::slotStopInstall" << m_module << "\n********************************";
+ if (!done) {
+ done = true;
+ qDebug() << "*********************************\nBtInstallThread::slotStopInstall, installing" << m_module << "was cancelled\n**************************************";
+ m_iMgr->terminate();
+ //this->terminate(); // It's dangerous to forcibly stop, but we will clean up the files
+ qDebug() << "BtInstallThread::slotStopInstall 2";
+ //qApp->processEvents();
+ // wait to terminate for some secs. We rather let the execution go on and cleaning up to fail than the app to freeze
+ int notRun = this->wait(200);
+ if (notRun) {
+ this->terminate();
+ this->wait(2);
+ qDebug() << "installthread ("<< m_module << ") terminated, delete m_iMgr";
+ delete m_iMgr; // this makes sure the ftp library will be cleaned up in the destroyer
+ m_iMgr = 0;
+ }
+ qDebug() << "BtInstallThread::slotStopInstall 3";
+ // cleanup: remove the module, remove the temp files
+ if (true) {
+ qDebug() << "BtInstallThread::slotStopInstall 4";
+ // remove the installed module, just to be sure because mgr may
+ // have been terminated when copying files
+ removeModule();
+ removeTempFiles();
+ qDebug() << "BtInstallThread::slotStopInstall will emit installStopped...";
+ emit installStopped(m_module, m_source);
+ }
+ }
+}
+
+void BtInstallThread::slotManagerStatusUpdated(int totalProgress, int /*fileProgress*/)
+{
+ //qDebug("BtInstallThread::slotManagerStatusUpdated");
+ emit statusUpdated(m_module, totalProgress);
+}
+
+void BtInstallThread::slotDownloadStarted()
+{
+ qDebug("BtInstallThread::slotDownloadStarted");
+ emit downloadStarted(m_module);
+}
+
+void BtInstallThread::removeModule()
+{
+ qDebug() << "BtInstallThread::removeModule start";
+ CSwordModuleInfo* m;
+ m = CPointers::backend()->findModuleByName(m_module);
+ if (!m) {
+ m = instbackend::backend(instbackend::source(m_destination.toLatin1()))->findModuleByName(m_module);
+ }
+ if (m) { //module found?
+ qDebug() << "BtInstallThread::removeModule, module" << m_module << "found";
+ QString prefixPath = m->config(CSwordModuleInfo::AbsoluteDataPath) + "/";
+ QString dataPath = m->config(CSwordModuleInfo::DataPath);
+ if (dataPath.left(2) == "./") {
+ dataPath = dataPath.mid(2);
+ }
+
+ if (prefixPath.contains(dataPath)) {
+ prefixPath.remove( prefixPath.indexOf(dataPath), dataPath.length() );
+ }
+ else {
+ prefixPath = QString::fromLatin1(CPointers::backend()->prefixPath);
+ }
+
+ sword::SWMgr mgr(prefixPath.toLatin1());
+ BtInstallMgr iMgr;
+ iMgr.removeModule(&mgr, m->name().toLatin1());
+ } else {
+ qDebug() << "BtInstallThread::removeModule, module" << m_module << "not found";
+ }
+}
+
+void BtInstallThread::removeTempFiles()
+{
+ qDebug("BtInstallThread::removeTempFiles start");
+
+ // (take the remote conf file for this module, take DataPath,
+ // take the absolute path of the InstallMgr)
+
+ //sword::InstallSource is = instbackend::source(m_source);
+ if (instbackend::isRemote(m_installSource)) {
+ // get the path for the module temp files
+ CSwordModuleInfo* mInfo = m_backendForSource->findModuleByName(m_module);
+ QString dataPath = mInfo->config(CSwordModuleInfo::AbsoluteDataPath);
+ qDebug() << "Delete path:" << dataPath;
+ // it's easier to use sword than qt
+ sword::FileMgr::removeDir(dataPath.toLatin1().data());
+ }
+}
diff --git a/src/frontend/bookshelfmanager/installpage/btinstallthread.h b/src/frontend/bookshelfmanager/installpage/btinstallthread.h
new file mode 100644
index 0000000..d10db95
--- /dev/null
+++ b/src/frontend/bookshelfmanager/installpage/btinstallthread.h
@@ -0,0 +1,99 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTINSTALLTHREAD_H
+#define BTINSTALLTHREAD_H
+
+#include "frontend/bookshelfmanager/btinstallmgr.h"
+
+#include <QThread>
+
+#include <boost/scoped_ptr.hpp>
+
+class BtInstallProgressDialog;
+
+/**
+* Thread for installing a module.
+*
+* See the Qt thread documents. We have to be careful with signals and slots,
+* with other things.
+
+The main thread creates and owns the BtInstallThread object.
+When the install thread (the run() method) has been started
+the install thread object receives status update signals
+from the installmgr object. This works because these signals are sent
+from the running install thread but received in the thread object which
+lives in the main thread (note the difference between a thread object and a
+running thread). The slot of the thread object is executed in the main thread
+event loop, not in the install thread.
+
+The running thread sends update signals to the progress dialog.
+(This works because the signals are queued, i.e. the dialog is running
+in the main app event loop which queues the signals. ???)
+
+When the user cancels installing the main thread sends signal to a slot
+in the thread object. The slot is then run in the main thread, not
+in the install thread (note again the difference between a thread object and a
+running thread). That slot terminates the running install thread immediately.
+That is not the cleanest way to do it, but the Sword library has no good
+support for threads. Terminating a Sword InstallMgr takes time and leads to
+slow response. Therefore we stop installing by force and clean up the
+temporary files manually.
+
+* Terminating a thread forcibly is "dangerous and discouraged" but we have to do it,
+* I couldn't get cancelling work reliably otherwise. The Sword library is bad for threads.
+* We use ftp connection and file resources; the connection can be ignored but the files
+* have to be cleaned up after termination.
+*/
+class BtInstallThread : public QThread
+{
+ Q_OBJECT
+public:
+ BtInstallThread(QObject* parent, QString moduleName, QString sourceName, QString destinationName);
+
+ ~BtInstallThread();
+
+public slots:
+ void slotStopInstall();
+ void slotManagerStatusUpdated(int totalProgress, int fileProgress);
+ void slotDownloadStarted();
+
+public: // data member
+ bool done;
+
+protected:
+ virtual void run();
+ void removeModule();
+ void removeTempFiles();
+
+ QString m_module;
+ QString m_destination;
+ QString m_source;
+ bool m_cancelled;
+ BtInstallMgr* m_iMgr;
+ //sword::InstallSource m_installSource;
+ //BtInstallMgr m_iMgr;
+ sword::InstallSource m_installSource;
+ //TODO: it would be best to get the backend from the bookshelf manager install page
+ // where it has already been created. Could fasten the progress dialog startup.
+ boost::scoped_ptr<CSwordBackend> m_backendForSource;
+
+signals:
+ /** Emitted when the install progress status is updated. */
+ void statusUpdated(QString module, int progressPercent);
+ /** Emitted when installing has been stopped/cancelled. */
+ void installStopped(QString module, QString source);
+ /** Emitted when installing is complete. */
+ void installCompleted(QString module, QString source, int errorStatus);
+ /** Emitted when the first file download has been started. */
+ void downloadStarted(QString module);
+ void preparingInstall(QString module, QString source);
+};
+
+#endif
diff --git a/src/frontend/bookshelfmanager/installpage/btsourcearea.cpp b/src/frontend/bookshelfmanager/installpage/btsourcearea.cpp
new file mode 100644
index 0000000..2f8de1a
--- /dev/null
+++ b/src/frontend/bookshelfmanager/installpage/btsourcearea.cpp
@@ -0,0 +1,298 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btsourcearea.h"
+
+#include "frontend/bookshelfmanager/instbackend.h"
+
+#include "util/ctoolclass.h"
+#include "util/cpointers.h"
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+
+#include "backend/managers/cswordbackend.h"
+#include "frontend/btaboutmoduledialog.h"
+
+#include <installmgr.h>
+
+#include <QString>
+#include <QWidget>
+#include <QMap>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QSpacerItem>
+#include <QLabel>
+#include <QPushButton>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+#include <QHeaderView>
+
+#include <QDebug>
+#include <QTime>
+
+// ****************************************************************
+// ******** Installation source and module list widget ************
+// ****************************************************************
+
+BtSourceArea::BtSourceArea(const QString& sourceName)
+ : QWidget(),
+ m_sourceName(sourceName),
+ m_treeAlreadyInitialized(false),
+ m_remoteBackend(0) //important!
+{
+ m_checkedModules = QMap<QString, bool>();
+ qDebug() << "BtSourceArea::BtSourceArea, " << m_sourceName;
+ initView();
+}
+
+BtSourceArea::~BtSourceArea()
+{
+ delete m_remoteBackend;
+}
+
+void BtSourceArea::initView()
+{
+ qDebug("BtSourceArea::initView");
+ QVBoxLayout *mainLayout = new QVBoxLayout(this);
+ //QHBoxLayout *refreshLabelLayout = new QHBoxLayout();
+ //QLabel *refreshLabel = new QLabel(tr("Last refreshed:"));
+ //m_refreshTimeLabel = new QLabel();
+ //QSpacerItem *refreshLabelSpacer = new QSpacerItem(201, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
+
+ //refreshLabelLayout->addWidget(refreshLabel);
+ //refreshLabelLayout->addWidget(m_refreshTimeLabel);
+ //refreshLabelLayout->addItem(refreshLabelSpacer);
+ // TODO: or would it be better to integrate this information into the tooltip
+ // of the source tab?
+ //mainLayout->addLayout(refreshLabelLayout);
+
+ // source related button row
+ QHBoxLayout *sourceLayout = new QHBoxLayout();
+ m_refreshButton = new QPushButton(tr("Refresh..."));
+ m_refreshButton->setToolTip(tr("Refresh the list of works from this source"));
+ m_refreshButton->setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::bookshelfmgr::installpage::refresh_icon));
+ //m_refreshButton->setEnabled(false);
+ QSpacerItem *sourceSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ //m_editButton = new QPushButton(tr("Edit..."));
+ //m_editButton->setEnabled(false); // TODO after writing the edit widget
+ m_deleteButton = new QPushButton(tr("Delete..."));
+ m_deleteButton->setToolTip(tr("Delete this source"));
+ m_deleteButton->setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::bookshelfmgr::installpage::delete_icon));
+ //m_deleteButton->setEnabled(false);
+ m_addButton = new QPushButton(tr("Add..."));
+ m_addButton->setToolTip(tr("Add new source"));
+ m_addButton->setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::bookshelfmgr::installpage::add_icon));
+
+ sourceLayout->addWidget(m_refreshButton);
+ sourceLayout->addItem(sourceSpacer);
+ //sourceLayout->addWidget(m_editButton);
+ sourceLayout->addWidget(m_deleteButton);
+ sourceLayout->addWidget(m_addButton);
+
+ mainLayout->addLayout(sourceLayout);
+ // There are no views for the stack yet, see initSources
+ m_view = new QTreeWidget(this);
+ m_view->setHeaderLabels(QStringList() << tr("Work") << tr("Description"));
+ m_view->setColumnWidth(0, CToolClass::mWidth(m_view, 20));
+ mainLayout->addWidget(m_view);
+
+ connect(m_view, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), SLOT(slotItemDoubleClicked(QTreeWidgetItem*, int)));
+ connect(CPointers::backend(), SIGNAL(sigSwordSetupChanged(CSwordBackend::SetupChangedReason)), SLOT(slotSwordSetupChanged()));
+ connect(this, SIGNAL(signalCreateTree()), SLOT(slotCreateTree()), Qt::QueuedConnection);
+}
+
+QSize BtSourceArea::sizeHint() const
+{
+ return QSize(100, m_refreshButton->height() + (m_view->header()->height() * 5));
+}
+
+void BtSourceArea::initTreeFirstTime()
+{
+ if (!m_treeAlreadyInitialized) {
+ createModuleTree();
+ m_treeAlreadyInitialized = true;
+ }
+}
+
+void BtSourceArea::createModuleTree()
+{
+ qDebug("BtSourceArea::createModuleTree start");
+ // Start creating tree with a queued connection.
+ // This makes showing the dialog possible even before the tree is initialized.
+ emit signalCreateTree();
+}
+void BtSourceArea::slotCreateTree()
+{
+ qDebug()<<"BtSourceArea::slotCreateTree" << QTime::currentTime ();
+ //let the dialog become visible
+ QCoreApplication::processEvents();
+ // Creating the view and populating list may take time
+ QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
+
+ // disconnect the signal so that we don't have to run functions for every module
+ // (note: what to do if we want to restore the item selection when rebuilding?
+ disconnect(m_view, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(slotSelectionChanged(QTreeWidgetItem*, int)) );
+ m_view->clear();
+
+ // TODO: if the tree already exists for this source,
+ // maybe the selections should be preserved
+ m_checkedModules.clear();
+
+ sword::InstallSource is = instbackend::source(m_sourceName);
+ delete m_remoteBackend; // the old one can be deleted
+ m_remoteBackend = instbackend::backend(is);
+ Q_ASSERT(m_remoteBackend);
+ m_moduleList = m_remoteBackend->moduleList();
+
+ // give the list to BTModuleTreeItem, create filter to remove
+ // those modules which are installed already
+ InstalledFilter alreadyInstalledFilter(m_sourceName);
+ QList<BTModuleTreeItem::Filter*> filterList;
+ filterList.append(&alreadyInstalledFilter);
+ BTModuleTreeItem rootItem(filterList, BTModuleTreeItem::CatLangMod, &m_moduleList);
+
+ addToTree(&rootItem, m_view->invisibleRootItem());
+ QCoreApplication::processEvents();
+ // receive signal when user checks modules
+ connect(m_view, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(slotSelectionChanged(QTreeWidgetItem*, int)) );
+ QApplication::restoreOverrideCursor();
+ qDebug()<< "BtSourceArea::createModuleTree end"<< QTime::currentTime ();
+}
+
+void BtSourceArea::addToTree(BTModuleTreeItem* item, QTreeWidgetItem* widgetItem)
+{
+ //qDebug()<<"BtSourceArea::addToTree "<<item->text();
+ //qDebug() << "BTMTItem type: " << item->type();
+
+ foreach (BTModuleTreeItem* i, item->children()) {
+ addToTree(i, new QTreeWidgetItem(widgetItem));
+ }
+ if (item->type() != BTModuleTreeItem::Root) {
+ CSwordModuleInfo* mInfo = item->moduleInfo();
+ widgetItem->setText(0, item->text());
+ if (item->type() == BTModuleTreeItem::Category || item->type() == BTModuleTreeItem::Language) {
+ //qDebug() << "item"<<item->text()<< "was cat or lang";
+ widgetItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate);
+ }
+ if (item->type() == BTModuleTreeItem::Module) {
+ //qDebug() << "item"<<item->text()<< "was a module";
+ widgetItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
+ widgetItem->setCheckState(0, Qt::Unchecked);
+
+ CSwordModuleInfo* const installedModule = CPointers::backend()->findModuleByName(mInfo->name());
+ QString installedV;
+
+ if (!installedModule) {
+ // possible TODO: save the module list of a source before refreshing,
+ // compare after refreshing, mark the newly added modules
+ //if not newly added:
+ //state: installable (no indicator)
+ //else: status: newly added, color yellow
+ } else { // the module is already installed
+ QBrush bg(QColor(255,153,153));
+ widgetItem->setBackground(0, bg);
+ widgetItem->setBackground(1, bg);
+ installedV = QString(installedModule->config(CSwordModuleInfo::ModuleVersion).toLatin1());
+ // set the color for the parent items
+ QTreeWidgetItem* parent1 = widgetItem->parent();
+ if (parent1) {
+ parent1->setBackground(0,bg);
+ parent1->setBackground(1,bg);
+ QTreeWidgetItem* parent2 = parent1->parent();
+ if (parent2) {
+ parent2->setBackground(0,bg);
+ parent2->setBackground(1,bg);
+ }
+ }
+ }
+
+
+ QString descr(mInfo->config(CSwordModuleInfo::Description));
+ QString toolTipText = CToolClass::remoteModuleToolTip(mInfo, installedV);
+
+ widgetItem->setText(1, descr);
+ widgetItem->setToolTip(0, toolTipText);
+ widgetItem->setToolTip(1, toolTipText);
+ }
+ }
+}
+
+QTreeWidget* BtSourceArea::treeWidget()
+{
+ return m_view;
+}
+
+// return the selected modules
+QMap<QString, bool>* BtSourceArea::selectedModules()
+{
+ return &m_checkedModules;
+}
+
+// when a module is checked/unchecked
+void BtSourceArea::slotSelectionChanged(QTreeWidgetItem* item, int column)
+{
+ //qDebug("BtSourceArea::slotSelectionChanged");
+ // modify the internal list of selected (actually checked) modules
+ // if() leaves groups away
+ if (!item->childCount() && column == 0) {
+ foreach (CSwordModuleInfo* module, m_moduleList) {
+ if (module->name() == item->text(0)) {
+ if (item->checkState(0) == Qt::Checked) {
+ qDebug() << module->name() << "was checked";
+ m_checkedModules.insert(module->name(), true);
+ } else {
+ qDebug() << module->name() << "was unchecked";
+ m_checkedModules.remove(module->name());
+ }
+ emit signalSelectionChanged(m_sourceName, m_checkedModules.count());
+ break;
+ }
+ }
+ }
+}
+
+void BtSourceArea::slotItemDoubleClicked(QTreeWidgetItem* item, int /*column*/)
+{
+ CSwordModuleInfo* mInfo = m_remoteBackend->findModuleByName(item->text(0));
+ if (mInfo) {
+ BTAboutModuleDialog* dialog = new BTAboutModuleDialog(this, mInfo);
+ dialog->show();
+ dialog->raise();
+ }
+}
+
+BtSourceArea::InstalledFilter::InstalledFilter(QString sourceName)
+ : BTModuleTreeItem::Filter(),
+ m_source(instbackend::source(sourceName)),
+ m_swordBackend(instbackend::backend(m_source))
+{
+ // these are set once to optimize away repeated calls
+ // m_source, m_swordBackend
+
+}
+//filter out already installed, not updateable modules
+bool BtSourceArea::InstalledFilter::filter(CSwordModuleInfo* mInfo)
+{
+ //qDebug() << "BtSourceArea::InstalledFilter::filter, module " << mInfo->name();
+ CSwordModuleInfo* const installedModule = CPointers::backend()->findModuleByName(mInfo->name());
+ if (installedModule) {
+ //qDebug("already installed, check if it's an update...");
+ const sword::SWVersion installedVersion(installedModule->config(CSwordModuleInfo::ModuleVersion).toLatin1());
+ const sword::SWVersion newVersion(mInfo->config(CSwordModuleInfo::ModuleVersion).toLatin1());
+ if (installedVersion >= newVersion) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void BtSourceArea::slotSwordSetupChanged()
+{
+ createModuleTree();
+}
diff --git a/src/frontend/bookshelfmanager/installpage/btsourcearea.h b/src/frontend/bookshelfmanager/installpage/btsourcearea.h
new file mode 100644
index 0000000..814bde8
--- /dev/null
+++ b/src/frontend/bookshelfmanager/installpage/btsourcearea.h
@@ -0,0 +1,97 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTSOURCEAREA_H
+#define BTSOURCEAREA_H
+
+#include "backend/btmoduletreeitem.h"
+
+#include <boost/scoped_ptr.hpp>
+
+#include <installmgr.h>
+
+#include <QWidget>
+#include <QMap>
+#include <QApplication>
+
+class QTreeWidget;
+class QTreeWidgetItem;
+class QLabel;
+class QPushButton;
+
+/**
+* Area for one install source.
+*
+* - Tree widget for modules
+* - Buttons for handling the source(s): refresh, edit, remove, add
+*
+* Each source has
+* QTreeWidget, populated with the module tree if the source
+* module list is in a local cache. Refreshing the source refreshes
+* the cache and rebuilds the module tree. Sources are not refreshed
+* automatically, only by the user action, one source at a time.
+*/
+class BtSourceArea : public QWidget
+{
+ Q_OBJECT
+
+ friend class BtSourceWidget;
+public:
+
+ struct InstalledFilter : BTModuleTreeItem::Filter {
+ InstalledFilter(QString sourceName);
+ bool filter(CSwordModuleInfo*);
+ sword::InstallSource m_source;
+ boost::scoped_ptr<CSwordBackend> m_swordBackend;
+ };
+
+ BtSourceArea(const QString& sourceName);
+ ~BtSourceArea();
+
+ void initView();
+ /** Reimplemented from QWidget. */
+ virtual QSize sizeHint() const;
+ void initTreeFirstTime();
+ QTreeWidget* treeWidget();
+
+ QMap<QString, bool>* selectedModules();
+
+public slots:
+ void slotSwordSetupChanged();
+ /** Create a module tree for a tree widget */
+ void createModuleTree();
+
+signals:
+ void signalSelectionChanged(QString sourceName, int selectedCount);
+ void signalCreateTree();
+
+private slots:
+ void slotCreateTree();
+ void slotSelectionChanged(QTreeWidgetItem* item, int column);
+ void slotItemDoubleClicked(QTreeWidgetItem* item, int column);
+private:
+ void addToTree(BTModuleTreeItem* item, QTreeWidgetItem* widgetItem);
+
+ QString m_sourceName;
+ bool m_treeAlreadyInitialized;
+ QMap<QString, bool> m_checkedModules;
+ CSwordBackend* m_remoteBackend; // needed for the module list
+ QList<CSwordModuleInfo*> m_moduleList;
+
+ QTreeWidget* m_view;
+ QLabel* m_refreshTimeLabel;
+ QPushButton* m_refreshButton;
+ QPushButton* m_editButton;
+ QPushButton* m_deleteButton;
+ QPushButton* m_addButton;
+
+
+};
+
+#endif
diff --git a/src/frontend/bookshelfmanager/installpage/btsourcewidget.cpp b/src/frontend/bookshelfmanager/installpage/btsourcewidget.cpp
new file mode 100644
index 0000000..586a680
--- /dev/null
+++ b/src/frontend/bookshelfmanager/installpage/btsourcewidget.cpp
@@ -0,0 +1,403 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btsourcewidget.h"
+
+#include "btinstallpage.h"
+#include "btsourcearea.h"
+#include "btinstallprogressdialog.h"
+#include "btinstallmodulechooserdialog.h"
+
+#include "frontend/bookshelfmanager/btmodulemanagerdialog.h"
+#include "frontend/bookshelfmanager/cswordsetupinstallsourcesdialog.h"
+#include "frontend/bookshelfmanager/btinstallmgr.h"
+#include "frontend/bookshelfmanager/instbackend.h"
+
+
+#include <QString>
+#include <QWidget>
+#include <QTabWidget>
+#include <QMessageBox>
+#include <QProgressDialog>
+#include <QPushButton>
+#include <QApplication>
+#include <QFileInfo>
+#include <QTabBar>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+#include <QHBoxLayout>
+#include <QLabel>
+
+// ****************************************************************
+// ******** Tab Widget that holds source widgets ******************
+// ****************************************************************
+
+BtSourceWidget::BtSourceWidget(BtInstallPage* parent)
+ : QTabWidget(parent),
+ m_page(parent)
+{
+ qDebug("BtSourceWidget::BtSourceWidget start");
+ initSources();
+
+ // TODO: choose the page from config
+
+}
+
+BtSourceArea* BtSourceWidget::area()
+{
+ return dynamic_cast<BtSourceArea*>(currentWidget());
+}
+
+QString BtSourceWidget::currentSourceName()
+{
+ qDebug() << "BtSourceWidget::currentSourceName: " << m_sourceNameList.at(currentIndex());
+ return m_sourceNameList.at(currentIndex());
+}
+
+void BtSourceWidget::initSourceConnections()
+{
+ qDebug("void BtSourceWidget::initSourceConnections() start");
+ if (area()) {
+ connect(area()->m_refreshButton, SIGNAL(clicked()), SLOT(slotRefresh()));
+ //connect(area()->m_editButton, SIGNAL(clicked()), SLOT(slotEdit()));
+ connect(area()->m_deleteButton, SIGNAL(clicked()), SLOT(slotDelete()));
+ connect(area()->m_addButton, SIGNAL(clicked()), SLOT(slotAdd()));
+ connect(area(), SIGNAL(signalSelectionChanged(QString, int)), SLOT(slotModuleSelectionChanged(QString, int)) );
+ }
+ qDebug("void BtSourceWidget::initSourceConnections() end");
+}
+
+void BtSourceWidget::slotEdit()
+{
+ qDebug("BtSourceWidget::slotEdit");
+ // open the source editor dialog
+
+ // if the source was changed, init the sources
+
+}
+
+void BtSourceWidget::slotDelete()
+{
+ qDebug("void BtSourceWidget::slotDelete() start");
+ // ask for confirmation
+ int ret = QMessageBox::warning(this, tr("Delete Source?"),
+ tr("Do you really want to delete this source?"),
+ QMessageBox::Yes | QMessageBox::No);
+
+ if (ret == QMessageBox::Yes) {
+ instbackend::deleteSource(currentSourceName());
+
+ // remove the UI elements
+ m_sourceNameList.removeAt(currentIndex());
+ QWidget* w = currentWidget();
+ removeTab(currentIndex());
+ delete w;
+ }
+}
+
+void BtSourceWidget::slotAdd()
+{
+ qDebug("void BtSourceWidget::slotAdd() start");
+ qDebug("open the old dialog, TODO: write new one");
+ sword::InstallSource newSource = CSwordSetupInstallSourcesDialog::getSource();
+ if ( !((QString)newSource.type.c_str()).isEmpty() ) { // we have a valid source to add
+ instbackend::addSource(newSource);
+ addSource(QString(newSource.caption.c_str()));
+ }
+}
+
+
+void BtSourceWidget::slotRefresh()
+{
+ qDebug("void BtSourceWidget::slotRefresh() start");
+ // (re)build the module cache for the source
+
+ QString sourceName = currentSourceName();
+
+ // quick enough, make it modal so that we don't need to take care of anything else
+ m_progressDialog = new QProgressDialog("", tr("Cancel"), 0 ,100, this);
+ m_progressDialog->setWindowTitle(tr("Refreshing Source"));
+ m_progressDialog->setMinimumDuration(0);
+
+ // TODO: get rid of the backend code, BtInstallMgr and progressdialog could handle this
+ //write method BtInstallMgr::slotRefreshCanceled()
+ connect(m_progressDialog, SIGNAL(canceled()), SLOT(slotRefreshCanceled()));
+
+ // BACKEND CODE **********************************************************
+ // would this be possible: instbackend::refreshSource( arguments );
+ qDebug("void BtSourceWidget::slotRefresh 1");
+ BtInstallMgr iMgr;
+ m_currentInstallMgr = &iMgr; //for the progress dialog
+ sword::InstallSource is = instbackend::source(sourceName);
+ bool success = false;
+ qDebug("void BtSourceWidget::slotRefresh 2");
+ // connect this directly to the dialog setValue(int) if possible
+ connect(&iMgr, SIGNAL(percentCompleted(const int, const int)), SLOT(slotRefreshCompleted(const int, const int)));
+
+ if (instbackend::isRemote(is)) {
+ m_progressDialog->show();
+ qApp->processEvents();
+ this->slotRefreshCompleted(0,0);
+ m_progressDialog->setLabelText(tr("Connecting..."));
+ m_progressDialog->setValue(0);
+ qApp->processEvents();
+ //qApp->flush();
+ //qApp->processEvents();
+ //m_progressDialog->repaint();
+ //qApp->processEvents();
+ qDebug("void BtSourceWidget::slotRefresh 3");
+ bool successful = iMgr.refreshRemoteSource( &is );
+ if (!successful ) { //make sure the sources were updated sucessfully
+ success = true;
+ m_progressDialog->setValue(100); //make sure the dialog closes
+ }
+ else {
+ qWarning("InstallMgr: refreshRemoteSources returned an error.");
+ success = false;
+ }
+ }
+ else {
+ // Local source, update the list
+ success = true;
+ }
+
+ delete m_progressDialog;
+ m_progressDialog = 0;
+
+ // rebuild the view tree and refresh the view
+ if (success) {
+ qDebug("void BtSourceWidget::slotRefresh 4");
+ area()->createModuleTree();
+ }
+}
+
+//TODO: try to move this to BtInstallMgr
+void BtSourceWidget::slotRefreshCanceled()
+{
+ qDebug("BtSourceWidget::slotRefreshCanceled");
+ Q_ASSERT(m_currentInstallMgr);
+ if (m_currentInstallMgr) {
+ m_currentInstallMgr->terminate();
+ }
+ qApp->processEvents();
+}
+
+//TODO: try to move this to progress dialog
+void BtSourceWidget::slotRefreshCompleted(const int, const int current)
+{
+ qDebug("BtSourceWidget::slotRefreshCompleted");
+ if (m_progressDialog) {
+ if (m_progressDialog->labelText() != tr("Refreshing...")) {
+ m_progressDialog->setLabelText(tr("Refreshing..."));
+ }
+ m_progressDialog->setValue(current);
+ }
+ qApp->processEvents();
+}
+
+// init the tabbar, setup the module tree for the current source
+void BtSourceWidget::initSources()
+{
+ qDebug("void BtSourceWidget::initSources() start");
+
+ // ***** Use the backend to get the list of sources *****
+ instbackend::initPassiveFtpMode();
+ QStringList sourceList = instbackend::sourceList();
+
+ // Add a default entry, the Crosswire main repository
+ // TODO: this is easy for the user, but should the edit dialog
+ // open automatically?
+ if (!sourceList.count()) {
+ sword::InstallSource is("FTP"); //default return value
+ is.caption = "Crosswire";
+ is.source = "ftp.crosswire.org";
+ is.directory = "/pub/sword/raw";
+ // passive ftp is not needed here, it's the default
+
+ instbackend::addSource(is);
+
+ sourceList = instbackend::sourceList();
+ //Q_ASSERT( sourceList.count() > 0 );
+ }
+ qDebug("void BtSourceWidget::initSources 1");
+ // Add the sources to the widget
+ foreach (QString sourceName, sourceList) {
+ addSource(sourceName);
+ }
+ // connect this after the tabs have been created,
+ // otherwise the signal is caught too early.
+ QObject::connect(this, SIGNAL(currentChanged(int)), this, SLOT(slotTabSelected(int)));
+ qDebug("void BtSourceWidget::initSources end");
+ // TODO: select the current source from the config
+ // It's important to choose something because the tree is not initialized until now
+ setCurrentIndex(0);
+ slotTabSelected(0); // setting the index wasn't enough if there were only 1 tab
+
+ if (sourceList.count() == 0) {
+ QHBoxLayout* l = new QHBoxLayout(this);
+ QLabel* message = new QLabel(QString("<i>") + tr("No sources were found in the SWORD configuration and BibleTime couldn't create a default source. Check your SWORD configuration and that the configuration path is writable. Then restart the Bookshelf Manager.") + QString("</i>"), this);
+ message->setWordWrap(true);
+ l->addWidget(message);
+ }
+}
+
+void BtSourceWidget::addSource(const QString& sourceName)
+{
+ qDebug("void BtSourceWidget::addSource(const QString& sourceName) start");
+ // The source has already been added to the backend.
+
+ QString type;
+ QString server;
+ QString path;
+ sword::InstallSource is = instbackend::source(sourceName);
+ if (instbackend::isRemote(is)) {
+ type = tr("Remote:");
+ server = is.source.c_str();
+ path = is.directory.c_str();
+ }
+ else { // local source
+ type = tr("Local:");
+ QFileInfo fi( is.directory.c_str() );
+ path = is.directory.c_str();
+ if (!(fi.isDir() )) {
+ path = path + QString(" ") + tr("Not a directory!"); //TODO: change this
+ }
+ if (!fi.isReadable()) {
+ path = path + QString(" ") + tr("Not readable!"); //TODO: change this
+ }
+ }
+
+ // Here the tab UI is created and added to the tab widget
+ BtSourceArea* area = new BtSourceArea(sourceName);
+ int tabNumber = this->addTab(area, sourceName);
+
+ // TODO: add "remote/local", server, path etc.
+ QString toolTip(QString("<p style='white-space:pre'>") + sourceName + QString("<br/><b>") + type + QString("</b> ") + server + path + QString("</p>"));
+ tabBar()->setTabToolTip(tabNumber, toolTip);
+
+ //select the new tab
+ setCurrentIndex(tabNumber);
+ m_sourceNameList.append(sourceName);
+ initSourceConnections();
+ qDebug("BtSourceWidget::addSource end");
+}
+
+//
+void BtSourceWidget::slotModuleSelectionChanged(QString sourceName, int selectedCount)
+{
+ //TODO: editing sources should update the map also
+ qDebug("BtSourceWidget::slotModuleSelectionChanged start");
+
+ int overallCount = 0;
+ m_selectedModulesCountMap.insert(sourceName, selectedCount);
+ foreach (int count, m_selectedModulesCountMap) {
+ qDebug() << "add" << count << "to overall count of selected modules";
+ overallCount += count;
+ }
+
+ if (overallCount > 0) {
+ m_page->setInstallEnabled(true);
+ } else {
+ m_page->setInstallEnabled(false);
+ }
+}
+
+void BtSourceWidget::slotTabSelected(int /*index*/)
+{
+ BtSourceArea* area = dynamic_cast<BtSourceArea*>(currentWidget());
+ if (area) area->initTreeFirstTime();
+}
+
+void BtSourceWidget::slotInstall()
+{
+ qDebug("void BtInstallPage::slotInstall start");
+
+ // check that the destination path is writable, do nothing if not and user doesn't want to continue
+ QDir dir = QDir(dynamic_cast<BtInstallPage*>(parent())->selectedInstallPath());
+ bool canWrite = true;
+ if (dir.isReadable()) {
+ const QFileInfo fi( dir.canonicalPath() );
+ if (!fi.exists() || !fi.isWritable()) {
+ canWrite = false;
+ }
+ } else {
+ canWrite = false;
+ }
+ if (!canWrite) {
+ const int result = QMessageBox::warning(this, tr("Warning"), tr("The destination directory is not writable or does not exist. Installation will fail unless this has first been fixed."), QMessageBox::Ignore|QMessageBox::Cancel, QMessageBox::Cancel);
+ if (result != QMessageBox::Ignore) {
+ return;
+ }
+ }
+
+ // create the confirmation dialog
+ // (module tree dialog, modules taken from all sources)
+ QString dlgTitle(tr("Install/Update works?"));
+ QString dlgLabel(tr("Do you really want to install these works?") +
+ QString("<br/><br/><small>") +
+ tr("Only one version of a work can be installed at the same time. Select only one if there are items marked with red.") +
+ QString("</small>"));
+
+ // with empty list we avoid creating the module tree inside the dialog code
+ QList<CSwordModuleInfo*> emptyList;
+ BtInstallModuleChooserDialog* dlg = new BtInstallModuleChooserDialog(this, dlgTitle, dlgLabel, &emptyList);
+ //dlg->setGrouping(BTModuleTreeItem::Mod);
+ QTreeWidget* treeWidget = dlg->treeWidget();
+ QTreeWidgetItem* rootItem = treeWidget->invisibleRootItem();
+
+ QStringList nameList;
+
+ // loop through each tab
+ for (int tab = 0; tab < count(); ++tab) {
+ BtSourceArea* sArea = dynamic_cast<BtSourceArea*>(widget(tab));
+ if (sArea && sArea->selectedModules()->count() > 0) {
+ // there are selected modules in the source, create items for these
+ QTreeWidgetItem* sourceItem = new QTreeWidgetItem(rootItem);
+ sourceItem->setText(0, m_sourceNameList.at(tab));
+ sourceItem->setFlags(Qt::ItemIsUserCheckable|Qt::ItemIsTristate|Qt::ItemIsEnabled);
+ foreach (QString mName, sArea->selectedModules()->keys()) {
+ dlg->initModuleItem(mName, sourceItem);
+ }
+ sourceItem->setExpanded(true);
+ }
+ }
+
+ //user accepts the dialog
+ connect(dlg, SIGNAL(modulesChanged(QList<CSwordModuleInfo*>, QTreeWidget*)), SLOT(slotInstallAccepted(QList<CSwordModuleInfo*>, QTreeWidget*)) );
+ // user checks/unchecks an item, needed for preventing double items
+ QObject::connect(treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), dlg, SLOT(slotItemChecked(QTreeWidgetItem*, int)));
+ dlg->exec();
+ // The OK signal sent by the dialog is catched with slotInstallAccepted.
+}
+
+void BtSourceWidget::slotStopInstall(QTreeWidget* /*treeWidget*/)
+{
+ qDebug() << "BtSourceWidget::slotStopInstall";
+ // not needed?
+}
+
+void BtSourceWidget::slotInstallAccepted(QList<CSwordModuleInfo*> /*modules*/, QTreeWidget* treeWidget)
+{
+ qDebug() << "BtSourceWidget::slotInstallAccepted";
+
+ //TODO: first remove all modules which will be updated from the module list
+ // but what modules? all with the same real name? (there may be _n modules...)
+
+ BtModuleManagerDialog* parentDialog = dynamic_cast<BtModuleManagerDialog*>(dynamic_cast<BtInstallPage*>(parent())->parentDialog());
+
+ BtInstallProgressDialog* dlg = new BtInstallProgressDialog(parentDialog, treeWidget, dynamic_cast<BtInstallPage*>(parent())->selectedInstallPath());
+
+ if (!parentDialog) qDebug("error, wrong parent!");
+
+ m_page->setInstallEnabled(false);
+ // the progress dialog is now modal, it can be made modeless later.
+ dlg->exec();
+
+ qDebug("BtSourceWidget::slotInstallAccepted end");
+}
diff --git a/src/frontend/bookshelfmanager/installpage/btsourcewidget.h b/src/frontend/bookshelfmanager/installpage/btsourcewidget.h
new file mode 100644
index 0000000..812c6ac
--- /dev/null
+++ b/src/frontend/bookshelfmanager/installpage/btsourcewidget.h
@@ -0,0 +1,86 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+#ifndef BTSOURCEWIDGET_H
+#define BTSOURCEWIDGET_H
+
+class CSwordModuleInfo;
+
+#include <QTabWidget>
+#include <QString>
+#include <QMap>
+
+class BtInstallMgr;
+class BtInstallPage;
+class BtSourceArea;
+
+class QProgressDialog;
+class QTreeWidget;
+
+/**
+* Tabwidget which holds the source widgets.
+* This widget implements the slots for the source action buttons and
+* applies the actions to the proper source(s).
+*/
+class BtSourceWidget : public QTabWidget
+{
+ Q_OBJECT
+public:
+ friend class BtInstallPage;
+
+ BtSourceWidget(BtInstallPage* parent);
+ virtual ~BtSourceWidget() {}
+
+ BtSourceArea* area();
+ QString currentSourceName();
+
+public slots:
+ /** Install button has been clicked. */
+ void slotInstall();
+ /** "Stop All" button clicked */
+ void slotStopInstall(QTreeWidget* treeWidget);
+
+private:
+ void initSourceConnections();
+ /** Add tabs/views for each source. */
+ void initSources();
+
+ /** Add one source to tabs/stack. */
+ void addSource(const QString& sourceName);
+
+private slots:
+
+ void slotRefresh();
+
+ void slotRefreshCanceled();
+
+ void slotRefreshCompleted(int, int);
+
+ /** Edit button clicked. */
+ void slotEdit();
+ /** Delete button clicked. */
+ void slotDelete();
+ /** Add button clicked. */
+ void slotAdd();
+ /** Modules have been checked/unchecked in the view. */
+ void slotModuleSelectionChanged(QString sourceName, int selectedCount);
+
+ void slotTabSelected(int index);
+ void slotInstallAccepted(QList<CSwordModuleInfo*> mi, QTreeWidget* treeWidget);
+
+
+
+private:
+ QStringList m_sourceNameList;
+ BtInstallPage* m_page;
+ QProgressDialog* m_progressDialog; // for refreshing
+ BtInstallMgr* m_currentInstallMgr; // for refreshing
+ QMap<QString, int> m_selectedModulesCountMap;
+};
+
+#endif
diff --git a/src/frontend/bookshelfmanager/instbackend.cpp b/src/frontend/bookshelfmanager/instbackend.cpp
new file mode 100644
index 0000000..f981f54
--- /dev/null
+++ b/src/frontend/bookshelfmanager/instbackend.cpp
@@ -0,0 +1,280 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "instbackend.h"
+
+#include "frontend/bookshelfmanager/btinstallmgr.h"
+#include "backend/managers/cswordbackend.h"
+
+#include "util/cpointers.h"
+#include "util/directoryutil.h"
+
+//Qt includes
+#include <QFile>
+#include <QFileInfo>
+#include <QDir>
+#include <QMessageBox>
+
+#include <QDebug>
+
+//Sword includes
+#include <filemgr.h>
+#include <swconfig.h>
+#include <swbuf.h>
+
+//Stl includes
+#include <functional>
+#include <map>
+#include <utility>
+
+using namespace sword;
+
+namespace instbackend {
+
+/** Adds the source described by Source to the backend. */
+bool addSource(sword::InstallSource& source)
+{
+ qDebug("backend::addSource");
+ SWConfig config(configFilename().toLatin1());
+ if (!strcmp(source.type, "FTP")) {
+ //make sure the path doesn't have a trailing slash, sword doesn't like it
+ if (source.directory[ source.directory.length()-1 ] == '/') {
+ source.directory--; //make one char shorter
+ }
+
+ config["Sources"].insert( std::make_pair(SWBuf("FTPSource"), source.getConfEnt()) );
+ }
+ else if (!strcmp(source.type, "DIR")) {
+ config["Sources"].insert( std::make_pair(SWBuf("DIRSource"), source.getConfEnt()) );
+ }
+ config.Save();
+ return true;
+}
+
+/** Returns the Source struct. */
+sword::InstallSource source(QString name)
+{
+ qDebug("backend::source");
+ BtInstallMgr mgr;
+ InstallSourceMap::iterator source = mgr.sources.find(name.toLatin1().data());
+ if (source != mgr.sources.end()) {
+ return *(source->second);
+ }
+ else { //not found in Sword, may be a local DIR source
+ SWConfig config(configFilename().toLatin1());
+ SectionMap::iterator sourcesSection = config.Sections.find("Sources");
+ if (sourcesSection != config.Sections.end()) {
+ ConfigEntMap::iterator sourceBegin =
+ sourcesSection->second.lower_bound("DIRSource");
+ ConfigEntMap::iterator sourceEnd =
+ sourcesSection->second.upper_bound("DIRSource");
+
+ while (sourceBegin != sourceEnd) {
+ InstallSource is("DIR", sourceBegin->second.c_str());
+ if (!strcmp(is.caption, name.toLatin1()) ) { //found local dir source
+ return is;
+ }
+
+ sourceBegin++;//next source
+ }
+ }
+ }
+
+ InstallSource is("EMPTY"); //default return value
+ is.caption = "unknown caption";
+ is.source = "unknown source";
+ is.directory = "unknown dir";
+ return is;
+}
+
+/** Deletes the source. */
+bool deleteSource(QString name)
+{
+ qDebug("backend::deleteSource");
+ sword::InstallSource is = source(name );
+
+ SWConfig config(configFilename().toLatin1());
+
+ //this code can probably be shortened by using the stl remove_if functionality
+ std::pair< ConfigEntMap::iterator, ConfigEntMap::iterator > range =
+ isRemote(is)
+ ? config["Sources"].equal_range("FTPSource")
+ : config["Sources"].equal_range("DIRSource");
+
+ ConfigEntMap::iterator it = range.first;
+ while (it != range.second) {
+ if (it->second == is.getConfEnt()) {
+ // qWarning("found the source!");
+ config["Sources"].erase(it);
+ break;
+ }
+ ++it;
+ }
+
+ config.Save();
+ return true; //TODO: dummy
+}
+
+/** Refreshes the remote source module list. */
+bool refreshSource(QString /*name*/)
+{
+ // not possible until manager and progressdialog work together
+ return true; //TODO: dummy
+}
+
+/** Returns the moduleinfo list for the source. Delete the pointer after using. IS THIS POSSIBLE?*/
+QList<CSwordModuleInfo*> moduleList(QString /*name*/)
+{
+ QList<CSwordModuleInfo*> list; //TODO: dummy
+ return list;
+}
+
+bool isRemote(const sword::InstallSource& source)
+{
+ return !strcmp(source.type, "FTP");
+}
+
+const QString configPath() {
+ const char *envhomedir = getenv("HOME");
+ QString confPath = QString(envhomedir ? envhomedir : ".");
+ confPath.append("/.sword/InstallMgr");
+
+ return confPath;
+}
+
+const QString configFilename() {
+ return (configPath() + "/InstallMgr.conf");
+}
+
+QStringList targetList()
+{
+ qDebug("backend::targetList");
+ QStringList names = CPointers::backend()->swordDirList();
+ return names;
+}
+
+bool setTargetList( const QStringList& targets )
+{
+ qDebug("backend::setTargetList");
+ //saves a new Sword config using the provided target list
+ //QString filename = KGlobal::dirs()->saveLocation("data", "bibletime/") + "sword.conf"; //default is to assume the real location isn't writable
+ //QString filename = util::filesystem::DirectoryUtil::getUserBaseDir().canonicalPath().append("/.sword/sword.conf");
+ //bool directAccess = false;
+ QString filename = swordConfigFilename();
+ QFileInfo i(filename);
+ QFileInfo dirInfo(i.absolutePath());
+
+
+ if ( !i.exists() && dirInfo.isWritable() ) {
+ // if the file doesn't exist but the parent is writable, create it
+ qWarning() << "The Sword config file does not exist, it has to be created";
+ QFile f(filename);
+ f.open(QIODevice::WriteOnly);
+ f.close();
+ i.refresh();
+ }
+ if ( i.exists() && i.isWritable() ) { //we can write to the file ourself
+ qDebug() << "The Sword config file is writable";
+ } else {
+ // There is no way to save to the file
+ qWarning() << "The Sword config file is not writable!";
+ QMessageBox::warning(0, QObject::tr("Can't write file"), QObject::tr("The Sword config file can't be written!"));
+ return false;
+ }
+ SWConfig conf(filename.toLocal8Bit());
+ conf.Sections.clear();
+ bool setDataPath = false;
+ for (QStringList::const_iterator it = targets.begin(); it != targets.end(); ++it) {
+ QString t = *it;
+ if (t.contains( util::filesystem::DirectoryUtil::getUserHomeDir().canonicalPath().append("/.sword") )) {
+ //we don't want $HOME/.sword in the config
+ continue;
+ }
+ else {
+ qDebug() << "Add path to the conf file" << filename << ":" << t;
+ conf["Install"].insert( std::make_pair(!setDataPath ? SWBuf("DataPath") : SWBuf("AugmentPath"), t.toLocal8Bit().data()) );
+ setDataPath = true;
+ }
+ }
+ qDebug() << "save the sword conf...";
+ conf.Save();
+ CPointers::backend()->reloadModules(CSwordBackend::PathChanged);
+ return true;
+}
+
+QStringList sourceList()
+{
+ qDebug("backend::sourceList");
+ BtInstallMgr mgr;
+ Q_ASSERT(mgr.installConf);
+
+ QStringList names;
+
+ //add Sword remote sources
+ for (InstallSourceMap::iterator it = mgr.sources.begin(); it != mgr.sources.end(); it++) {
+ names << QString::fromLocal8Bit(it->second->caption);
+ }
+
+ // Add local directory sources
+ SWConfig config(configFilename().toLatin1());
+ sword::SectionMap::iterator sourcesSection = config.Sections.find("Sources");
+ if (sourcesSection != config.Sections.end()) {
+ sword::ConfigEntMap::iterator sourceBegin = sourcesSection->second.lower_bound("DIRSource");
+ sword::ConfigEntMap::iterator sourceEnd = sourcesSection->second.upper_bound("DIRSource");
+
+ while (sourceBegin != sourceEnd) {
+ InstallSource is("DIR", sourceBegin->second.c_str());
+ names << QString::fromLatin1(is.caption.c_str());
+
+ sourceBegin++;
+ }
+ }
+
+ return names;
+}
+
+
+void initPassiveFtpMode()
+{
+ qDebug("backend::initPassiveFtpMode");
+ SWConfig config(configFilename().toLatin1());
+ config["General"]["PassiveFTP"] = "true";
+ config.Save();
+}
+const QString swordConfigFilename()
+{
+ qDebug("backend::swordConfigFilename");
+ qDebug() << util::filesystem::DirectoryUtil::getUserHomeDir().absolutePath().append("/.sword/sword.conf");
+ return util::filesystem::DirectoryUtil::getUserHomeDir().absolutePath().append("/.sword/sword.conf");
+}
+
+const QDir swordDir()
+{
+ return QDir(util::filesystem::DirectoryUtil::getUserHomeDir().absolutePath().append("/.sword/"));
+}
+
+CSwordBackend* backend( const sword::InstallSource& is)
+{
+ qDebug("backend::backend");
+ CSwordBackend* ret = 0;
+ if (isRemote(is)) {
+ ret = new CSwordBackend( QString(is.localShadow.c_str()), false );
+ }
+ else {
+ ret = new CSwordBackend( QString(is.directory.c_str()), false);
+ }
+
+ Q_ASSERT(ret);
+ if (ret) {
+ ret->initModules(CSwordBackend::OtherChange);
+ }
+ return ret;
+}
+
+}
diff --git a/src/frontend/bookshelfmanager/instbackend.h b/src/frontend/bookshelfmanager/instbackend.h
new file mode 100644
index 0000000..4f60ed9
--- /dev/null
+++ b/src/frontend/bookshelfmanager/instbackend.h
@@ -0,0 +1,74 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef INSTBACKEND_H
+#define INSTBACKEND_H
+
+#include "backend/managers/cswordbackend.h"
+
+class CSwordModuleInfo;
+
+#include <QString>
+#include <QDir>
+
+#include <installmgr.h>
+
+
+namespace instbackend {
+
+/** Adds the source to the backend. */
+bool addSource(sword::InstallSource& source);
+
+/** Returns the source struct. */
+sword::InstallSource source(QString name);
+
+/** Deletes the source. */
+bool deleteSource(QString name);
+
+/** Refreshes the remote source module list. */
+bool refreshSource(QString name);
+
+/** Returns the moduleinfo list for the source. */
+QList<CSwordModuleInfo*> moduleList(QString name);
+
+/** Tells if the source is remote or local. */
+bool isRemote(const sword::InstallSource& source);
+
+/** Returns the list of available install target paths. */
+QStringList targetList();
+
+/** Saves the list of available install target paths to the sword config. Return success indicator.*/
+bool setTargetList( const QStringList& targets );
+
+QStringList sourceList();
+
+/** Returns the path of the sword installer configuration file. */
+const QString configPath();
+
+/** Returns the name of the sword installer configuration file. */
+const QString configFilename();
+
+/** Sets the passive mode for as default.
+* TODO: see if we can en/disable this per source.
+*/
+void initPassiveFtpMode();
+
+/** Returns the file name for the Sword config file. */
+const QString swordConfigFilename();
+
+/** Returns the Sword directory ($HOME/.sword/) as a QDir, created with absolute path (not canonical).
+*/
+const QDir swordDir();
+
+/** Returns backend Sword manager for the source. */
+CSwordBackend* backend( const sword::InstallSource& is);
+
+}
+
+#endif
diff --git a/src/frontend/bookshelfmanager/removepage/btremovepage.cpp b/src/frontend/bookshelfmanager/removepage/btremovepage.cpp
new file mode 100644
index 0000000..c4324e3
--- /dev/null
+++ b/src/frontend/bookshelfmanager/removepage/btremovepage.cpp
@@ -0,0 +1,229 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+#include "btremovepage.h"
+
+
+#include "backend/btmoduletreeitem.h"
+#include "backend/config/cbtconfig.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+
+#include "util/ctoolclass.h"
+#include "util/cpointers.h"
+#include "util/directoryutil.h"
+#include "util/cresmgr.h"
+
+#include <swmgr.h>
+#include <installmgr.h>
+
+#include <QString>
+#include <QGridLayout>
+#include <QLabel>
+#include <QPushButton>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+#include <QMessageBox>
+#include <QList>
+#include <QMultiMap>
+
+#include <QDebug>
+
+
+
+BtRemovePage::BtRemovePage()
+ : BtConfigPage()
+{
+ QGridLayout* layout = new QGridLayout(this);
+ layout->setMargin(5);
+
+ layout->setSpacing(10);
+ layout->setColumnStretch(1,1);
+ layout->setRowStretch(2,1);
+
+ m_view = new QTreeWidget(this);
+ m_view->setHeaderLabels(QStringList() << tr("Work") << tr("Install path"));
+ m_view->setColumnWidth(0, CToolClass::mWidth(m_view, 20));
+
+ layout->addWidget( m_view, 2, 0, 1, 2);
+
+ m_removeButton = new QPushButton(tr("Remove..."), this);
+ m_removeButton->setToolTip(tr("Remove the selected works"));
+ m_removeButton->setIcon( util::filesystem::DirectoryUtil::getIcon(CResMgr::bookshelfmgr::removepage::remove_icon) );
+ m_removeButton->setEnabled(false);
+ layout->addWidget(m_removeButton, 3, 1, Qt::AlignRight);
+
+ connect(m_view, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), SLOT(slotItemDoubleClicked(QTreeWidgetItem*, int)));
+ connect(m_removeButton, SIGNAL(clicked()), this, SLOT(slotRemoveModules()));
+ connect(CPointers::backend(), SIGNAL(sigSwordSetupChanged(CSwordBackend::SetupChangedReason)), SLOT(slotSwordSetupChanged()));
+ populateModuleList();
+}
+
+QString BtRemovePage::label()
+{
+ return tr("Remove installed works. Select the works and click Remove button.");
+}
+QString BtRemovePage::iconName()
+{
+ return CResMgr::bookshelfmgr::removepage::icon;
+}
+QString BtRemovePage::header()
+{
+ return tr("Remove");
+}
+
+
+void BtRemovePage::populateModuleList()
+{
+
+ m_view->clear();
+ m_selectedModules.clear();
+
+ // disconnect the signal so that we don't have to run functions for every module
+ disconnect(m_view, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(slotSelectionChanged(QTreeWidgetItem*, int)) );
+
+ QList<BTModuleTreeItem::Filter*> empty;
+ BTModuleTreeItem rootItem(empty, (BTModuleTreeItem::Grouping)CBTConfig::get(CBTConfig::bookshelfGrouping));
+ addToTree(&rootItem, m_view->invisibleRootItem());
+
+ // receive signal when user checks modules
+ connect(m_view, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(slotSelectionChanged(QTreeWidgetItem*, int)) );
+ qDebug("BtSourceArea::createModuleTree end");
+}
+
+void BtRemovePage::addToTree(BTModuleTreeItem* item, QTreeWidgetItem* widgetItem)
+{
+ //qDebug()<<"BtRemovePage::addToTree "<<item->text();
+ //qDebug() << "BTMTItem type: " << item->type();
+
+ foreach (BTModuleTreeItem* i, item->children()) {
+ addToTree(i, new QTreeWidgetItem(widgetItem));
+ }
+ if (item->type() != BTModuleTreeItem::Root) {
+ CSwordModuleInfo* mInfo = item->moduleInfo();
+ widgetItem->setText(0, item->text());
+ if (item->type() == BTModuleTreeItem::Category || item->type() == BTModuleTreeItem::Language) {
+ //qDebug() << "item"<<item->text()<< "was cat or lang";
+ widgetItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate);
+ }
+ if (item->type() == BTModuleTreeItem::Module) {
+ //qDebug() << "item"<<item->text()<< "was a module";
+ widgetItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
+ widgetItem->setCheckState(0, Qt::Unchecked);
+
+ //TODO: add the relevant information in to item or tooltip
+ // (install path, is still available from some source)
+
+ QString descr(mInfo->config(CSwordModuleInfo::AbsoluteDataPath));
+ QString toolTipText = CToolClass::moduleToolTip(mInfo);
+ widgetItem->setText(1, descr);
+ widgetItem->setToolTip(0, toolTipText);
+ widgetItem->setToolTip(1, descr);
+ }
+ }
+}
+
+
+
+void BtRemovePage::slotRemoveModules()
+{
+ if ( m_selectedModules.empty() ) {
+ return; //no message, just do nothing
+ }
+
+ QStringList moduleNames;
+ foreach (CSwordModuleInfo* m, m_selectedModules) {
+ moduleNames.append(m->name());
+ }
+ const QString message = tr("You selected the following work(s): ")
+ .append(moduleNames.join(", "))
+ .append("\n\n")
+ .append(tr("Do you really want to remove them from your system?"));
+
+ if ((QMessageBox::question(this, tr("Remove Works?"), message, QMessageBox::Yes|QMessageBox::No, QMessageBox::No) == QMessageBox::Yes)) { //Yes was pressed.
+
+ // Update the module list before really removing. Remember deleting the pointers later.
+ QList<CSwordModuleInfo*> toBeDeleted = CPointers::backend()->takeModulesFromList(moduleNames);
+
+ sword::InstallMgr installMgr;
+ QMap<QString, sword::SWMgr*> mgrDict; //maps config paths to SWMgr objects
+ foreach ( CSwordModuleInfo* mInfo, toBeDeleted ) {
+ Q_ASSERT(mInfo); // Only installed modules could have been selected and returned by takeModulesFromList
+ // Find the install path for the sword manager
+ QString prefixPath = mInfo->config(CSwordModuleInfo::AbsoluteDataPath) + "/";
+ QString dataPath = mInfo->config(CSwordModuleInfo::DataPath);
+ if (dataPath.left(2) == "./") {
+ dataPath = dataPath.mid(2);
+ }
+ if (prefixPath.contains(dataPath)) { //remove module part to get the prefix path
+ prefixPath = prefixPath.remove( prefixPath.indexOf(dataPath), dataPath.length() );
+ }
+ else { //This is an error, should not happen
+ qWarning() << "Removing" << mInfo->name() << "didn't succeed because the absolute path" << prefixPath << "didn't contain the data path" << dataPath;
+ continue; // don't remove this, go to next of the for loop
+ }
+
+ // Create the sword manager and remove the module
+ sword::SWMgr* mgr = mgrDict[ prefixPath ];
+ if (!mgr) { //create new mgr if it's not yet available
+ mgrDict.insert(prefixPath, new sword::SWMgr(prefixPath.toLocal8Bit()));
+ mgr = mgrDict[ prefixPath ];
+ }
+ qDebug() << "Removing the module"<< mInfo->name() << "...";
+ installMgr.removeModule(mgr, mInfo->module()->Name());
+ }
+ //delete the removed moduleinfo pointers
+ qDeleteAll(toBeDeleted);
+ //delete all mgrs which were created above
+ qDeleteAll(mgrDict);
+ mgrDict.clear();
+ }
+}
+
+
+void BtRemovePage::slotSelectionChanged(QTreeWidgetItem* item, int column)
+{
+ //qDebug("BtRemovePage::slotSelectionChanged");
+ // modify the internal list of checked modules
+ // if() leaves groups away
+ if (!item->childCount() && column == 0) {
+ CSwordModuleInfo* mInfo = 0;
+ //qDebug("BtRemovePage::slotSelectionChanged");
+ foreach (CSwordModuleInfo* module, CPointers::backend()->moduleList()) {
+ if (module->name() == item->text(0) && module->config(CSwordModuleInfo::AbsoluteDataPath) == item->text(1)) {
+ mInfo = module;
+ break;
+ }
+ }
+ Q_ASSERT(mInfo); // this should have been found
+ if (item->checkState(0) == Qt::Checked) {
+ //qDebug() << item->text(0) << "in" << item->text(1) << "was checked";
+ m_selectedModules.append(mInfo);
+ } else {
+ //qDebug() << mInfo->name() << "was unchecked";
+ m_selectedModules.removeAll(mInfo); // there is only one, it's a pointer
+ }
+
+ if (m_selectedModules.count() > 0) {
+ m_removeButton->setEnabled(true);
+ } else {
+ m_removeButton->setEnabled(false);
+ }
+ }
+}
+
+void BtRemovePage::slotItemDoubleClicked(QTreeWidgetItem* /*item*/, int /*column*/)
+{
+ // TODO: Open the About dialog.
+}
+
+void BtRemovePage::slotSwordSetupChanged()
+{
+ populateModuleList();
+}
diff --git a/src/frontend/bookshelfmanager/removepage/btremovepage.h b/src/frontend/bookshelfmanager/removepage/btremovepage.h
new file mode 100644
index 0000000..046534c
--- /dev/null
+++ b/src/frontend/bookshelfmanager/removepage/btremovepage.h
@@ -0,0 +1,67 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+#ifndef BTREMOVEPAGE_H
+#define BTREMOVEPAGE_H
+
+#include "frontend/bookshelfmanager/btconfigdialog.h"
+#include "backend/btmoduletreeitem.h"
+
+#include <QString>
+#include <QMultiMap>
+
+//class BTModuleTreeItem;
+
+class QTreeWidget;
+class QTreeWidgetItem;
+class QPushButton;
+
+
+class BtRemovePage : public BtConfigPage
+{
+ Q_OBJECT
+
+public:
+ BtRemovePage();
+
+ ~BtRemovePage(){}
+
+ // BtConfigPage methods
+ QString header();
+ QString iconName();
+ QString label();
+
+ void populateModuleList();
+
+//signals:
+ //void swordSetupChanged();
+
+public slots:
+ void slotSwordSetupChanged();
+
+private slots:
+
+ void slotRemoveModules();
+ /** Handles activating the Remove button. */
+ void slotSelectionChanged(QTreeWidgetItem* item, int column);
+ void slotItemDoubleClicked(QTreeWidgetItem* item, int column);
+
+private: // methods
+ void addToTree(BTModuleTreeItem* item, QTreeWidgetItem* widgetItem);
+
+private: // data
+ QTreeWidget* m_view;
+ QPushButton* m_removeButton;
+ /** Map of module name and install path (absolute path from the moduleinfo config entry).*/
+ QList<CSwordModuleInfo*> m_selectedModules;
+
+};
+
+#endif
diff --git a/src/frontend/btaboutmoduledialog.cpp b/src/frontend/btaboutmoduledialog.cpp
new file mode 100644
index 0000000..1cb326e
--- /dev/null
+++ b/src/frontend/btaboutmoduledialog.cpp
@@ -0,0 +1,45 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btaboutmoduledialog.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "util/dialogutil.h"
+
+#include <QWidget>
+#include <QDialog>
+#include <QTextEdit>
+#include <QVBoxLayout>
+#include <QDialogButtonBox>
+
+BTAboutModuleDialog::BTAboutModuleDialog(QWidget* parent, CSwordModuleInfo* info)
+ : QDialog(parent)
+{
+ //Set the flag to destroy when closed - otherwise eats memory
+ setAttribute(Qt::WA_DeleteOnClose);
+ setWindowTitle(tr("Information About %1").arg(info->name()));
+ resize(650, 400);
+ QVBoxLayout* vboxLayout = new QVBoxLayout(this);
+
+ QTextEdit* textEdit = new QTextEdit(this);
+ textEdit->setReadOnly(true);
+ textEdit->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ vboxLayout->addWidget(textEdit);
+ textEdit->setHtml(info->aboutText());
+
+ QDialogButtonBox* buttonBox = new QDialogButtonBox(this);
+ buttonBox->setOrientation(Qt::Horizontal);
+ buttonBox->setStandardButtons(QDialogButtonBox::Close);
+ util::prepareDialogBox(buttonBox);
+ vboxLayout->addWidget(buttonBox);
+
+
+ QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+}
diff --git a/src/frontend/btaboutmoduledialog.h b/src/frontend/btaboutmoduledialog.h
new file mode 100644
index 0000000..b705893
--- /dev/null
+++ b/src/frontend/btaboutmoduledialog.h
@@ -0,0 +1,30 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTABOUTMODULEDIALOG_H
+#define BTABOUTMODULEDIALOG_H
+
+#include <QDialog>
+
+class CSwordModuleInfo;
+class QWidget;
+
+/**
+ Dialog to show the information about a module.
+
+ @author The BibleTime team <info@bibletime.info>
+*/
+class BTAboutModuleDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ BTAboutModuleDialog(QWidget* parent, CSwordModuleInfo* info);
+};
+
+#endif
diff --git a/src/frontend/cdragdrop.cpp b/src/frontend/cdragdrop.cpp
new file mode 100644
index 0000000..84d6376
--- /dev/null
+++ b/src/frontend/cdragdrop.cpp
@@ -0,0 +1,57 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 2007 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+#include "cdragdrop.h"
+
+#include <QString>
+#include <QByteArray>
+#include <QMimeData>
+#include <QList>
+
+BTMimeData::BTMimeData()
+{}
+
+BTMimeData::~BTMimeData()
+{}
+
+/** Creates a new BTMimeData.
+* Creates a new bookmark item and appends it to the list.
+*/
+BTMimeData::BTMimeData(QString module, QString key, QString description)
+{
+ appendBookmark(module, key, description);
+}
+
+/** Creates a new BTMimeData, setting the text MIME type (see QMimeData::setText()). */
+BTMimeData::BTMimeData(QString text)
+{
+ setText(text);
+}
+
+/** Appends a new bookmark item into the list.*/
+void BTMimeData::appendBookmark(QString module, QString key, QString description)
+{
+ BookmarkItem bm = BookmarkItem(module, key, description);
+ m_bookmarkList.append(bm);
+ setData("BibleTime/Bookmark", QByteArray());
+}
+
+
+
+/** Returns the first bookmark item in the list. */
+const BookmarkItem& BTMimeData::bookmark() const
+{
+ return m_bookmarkList.first();
+}
+
+/** Creates a new bookmark item. */
+BookmarkItem::BookmarkItem(QString module, QString key, QString description)
+: m_moduleName(module), m_key(key), m_description(description)
+{}
diff --git a/src/frontend/cdragdrop.h b/src/frontend/cdragdrop.h
new file mode 100644
index 0000000..2804544
--- /dev/null
+++ b/src/frontend/cdragdrop.h
@@ -0,0 +1,85 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 2007 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CDRAGDROP_H
+#define CDRAGDROP_H
+
+#include <QMimeData>
+#include <QString>
+#include <QStringList>
+
+
+/** Class which represents a bookmark.
+* Includes key, module name and description, all QStrings which have getter methods.
+* Can be created only through BTMimeData object.
+*/
+class BookmarkItem {
+public:
+ /** Returns the key */
+ const QString& key() const {return m_key;} ;
+ /** Returns the module name */
+ const QString& module() const {return m_moduleName;} ;
+ /** Returns the bookmark description */
+ const QString& description() const {return m_description;};
+protected:
+ friend class BTMimeData;
+ BookmarkItem(QString, QString, QString);
+ QString m_moduleName; //the module which is used by this item
+ QString m_key; //the key of a bookmark
+ QString m_description; //the description of a bookmark
+};
+
+
+/**
+* Represents the Drag'n'Drop data.
+* Inherits QMimeData as described in its documentation,
+* "storing custom data in a QMimeData object": approach 3.
+* Any custom data may be added and extracted as with QMimeData, but this class
+* includes also a list of bookmark items.
+* For further documentation see http://doc.trolltech.com/4.3/dnd.html
+*/
+class BTMimeData : public QMimeData {
+ Q_OBJECT
+public:
+
+ /** Type for bookmark item list. Usage: BTMimeData::ItemList. */
+ typedef QList<BookmarkItem> ItemList;
+
+ /** Creates a new empty BTMimeData. */
+ BTMimeData();
+
+ virtual ~BTMimeData();
+
+ /** Creates a new BTMimeData.
+ * Creates a new bookmark item and appends it to the list.
+ * MIME type "BibleTime/Bookmark" is added.
+ * Bookmarks can not be reached by data() method, use bookmark() or bookmarks() instead.
+ */
+ BTMimeData(QString module, QString key, QString description);
+ /** Creates a new BTMimeData, setting the text MIME type (see QMimeData::setText()). */
+ BTMimeData(QString text);
+
+
+ /** Appends a new bookmark item into the list.
+ * Creates the item using the arguments.
+ * MIME type "BibleTime/Bookmark" is added.
+ */
+ virtual void appendBookmark(QString module, QString key, QString description);
+ /** Returns the bookmarks list. */
+ virtual const ItemList& bookmarks() const {return m_bookmarkList;} ;
+ /** Returns the first bookmark item in the list. */
+ virtual const BookmarkItem& bookmark() const;
+
+private:
+ ItemList m_bookmarkList;
+};
+
+#endif
diff --git a/src/frontend/cdragdropmgr.cpp b/src/frontend/cdragdropmgr.cpp
new file mode 100644
index 0000000..11dab79
--- /dev/null
+++ b/src/frontend/cdragdropmgr.cpp
@@ -0,0 +1,262 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#include "cdragdropmgr.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/cswordbackend.h"
+#include "backend/keys/cswordversekey.h"
+#include "util/cpointers.h"
+
+//Sword includes
+#include "versekey.h"
+
+//Qt includes
+#include <qevent.h>
+#include <qdom.h>
+//Added by qt3to4:
+#include <Q3CString>
+
+
+//This is the old old d'n'd system. Use cdragdrop instead.
+
+
+CDragDropMgr::BTDrag::BTDrag( const QString& xml, QWidget* dragSource, const char* name)
+: Q3TextDrag(xml, dragSource, name) {}
+;
+
+//static function to see whether we can decode tje given mime type
+bool CDragDropMgr::BTDrag::canDecode( const QMimeSource * mime ) {
+ if ( mime->provides("BibleTime/DND") ) { //we can decode this type!
+ return true;
+ }
+ return false; //not yet implemented
+};
+
+bool CDragDropMgr::BTDrag::provides( const char* type ) const {
+ return (type == "BibleTime/DND"); //return only true if the type is BibleTime/DND
+};
+
+const char* CDragDropMgr::BTDrag::format( int i ) const {
+ if ( i == 0) { //we support only one format!
+ return "BibleTime/DND";
+ };
+ return 0;
+};
+
+bool CDragDropMgr::BTDrag::decode(const QMimeSource* e, QString& str) {
+ if (canDecode(e)) {
+ str = QString( e->encodedData( "BibleTime/DND" ) );
+ return true;
+ }
+ return false;
+};
+
+bool CDragDropMgr::BTDrag::decode(const QMimeSource* e, QString& str, Q3CString& /*subtype*/) {
+ return decode(e, str);
+};
+
+QByteArray CDragDropMgr::BTDrag::encodedData( const char* /*type*/ ) const {
+ return Q3TextDrag::encodedData("text/plain"); //hack because QTextDrag only accepts text/plainand not our BibleTime/DND type
+};
+
+///////////////////////////// new class //////////////////////
+
+CDragDropMgr::Item::Item( const QString& text )
+: m_type(Text),
+m_bookmarkModuleName(QString::null),
+m_bookmarkKey(QString::null),
+m_bookmarkDescription(QString::null),
+m_text(text) {}
+
+CDragDropMgr::Item::Item( const QString& moduleName, const QString& key, const QString& description )
+: m_type(Bookmark),
+m_bookmarkModuleName(moduleName),
+m_bookmarkKey(key),
+m_bookmarkDescription(description),
+m_text(QString::null) {
+ //we have to make sure the key is saved in it's english representation, so we convert it
+ if (CSwordModuleInfo* mod = CPointers::backend()->findModuleByName( moduleName )) {
+ if (mod->type() == CSwordModuleInfo::Bible || mod->type() == CSwordModuleInfo::Commentary) {
+ CSwordVerseKey vk(0);
+ vk.key( key );
+ vk.setLocale("en");
+
+ m_bookmarkKey = vk.key();
+ // qWarning("english key of %s is %s", key.latin1(), m_bookmarkKey.latin1());
+ }
+ }
+}
+
+CDragDropMgr::Item::~Item() {}
+
+const CDragDropMgr::Item::Type& CDragDropMgr::Item::type() const {
+ //returns the type of drag & drop action this item represents
+ return m_type;
+}
+
+/** Returns the text which is used by this DragDrop Item, only valid if type() == Text */
+const QString& CDragDropMgr::Item::text() const {
+ // Q_ASSERT(!m_text.isEmpty());
+ return m_text;
+}
+
+/** Returns the key, ony valid if type() == Bookmark */
+const QString& CDragDropMgr::Item::bookmarkKey() const {
+ // Q_ASSERT(!m_bookmarkKey.isEmpty());
+ return m_bookmarkKey;
+}
+
+/** Returns the bookmark module, ony valid if type() == Bookmark */
+const QString& CDragDropMgr::Item::bookmarkModule() const {
+ // Q_ASSERT(!m_bookmarkModuleName.isEmpty());
+ return m_bookmarkModuleName;
+}
+
+/** Returns the bookmark description, ony valid if type() == Bookmark */
+const QString& CDragDropMgr::Item::bookmarkDescription() const {
+ // Q_ASSERT(!m_bookmarkDescription.isEmpty());
+ return m_bookmarkDescription;
+}
+
+////////////////////////////////// NEW CLASS //////////////////////////
+
+CDragDropMgr::CDragDropMgr() {}
+
+CDragDropMgr::~CDragDropMgr() {}
+
+const bool CDragDropMgr::canDecode( const QMimeSource* const mime ) {
+ if (CDragDropMgr::BTDrag::canDecode(mime)) {
+ return true;
+ }
+ else if( Q3TextDrag::canDecode(mime) ) {
+ qWarning("QTextDrag can decode this mime!");
+ return true;
+ };
+ return false;
+};
+
+Q3DragObject* const CDragDropMgr::dragObject( CDragDropMgr::ItemList& items, QWidget* dragSource ) {
+ if ( items.count() ) {
+ //process the items and set the data to the dragobject we return later
+ QDomDocument doc("DOC");
+ doc.appendChild( doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
+ QDomElement content = doc.createElement("BibleTimeDND");
+ content.setAttribute("syntaxVersion", "1.0");
+ doc.appendChild(content);
+
+ CDragDropMgr::ItemList::iterator it;
+ for ( it = items.begin(); it != items.end(); ++it ) {
+ Item item = (*it);
+ if (item.type() == Item::Bookmark) { //a bookmark was dragged
+ //append the XML stuff for a bookmark
+ QDomElement bookmark = doc.createElement("BOOKMARK");
+ bookmark.setAttribute("key", item.bookmarkKey());
+ bookmark.setAttribute("description", item.bookmarkDescription());
+ bookmark.setAttribute("moduleName", item.bookmarkModule());
+
+ content.appendChild(bookmark);
+ }
+ else if (item.type() == Item::Text) { //plain text was dragged
+ //append the XML stuff for plain text
+ QDomElement plainText = doc.createElement("TEXT");
+ plainText.setAttribute("text", item.text());
+
+ content.appendChild(plainText);
+ }
+ }
+
+ BTDrag* dragObject = new BTDrag( doc.toString(), dragSource );
+ // qWarning("DND data created: %s", (const char*)doc.toString().utf8());
+ return dragObject;
+ };
+ return 0;
+};
+
+CDragDropMgr::ItemList CDragDropMgr::decode( const QMimeSource* const src) {
+ //if the drag was started by another widget which doesn't use CDragDropMgr (a drag created by QTextDrag)
+ if (canDecode(src) && Q3TextDrag::canDecode(src)) { //if we can decode but it's a QTextDrag and not a BTDrag object
+ QString text;
+ Q3TextDrag::decode(src, text);
+ // qWarning(text.latin1());
+
+ CDragDropMgr::ItemList dndItems;
+ dndItems.append( Item(text) );
+ return dndItems;
+ }
+ else if (!canDecode(src)) { //if we can't decode it
+ return CDragDropMgr::ItemList();
+ };
+
+ QString xmlData;
+ BTDrag::decode(src, xmlData);
+
+ if (xmlData.isEmpty()) { //something went wrong!
+ // qWarning("CDragDropMgr::decode: empty xml data!");
+ return CDragDropMgr::ItemList();
+ }
+ // else {
+ // qWarning("Drag&Drop data is: %s", xmlData.latin1());
+ // }
+
+ //we can handle the dropEvent and have xml data to work on!
+ ItemList dndItems;
+
+ QDomDocument doc;
+ doc.setContent( xmlData );
+
+ QDomElement document = doc.documentElement();
+ if( document.tagName() != "BibleTimeDND" ) { //BibleTime was used in syntax version 1.0
+ qWarning("DragDropMgr::decode: Missing BibleTimeDND doc");
+ return CDragDropMgr::ItemList();
+ }
+ // see if there's a section with the name MAINWINDOW
+ QDomElement elem = document.firstChild().toElement();
+ while (!elem.isNull()) {
+ if (elem.tagName() == "BOOKMARK") { //we found a bookmark!
+ // qWarning("found a bookmark!");
+ const QString key = elem.hasAttribute("key") ? elem.attribute("key") : QString::null;
+ const QString moduleName = elem.hasAttribute("moduleName") ? elem.attribute("moduleName") : QString::null;
+ const QString description = elem.hasAttribute("description") ? elem.attribute("description") : QString::null;
+
+ dndItems.append( CDragDropMgr::Item(moduleName, key, description) );
+ }
+ else if (elem.tagName() == "TEXT") { //we found a plain text passage!
+ const QString text = elem.hasAttribute("text") ? elem.attribute("text") : QString::null;
+ dndItems.append( CDragDropMgr::Item(text) );
+ };
+ elem = elem.nextSibling().toElement();
+ };
+
+ return dndItems;
+};
+
+/** Returns which type the given drop event has, if it's a mixed one (both bookmarks and plain text), which shouldn't happen, it return Item::Unknown. */
+CDragDropMgr::Item::Type CDragDropMgr::dndType( const QMimeSource* e ) {
+ ItemList dndItems = decode(e);
+ if (dndItems.isEmpty()) {//wrong dropEvent or something strange
+ return Item::Unknown;
+ };
+
+ //check whether all items have the ssame type, if they do return the type
+ //as soon as two items have different types return Item::Unknown
+ ItemList::Iterator it;
+ Item::Type type = Item::Unknown;
+ for( it = dndItems.begin(); it != dndItems.end(); ++it ) {
+ if( type == Item::Unknown) { //if Unknown is set this is the first loop, don't return Unknown
+ type = (*it).type();
+ }
+ else if (type != (*it).type() ) {//items have different type, return Item::Unknown
+ return Item::Unknown;
+ };
+ };
+ return type;
+}
diff --git a/src/frontend/cdragdropmgr.h b/src/frontend/cdragdropmgr.h
new file mode 100644
index 0000000..5abad6c
--- /dev/null
+++ b/src/frontend/cdragdropmgr.h
@@ -0,0 +1,160 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CDRAGDROPMGR_H
+#define CDRAGDROPMGR_H
+
+//Qt includes
+#include <QString>
+#include <q3cstring.h>
+#include <q3dragobject.h>
+#include <q3valuelist.h>
+//Added by qt3to4:
+#include <QDropEvent>
+
+//forward declarations
+class QDropEvent;
+class QWidget;
+
+/** This class is the drag'n' drop manager for BibleTime.
+ *
+ * This d'n'd system is replaced with the new classes in cdragdrop.h/cpp. (cdragdropmgr will be deleted later.)
+ *
+ * The dnd is managed by XML code, which defines the type of the drag/drop, the items and the action (moe, copy etc.).
+ * It's possible to create the XML code by passing a list of keys etc.
+ *
+ * Functions:
+ * - dnd_type(), returns either CDragDropMgr::Action_Drag or CDragDropMgr::Action_Drop
+ * - dnd_action(), returns either CDragDropMgr::Move or CDragDropMgr::Copy
+ * - dnd_acceptDrop(), returns true or false. True if the drop could be handled by the CDragDropMgr class, otherwise false
+ *
+ *
+ * The functions which create the XML stuff can't be reimplemented, too. Otherwise we could not guarantee for good XML code
+ * which works everywhere.
+ *
+ * @author The BibleTime team
+ */
+class CDragDropMgr {
+public:
+ //The class which represents one single drag&drop entry (e.g. a bookmark or a portion of text)
+ class Item {
+public:
+ /**
+ * The possible types of Drag&Drop actions.
+ */
+ enum Type {
+ Bookmark = 0, /* A bookmark: Has a key, a module and a description*/
+ Text, /* Simple text, e.g. can be dropped on a module to start a search in this module using the dropped text */
+ Unknown /* For situatiosn like CDragDropMgr::dndType */
+ };
+ /**
+ * This function returns the type of drag this item has
+ */
+ const CDragDropMgr::Item::Type& type() const;
+ /**
+ * Returns the key, ony valid if type() == Bookmark
+ */
+ const QString& bookmarkKey() const;
+ /**
+ * Returns the module name, ony valid if type() == Bookmark
+ */
+ const QString& bookmarkModule() const;
+ /**
+ * Returns the bookmark description, ony valid if type() == Bookmark
+ */
+ const QString& bookmarkDescription() const;
+ /**
+ * Returns the text which is used by this DragDrop Item, only valid if type() == Text
+ */
+ const QString& text() const;
+
+ // protected:
+ friend class CDragDropMgr;
+ /*
+ * We use protected constructor and destructor because creation of objects
+ * of this class sould only be possible for CDragDropMgr
+ */
+
+ /** Constructor for a text item
+ * This constructor automatically sets the type member to Text
+ * This is also the default constructor
+ */
+ Item(const QString& text = QString::null );
+ /** Constructor for a Bookmark item
+ * This constructor automatically sets the type member to Bookmark
+ */
+ Item(const QString& moduleName, const QString& key, const QString& description);
+ virtual ~Item();
+
+private:
+ Type m_type; //the member to save the type of the action
+ QString m_bookmarkModuleName; //the modules which is used by this item, only valid for type() == Bookmark
+ QString m_bookmarkKey; //the key of a bookmark, only valid if type() == Bookmark
+ QString m_bookmarkDescription; //the description of a bookmark, only valid if type() == Bookmark
+ QString m_text; //the text of this item, only valid if type() == Text
+ }
+ ; //end of class CDragDropMgr::Item
+
+ //the item list we're using
+ typedef Q3ValueList<Item> ItemList;
+
+ /** Return whether the drop should be accepted
+ * This functions tests whether the drop should be accepted or not. It returns true if the drop object
+ * is supported by the CDragDropMgr and if it cotains valid data. Oterwise this function returns false.
+ */
+ static const bool canDecode( const QMimeSource* const mime );
+ /**
+ * This function returns the drag object with the data which represents the items given as parameter
+ * If the list is invalid or empty we return NULL.
+ */
+ static Q3DragObject* const dragObject( CDragDropMgr::ItemList& items, QWidget* dragSource );
+
+ /**
+ * Decodes the XML stuff we passed to the dragObject at creation time.
+ * Returns a list of CDragDropMgr::Item objects.
+ * If it's a wrong dropEvent we return an empty ist
+ */
+ static CDragDropMgr::ItemList decode( const QMimeSource* const src );
+ /**
+ * Returns which type the given drop event has, if it's a mixed one (both bookmarks and plain text),
+ * which shouldn't happen, it return Item::Unknown.
+ * It also returns Unknown if the drop event is not supported.
+ */
+ static CDragDropMgr::Item::Type dndType( const QMimeSource* e );
+
+protected:
+ //The class which represents our XML drag object stuff
+class BTDrag : public Q3TextDrag {
+public:
+ BTDrag( const QString& xml, QWidget* dragSource = 0, const char* name = 0);
+ //reimplemented static publoc function to provide functionality for BibleTime XML drags
+ static bool canDecode( const QMimeSource * e );
+ virtual bool provides( const char* type ) const;
+ virtual const char* format( int i = 0 ) const;
+
+ virtual QByteArray encodedData( const char* type ) const;
+
+protected:
+ friend class CDragDropMgr;
+ //made protected because the BibleTime classes may not manage the data of BTDrag
+ // virtual void setText(const QString& text);
+
+ //made protected because the BibleTime classes should not manage the DRag&Drop stuff themself
+ static bool decode(const QMimeSource* e, QString& str);
+ static bool decode(const QMimeSource* e, QString& str, Q3CString& subtype);
+ };
+
+ //protected constructor and destructor because we do not allow inheritance, functionality is provided by static functions
+ CDragDropMgr();
+ virtual ~CDragDropMgr();
+};
+
+#endif
diff --git a/src/frontend/cexportmanager.cpp b/src/frontend/cexportmanager.cpp
new file mode 100644
index 0000000..5c94c39
--- /dev/null
+++ b/src/frontend/cexportmanager.cpp
@@ -0,0 +1,546 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#include "cexportmanager.h"
+
+#include "backend/keys/cswordkey.h"
+#include "backend/keys/cswordversekey.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/creferencemanager.h"
+#include "backend/managers/cdisplaytemplatemgr.h"
+#include "backend/rendering/centrydisplay.h"
+#include "backend/rendering/chtmlexportrendering.h"
+#include "backend/rendering/cplaintextexportrendering.h"
+
+#include "frontend/cprinter.h"
+
+#include "util/ctoolclass.h"
+#include <boost/scoped_ptr.hpp>
+
+//Qt includes
+#include <QClipboard>
+#include <QList>
+#include <QProgressDialog>
+#include <QTextStream>
+#include <QApplication>
+#include <QFileDialog>
+
+//KDE includes
+
+
+//Sword includes
+#include <swkey.h>
+#include <listkey.h>
+
+using namespace Rendering;
+using namespace Printing;
+
+CExportManager::CExportManager(const QString& caption, const bool showProgress, const QString& progressLabel, const CSwordBackend::FilterOptions filterOptions, const CSwordBackend::DisplayOptions displayOptions) {
+ m_caption = !caption.isEmpty() ? caption : QString::fromLatin1("BibleTime");
+ m_progressLabel = progressLabel;
+ m_filterOptions = filterOptions;
+ m_displayOptions = displayOptions;
+ m_showProgress = showProgress;
+ m_progressDialog = 0;
+}
+
+bool CExportManager::saveKey(CSwordKey* key, const Format format, const bool addText) {
+ if (!key) {
+ return false;
+ }
+ if (!key->module()) {
+ return false;
+ }
+ const QString filename = getSaveFileName(format);
+ if (filename.isEmpty()) {
+ return false;
+ }
+
+ CSwordBackend::FilterOptions filterOptions = m_filterOptions;
+ filterOptions.footnotes = false;
+ filterOptions.strongNumbers = false;
+ filterOptions.morphTags = false;
+ filterOptions.lemmas = false;
+ filterOptions.scriptureReferences = false;
+ filterOptions.textualVariants = false;
+
+ CHTMLExportRendering::Settings settings(addText);
+ boost::scoped_ptr<CTextRendering> render (
+ (format == HTML)
+ ? new CHTMLExportRendering(settings, m_displayOptions, filterOptions)
+ : new CPlainTextExportRendering(settings, m_displayOptions, filterOptions)
+ );
+
+ QString text;
+ QString startKey;
+ QString stopKey;
+
+ QList<CSwordModuleInfo*> modules;
+ modules.append(key->module());
+
+ CSwordVerseKey *vk = dynamic_cast<CSwordVerseKey*>(key);
+ if (vk && vk->isBoundSet()) {
+ text = render->renderKeyRange( QString::fromUtf8(vk->LowerBound()), QString::fromUtf8(vk->UpperBound()), modules );
+ }
+ else { //no range supported
+ text = render->renderSingleKey(key->key(), modules);
+ }
+
+ if (!progressWasCancelled()) {
+ CToolClass::savePlainFile(filename, text, false, (format==HTML) ? QTextCodec::codecForName("UTF-8") : QTextCodec::codecForLocale() );
+ closeProgressDialog();
+ return true;
+ }
+ return false;
+}
+
+bool CExportManager::saveKeyList(sword::ListKey* list, CSwordModuleInfo* module, const Format format, const bool addText) {
+ if (!list->Count())
+ return false;
+
+ const QString filename = getSaveFileName(format);
+ if (filename.isEmpty()) {
+ return false;
+ }
+
+ CSwordBackend::FilterOptions filterOptions = m_filterOptions;
+ filterOptions.footnotes = false;
+ filterOptions.strongNumbers = false;
+ filterOptions.morphTags = false;
+ filterOptions.lemmas = false;
+ filterOptions.scriptureReferences = false;
+ filterOptions.textualVariants = false;
+
+ CHTMLExportRendering::Settings settings(addText);
+ boost::scoped_ptr<CTextRendering> render (
+ (format == HTML)
+ ? new CHTMLExportRendering(settings, m_displayOptions, filterOptions)
+ : new CPlainTextExportRendering(settings, m_displayOptions, filterOptions)
+ );
+
+ CTextRendering::KeyTree tree;
+
+ setProgressRange(list->Count());
+ CTextRendering::KeyTreeItem::Settings itemSettings;
+ itemSettings.highlight = false;
+
+ *list = sword::TOP;
+ while (!list->Error() && !progressWasCancelled()) {
+ tree.append( new CTextRendering::KeyTreeItem(QString::fromLocal8Bit((const char*)(*list)) , module, itemSettings) );
+ incProgress();
+
+ (*list)++;
+ }
+
+ const QString text = render->renderKeyTree(tree);
+
+ if (!progressWasCancelled()) {
+ CToolClass::savePlainFile(filename, text, false, (format==HTML) ? QTextCodec::codecForName("UTF-8") : QTextCodec::codecForLocale() );
+ closeProgressDialog();
+ return true;
+ }
+ return false;
+}
+
+bool CExportManager::saveKeyList(QList<CSwordKey*>& list, const Format format, const bool addText ) {
+ if (!list.count())
+ return false;
+
+ const QString filename = getSaveFileName(format);
+ if (filename.isEmpty()) {
+ return false;
+ }
+
+ CSwordBackend::FilterOptions filterOptions = m_filterOptions;
+ filterOptions.footnotes = false;
+ filterOptions.strongNumbers = false;
+ filterOptions.morphTags = false;
+ filterOptions.lemmas = false;
+ filterOptions.scriptureReferences = false;
+ filterOptions.textualVariants = false;
+
+ CHTMLExportRendering::Settings settings(addText);
+ boost::scoped_ptr<CTextRendering> render (
+ (format == HTML)
+ ? new CHTMLExportRendering(settings, m_displayOptions, filterOptions)
+ : new CPlainTextExportRendering(settings, m_displayOptions, filterOptions)
+ );
+
+ CTextRendering::KeyTree tree;
+
+ setProgressRange(list.count());
+ CTextRendering::KeyTreeItem::Settings itemSettings;
+ itemSettings.highlight = false;
+
+ QListIterator<CSwordKey*> it(list);
+ while (it.hasNext() && !progressWasCancelled()){
+ CSwordKey* k = it.next();
+ tree.append( new CTextRendering::KeyTreeItem(k->key(), k->module(), itemSettings) );
+ incProgress();
+ };
+
+ const QString text = render->renderKeyTree(tree);
+
+ if (!progressWasCancelled()) {
+ CToolClass::savePlainFile(filename, text, false, (format==HTML) ? QTextCodec::codecForName("UTF-8") : QTextCodec::codecForLocale() );
+ closeProgressDialog();
+ return true;
+ }
+ return false;
+}
+
+bool CExportManager::copyKey(CSwordKey* key, const Format format, const bool addText) {
+ if (!key) {
+ return false;
+ }
+ if (!key->module()) {
+ return false;
+ }
+
+ CSwordBackend::FilterOptions filterOptions = m_filterOptions;
+ filterOptions.footnotes = false;
+ filterOptions.strongNumbers = false;
+ filterOptions.morphTags = false;
+ filterOptions.lemmas = false;
+ filterOptions.scriptureReferences = false;
+ filterOptions.textualVariants = false;
+
+ CHTMLExportRendering::Settings settings(addText);
+ boost::scoped_ptr<CTextRendering> render (
+ (format == HTML)
+ ? new CHTMLExportRendering(settings, m_displayOptions, filterOptions)
+ : new CPlainTextExportRendering(settings, m_displayOptions, filterOptions)
+ );
+
+ QString text;
+ QString startKey;
+ QString stopKey;
+
+ QList<CSwordModuleInfo*> modules;
+ modules.append(key->module());
+
+ CSwordVerseKey *vk = dynamic_cast<CSwordVerseKey*>(key);
+ if (vk && vk->isBoundSet()) {
+ text = render->renderKeyRange(
+ QString::fromUtf8(vk->LowerBound()),
+ QString::fromUtf8(vk->UpperBound()),
+ modules
+ );
+ }
+ else { //no range supported
+ text = render->renderSingleKey(key->key(), modules);
+ }
+
+ QApplication::clipboard()->setText(text);
+ return true;
+}
+
+bool CExportManager::copyKeyList(sword::ListKey* list, CSwordModuleInfo* module, const Format format, const bool addText) {
+ if (!list->Count())
+ return false;
+
+ CSwordBackend::FilterOptions filterOptions = m_filterOptions;
+ filterOptions.footnotes = false;
+ filterOptions.strongNumbers = false;
+ filterOptions.morphTags = false;
+ filterOptions.lemmas = false;
+ filterOptions.scriptureReferences = false;
+ filterOptions.textualVariants = false;
+
+ CHTMLExportRendering::Settings settings(addText);
+ boost::scoped_ptr<CTextRendering> render (
+ (format == HTML)
+ ? new CHTMLExportRendering(settings, m_displayOptions, filterOptions)
+ : new CPlainTextExportRendering(settings, m_displayOptions, filterOptions)
+ );
+
+ CTextRendering::KeyTree tree;
+ CTextRendering::KeyTreeItem::Settings itemSettings;
+ itemSettings.highlight = false;
+
+ *list = sword::TOP;
+ while (!list->Error() && !progressWasCancelled()) {
+ tree.append( new CTextRendering::KeyTreeItem(QString::fromLocal8Bit((const char*)(*list)) , module, itemSettings) );
+
+ (*list)++;
+ }
+
+ const QString text = render->renderKeyTree(tree);
+ QApplication::clipboard()->setText(text);
+ return true;
+}
+
+
+bool CExportManager::copyKeyList(QList<CSwordKey*>& list, const Format format, const bool addText ) {
+ if (!list.count())
+ return false;
+
+ CSwordBackend::FilterOptions filterOptions = m_filterOptions;
+ filterOptions.footnotes = false;
+ filterOptions.strongNumbers = false;
+ filterOptions.morphTags = false;
+ filterOptions.lemmas = false;
+ filterOptions.scriptureReferences = false;
+ filterOptions.textualVariants = false;
+
+ CHTMLExportRendering::Settings settings(addText);
+ boost::scoped_ptr<CTextRendering> render (
+ (format == HTML)
+ ? new CHTMLExportRendering(settings, m_displayOptions, filterOptions)
+ : new CPlainTextExportRendering(settings, m_displayOptions, filterOptions)
+ );
+
+ CTextRendering::KeyTree tree;
+
+ CTextRendering::KeyTreeItem::Settings itemSettings;
+ itemSettings.highlight = false;
+
+ QListIterator<CSwordKey*> it(list);
+ while (it.hasNext() && !progressWasCancelled()){
+ CSwordKey* k = it.next();
+ tree.append( new CTextRendering::KeyTreeItem(k->key(), k->module(), itemSettings) );
+ incProgress();
+ };
+
+ const QString text = render->renderKeyTree(tree);
+ QApplication::clipboard()->setText(text);
+ if (!progressWasCancelled()){
+ closeProgressDialog();
+ }
+ return true;
+}
+
+bool CExportManager::printKeyList(sword::ListKey* list, CSwordModuleInfo* module, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions) {
+ CPrinter::KeyTreeItem::Settings settings;
+ CPrinter::KeyTree tree;
+
+ QString startKey, stopKey;
+ setProgressRange(list->Count());
+
+ (*list) = sword::TOP;
+ while (!list->Error() && !progressWasCancelled()) {
+ sword::VerseKey* vk = dynamic_cast<sword::VerseKey*>(list);
+ if (vk) {
+ startKey = QString::fromUtf8((const char*)(vk->LowerBound()) );
+ stopKey = QString::fromUtf8((const char*)(vk->UpperBound()) );
+ tree.append( new CPrinter::KeyTreeItem(startKey, stopKey, module, settings) );
+ }
+ else {
+ startKey = QString::fromUtf8((const char*)*list);
+ tree.append( new CPrinter::KeyTreeItem(startKey, module, settings) );
+ }
+
+ (*list)++;
+ incProgress();
+ }
+
+ boost::scoped_ptr<CPrinter> printer(new CPrinter(0, displayOptions, filterOptions));
+
+ if (!progressWasCancelled()) {
+ printer->printKeyTree(tree);
+ closeProgressDialog();
+ return true;
+ }
+
+ return false;
+}
+
+bool CExportManager::printKey( CSwordModuleInfo* module, const QString& startKey, const QString& stopKey, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions ) {
+ CPrinter::KeyTreeItem::Settings settings;
+ settings.keyRenderingFace =
+ displayOptions.verseNumbers
+ ? CPrinter::KeyTreeItem::Settings::SimpleKey
+ : CPrinter::KeyTreeItem::Settings::NoKey;
+
+ CPrinter::KeyTree tree;
+ if (startKey != stopKey) {
+ tree.append( new CPrinter::KeyTreeItem(startKey, stopKey, module, settings) );
+ }
+ else {
+ tree.append( new CPrinter::KeyTreeItem(startKey, module, settings) );
+ }
+
+ boost::scoped_ptr<CPrinter> printer(new CPrinter(0, displayOptions, filterOptions));
+ printer->printKeyTree(tree);
+ return true;
+}
+
+bool CExportManager::printKey( CSwordKey* key, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions) {
+ CPrinter::KeyTreeItem::Settings settings;
+ settings.keyRenderingFace =
+ displayOptions.verseNumbers
+ ? CPrinter::KeyTreeItem::Settings::SimpleKey
+ : CPrinter::KeyTreeItem::Settings::NoKey;
+
+ CPrinter::KeyTree tree;
+ tree.append( new CPrinter::KeyTreeItem(key->key(), key->module(), settings) );
+
+ boost::scoped_ptr<CPrinter> printer(new CPrinter(0, displayOptions, filterOptions));
+ printer->printKeyTree(tree);
+ return true;
+}
+
+/** Prints a key using the hyperlink created by CReferenceManager. */
+bool CExportManager::printByHyperlink( const QString& hyperlink, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions ) {
+ QString moduleName;
+ QString keyName;
+ CReferenceManager::Type type;
+
+ CReferenceManager::decodeHyperlink(hyperlink, moduleName, keyName, type);
+ if (moduleName.isEmpty()) {
+ moduleName = CReferenceManager::preferredModule(type);
+ }
+
+ CPrinter::KeyTree tree;
+ CPrinter::KeyTreeItem::Settings settings;
+ settings.keyRenderingFace =
+ displayOptions.verseNumbers
+ ? CPrinter::KeyTreeItem::Settings::SimpleKey
+ : CPrinter::KeyTreeItem::Settings::NoKey;
+
+ CSwordModuleInfo* module = backend()->findModuleByName(moduleName);
+ Q_ASSERT(module);
+
+ if (module) {
+ //check if we have a range of entries or a single one
+ if ((module->type() == CSwordModuleInfo::Bible) || (module->type() == CSwordModuleInfo::Commentary)) {
+ sword::ListKey verses = sword::VerseKey().ParseVerseList((const char*)keyName.toUtf8(), "Genesis 1:1", true);
+
+ for (int i = 0; i < verses.Count(); ++i) {
+ sword::VerseKey* element = dynamic_cast<sword::VerseKey*>(verses.GetElement(i));
+ if (element) {
+ const QString startKey = QString::fromUtf8(element->LowerBound().getText());
+ const QString stopKey = QString::fromUtf8(element->UpperBound().getText());
+
+ tree.append( new CPrinter::KeyTreeItem(startKey, stopKey, module, settings) );
+ }
+ else if (verses.GetElement(i)) {
+ const QString key = QString::fromUtf8(verses.GetElement(i)->getText());
+
+ tree.append( new CPrinter::KeyTreeItem(key, module, settings) );
+ }
+ }
+ }
+ else {
+ tree.append( new CPrinter::KeyTreeItem(keyName, module, settings) );
+ }
+ }
+
+ boost::scoped_ptr<CPrinter> printer(new CPrinter(0, displayOptions, filterOptions));
+ printer->printKeyTree(tree);
+ return true;
+}
+
+bool CExportManager::printKeyList(const QStringList& list,CSwordModuleInfo* module, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions) {
+ CPrinter::KeyTreeItem::Settings settings;
+ settings.keyRenderingFace =
+ displayOptions.verseNumbers
+ ? CPrinter::KeyTreeItem::Settings::SimpleKey
+ : CPrinter::KeyTreeItem::Settings::NoKey;
+
+ CPrinter::KeyTree tree;
+ setProgressRange(list.count());
+
+ const QStringList::const_iterator end = list.constEnd();
+ for (QStringList::const_iterator it = list.constBegin(); (it != end) && !progressWasCancelled(); ++it) {
+ tree.append( new CPrinter::KeyTreeItem(*it, module, settings) );
+ incProgress();
+ }
+
+ boost::scoped_ptr<CPrinter> printer(new CPrinter(0, displayOptions, filterOptions));
+
+ if (!progressWasCancelled()) {
+ printer->printKeyTree(tree);
+ closeProgressDialog();
+ return true;
+ }
+
+ return false;
+}
+
+/** Returns the string for the filedialogs to show the correct files. */
+const QString CExportManager::filterString( const Format format ) {
+ switch (format) {
+ case HTML:
+ return QObject::tr("HTML files") + QString(" (*.html *.htm);;") + QObject::tr("All files") + QString(" (*.*)");
+ case Text:
+ return QObject::tr("Text files") + QString(" (*.txt);;") + QObject::tr("All files") + QString(" (*.*)");
+ default:
+ return QObject::tr("All files") + QString(" (*.*)");
+ }
+}
+
+/** Returns a filename to save a file. */
+const QString CExportManager::getSaveFileName(const Format format) {
+ return QFileDialog::getSaveFileName(0, QObject::tr("Save file"), "", filterString(format), 0);
+}
+
+/** Returns a string containing the linebreak for the current format. */
+const QString CExportManager::lineBreak(const Format format) {
+ if (static_cast<bool>(m_displayOptions.lineBreaks))
+ return (format == HTML) ? QString::fromLatin1("<br/>\n") : QString::fromLatin1("\n");
+
+ return QString::null;
+}
+
+/** No descriptions */
+void CExportManager::setProgressRange( const int items ) {
+ if (QProgressDialog* dlg = progressDialog()) {
+ dlg->setMaximum(items);
+ dlg->setValue(0);
+ dlg->setMinimumDuration(0);
+ dlg->show();
+ // dlg->repaint();
+ qApp->processEvents(); //do not lock the GUI!
+ }
+}
+
+/** Creates the progress dialog with the correct settings. */
+QProgressDialog* CExportManager::progressDialog() {
+ if (!m_showProgress) {
+ return 0;
+ }
+
+ if (!m_progressDialog) {
+ m_progressDialog = new QProgressDialog(0, Qt::Dialog );
+ m_progressDialog->setLabelText(m_progressLabel);
+
+ m_progressDialog->setWindowTitle("BibleTime");
+ }
+
+ return m_progressDialog;
+}
+
+/** Increments the progress by one item. */
+void CExportManager::incProgress() {
+ if (QProgressDialog* dlg = progressDialog()) {
+ dlg->setValue( dlg->value() + 1 );
+ }
+}
+
+/** No descriptions */
+bool CExportManager::progressWasCancelled() {
+ if (QProgressDialog* dlg = progressDialog()) {
+ return dlg->wasCanceled();
+ }
+
+ return true;
+}
+
+/** Closes the progress dialog immediatly. */
+void CExportManager::closeProgressDialog() {
+ if (QProgressDialog* dlg = progressDialog()) {
+ dlg->close();
+ dlg->reset();
+ }
+
+ qApp->processEvents(); //do not lock the GUI!
+}
diff --git a/src/frontend/cexportmanager.h b/src/frontend/cexportmanager.h
new file mode 100644
index 0000000..210bb2b
--- /dev/null
+++ b/src/frontend/cexportmanager.h
@@ -0,0 +1,95 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CEXPORTMANAGER_H
+#define CEXPORTMANAGER_H
+
+#include "backend/config/cbtconfig.h"
+#include "backend/managers/cswordbackend.h"
+#include "util/cpointers.h"
+
+#include <QString>
+#include <QList>
+
+class ListKey;
+class CSwordKey;
+class CSwordModuleInfo;
+class QProgressDialog;
+
+/** Contains the functions to export text to disk, clipboard or printer.
+ * @author The BibleTime team
+ */
+class CExportManager : CPointers {
+public:
+ /** The format the export actions should have
+ */
+ enum Format {
+ HTML,
+ Text
+ };
+
+ CExportManager(const QString& caption, const bool showProgress = true, const QString& progressLabel = QString::null, const CSwordBackend::FilterOptions filterOptions = CBTConfig::getFilterOptionDefaults(), const CSwordBackend::DisplayOptions displayOptions = CBTConfig::getDisplayOptionDefaults());
+
+ bool saveKey(CSwordKey* key, const Format format, const bool addText);
+ bool saveKeyList(sword::ListKey* list, CSwordModuleInfo* module, const Format format, const bool addText);
+ bool saveKeyList(QList<CSwordKey*>& list, const Format format, const bool addText );
+
+ bool copyKey(CSwordKey* key, const Format format, const bool addText);
+ bool copyKeyList(sword::ListKey* list, CSwordModuleInfo* module, const Format format, const bool addText);
+ bool copyKeyList(QList<CSwordKey*>& list, const Format format, const bool addText );
+
+ bool printKey(CSwordKey* key, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions);
+ bool printKey( CSwordModuleInfo* module, const QString& startKey, const QString& stopKey, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions );
+ bool printByHyperlink(const QString& hyperlink, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions);
+ bool printKeyList(sword::ListKey* list, CSwordModuleInfo* module, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions);
+ bool printKeyList(const QStringList& list,CSwordModuleInfo* module, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions);
+
+protected: // Protected methods
+ /**
+ * Returns the string for the filedialogs to show the correct files.
+ */
+ const QString filterString( const Format format );
+ /**
+ * Returns a filename to save a file.
+ */
+ const QString getSaveFileName(const Format format);
+ /**
+ * Returns a string containing the linebreak for the current format.
+ */
+ const QString lineBreak( const Format format );
+
+private:
+ QString m_caption;
+ QString m_progressLabel;
+ bool m_showProgress;
+ CSwordBackend::FilterOptions m_filterOptions;
+ CSwordBackend::DisplayOptions m_displayOptions;
+
+ QProgressDialog* m_progressDialog;
+
+ /**
+ * Creates the progress dialog with the correct settings.
+ */
+ QProgressDialog* progressDialog();
+ /**
+ * Returns the CSS string used in HTML pages.
+ */
+ void setProgressRange( const int item );
+ /**
+ * Increments the progress by one item.
+ */
+ inline void incProgress();
+ bool progressWasCancelled();
+ /**
+ * Closes the progress dialog immediately.
+ */
+ void closeProgressDialog();
+};
+
+#endif
diff --git a/src/frontend/cinfodisplay.cpp b/src/frontend/cinfodisplay.cpp
new file mode 100644
index 0000000..0c167c4
--- /dev/null
+++ b/src/frontend/cinfodisplay.cpp
@@ -0,0 +1,466 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+// BibleTime includes
+#include "cinfodisplay.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/keys/cswordkey.h"
+#include "backend/keys/cswordversekey.h"
+#include "backend/managers/creferencemanager.h"
+#include "backend/managers/cdisplaytemplatemgr.h"
+
+#include "backend/config/cbtconfig.h"
+#include "frontend/crossrefrendering.h"
+
+#include "frontend/display/cdisplay.h"
+#include "frontend/display/creaddisplay.h"
+
+#include <boost/scoped_ptr.hpp>
+
+// Sword includes
+#include <listkey.h>
+
+// Qt includes
+#include <QLayout>
+#include <QLabel>
+#include <QRegExp>
+#include <QVBoxLayout>
+#include <QAction>
+#include <QDebug>
+#include <QSize>
+
+using namespace Rendering;
+using namespace sword;
+
+namespace InfoDisplay {
+
+CInfoDisplay::CInfoDisplay(QWidget *parent) : QWidget(parent)
+{
+ QVBoxLayout* layout = new QVBoxLayout(this);
+ setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);
+
+ m_htmlPart = CDisplay::createReadInstance(0, this);
+ m_htmlPart->setMouseTracking(false); //we don't want strong/lemma/note mouse infos
+ m_htmlPart->view()->setAcceptDrops(false);
+
+ m_copyAction = new QAction(tr("Copy"), this);
+ m_copyAction->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_C) );
+ QObject::connect(m_copyAction, SIGNAL(triggered()), m_htmlPart->connectionsProxy(), SLOT(copySelection()) );
+
+ connect(
+ m_htmlPart->connectionsProxy(),
+ SIGNAL(referenceClicked(const QString&, const QString&)),
+ SLOT(lookupInfo(const QString&, const QString&))
+ );
+
+ layout->addWidget(m_htmlPart->view());
+ QString initialMagText = tr("<small>This is the Mag viewer area. Hover the mouse over links or other items which include some data and the contents appear in the Mag after a short delay. Move the mouse into Mag rapidly or lock the view by pressing and holding Shift while moving the mouse.</small>");
+ m_htmlPart->setText(initialMagText);
+}
+
+
+CInfoDisplay::~CInfoDisplay() {
+ delete m_copyAction;
+}
+
+void CInfoDisplay::lookupInfo(const QString &mod_name, const QString &key_text) {
+ qDebug("CInfoDisplay::lookup");
+ qDebug() << mod_name << key_text;
+ CSwordModuleInfo* m = CPointers::backend()->findModuleByName(mod_name);
+ Q_ASSERT(m);
+ if (!m)
+ return;
+
+ boost::scoped_ptr<CSwordKey> key( CSwordKey::createInstance(m) );
+ key->key( key_text );
+
+ CDisplayTemplateMgr* mgr = CPointers::displayTemplateManager();
+ CDisplayTemplateMgr::Settings settings;
+ settings.pageCSS_ID = "infodisplay";
+ // settings.langAbbrev = "";
+ QString content = mgr->fillTemplate(CBTConfig::get
+ (CBTConfig::displayStyle), key->renderedText(), settings);
+ m_htmlPart->setText(content);
+ // qWarning("setting text:\n%s", content.latin1());
+}
+
+void CInfoDisplay::setInfo(const InfoType type, const QString& data) {
+ ListInfoData list;
+ list.append( qMakePair(type, data) );
+
+ setInfo(list);
+}
+
+
+void CInfoDisplay::setInfo(const ListInfoData& list) {
+ //if the widget is hidden it would be inefficient to render and display the data
+ if (!isVisible()) {
+ return;
+ }
+
+ if (list.count() == 0) {
+ m_htmlPart->setText("<html></html>");
+ return;
+ }
+
+ QString text;
+
+ ListInfoData::const_iterator end = list.end();
+ for (ListInfoData::const_iterator it = list.begin(); it != end; ++it) {
+ switch ( (*it).first ) {
+ case Lemma:
+ text.append( decodeStrongs( (*it).second ) );
+ continue;
+ case Morph:
+ text.append( decodeMorph( (*it).second ) );
+ continue;
+ case CrossReference:
+ text.append( decodeCrossReference( (*it).second ) );
+ continue;
+ case Footnote:
+ text.append( decodeFootnote( (*it).second ) );
+ continue;
+ case WordTranslation:
+ text.append( getWordTranslation( (*it).second ) );
+ continue;
+ case WordGloss:
+ //text.append( getWordTranslation( (*it).second ) );
+ continue;
+ case Abbreviation:
+ text.append( decodeAbbreviation( (*it).second ) );
+ continue;
+ case Text:
+ text.append( (*it).second );
+ continue;
+ default:
+ continue;
+ };
+ }
+
+ CDisplayTemplateMgr* mgr = CPointers::displayTemplateManager();
+ CDisplayTemplateMgr::Settings settings;
+ settings.pageCSS_ID = "infodisplay";
+ // settings.langAbbrev = "";
+ QString content = mgr->fillTemplate(CBTConfig::get
+ (CBTConfig::displayStyle), text, settings);
+
+ // qWarning("setting text:\n%s", content.latin1());
+
+ m_htmlPart->setText(content);
+}
+
+
+const QString CInfoDisplay::decodeAbbreviation( const QString& data ) {
+ // QStringList strongs = QStringList::split("|", data);
+ QString ret;
+ QString text = data;
+
+ ret.append(
+ QString("<div class=\"abbreviation\"><h3>%1: %2</h3><p>%3</p></div>")
+ .arg(tr("Abbreviation"))
+ .arg("text")
+ .arg(text));
+
+ return ret;
+}
+
+const QString CInfoDisplay::decodeCrossReference( const QString& data ) {
+ Q_ASSERT(!data.isEmpty());
+ if (data.isEmpty()) {
+ return QString("<div class=\"crossrefinfo\"><h3>%1</h3></div>")
+ .arg(tr("Cross references"));
+ }
+
+ // qWarning("setting crossref %s", data.latin1());
+
+ CSwordBackend::DisplayOptions dispOpts;
+ dispOpts.lineBreaks = false;
+ dispOpts.verseNumbers = true;
+
+ CSwordBackend::FilterOptions filterOpts;
+ filterOpts.headings = false;
+ filterOpts.strongNumbers = false;
+ filterOpts.morphTags = false;
+ filterOpts.lemmas = false;
+ filterOpts.footnotes = false;
+ filterOpts.scriptureReferences = false;
+
+ CrossRefRendering renderer(dispOpts, filterOpts);
+ CTextRendering::KeyTree tree;
+
+ // const bool isBible = true;
+ CSwordModuleInfo* module = CBTConfig::get
+ (CBTConfig::standardBible);
+
+ //a prefixed module gives the module to look into
+ QRegExp re("^[^ ]+:");
+ // re.setMinimal(true);
+ int pos = re.indexIn(data);
+ if (pos != -1) {
+ pos += re.matchedLength()-1;
+ }
+
+ if (pos > 0) {
+ const QString moduleName = data.left(pos);
+ // qWarning("found module %s", moduleName.latin1());
+ module = CPointers::backend()->findModuleByName(moduleName);
+ if (!module) {
+ module = CBTConfig::get
+ (CBTConfig::standardBible);
+ }
+ // Q_ASSERT(module);
+ }
+
+ //Q_ASSERT(module); //why? the existense of the module is tested later
+ CTextRendering::KeyTreeItem::Settings settings (
+ false,
+ CTextRendering::KeyTreeItem::Settings::CompleteShort
+ );
+
+ if (module && (module->type() == CSwordModuleInfo::Bible)) {
+ VerseKey vk;
+ sword::ListKey refs = vk.ParseVerseList((const char*)data.mid((pos == -1) ? 0 : pos+1).toUtf8(), "Gen 1:1", true);
+
+ for (int i = 0; i < refs.Count(); ++i) {
+ SWKey* key = refs.getElement(i);
+ Q_ASSERT(key);
+ VerseKey* vk = dynamic_cast<VerseKey*>(key);
+
+ CTextRendering::KeyTreeItem* itm = (CTextRendering::KeyTreeItem*)0; //explicit conversion for MS VS
+ if (vk && vk->isBoundSet()) { //render a range of keys
+ itm = new CTextRendering::KeyTreeItem(
+ QString::fromUtf8(vk->LowerBound().getText()),
+ QString::fromUtf8(vk->UpperBound().getText()),
+ module,
+ settings
+ );
+ }
+ else {
+ itm = new CTextRendering::KeyTreeItem(
+ QString::fromUtf8(key->getText()),
+ QString::fromUtf8(key->getText()),
+ module,
+ settings
+ );
+ }
+
+ Q_ASSERT(itm);
+
+ tree.append( itm );
+ }
+ }
+ else if (module) {
+ CTextRendering::KeyTreeItem* itm = new CTextRendering::KeyTreeItem(
+ data.mid((pos == -1) ? 0 : pos+1),
+ module,
+ settings
+ );
+ tree.append( itm );
+ }
+
+ // qWarning("rendered the tree: %s", renderer.renderKeyTree(tree).latin1());
+ //spanns containing rtl text need dir=rtl on their parent tag to be aligned properly
+ return QString("<div class=\"crossrefinfo\"><h3>%1</h3><div class=\"para\" dir=\"%2\">%3</div></div>")
+ .arg(tr("Cross references"))
+ .arg(module ? ((module->textDirection() == CSwordModuleInfo::LeftToRight) ? "ltr" : "rtl") : "")
+ .arg(renderer.renderKeyTree(tree));
+}
+
+/*!
+ \fn CInfoDisplay::decodeFootnote( const QString& data )
+ */
+const QString CInfoDisplay::decodeFootnote( const QString& data ) {
+ QStringList list = data.split("/");
+ Q_ASSERT(list.count() >= 3);
+ if (!list.count()) {
+ return QString::null;
+ }
+
+ const QString modulename = list.first();
+ const QString swordFootnote = list.last();
+
+ // remove the first and the last and then rejoin it to get a key
+ list.pop_back(); list.pop_front();
+ const QString keyname = list.join("/");
+
+ CSwordModuleInfo* module = CPointers::backend()->findModuleByName(modulename);
+ if (!module) {
+ return QString::null;
+ }
+
+ boost::scoped_ptr<CSwordKey> key( CSwordKey::createInstance(module) );
+ key->key(keyname);
+ key->renderedText(); //force entryAttributes
+
+ const char* note =
+ module->module()->getEntryAttributes()
+ ["Footnote"][swordFootnote.toLatin1().data()]["body"].c_str();
+
+ QString text = module->isUnicode() ? QString::fromUtf8(note) : QString(note);
+ text = QString::fromUtf8(module->module()->RenderText(
+ module->isUnicode()
+ ? (const char*)text.toUtf8()
+ : (const char*)text.toLatin1()
+ ));
+
+ return QString("<div class=\"footnoteinfo\"><h3>%1</h3><p>%2</p></div>")
+ .arg(tr("Footnote"))
+ .arg(text);
+}
+
+const QString CInfoDisplay::decodeStrongs( const QString& data ) {
+ QStringList strongs = data.split("|");
+ QString ret;
+
+ QStringList::const_iterator end = strongs.end();
+ for (QStringList::const_iterator it = strongs.begin(); it != end; ++it) {
+ CSwordModuleInfo* const module = CBTConfig::get
+ (
+ ((*it).left(1) == QString("H")) ?
+ CBTConfig::standardHebrewStrongsLexicon :
+ CBTConfig::standardGreekStrongsLexicon
+ );
+
+ QString text;
+ if (module) {
+ boost::scoped_ptr<CSwordKey> key( CSwordKey::createInstance(module) );
+ key->key( (*it).mid(1) ); //skip H or G (language sign), will have to change later if we have better modules
+ text = key->renderedText();
+ }
+ //if the module could not be found just display an empty lemma info
+
+ ret.append(
+ QString("<div class=\"strongsinfo\"><h3>%1: %2</h3><p>%3</p></div>")
+ .arg(tr("Strongs"))
+ .arg(*it)
+ .arg(text)
+ );
+ }
+
+ return ret;
+}
+
+const QString CInfoDisplay::decodeMorph( const QString& data ) {
+ QStringList morphs = data.split("|");
+ QString ret;
+
+ foreach(QString morph, morphs) {
+ //qDebug() << "CInfoDisplay::decodeMorph, morph: " << morph;
+ CSwordModuleInfo* module = 0;
+ bool skipFirstChar = false;
+ QString value = "";
+ QString valueClass = "";
+
+ int valStart = morph.indexOf(':');
+ if (valStart > -1) {
+ valueClass = morph.mid(0, valStart);
+ //qDebug() << "valueClass: " << valueClass;
+ module = CPointers::backend()->findModuleByName( valueClass );
+ }
+ value = morph.mid(valStart+1); //works for prepended module and without (-1 +1 == 0).
+
+ // if we don't have a class assigned or desired one isn't installed...
+ if (!module) {
+ // Morphs usually don't have [GH] prepended, but some old OLB
+ // codes do. We should check if we're digit after first char
+ // to better guess this.
+ if (value.size() > 1 && value.at(1).isDigit()) {
+ switch (value.at(0).toLatin1()) {
+ case 'G':
+ module = CBTConfig::get
+ (CBTConfig::standardGreekMorphLexicon);
+ skipFirstChar = true;
+ break;
+ case 'H':
+ module = CBTConfig::get
+ (CBTConfig::standardHebrewMorphLexicon);
+ skipFirstChar = true;
+ break;
+ default:
+ skipFirstChar = false;
+ //TODO: we can't tell here if it's a greek or hebrew moprh code, that's a problem we have to solve
+ // module = CBTConfig::get(CBTConfig::standardGreekMorphLexicon);
+ break;
+ }
+ }
+ //if it is still not set use the default
+ if (!module) {
+ module = CBTConfig::get
+ (CBTConfig::standardGreekMorphLexicon);
+ }
+ }
+
+ QString text;
+ //Q_ASSERT(module);
+ if (module) {
+ boost::scoped_ptr<CSwordKey> key( CSwordKey::createInstance(module) );
+
+ //skip H or G (language sign) if we have to skip it
+ const bool isOk = key->key( skipFirstChar ? value.mid(1) : value );
+ //Q_ASSERT(isOk);
+ if (!isOk) { //try to use the other morph lexicon, because this one failed with the current morph code
+ key->module(CBTConfig::get
+ (CBTConfig::standardHebrewMorphLexicon));
+ key->key( skipFirstChar ? value.mid(1) : value );
+ }
+
+ text = key->renderedText();
+ }
+
+ //if the module wasn't found just display an empty morph info
+ ret.append( QString("<div class=\"morphinfo\"><h3>%1: %2</h3><p>%3</p></div>")
+ .arg(tr("Morphology"))
+ .arg(value)
+ .arg(text)
+ );
+ }
+
+ return ret;
+}
+
+const QString CInfoDisplay::getWordTranslation( const QString& data ) {
+ CSwordModuleInfo* const module = CBTConfig::get
+ (CBTConfig::standardLexicon);
+ if (!module) {
+ return QString::null;
+ }
+
+ boost::scoped_ptr<CSwordKey> key( CSwordKey::createInstance(module) );
+ key->key( data );
+ if (key->key().toUpper() != data.toUpper()) { //key not present in the lexicon
+ return QString::null;
+ }
+
+ QString ret = QString("<div class=\"translationinfo\"><h3>%1: %2</h3><p>%3</p></div>")
+ .arg(tr("Word lookup"))
+ .arg(data)
+ .arg(key->renderedText());
+
+ return ret;
+}
+
+
+/*!
+ \fn CInfoDisplay::clearInfo()
+ */
+void CInfoDisplay::clearInfo() {
+ CDisplayTemplateMgr* tmgr = CPointers::displayTemplateManager();
+ CDisplayTemplateMgr::Settings settings;
+ settings.pageCSS_ID = "infodisplay";
+
+ m_htmlPart->setText( tmgr->fillTemplate(CBTConfig::get(CBTConfig::displayStyle), QString::null, settings) );
+}
+
+QSize CInfoDisplay::sizeHint() const
+{
+ return QSize(100,150);
+}
+
+} //end of namespace InfoDisplay
diff --git a/src/frontend/cinfodisplay.h b/src/frontend/cinfodisplay.h
new file mode 100644
index 0000000..040667f
--- /dev/null
+++ b/src/frontend/cinfodisplay.h
@@ -0,0 +1,71 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CINFODISPLAY_H
+#define CINFODISPLAY_H
+
+//Backend
+#include "backend/rendering/ctextrendering.h"
+
+//Qt includes
+#include <QWidget>
+#include <QPair>
+#include <QList>
+
+//class forward declarations
+class CReadDisplay;
+class QAction;
+class QSize;
+
+namespace InfoDisplay {
+
+class CInfoDisplay : public QWidget {
+ Q_OBJECT
+public:
+ enum InfoType {
+ Abbreviation,
+ CrossReference,
+ Footnote,
+ Lemma,
+ Morph,
+ WordTranslation,
+ WordGloss,
+ Text
+ };
+
+ typedef QPair<InfoType, QString> InfoData;
+ typedef QList<InfoData> ListInfoData;
+
+ CInfoDisplay(QWidget *parent = 0);
+ virtual ~CInfoDisplay();
+
+ void setInfo(const InfoType, const QString& data);
+ void setInfo(const ListInfoData&);
+ void clearInfo();
+ QSize sizeHint() const;
+
+protected:
+ const QString decodeAbbreviation( const QString& data );
+ const QString decodeCrossReference( const QString& data );
+ const QString decodeFootnote( const QString& data );
+ const QString decodeStrongs( const QString& data );
+ const QString decodeMorph( const QString& data );
+ const QString getWordTranslation( const QString& data );
+
+protected slots:
+ void lookupInfo(const QString &, const QString &);
+
+private:
+ CReadDisplay* m_htmlPart;
+ QAction* m_copyAction;
+};
+
+} //end of InfoDisplay namespace
+
+#endif
diff --git a/src/frontend/cinputdialog.cpp b/src/frontend/cinputdialog.cpp
new file mode 100644
index 0000000..59b178d
--- /dev/null
+++ b/src/frontend/cinputdialog.cpp
@@ -0,0 +1,95 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+//own includes
+#include "cinputdialog.h"
+#include "util/dialogutil.h"
+
+//Qt includes
+#include <QDialog>
+#include <QWidget>
+#include <QLabel>
+#include <QTextEdit>
+#include <QPushButton>
+#include <QDialogButtonBox>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+
+#include <QDebug>
+
+
+CInputDialog::CInputDialog
+ (const QString& caption, const QString& description, const QString& text, QWidget *parent, Qt::WindowFlags wflags )
+ : QDialog(parent, wflags)
+{
+ QVBoxLayout *vboxLayout;
+ QLabel *label;
+ QHBoxLayout *hboxLayout;
+ QPushButton *clearButton;
+ QSpacerItem *spacerItem;
+ QDialogButtonBox *buttonBox;
+
+ setWindowTitle(caption);
+
+ resize(400, 300);
+ vboxLayout = new QVBoxLayout(this);
+ label = new QLabel(description, this);
+ vboxLayout->addWidget(label);
+
+ m_textEdit = new QTextEdit(this);
+ vboxLayout->addWidget(m_textEdit);
+ m_textEdit->setWordWrapMode( QTextOption::WordWrap );
+ m_textEdit->setText(text);
+ if (!text.isEmpty())
+ m_textEdit->selectAll();
+
+ hboxLayout = new QHBoxLayout();
+ clearButton = new QPushButton(this);
+ clearButton->setText(tr("Clear"));
+ hboxLayout->addWidget(clearButton);
+ spacerItem = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ hboxLayout->addItem(spacerItem);
+ buttonBox = new QDialogButtonBox(this);
+ buttonBox->setOrientation(Qt::Horizontal);
+ buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok);
+ util::prepareDialogBox(buttonBox);
+ hboxLayout->addWidget(buttonBox);
+
+ vboxLayout->addLayout(hboxLayout);
+
+ QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+ QObject::connect(clearButton, SIGNAL(clicked()), m_textEdit, SLOT(clear()));
+
+ m_textEdit->setFocus();
+}
+
+/** Returns the text entered at the moment. */
+const QString CInputDialog::text() {
+ return m_textEdit->toPlainText();
+}
+
+/** A static function to get some using CInputDialog. */
+const QString CInputDialog::getText
+ ( const QString& caption, const QString& description, const QString& text, bool* ok, QWidget* parent, Qt::WindowFlags wflags)
+{
+ CInputDialog* dlg = new CInputDialog(caption, description, text, parent, wflags);
+
+ QString ret = QString::null;
+ *ok = (dlg->exec() == QDialog::Accepted)?true:false;
+ if (*ok) {
+ //qDebug() << "dialog was accepted, return text: " << dlg->text();
+ ret = dlg->text();
+ }
+
+ delete dlg;
+ return ret;
+}
diff --git a/src/frontend/cinputdialog.h b/src/frontend/cinputdialog.h
new file mode 100644
index 0000000..7cd30b2
--- /dev/null
+++ b/src/frontend/cinputdialog.h
@@ -0,0 +1,43 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CINPUTDIALOG_H
+#define CINPUTDIALOG_H
+
+
+#include <QDialog>
+
+class QTextEdit;
+class QWidget;
+
+/** This is a small input dialog with
+ * a multiline edit for the text input.
+ * @author The BibleTime team
+ */
+class CInputDialog : public QDialog {
+ Q_OBJECT
+public:
+ CInputDialog(const QString& caption, const QString& description, const QString& text, QWidget *parent=0, Qt::WindowFlags wflags = Qt::Dialog);
+ /**
+ * A static function to get some using CInputDialog.
+ */
+ static const QString getText( const QString& caption, const QString& description, const QString& text = QString::null, bool* ok = 0, QWidget* parent = 0, Qt::WindowFlags wflags = Qt::Dialog);
+ /**
+ * Returns the text entered at the moment.
+ */
+ const QString text();
+ // ~CInputDialog();
+
+private:
+ QTextEdit* m_textEdit;
+};
+
+#endif
diff --git a/src/frontend/cmdiarea.cpp b/src/frontend/cmdiarea.cpp
new file mode 100644
index 0000000..69f3e7a
--- /dev/null
+++ b/src/frontend/cmdiarea.cpp
@@ -0,0 +1,244 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cmdiarea.h"
+
+//QT includes
+#include <QTimer>
+#include <QEvent>
+#include <QWindowStateChangeEvent>
+#include <QMdiSubWindow>
+#include <QDebug>
+
+CMDIArea::CMDIArea(QWidget *parent) : QMdiArea(parent),
+ m_mdiArrangementMode(ArrangementModeManual)
+{
+ setActivationOrder( CreationOrder ); //keep window order consistent
+ connect(this, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(slotClientActivated(QMdiSubWindow*)));
+}
+
+QMdiSubWindow* CMDIArea::addSubWindow(QWidget * widget, Qt::WindowFlags windowFlags)
+{
+ QMdiSubWindow* subWindow = QMdiArea::addSubWindow(widget, windowFlags);
+ subWindow->installEventFilter(this);
+
+ //If we do have a maximized Window, set it to normal so that the new window can be seen
+ if (activeSubWindow() && activeSubWindow()->isMaximized()){
+ activeSubWindow()->showNormal();
+ }
+
+ if (m_mdiArrangementMode == ArrangementModeManual)
+ {
+ subWindow->resize(400, 400); //set the window to be big enough
+ subWindow->raise();
+ }
+ else
+ {
+ triggerWindowUpdate();
+ }
+ return subWindow;
+}
+
+void CMDIArea::deleteAll() {
+ closeAllSubWindows();
+}
+
+void CMDIArea::setMDIArrangementMode( const MDIArrangementMode newArrangementMode ) {
+ m_mdiArrangementMode = newArrangementMode;
+ triggerWindowUpdate();
+}
+
+CMDIArea::MDIArrangementMode CMDIArea::getMDIArrangementMode(void) const {
+ return m_mdiArrangementMode;
+}
+
+void CMDIArea::myTileVertical() {
+ if (!updatesEnabled() || !usableWindowList().count() ) {
+ return;
+ }
+
+ QList<QMdiSubWindow*> windows = usableWindowList();
+ if (activeSubWindow() && activeSubWindow()->isMaximized()){
+ if (activeSubWindow()->size() != this->size()) {
+ activeSubWindow()->resize(this->size());
+ }
+ }
+ else if (windows.count() == 1) {
+ windows.at(0)->showMaximized();
+ }
+ else {
+ setUpdatesEnabled(false);
+ QMdiSubWindow* active = activeSubWindow();
+ QMdiArea::tileSubWindows();
+ if (active) active->setFocus();
+ setUpdatesEnabled(true);
+ }
+ emitWindowCaptionChanged();
+}
+
+void CMDIArea::myTileHorizontal() {
+ if (!updatesEnabled() || !usableWindowList().count() ) {
+ return;
+ }
+
+ QList<QMdiSubWindow*> windows = usableWindowList();
+
+ if (activeSubWindow() && activeSubWindow()->isMaximized()){
+ if (activeSubWindow()->size() != this->size()) {
+ activeSubWindow()->resize(this->size());
+ }
+ }
+ else if (windows.count() == 1) {
+ windows.at(0)->showMaximized();
+ }
+ else {
+ setUpdatesEnabled(false);
+
+ QMdiSubWindow* active = activeSubWindow();
+
+ const int heightForEach = height() / windows.count();
+ unsigned int y = 0;
+ foreach (QMdiSubWindow *window, windows) {
+ window->showNormal();
+
+ const int preferredHeight = window->minimumHeight() + window->baseSize().height();
+ const int actHeight = qMax(heightForEach, preferredHeight);
+
+ window->setGeometry( 0, y, width(), actHeight );
+ y += actHeight;
+ }
+ active->setFocus();
+ setUpdatesEnabled(true);
+ }
+ emitWindowCaptionChanged();
+}
+
+void CMDIArea::myCascade() {
+ if (!updatesEnabled() || !usableWindowList().count() ) {
+ return;
+ }
+
+ QList<QMdiSubWindow*> windows = usableWindowList();
+
+ if (activeSubWindow() && activeSubWindow()->isMaximized()){
+ if (activeSubWindow()->size() != this->size()) {
+ activeSubWindow()->resize(this->size());
+ }
+ }
+ else if (windows.count() == 1) {
+ windows.at(0)->showMaximized();
+ }
+ else {
+ setUpdatesEnabled(false);
+
+ QMdiSubWindow* active = activeSubWindow();
+
+ const unsigned int offsetX = 40;
+ const unsigned int offsetY = 40;
+ const unsigned int windowWidth = width() - (windows.count()-1)*offsetX;
+ const unsigned int windowHeight = height() - (windows.count()-1)*offsetY;
+ unsigned int x = 0;
+ unsigned int y = 0;
+
+ foreach (QMdiSubWindow* window, windows) {
+ if (window == active) { //leave out the active window which should be the top window
+ continue;
+ }
+ window->raise(); //make it the on-top-of-window-stack window to make sure they're in the right order
+ window->setGeometry(x, y, windowWidth, windowHeight);
+ x += offsetX;
+ y += offsetY;
+ }
+ active->setGeometry(x, y, windowWidth, windowHeight);
+ active->raise();
+ active->activateWindow();
+
+ setUpdatesEnabled(true);
+ }
+ emitWindowCaptionChanged();
+}
+
+void CMDIArea::emitWindowCaptionChanged() {
+ QString appCaption;
+ if (activeSubWindow()) {
+ appCaption = activeSubWindow()->windowTitle();
+ }
+ emit sigSetToplevelCaption(appCaption);
+}
+
+QList<QMdiSubWindow*> CMDIArea::usableWindowList() {
+ //Take care: when new windows are added, they will not appear
+ //in subWindowList() when their ChildAdded-Event is triggered
+ QList<QMdiSubWindow*> ret;
+ foreach(QMdiSubWindow* w, subWindowList())
+ {
+ if (w->isMinimized() || w->isHidden()) { //not usable for us
+ continue;
+ }
+ ret.append( w );
+ }
+ return ret;
+}
+
+void CMDIArea::slotClientActivated(QMdiSubWindow* client) {
+ if (!client || !updatesEnabled()) {
+ return;
+ }
+ emit sigSetToplevelCaption( client->windowTitle().trimmed() );
+}
+
+//resize event of the MDI area itself, update layout if necessary
+void CMDIArea::resizeEvent(QResizeEvent* /*e*/) {
+ //do not call QMdiArea::resizeEvent(e), this would mess up our layout
+ if (updatesEnabled()) triggerWindowUpdate();
+}
+
+//handle events of the client windows to update layout if necessary
+bool CMDIArea::eventFilter(QObject *o, QEvent *e) {
+ QMdiSubWindow* w = dynamic_cast<QMdiSubWindow*>(o);
+ if (!w) return false; //let the event be handled by other filters too
+
+ if (e->type() == QEvent::WindowStateChange) {
+ Qt::WindowStates newState = w->windowState();
+ Qt::WindowStates oldState = ((QWindowStateChangeEvent*)e)->oldState();
+
+ //Do not handle window activation or deactivation here, it will produce wrong
+ //results because this event is handled too early. Let slotClientActivated() handle this.
+
+ bool needsLayoutUpdate = false;
+ //Window was maximized or un-maximized
+ if ((newState ^ oldState) & Qt::WindowMaximized) needsLayoutUpdate = true;
+ //Window was minimized or de-minimized
+ if ((newState ^ oldState) & Qt::WindowMinimized) needsLayoutUpdate = true;
+ //update Layout?
+ if (needsLayoutUpdate) triggerWindowUpdate();
+ }
+ if (e->type() == QEvent::Close) {
+ triggerWindowUpdate();
+ }
+ return false; //let the event be handled by other filters too
+}
+
+void CMDIArea::triggerWindowUpdate() {
+ if (updatesEnabled()) {
+ switch (m_mdiArrangementMode) {
+ case ArrangementModeTileVertical:
+ QTimer::singleShot(0, this, SLOT(myTileVertical()));
+ break;
+ case ArrangementModeTileHorizontal:
+ QTimer::singleShot(0, this, SLOT(myTileHorizontal()));
+ break;
+ case ArrangementModeCascade:
+ QTimer::singleShot(0, this, SLOT(myCascade()));
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/src/frontend/cmdiarea.h b/src/frontend/cmdiarea.h
new file mode 100644
index 0000000..682ca12
--- /dev/null
+++ b/src/frontend/cmdiarea.h
@@ -0,0 +1,116 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CMDIAREA_H
+#define CMDIAREA_H
+
+//Qt includes
+#include <QMdiArea>
+#include <QList>
+
+class CSwordModuleInfo;
+class QEvent;
+class QResizeEvent;
+class QMdiSubWindow;
+
+/** The MDI widget we use in BibleTime.
+ * Enhances QMdiArea.
+ */
+class CMDIArea : public QMdiArea {
+ Q_OBJECT
+ Q_PROPERTY(MDIArrangementMode m_mdiArrangementMode READ getMDIArrangementMode WRITE setMDIArrangementMode)
+
+public:
+ /**
+ * The options you can set for this widget.
+ */
+ enum MDIArrangementMode {
+ ArrangementModeTileVertical = 1,
+ ArrangementModeTileHorizontal = 2,
+ ArrangementModeCascade = 3,
+ ArrangementModeManual = 4,
+ MDIArrangementModeMIN = ArrangementModeTileVertical,
+ MDIArrangementModeMAX = ArrangementModeManual
+ };
+ CMDIArea(QWidget *parent);
+ /** Reimplementation
+ */
+ virtual QMdiSubWindow* addSubWindow(QWidget* widget, Qt::WindowFlags windowFlags = 0);
+ /**
+ */
+ void setMDIArrangementMode( const MDIArrangementMode );
+ /** */
+ MDIArrangementMode getMDIArrangementMode(void) const;
+ /**
+ */
+ void emitWindowCaptionChanged();
+ /**
+ * Forces an update of the currently chosen window arrangement.
+ */
+ void triggerWindowUpdate();
+ /** Lists all subWindows which are not minimized or hidden
+ */
+ QList<QMdiSubWindow*> usableWindowList();
+
+public slots:
+ /**
+ * Called whan a client window was activated
+ */
+ void slotClientActivated(QMdiSubWindow* client);
+ /**
+ * Deletes all the presenters in the MDI area.
+ */
+ void deleteAll();
+ /** Our own cascade version which, if only one window is left, shows this maximized.
+ * Also necessary for autoCasacde feature
+ */
+ void myCascade();
+ /** Our own cascade version which, if only one window is left, shows this maximized.
+ * Also necessary for autoTile feature
+ */
+ void myTileVertical();
+ /** Horizontal tile function
+ * This function was taken from Qt's MDI example.
+ */
+ void myTileHorizontal();
+ /**
+ * Emits the signal to create a new display window in the MDI area.
+ */
+ inline void emitCreateDisplayWindow(QList<CSwordModuleInfo*> modules, const QString keyName);
+
+signals: // Signals
+ /**
+ * Emits a signal to set the acption of the toplevel widget.
+ */
+ void sigSetToplevelCaption(const QString&);
+ /**
+ */
+ void createReadDisplayWindow(QList<CSwordModuleInfo*> modules, const QString& keyName);
+
+private:
+ /**
+ * Reimplementation
+ */
+ virtual void resizeEvent(QResizeEvent* e);
+ /**
+ * Used to handle Events of MDI windows
+ * */
+ bool eventFilter( QObject *o, QEvent *e );
+ /**
+ */
+ MDIArrangementMode m_mdiArrangementMode;
+};
+
+/** Emits the signal to create a new display window in the MDI area. */
+inline void CMDIArea::emitCreateDisplayWindow(QList<CSwordModuleInfo*> modules, const QString keyName) {
+ emit createReadDisplayWindow(modules, keyName);
+}
+
+
+#endif
diff --git a/src/frontend/cmodulechooserdialog.cpp b/src/frontend/cmodulechooserdialog.cpp
new file mode 100644
index 0000000..e7b96c8
--- /dev/null
+++ b/src/frontend/cmodulechooserdialog.cpp
@@ -0,0 +1,156 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cmodulechooserdialog.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/cswordbackend.h"
+#include "backend/btmoduletreeitem.h"
+
+#include "util/cpointers.h"
+#include "util/cresmgr.h"
+#include "util/ctoolclass.h"
+#include "util/dialogutil.h"
+#include "util/directoryutil.h"
+#include "backend/config/cbtconfig.h"
+
+#include <QDialog>
+#include <QButtonGroup>
+#include <QDialogButtonBox>
+#include <QHBoxLayout>
+#include <QSpacerItem>
+#include <QTreeWidget>
+#include <QVBoxLayout>
+#include <QStringList>
+#include <QDebug>
+#include <QHeaderView>
+#include <QLabel>
+
+
+CModuleChooserDialog::CModuleChooserDialog( QWidget* parent, QString title, QString label, QList<CSwordModuleInfo*>* allModules)
+ : QDialog(parent),
+ m_title(title),
+ m_labelText(label)
+{
+ m_grouping = (BTModuleTreeItem::Grouping)CBTConfig::get(CBTConfig::bookshelfGrouping);
+ m_filters = QList<BTModuleTreeItem::Filter*>();
+ if (!allModules) {
+ m_moduleList = CPointers::backend()->moduleList();
+ }
+ else m_moduleList = *allModules;
+}
+
+/**
+* Call init() after the constructor, either in the end of your own constructor or from outside.
+*/
+void CModuleChooserDialog::init()
+{
+ //Set the flag to destroy when closed - otherwise eats memory
+ setAttribute(Qt::WA_DeleteOnClose);
+ setWindowTitle(m_title);
+ initView();
+ initTree();
+}
+
+/** Initializes the view of this dialog */
+void CModuleChooserDialog::initView()
+{
+ //TODO: choose the button text?
+
+ QVBoxLayout *vboxLayout;
+ QHBoxLayout *hboxLayout;
+ QSpacerItem *spacerItem;
+
+ vboxLayout = new QVBoxLayout(this);
+
+ QLabel* label = CToolClass::explanationLabel(this, QString::null, m_labelText);
+ vboxLayout->addWidget(label);
+
+ m_moduleChooser = new QTreeWidget(this);
+ m_moduleChooser->header()->hide();
+
+ vboxLayout->addWidget(m_moduleChooser);
+
+ hboxLayout = new QHBoxLayout();
+
+ spacerItem = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ hboxLayout->addItem(spacerItem);
+
+ m_buttonBox = new QDialogButtonBox(this);
+ m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
+ util::prepareDialogBox(m_buttonBox);
+ hboxLayout->addWidget(m_buttonBox);
+
+ vboxLayout->addLayout(hboxLayout);
+
+ QObject::connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(slotOk()) );
+ //The QDialog doc is a bit unclear but calling reject also destroys the dialog
+ // in this situation.
+ QObject::connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()) );
+}
+
+
+void CModuleChooserDialog::initTree()
+{
+ //qDebug("CModuleChooserDialog::initTree");
+
+ // See BTModuleTreeItem documentation.
+ BTModuleTreeItem root(m_filters, m_grouping, &m_moduleList);
+ createModuleTree(&root, m_moduleChooser->invisibleRootItem());
+
+}
+
+void CModuleChooserDialog::createModuleTree(BTModuleTreeItem* item, QTreeWidgetItem* widgetItem)
+{
+ foreach (BTModuleTreeItem* i, item->children()) {
+ createModuleTree(i, new QTreeWidgetItem(widgetItem));
+ }
+ if (item->type() != BTModuleTreeItem::Root) {
+ widgetItem->setText(0, item->text());
+ if (item->type() == BTModuleTreeItem::Category || item->type() == BTModuleTreeItem::Language) {
+ widgetItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate);
+ }
+ if (item->type() == BTModuleTreeItem::Module) {
+ initModuleItem(item, widgetItem);
+ }
+ }
+}
+
+
+/** Emits the signal with the list of the selected modules. */
+void CModuleChooserDialog::slotOk()
+{
+ Q_ASSERT(m_moduleChooser);
+ //create the list of selected modules
+ QList<CSwordModuleInfo*> mods;
+ QTreeWidgetItemIterator it( m_moduleChooser );
+ for ( ; *it; ++it ) {
+ //add the module to list if the box is checked
+ if ((*it)->checkState(0) == Qt::Checked) {
+ qDebug("was checked");
+ for (QList<CSwordModuleInfo*>::iterator all_iter(m_moduleList.begin()); all_iter != m_moduleList.end(); ++all_iter) {
+ if ((*all_iter)->name() == (*it)->text(0)) {
+ qDebug("append");
+ mods.append(*all_iter);
+ break;
+ }
+ }
+
+ }
+ }
+
+ // The selection is handled first, then the dialog is closed and destroyed.
+ emit modulesChanged(mods, m_moduleChooser);
+ QDialog::done(QDialog::Accepted);
+}
+
+QPushButton* CModuleChooserDialog::okButton()
+{
+ return m_buttonBox->button(QDialogButtonBox::Ok);
+}
diff --git a/src/frontend/cmodulechooserdialog.h b/src/frontend/cmodulechooserdialog.h
new file mode 100644
index 0000000..2f1e93c
--- /dev/null
+++ b/src/frontend/cmodulechooserdialog.h
@@ -0,0 +1,103 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2007 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CMODULECHOOSERDIALOG_H
+#define CMODULECHOOSERDIALOG_H
+
+class CSwordModuleInfo;
+#include "backend/btmoduletreeitem.h"
+
+#include <QDialog>
+#include <QList>
+#include <QTreeWidget>
+
+
+class QDialogButtonBox;
+
+
+/**
+* Abstract dialog which lets the user select modules with checkboxes.
+* The dialog will be destroyed after closing. Connect the modulesChanged() signal
+* to handle the selection before the dialog is destroyed.
+*/
+class CModuleChooserDialog : public QDialog
+{
+ Q_OBJECT
+public:
+
+ /**
+ * Use your own constructor to set extra members.
+ * Filters list is given to the module tree creator, see BTModuleTreeItem.
+ * For module list see BTModuleTreeItem constructor documentation.
+ * Call init() after the constructor, either in the end of your own constructor or from outside.
+ */
+ CModuleChooserDialog(QWidget* parent, QString title, QString label, QList<CSwordModuleInfo*>* allModules = 0);
+
+ virtual ~CModuleChooserDialog() {}
+
+ /** Call this after/from the constructor.*/
+ void init();
+
+ /** Set the module tree grouping.
+ * Initially it's taken from the CBTConfig so it needs to be set only if that default is not adequate.
+ * This must be called before the tree is initialized, i.e. before init().
+ */
+ void setGrouping(BTModuleTreeItem::Grouping grouping) {m_grouping = grouping;}
+
+ /** Set the module tree filters. See setGrouping() for the calling convention and
+ * BTModuleTreeItem for the filters. By default the filters list is empty.
+ */
+ void setFilters(QList<BTModuleTreeItem::Filter*> filters) {m_filters = filters;}
+
+ QTreeWidget* treeWidget() {return m_moduleChooser;}
+
+ QPushButton* okButton();
+
+signals:
+
+ /** The signal is sent when the OK button is clicked. The list includes the selected (checked) modules. The tree widget can be used through the pointer for more complicated actions. */
+ void modulesChanged(QList<CSwordModuleInfo*>, QTreeWidget*);
+
+protected:
+
+ /**
+ * Initialize one tree widget item.
+ * To be overridden. This is called for each QTreeWidgetItem when it is created.
+ * Here you can set for example the checked status of the item.
+ */
+ virtual void initModuleItem(BTModuleTreeItem* btItem, QTreeWidgetItem* widgetItem) = 0;
+
+
+
+private slots:
+
+ /** Emits the signal modulesChanged() with the list of the selected modules. */
+ void slotOk();
+
+private:
+ /** Initialize the module tree. */
+ void initTree();
+
+ /** Initializes the view of this dialog.*/
+ void initView();
+
+ /** Call this from initTree(). */
+ void createModuleTree(BTModuleTreeItem* item, QTreeWidgetItem* widgetItem);
+
+ QTreeWidget *m_moduleChooser;
+ QDialogButtonBox *m_buttonBox;
+ QString m_title;
+ QString m_labelText;
+ QList<BTModuleTreeItem::Filter*> m_filters;
+ BTModuleTreeItem::Grouping m_grouping;
+ QList<CSwordModuleInfo*> m_moduleList;
+};
+
+
+#endif
diff --git a/src/frontend/cmoduleindexdialog.cpp b/src/frontend/cmoduleindexdialog.cpp
new file mode 100644
index 0000000..7edcd8c
--- /dev/null
+++ b/src/frontend/cmoduleindexdialog.cpp
@@ -0,0 +1,104 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cmoduleindexdialog.h"
+
+#include "util/cpointers.h"
+#include "backend/managers/cswordbackend.h"
+
+#include <boost/scoped_ptr.hpp>
+
+//Qt includes
+#include <QString>
+#include <QProgressDialog>
+#include <QDebug>
+#include <QApplication>
+#include <QMessageBox>
+
+CModuleIndexDialog* CModuleIndexDialog::getInstance() {
+ qDebug("CModuleIndexDialog::getInstance");
+ static CModuleIndexDialog* instance = 0;
+ if (instance == 0) {
+ instance = new CModuleIndexDialog();
+ }
+ qDebug("CModuleIndexDialog::getInstance end");
+ return instance;
+}
+
+void CModuleIndexDialog::indexAllModules( const QList<CSwordModuleInfo*>& modules )
+{
+ static bool indexing = false;
+ if (!indexing) {
+ indexing = true;
+ if (modules.count() < 1) return;
+
+ m_currentModuleIndex = 0;
+ m_progress = new QProgressDialog(QString(""), tr("Cancel"), 0, modules.count()*100);
+ m_progress->setWindowModality(Qt::WindowModal); // not useful actually, should have parent for this
+ m_progress->setWindowTitle(tr("Creating indices"));
+ m_progress->show();
+ m_progress->raise();
+
+ foreach (CSwordModuleInfo* info, modules) {
+ //TODO: how to cancel
+ //QObject::connect(CPointers::backend(), SIGNAL(sigSwordSetupChanged()), this, SLOT(swordSetupChanged()));
+ connect(this, SIGNAL(sigCancel()), info, SLOT(cancelIndexing()) );
+ connect(m_progress, SIGNAL(canceled()), info, SLOT(cancelIndexing()));
+ connect(info, SIGNAL(indexingFinished()), this, SLOT(slotFinished()));
+ connect(info, SIGNAL(indexingProgress(int)), this, SLOT(slotModuleProgress(int)) );
+ QString modname(info->name());
+ const QString labelText = tr("Creating index for work: %1").arg(modname);
+ m_progress->setLabelText(labelText);
+ //todo: if we want to cancel indexing from
+ info->buildIndex(); //waits until this module is finished
+
+ m_currentModuleIndex++;
+ disconnect(m_progress, SIGNAL(canceled()), info, SLOT(cancelIndexing()));
+ disconnect(info, SIGNAL(indexingFinished()), this, SLOT(slotFinished()));
+ disconnect(info, SIGNAL(indexingProgress(int)), this, SLOT(slotModuleProgress(int)) );
+ if (m_progress->wasCanceled()) break;
+ }
+
+ delete m_progress;
+ m_progress = 0;
+ indexing = false;
+ }
+}
+
+void CModuleIndexDialog::indexUnindexedModules( const QList<CSwordModuleInfo*>& modules ) {
+ QList<CSwordModuleInfo*> unindexedMods;
+
+ QList<CSwordModuleInfo*>::const_iterator end_it = modules.end();
+ for( QList<CSwordModuleInfo*>::const_iterator it = modules.begin(); it != end_it; ++it) {
+ if ((*it)->hasIndex()) {
+ continue;
+ }
+
+ unindexedMods << (*it);
+ }
+ indexAllModules(unindexedMods);
+}
+
+void CModuleIndexDialog::slotModuleProgress( int percentage ) {
+ m_progress->setValue(m_currentModuleIndex * 100 + percentage);
+ qApp->processEvents();
+}
+
+void CModuleIndexDialog::slotFinished( ) {
+ m_progress->setValue(m_currentModuleIndex * 100 + 100);
+ qApp->processEvents();
+}
+
+// Modules may be removed
+void CModuleIndexDialog::slotSwordSetupChanged()
+{
+ qDebug("CModuleIndexDialog::slotSwordSetupChanged, TODO: cancel if modules are removed");
+ QMessageBox::information(0, tr("Indexing Is Cancelled"), tr("Indexing is cancelled because modules are removed."));
+ emit sigCancel();
+}
diff --git a/src/frontend/cmoduleindexdialog.h b/src/frontend/cmoduleindexdialog.h
new file mode 100644
index 0000000..63c14b5
--- /dev/null
+++ b/src/frontend/cmoduleindexdialog.h
@@ -0,0 +1,61 @@
+//
+// C++ Interface: cmoduleindexdialog
+//
+// Description:
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 2006-2007
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CMODULEINDEXDIALOG_H
+#define CMODULEINDEXDIALOG_H
+
+class CSwordModuleInfo;
+
+//Qt includes
+#include <QObject>
+
+//forward declaration
+//class KProgressDialog;
+class QProgressDialog;
+
+/**
+ * This dialog is used to index a list of modules and to show progress for that.\
+ * While the indexing is in progress it creates a blocking, top level dialog which shows the progress
+ * while the indexing is done.
+ *
+ * @author The BibleTime team <info@bibletime.info>
+*/
+class CModuleIndexDialog : public QObject {
+ Q_OBJECT
+public:
+ /** Get the singleton instance.
+ *
+ */
+ static CModuleIndexDialog* getInstance();
+
+ /** Starts the actual indexing. It shows the dialog with progress information.
+ */
+ void indexAllModules( const QList<CSwordModuleInfo*>& modules );
+
+ /** Indexes all modules in the list which don't have an index yet.
+ */
+ void indexUnindexedModules( const QList<CSwordModuleInfo*>& modules );
+
+signals:
+ /** Indexing is cancelled programmatically. */
+ void sigCancel();
+
+private:
+ QProgressDialog* m_progress;
+ int m_currentModuleIndex;
+
+protected slots:
+ void slotModuleProgress( int percentage );
+ void slotFinished();
+ void slotSwordSetupChanged();
+};
+
+#endif
diff --git a/src/frontend/cprinter.cpp b/src/frontend/cprinter.cpp
new file mode 100644
index 0000000..92699af
--- /dev/null
+++ b/src/frontend/cprinter.cpp
@@ -0,0 +1,136 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cprinter.h"
+
+#include "backend/managers/cdisplaytemplatemgr.h"
+#include "backend/keys/cswordversekey.h"
+#include "util/cpointers.h"
+
+#include <QWebPage>
+#include <QWebFrame>
+#include <QPrinter>
+#include <QPrintDialog>
+
+namespace Printing
+{
+
+CPrinter::CPrinter(QObject*, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions)
+ : QObject(0),
+ CDisplayRendering(displayOptions, filterOptions),
+ m_htmlPage(new QWebPage())
+{
+ m_htmlPage->setParent(this);
+
+ //override the filteroptions set in the c-tor of CDisplayRendering
+ m_filterOptions.footnotes = false;
+ m_filterOptions.scriptureReferences = false;
+ m_filterOptions.strongNumbers = false;
+ m_filterOptions.morphTags = false;
+ m_filterOptions.headings = false;
+}
+
+CPrinter::~CPrinter()
+{
+ delete m_htmlPage;
+ m_htmlPage = 0;
+}
+
+void CPrinter::printKeyTree( KeyTree& tree )
+{
+ m_htmlPage->mainFrame()->setHtml(renderKeyTree(tree));
+
+ QPrinter printer;
+ QPrintDialog printDialog(&printer);
+ if (printDialog.exec() == QDialog::Accepted)
+ {
+ m_htmlPage->mainFrame()->print(&printer);
+ }
+}
+
+const QString CPrinter::entryLink(const KeyTreeItem& item, CSwordModuleInfo* module)
+{
+ Q_ASSERT(module);
+ if (module->type() == CSwordModuleInfo::Bible)
+ {
+ CSwordVerseKey vk(module);
+ vk.key(item.key());
+ switch (item.settings().keyRenderingFace)
+ {
+ case KeyTreeItem::Settings::CompleteShort:
+ return QString::fromUtf8(vk.getShortText());
+
+ case KeyTreeItem::Settings::CompleteLong:
+ return vk.key();
+
+ case KeyTreeItem::Settings::NoKey:
+ return QString::null;
+
+ case KeyTreeItem::Settings::SimpleKey: //fall through
+ default:
+ return QString::number(vk.Verse());
+ }
+ }
+ return item.key();
+}
+
+const QString CPrinter::renderEntry( const KeyTreeItem& i, CSwordKey* )
+{
+ const CPrinter::KeyTreeItem* printItem = dynamic_cast<const CPrinter::KeyTreeItem*>(&i);
+ Q_ASSERT(printItem);
+
+ if (printItem && printItem->hasAlternativeContent())
+ {
+ QString ret = QString::fromLatin1("<div class=\"entry\"><div class=\"rangeheading\">%1</div>").arg(printItem->getAlternativeContent());
+
+ if (!i.childList()->isEmpty())
+ {
+ KeyTree const * tree = i.childList();
+
+ foreach ( KeyTreeItem* c, (*tree))
+ {
+ ret.append( CDisplayRendering::renderEntry( *c ) );
+ }
+ }
+
+ ret.append("</div>");
+ return ret;
+ }
+ return CDisplayRendering::renderEntry(i);
+}
+
+const QString CPrinter::finishText(const QString& text, KeyTree& tree)
+{
+ QList<CSwordModuleInfo*> modules = collectModules(&tree);
+ Q_ASSERT(modules.count() > 0);
+
+ const CLanguageMgr::Language* const lang = modules.first()->language();
+ Q_ASSERT(lang);
+
+ CDisplayTemplateMgr::Settings settings;
+ //settings.modules = modules;
+ settings.pageCSS_ID = "printer";
+ settings.langAbbrev = ( lang && (modules.count() == 1) && lang->isValid() ) ? lang->abbrev() : "unknown";
+
+ //the previous version gave compiler error for some strange reason
+ //(well, I don't like ?: anyway, let alone nested)
+ if (modules.count() != 1)
+ {
+ settings.pageDirection = QString::null;
+ }
+ else
+ {
+ settings.pageDirection = ( modules.first()->textDirection() == CSwordModuleInfo::LeftToRight ) ? "ltr" : "rtl";
+ }
+
+ CDisplayTemplateMgr* tMgr = CPointers::displayTemplateManager();
+ return tMgr->fillTemplate(CBTConfig::get(CBTConfig::displayStyle), text, settings);
+}
+
+} //end of namespace
diff --git a/src/frontend/cprinter.h b/src/frontend/cprinter.h
new file mode 100644
index 0000000..8b85691
--- /dev/null
+++ b/src/frontend/cprinter.h
@@ -0,0 +1,45 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CPRINTER_H
+#define CPRINTER_H
+
+#include "backend/managers/cswordbackend.h"
+#include "backend/rendering/cdisplayrendering.h"
+#include "backend/config/cbtconfig.h"
+
+#include <QObject>
+
+class QWebPage;
+
+namespace Printing
+{
+
+ // The CPrinter class manages the print item queue and the printing of them to the printer.
+
+class CPrinter : public QObject, public Rendering::CDisplayRendering
+{
+ Q_OBJECT
+public:
+ CPrinter(QObject* parent, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions);
+ virtual ~CPrinter();
+ void printKeyTree( KeyTree& );
+
+protected:
+ virtual const QString entryLink(const KeyTreeItem& item, CSwordModuleInfo* const module);
+ virtual const QString renderEntry( const KeyTreeItem&, CSwordKey* = 0 );
+ virtual const QString finishText(const QString& arg1, KeyTree& tree);
+
+private:
+ QWebPage* m_htmlPage;
+};
+
+} //namespace Printing
+
+#endif
diff --git a/src/frontend/crossrefrendering.cpp b/src/frontend/crossrefrendering.cpp
new file mode 100644
index 0000000..3aa8130
--- /dev/null
+++ b/src/frontend/crossrefrendering.cpp
@@ -0,0 +1,90 @@
+//
+// C++ Implementation: crossrefrendering
+//
+// Description:
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 2004, 2007
+//
+// Copyright: See COPYING file that comes with this distribution
+
+
+#include "crossrefrendering.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/keys/cswordversekey.h"
+#include "backend/managers/creferencemanager.h"
+
+namespace InfoDisplay {
+
+/**
+ */
+CrossRefRendering::CrossRefRendering( CSwordBackend::DisplayOptions displayOptions,
+ CSwordBackend::FilterOptions filterOptions
+ )
+ : CHTMLExportRendering(Settings(), displayOptions, filterOptions)
+{}
+
+const QString CrossRefRendering::finishText( const QString& text, KeyTree& ) {
+ // qDebug("CrossRefRendering::finishText");
+ return text;
+}
+
+const QString CrossRefRendering::entryLink( const KeyTreeItem& item, CSwordModuleInfo* module ) {
+ QString linkText;
+
+ const bool isBible = module && (module->type() == CSwordModuleInfo::Bible);
+ CSwordVerseKey vk(module); //only valid for bible modules, i.e. isBible == true
+ if (isBible) {
+ vk.key(item.key());
+ }
+
+ switch (item.settings().keyRenderingFace) {
+ case KeyTreeItem::Settings::NoKey: {
+ linkText = QString::null;
+ break; //no key is valid for all modules
+ }
+ case KeyTreeItem::Settings::CompleteShort: {
+ if (isBible) {
+ linkText = QString::fromUtf8(vk.getShortText());
+ break;
+ }
+ //fall through for non-Bible modules
+ }
+ case KeyTreeItem::Settings::CompleteLong: {
+ if (isBible) {
+ linkText = vk.key();
+ break;
+ }
+ //fall through for non-Bible modules
+ }
+ case KeyTreeItem::Settings::SimpleKey: {
+ if (isBible) {
+ linkText = QString::number(vk.Verse());
+ break;
+ }
+ //fall through for non-Bible modules
+ }
+ default: { //default behaviour to return the passed key
+ linkText = item.key();
+ break;
+ }
+ }
+
+ if (!linkText.isEmpty()) { //if we have a valid link text
+ // qWarning("rendering");
+ return QString("<a href=\"%1\">%2</a>")
+ .arg(
+ CReferenceManager::encodeHyperlink(
+ module->name(),
+ item.key(),
+ CReferenceManager::typeFromModule(module->type())
+ )
+ )
+ .arg(linkText);
+ }
+
+ return QString::null;
+}
+
+}
diff --git a/src/frontend/crossrefrendering.h b/src/frontend/crossrefrendering.h
new file mode 100644
index 0000000..99fdd7c
--- /dev/null
+++ b/src/frontend/crossrefrendering.h
@@ -0,0 +1,37 @@
+//
+// C++ Interface: crossrefrendering
+//
+// Description:
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 2004, 2007
+//
+// Copyright: See COPYING file that comes with this distribution
+
+
+#ifndef INFODISPLAYCROSSREFRENDERING_H
+#define INFODISPLAYCROSSREFRENDERING_H
+
+//Backend includes
+#include "backend/rendering/chtmlexportrendering.h"
+
+namespace InfoDisplay {
+
+class CrossRefRendering : public Rendering::CHTMLExportRendering
+{
+protected:
+ friend class CInfoDisplay;
+
+ CrossRefRendering(
+ CSwordBackend::DisplayOptions displayOptions = CBTConfig::getDisplayOptionDefaults(),
+ CSwordBackend::FilterOptions filterOptions = CBTConfig::getFilterOptionDefaults()
+ );
+
+ virtual const QString entryLink( const KeyTreeItem& item, CSwordModuleInfo* module );
+ virtual const QString finishText( const QString&, KeyTree& tree );
+};
+
+
+}
+
+#endif
diff --git a/src/frontend/display/btcolorwidget.cpp b/src/frontend/display/btcolorwidget.cpp
new file mode 100644
index 0000000..f807b05
--- /dev/null
+++ b/src/frontend/display/btcolorwidget.cpp
@@ -0,0 +1,65 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btcolorwidget.h"
+#include <QPalette>
+#include <QColor>
+#include <QMouseEvent>
+#include <QColorDialog>
+
+BtColorWidget::BtColorWidget(QWidget* parent)
+ : QFrame(parent)
+{
+ setFrameShadow(QFrame::Sunken);
+ setFrameShape(QFrame::StyledPanel);
+ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ setAutoFillBackground(true);
+}
+
+BtColorWidget::~BtColorWidget()
+{
+}
+
+QSize BtColorWidget::sizeHint() const
+{
+ return QSize(35,18);
+}
+
+void BtColorWidget::setColor(const QColor& color)
+{
+ QPalette p = palette();
+ p.setColor(QPalette::Normal, QPalette::Window, color);
+ setPalette(p);
+
+ if (color.isValid())
+ m_color = color;
+ else
+ m_color = QColor(0,0,0);
+ update();
+}
+
+void BtColorWidget::mouseReleaseEvent(QMouseEvent* event)
+{
+ if (event->button() == Qt::LeftButton)
+ {
+ event->accept();
+ showColorDialog();
+ return;
+ }
+}
+
+void BtColorWidget::showColorDialog()
+{
+ QColor color = QColorDialog::getColor(m_color, this);
+ if (color.isValid())
+ {
+ m_color = color;
+ emit changed(m_color);
+ }
+}
diff --git a/src/frontend/display/btcolorwidget.h b/src/frontend/display/btcolorwidget.h
new file mode 100644
index 0000000..0309832
--- /dev/null
+++ b/src/frontend/display/btcolorwidget.h
@@ -0,0 +1,44 @@
+//
+// C++ Interface: BtColorWidget
+//
+// Description: A color choosing widget for the toolbar
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 1999-2008
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#ifndef BTCOLORWIDGET_H
+#define BTCOLORWIDGET_H
+
+#include <QFrame>
+class QPaintEvent;
+
+class BtColorWidget : public QFrame
+{
+ Q_OBJECT
+
+public:
+ BtColorWidget(QWidget* parent=0);
+ ~BtColorWidget();
+ QSize sizeHint() const;
+ void setColor(const QColor& color);
+
+protected:
+// void paintEvent( QPaintEvent* );
+ void mouseReleaseEvent(QMouseEvent* event);
+
+private:
+ void showColorDialog();
+
+ QColor m_color;
+
+signals:
+ void changed(const QColor& color);
+};
+
+#endif
+
+
diff --git a/src/frontend/display/btfontsizewidget.cpp b/src/frontend/display/btfontsizewidget.cpp
new file mode 100644
index 0000000..3f03693
--- /dev/null
+++ b/src/frontend/display/btfontsizewidget.cpp
@@ -0,0 +1,51 @@
+/*********
+*
+* This file is part of BtFontSizeWidget's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BtFontSizeWidget developers.
+* The BtFontSizeWidget source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btfontsizewidget.h"
+#include <QFontDatabase>
+#include <QCompleter>
+
+BtFontSizeWidget::BtFontSizeWidget(QWidget* parent)
+ : QComboBox(parent)
+{
+ setEditable(true);
+ completer()->setCompletionMode(QCompleter::PopupCompletion);
+
+ QFontDatabase database;
+ const QList<int> sizes = database.standardSizes();
+ QStringList list;
+ for ( QList<int>::ConstIterator it = sizes.begin(); it != sizes.end(); ++it )
+ list.append( QString::number( *it ) );
+ addItems(list);
+
+ bool ok = connect(this, SIGNAL(currentIndexChanged(const QString&)),
+ this, SLOT(changed(const QString&)));
+ Q_ASSERT(ok);
+}
+
+BtFontSizeWidget::~BtFontSizeWidget()
+{
+}
+
+void BtFontSizeWidget::changed(const QString& text)
+{
+ emit fontSizeChanged(text.toInt());
+}
+
+void BtFontSizeWidget::setFontSize(int size)
+{
+ int index = findText(QString::number(size));
+ if (index >= 0)
+ setCurrentIndex(index);
+}
+
+int BtFontSizeWidget::fontSize() const
+{
+ return currentText().toInt();
+}
diff --git a/src/frontend/display/btfontsizewidget.h b/src/frontend/display/btfontsizewidget.h
new file mode 100644
index 0000000..2366744
--- /dev/null
+++ b/src/frontend/display/btfontsizewidget.h
@@ -0,0 +1,36 @@
+//
+// C++ Interface: BtFontSizeWidget
+//
+// Description: A font combobox widget for the toolbar
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 1999-2008
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#ifndef BTFONTSIZEWIDGET_H
+#define BTFONTSIZEWIDGET_H
+
+#include <QComboBox>
+
+
+class BtFontSizeWidget : public QComboBox
+{
+ Q_OBJECT
+
+public:
+ BtFontSizeWidget(QWidget* parent=0);
+ ~BtFontSizeWidget();
+ void setFontSize(int size);
+ int fontSize() const;
+
+private slots:
+ virtual void changed(const QString& text);
+
+signals:
+ void fontSizeChanged( int );
+};
+
+#endif
diff --git a/src/frontend/display/bthtml.js b/src/frontend/display/bthtml.js
new file mode 100644
index 0000000..d64215d
--- /dev/null
+++ b/src/frontend/display/bthtml.js
@@ -0,0 +1,146 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+var X = 0;
+var Y = 0;
+var attribs = [];
+var eventType = "";
+var prevNode = 0;
+var currentNode = 0;
+var timeOutId = -1;
+
+// Scroll window to html anchor
+function gotoAnchor(anchor)
+{
+ document.location=document.location + "#" + anchor;
+}
+
+// Set body editable
+function setEditable()
+{
+ var theBody = document.getElementsByTagName('body')[0];
+ theBody.setAttribute('contenteditable','true');
+}
+
+// Set body not editable
+function setNotEditable()
+{
+ var theBody = document.getElementsByTagName('body')[0];
+ theBody.setAttribute('contenteditable','false');
+}
+
+// Mouse button clicked handler
+function mouseClickHandler (mEvent)
+{
+ var mTarget = mEvent.target;
+ if (mTarget)
+ {
+ var url = "";
+ var tmpUrl = mEvent.target.getAttribute("href");
+ if (tmpUrl)
+ url = tmpUrl;
+ btHtmlJsObject.mouseClick(url);
+ }
+}
+
+// Mouse button pressed down handler
+function mouseDownHandler (mEvent)
+{
+ var node;
+ var url = "";
+ var lemma = "";
+ var mTarget = mEvent.target;
+ if (mTarget)
+ {
+ var tmpUrl = mEvent.target.getAttribute("href");
+ if (tmpUrl)
+ url = tmpUrl;
+ var tmpLemma = mEvent.target.getAttribute("lemma");
+ if (tmpLemma)
+ lemma = tmpLemma;
+ }
+
+ if (mEvent.button === 2) // Right mouse button
+ {
+ btHtmlJsObject.mouseDownRight(url, lemma);
+ }
+ if (mEvent.button === 0) // Left mouse button
+ {
+ if (!(mEvent.target === undefined))
+ {
+ var X = mEvent.clientX;
+ var Y = mEvent.clientY;
+ btHtmlJsObject.mouseDownLeft(url, X, Y);
+ }
+ }
+}
+
+// Mouse moved event handler
+function mouseMoveHandler (mEvent)
+{
+ currentNode = mEvent.target;
+ var shiftKey = mEvent.shiftKey;
+ var x = mEvent.clientX;
+ var y = mEvent.clientY;
+ var node = mEvent.target;
+ if ( node != undefined && node != prevNode )
+ {
+ prevNode = node;
+
+ if (node.attributes.length > 0)
+ {
+ attribList = getNodeAttributes(node);
+ btHtmlJsObject.mouseMoveEvent(attribList, x, y, shiftKey);
+ }
+ }
+}
+
+// Get attributes of a DOM node and put into a single string
+function getNodeAttributes(node)
+{
+ var attribList = '';
+ if (node.attributes.length > 0)
+ {
+ for (i = 0; i < node.attributes.length; i++)
+ {
+ attribList = attribList + node.attributes[i].nodeName + '=' + node.attributes[i].nodeValue + '||';
+ }
+ }
+ return attribList;
+}
+
+// Start a timer event
+function startTimer(time)
+{
+ clearTimeout(timeOutId);
+ timeOutId = setTimeout("timerEvent()",time);
+}
+
+// Handles a timer event
+function timerEvent()
+{
+ timeOutId = -1;
+ if (currentNode != 0 && currentNode == prevNode)
+ {
+ var attributes = getNodeAttributes(currentNode);
+ btHtmlJsObject.timeOutEvent(attributes);
+ }
+}
+
+document.getElementsByTagName("body")[0].addEventListener ('mousedown', function (eve) { mouseDownHandler (eve); }, true);
+document.getElementsByTagName("body")[0].addEventListener ('mousemove', function (eve) { mouseMoveHandler (eve); }, true);
+document.getElementsByTagName("body")[0].addEventListener ('click', function (eve) { mouseClickHandler (eve); }, true);
+
+btHtmlJsObject.startTimer.connect(this, this.startTimer);
+btHtmlJsObject.gotoAnchor.connect(this, this.gotoAnchor);
+btHtmlJsObject.setDocumentEditable.connect(this, this.setEditable);
+btHtmlJsObject.setDocumentNotEditable.connect(this, this.setNotEditable);
+
+;
+
diff --git a/src/frontend/display/bthtmlfindtext.cpp b/src/frontend/display/bthtmlfindtext.cpp
new file mode 100644
index 0000000..9041173
--- /dev/null
+++ b/src/frontend/display/bthtmlfindtext.cpp
@@ -0,0 +1,106 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "bthtmlfindtext.h"
+#include "bthtmlreaddisplay.h"
+#include "creaddisplay.h"
+#include "frontend/cmdiarea.h"
+#include "frontend/displaywindow/cdisplaywindow.h"
+#include <QMdiSubWindow>
+
+static BtHtmlFindText* dialog = 0;
+
+void showBtHtmlFindText(CMDIArea* mdiArea)
+{
+ if (dialog == 0)
+ dialog = new BtHtmlFindText(mdiArea, mdiArea);
+ dialog->show();
+}
+
+BtHtmlFindText::BtHtmlFindText(CMDIArea* mdiArea, QWidget *parent, Qt::WindowFlags f)
+ : QDialog(parent,f), m_mdiArea(mdiArea)
+{
+ ui.setupUi(this);
+ bool ok;
+ ok = connect(ui.nextButton,SIGNAL(clicked()), this, SLOT(findNext()));
+ Q_ASSERT(ok);
+ ok = connect(ui.previousButton,SIGNAL(clicked()), this, SLOT(findPrevious()));
+ Q_ASSERT(ok);
+}
+
+BtHtmlFindText::~BtHtmlFindText()
+{
+}
+
+void BtHtmlFindText::findNext()
+{
+ QWebView* webView = getActiveWindowWebView();
+ if (webView != 0)
+ {
+ QWebPage::FindFlags options = 0;
+ if (ui.caseBox->checkState() == Qt::Checked)
+ options |= QWebPage::FindCaseSensitively;
+ QString searchText = ui.findTextComboBox->currentText();
+ if (!searchText.isEmpty())
+ webView->findText(searchText, options);
+ }
+}
+
+void BtHtmlFindText::doHide()
+{
+ hide();
+}
+
+void BtHtmlFindText::findPrevious()
+{
+ QWebView* webView = getActiveWindowWebView();
+ if (webView != 0)
+ {
+ QWebPage::FindFlags options = QWebPage::FindBackward;
+ if (ui.caseBox->checkState() == Qt::Checked)
+ options |= QWebPage::FindCaseSensitively;
+ QString searchText = ui.findTextComboBox->currentText();
+ if (!searchText.isEmpty())
+ webView->findText(searchText,options);
+ }
+}
+
+
+QWebView* BtHtmlFindText::getActiveWindowWebView()
+{
+ QMdiSubWindow* activeSubWindow = m_mdiArea->activeSubWindow();
+ if (activeSubWindow == 0)
+ return 0;
+
+ QWidget* activeWindowWidget = activeSubWindow->widget();
+ if (activeWindowWidget == 0)
+ return 0;
+
+ CDisplayWindow* cDisplayWindow = qobject_cast<CDisplayWindow*>(activeWindowWidget);
+ if (cDisplayWindow == 0)
+ return 0;
+
+ CDisplay* cDisplay = cDisplayWindow->displayWidget();
+ if (cDisplay == 0)
+ return 0;
+
+ QWidget* textView = cDisplay->view();
+ if (textView == 0)
+ return 0;
+
+ QWebView* webView = qobject_cast<QWebView*>(textView);
+ return webView;
+}
+
+
+
+
+
+
+
diff --git a/src/frontend/display/bthtmlfindtext.h b/src/frontend/display/bthtmlfindtext.h
new file mode 100644
index 0000000..d6a1fe9
--- /dev/null
+++ b/src/frontend/display/bthtmlfindtext.h
@@ -0,0 +1,35 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTHTMLFINDTEXT_H
+#define BTHTMLFINDTEXT_H
+
+#include "ui_bthtmlfindtext.h"
+class CMDIArea;
+class QWebView;
+
+class BtHtmlFindText : public QDialog
+{
+ Q_OBJECT
+
+public:
+ BtHtmlFindText(CMDIArea* mdiArea, QWidget *parent=0, Qt::WindowFlags f=0);
+ ~BtHtmlFindText();
+public slots:
+ void findNext();
+ void findPrevious();
+ void doHide();
+private:
+ QWebView* getActiveWindowWebView();
+ Ui_findTextDialog ui;
+ CMDIArea* m_mdiArea;
+};
+
+
+#endif
diff --git a/src/frontend/display/bthtmlfindtext.ui b/src/frontend/display/bthtmlfindtext.ui
new file mode 100644
index 0000000..97c373e
--- /dev/null
+++ b/src/frontend/display/bthtmlfindtext.ui
@@ -0,0 +1,145 @@
+<ui version="4.0" >
+ <class>findTextDialog</class>
+ <widget class="QDialog" name="findTextDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>227</width>
+ <height>115</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Find Text</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <widget class="QFrame" name="findFrame" >
+ <property name="frameShape" >
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow" >
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2" >
+ <item>
+ <spacer name="verticalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QComboBox" name="findTextComboBox" >
+ <property name="toolTip" >
+ <string>The text you want to search for</string>
+ </property>
+ <property name="editable" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="caseBox" >
+ <property name="toolTip" >
+ <string>Seach with case sensitivity</string>
+ </property>
+ <property name="text" >
+ <string>Case &amp;sensitive</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_6" >
+ <item>
+ <spacer name="horizontalSpacer_6" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="previousButton" >
+ <property name="toolTip" >
+ <string>Find the previous location of the text</string>
+ </property>
+ <property name="text" >
+ <string>&amp;Previous</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="nextButton" >
+ <property name="toolTip" >
+ <string>Find the next location of the text</string>
+ </property>
+ <property name="text" >
+ <string>&amp;Next</string>
+ </property>
+ <property name="default" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="closeButton" >
+ <property name="toolTip" >
+ <string>Close the dialog</string>
+ </property>
+ <property name="text" >
+ <string>&amp;Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>closeButton</sender>
+ <signal>clicked()</signal>
+ <receiver>findTextDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>200</x>
+ <y>124</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>224</x>
+ <y>106</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/frontend/display/bthtmljsobject.cpp b/src/frontend/display/bthtmljsobject.cpp
new file mode 100644
index 0000000..836a6a3
--- /dev/null
+++ b/src/frontend/display/bthtmljsobject.cpp
@@ -0,0 +1,175 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+#include "bthtmljsobject.h"
+#include "bthtmlreaddisplay.h"
+#include "frontend/cinfodisplay.h"
+#include "frontend/cdragdrop.h"
+#include "backend/managers/creferencemanager.h"
+#include "backend/managers/cswordbackend.h"
+#include "backend/keys/cswordkey.h"
+#include "backend/config/cbtconfig.h"
+#include <boost/scoped_ptr.hpp>
+#include <QObject>
+
+using namespace InfoDisplay;
+
+// This class works along with the BtHtmlReadDisplay class. The BtHtmlReadDisplay class loads
+// Javascript (bthtml.js) along with the html it displays. This class is added to the Javascript model
+// so that Javascript can call this class, or this class can call Javascript.
+// Access to DOM objects is implemented in Javascript and is communicated back to c++ through this class
+
+BtHtmlJsObject::BtHtmlJsObject(BtHtmlReadDisplay* display)
+ : m_display(display)
+{
+}
+
+void BtHtmlJsObject::moveToAnchor(const QString& anchor)
+{
+ // Call gotoAnchor in Javascript
+ emit gotoAnchor(anchor);
+}
+
+void BtHtmlJsObject::setBodyEditable(bool editable)
+{
+ if (editable)
+ emit setDocumentEditable();
+ else
+ emit setDocumentNotEditable();
+}
+
+void BtHtmlJsObject::mouseDownLeft(const QString& url, const int& x, const int& y)
+{
+ m_dndData.mousePressed = true;
+ m_dndData.isDragging = false;
+ m_dndData.startPos = QPoint(x,y);
+ m_dndData.url = url;
+}
+
+void BtHtmlJsObject::mouseClick(const QString& url)
+{
+ m_dndData.mousePressed = false;
+ if (!url.isEmpty() && CReferenceManager::isHyperlink(url))
+ {
+ QString module;
+ QString key;
+ CReferenceManager::Type type;
+
+ CReferenceManager::decodeHyperlink(url, module, key, type);
+ if (module.isEmpty())
+ {
+ module = CReferenceManager::preferredModule( type );
+ }
+ m_display->connectionsProxy()->emitReferenceClicked(module,key);
+ }
+}
+
+void BtHtmlJsObject::mouseDownRight(const QString& url, const QString& lemma)
+{
+ m_display->setActiveAnchor(url);
+ if (lemma.isEmpty())
+ m_display->setLemma(QString::null);
+ else
+ m_display->setLemma(lemma);
+}
+
+void BtHtmlJsObject::mouseMoveEvent(const QString& /*attributes*/, const int& x, const int& y, const bool& shiftKey)
+{
+ if(!m_dndData.isDragging && m_dndData.mousePressed)
+ {
+ QPoint current(x,y);
+ if ((current - m_dndData.startPos).manhattanLength() > 4 /*qApp->startDragDistance()*/ )
+ {
+ QDrag* d = 0;
+ if (m_dndData.url.size() != 0 )
+ {
+ // create a new bookmark drag!
+ QString moduleName = QString::null;
+ QString keyName = QString::null;
+ CReferenceManager::Type type;
+ if ( !CReferenceManager::decodeHyperlink(m_dndData.url, moduleName, keyName, type) )
+ return;
+ d = new QDrag(m_display->view());
+ BTMimeData* mimedata = new BTMimeData(moduleName, keyName, QString::null);
+ d->setMimeData(mimedata);
+ //add real Bible text from module/key
+ if (CSwordModuleInfo* module = CPointers::backend()->findModuleByName(moduleName))
+ {
+ boost::scoped_ptr<CSwordKey> key( CSwordKey::createInstance(module) );
+ key->key( keyName );
+ mimedata->setText(key->strippedText()); // This works across applications!
+ }
+ }
+#if 0
+ else if ((m_dndData.dragType == DNDData::Text) && !m_dndData.selection.isEmpty()) {
+ d = new QDrag(KHTMLPart::view()->viewport());
+ BTMimeData* mimedata = new BTMimeData(m_dndData.selection);
+ d->setMimeData(mimedata);
+ }
+#endif
+ if (d) {
+ m_dndData.isDragging = true;
+ m_dndData.mousePressed = false;
+
+ //first make a virtual mouse click to end the selection, if it's in progress
+// QMouseEvent e(QEvent::MouseButtonRelease, QPoint(0,0), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+// QApplication::sendEvent(view()->viewport(), &e);
+ d->exec(Qt::CopyAction, Qt::CopyAction);
+
+ }
+ }
+ }
+ else if (m_display->getMouseTracking() && !shiftKey)
+ {
+ //no mouse button pressed and tracking enabled
+ // After some millisecs the new timer activates the Mag window update, see timerEvent()
+ // QObject has simple timer
+ emit startTimer(CBTConfig::get(CBTConfig::magDelay));
+ }
+}
+
+void BtHtmlJsObject::timeOutEvent(const QString& attributes)
+{
+ CInfoDisplay::ListInfoData infoList;
+ QStringList attrList = attributes.split("||");
+ for (int i=0; i<attrList.count(); i++)
+ {
+ QString attrPair = attrList[i];
+ QStringList attr = attrPair.split("=");
+ if (attr.count() == 2)
+ {
+ QString attrName = attr[0];
+ QString attrValue= attr[1];
+ if (attrName == "note")
+ {
+ infoList.append( qMakePair(CInfoDisplay::Footnote, attrValue));
+ }
+ if (attrName == "lemma")
+ {
+ infoList.append( qMakePair(CInfoDisplay::Lemma, attrValue));
+ }
+ if (attrName == "morph")
+ {
+ infoList.append( qMakePair(CInfoDisplay::Morph, attrValue));
+ }
+ if (attrName == "expansion")
+ {
+ infoList.append( qMakePair(CInfoDisplay::Abbreviation, attrValue));
+ }
+ if (attrName == "crossrefs")
+ {
+ infoList.append( qMakePair(CInfoDisplay::CrossReference, attrValue));
+ }
+ }
+ }
+ // Update the mag if there is new content
+ if (!(infoList.isEmpty()))
+ {
+ CPointers::infoDisplay()->setInfo(infoList);
+ }
+}
diff --git a/src/frontend/display/bthtmljsobject.h b/src/frontend/display/bthtmljsobject.h
new file mode 100644
index 0000000..a124c1c
--- /dev/null
+++ b/src/frontend/display/bthtmljsobject.h
@@ -0,0 +1,60 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+#ifndef BTHTMLJSOBJECT_H
+#define BTHTMLJSOBJECT_H
+
+#include <QObject>
+#include <QPoint>
+
+class BtHtmlReadDisplay;
+
+class BtHtmlJsObject: public QObject
+{
+ Q_OBJECT
+
+public:
+ BtHtmlJsObject(BtHtmlReadDisplay* display);
+ ~BtHtmlJsObject(){}
+ void moveToAnchor(const QString& anchor);
+ void setBodyEditable(bool editable);
+
+public slots: void mouseMoveEvent(const QString& attributes, const int& x, const int& y, const bool& shiftKey);
+ void mouseClick(const QString& url);
+ void mouseDownLeft(const QString& url, const int& X, const int& Y);
+ void mouseDownRight(const QString& url, const QString& lemma);
+ void timeOutEvent(const QString& attributes);
+
+signals:
+ void startTimer(int time);
+ void mouseMoveAttribute(const QString& attrName, const QString& attrValue);
+ void gotoAnchor(const QString& anchor);
+ void selectAll();
+ void setDocumentEditable();
+ void setDocumentNotEditable();
+
+private:
+ int m_int;
+ BtHtmlReadDisplay* m_display;
+
+ struct DNDData
+ {
+ bool mousePressed;
+ bool isDragging;
+ QPoint startPos;
+ QString url;
+ enum DragType
+ {
+ Link,
+ Text
+ } dragType;
+ } m_dndData;
+
+};
+
+#endif
diff --git a/src/frontend/display/bthtmlreaddisplay.cpp b/src/frontend/display/bthtmlreaddisplay.cpp
new file mode 100644
index 0000000..7f016cd
--- /dev/null
+++ b/src/frontend/display/bthtmlreaddisplay.cpp
@@ -0,0 +1,364 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "bthtmlreaddisplay.h"
+#include "bthtmljsobject.h"
+#include "frontend/displaywindow/cdisplaywindow.h"
+#include "frontend/displaywindow/creadwindow.h"
+#include "frontend/cdragdrop.h"
+#include "frontend/cinfodisplay.h"
+#include "backend/managers/creferencemanager.h"
+#include "backend/keys/cswordkey.h"
+#include "backend/config/cbtconfig.h"
+#include "util/ctoolclass.h"
+#include "util/cpointers.h"
+#include "util/directoryutil.h"
+#include <boost/scoped_ptr.hpp>
+#include <QString>
+#include <QMenu>
+
+using namespace InfoDisplay;
+
+void showBtHtmlFindText(CMDIArea*);
+
+static const QString body = "</body>";
+static const QString jsBegin = "<script type=\"text/javascript\">";
+static const QString jsEnd = "</script>";
+static QString javascript; // Initialized from file bthtml.js
+
+
+BtHtmlReadDisplay::BtHtmlReadDisplay(CReadWindow* readWindow, QWidget* parentWidget)
+ : QWebPage(parentWidget),CReadDisplay(readWindow), m_magTimerId(0), m_view(0), m_jsObject(0)
+
+{
+ settings()->setAttribute(QWebSettings::JavascriptEnabled, true);
+ m_view = new BtHtmlReadDisplayView(this, parentWidget ? parentWidget : readWindow);
+ m_view->setAcceptDrops(true);
+ m_view->setPage(this);
+ setParent(m_view);
+ m_view->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ m_view->setHtml("");
+ initJavascript();
+ bool ok = connect(this, SIGNAL(loadFinished(bool)), this, SLOT(slotLoadFinished(bool)));
+ Q_ASSERT(ok);
+}
+
+BtHtmlReadDisplay::~BtHtmlReadDisplay()
+{
+ setView(0);
+}
+
+// Read javascript into memory once and create the c++ javascript object
+void BtHtmlReadDisplay::initJavascript()
+{
+ // read bthtml.js javascript file once
+ if (javascript.size() == 0)
+ {
+ QString jsFile = util::filesystem::DirectoryUtil::getJavascriptDir().canonicalPath() + "/bthtml.js";
+ QFile file(jsFile);
+ if (file.open(QFile::ReadOnly))
+ {
+ while (!file.atEnd())
+ {
+ QByteArray line = file.readLine();
+ javascript = javascript + line;
+ }
+ file.close();
+ }
+ }
+
+ // Setup BtHtmlJsObject which will be called from javascript
+ m_jsObject = new BtHtmlJsObject(this);
+ m_jsObject->setObjectName("btHtmlJsObject");
+}
+
+// When the QWebFrame is cleared, this function is called to install the
+// javascript object (BtHtmlJsObject class) into the Javascript model
+void BtHtmlReadDisplay::loadJSObject()
+{
+ mainFrame()->addToJavaScriptWindowObject(m_jsObject->objectName(), m_jsObject);
+}
+
+const QString BtHtmlReadDisplay::text( const CDisplay::TextType format, const CDisplay::TextPart part)
+{
+ switch (part)
+ {
+ case Document:
+ {
+ if (format == HTMLText)
+ {
+ return mainFrame()->toHtml();
+ }
+ else
+ {
+ CDisplayWindow* window = parentWindow();
+ CSwordKey* const key = window->key();
+ CSwordModuleInfo* module = key->module();
+ //This is never used for Bibles, so it is not implemented for
+ //them. If it should be, see CReadDisplay::print() for example
+ //code.
+ Q_ASSERT(module->type() == CSwordModuleInfo::Lexicon ||
+ module->type() == CSwordModuleInfo::Commentary ||
+ module->type() == CSwordModuleInfo::GenericBook);
+ if (module->type() == CSwordModuleInfo::Lexicon ||
+ module->type() == CSwordModuleInfo::Commentary ||
+ module->type() == CSwordModuleInfo::GenericBook){
+ //TODO: This is a BAD HACK, we have to fnd a better solution to manage the settings now
+ CSwordBackend::FilterOptions filterOptions;
+ filterOptions.footnotes = false;
+ filterOptions.strongNumbers = false;
+ filterOptions.morphTags = false;
+ filterOptions.lemmas = false;
+ filterOptions.scriptureReferences = false;
+ filterOptions.textualVariants = false;
+
+ CPointers::backend()->setFilterOptions(filterOptions);
+
+ return QString(key->strippedText()).append("\n(")
+ .append(key->key())
+ .append(", ")
+ .append(key->module()->name())
+ .append(")");
+ }
+ }
+ }
+
+ case SelectedText:
+ {
+ if (!hasSelection())
+ {
+ return QString::null;
+ }
+ else if (format == HTMLText)
+ {
+ // TODO: It does not appear this is ever called
+ }
+ else
+ { //plain text requested
+ return selectedText();
+ }
+ }
+
+ case AnchorOnly:
+ {
+ QString moduleName;
+ QString keyName;
+ CReferenceManager::Type type;
+ CReferenceManager::decodeHyperlink(activeAnchor(), moduleName, keyName, type);
+
+ return keyName;
+ }
+
+ case AnchorTextOnly:
+ {
+ QString moduleName;
+ QString keyName;
+ CReferenceManager::Type type;
+ CReferenceManager::decodeHyperlink(activeAnchor(), moduleName, keyName, type);
+
+ if (CSwordModuleInfo* module = backend()->findModuleByName(moduleName))
+ {
+ boost::scoped_ptr<CSwordKey> key( CSwordKey::createInstance(module) );
+ key->key( keyName );
+
+ return key->strippedText();
+ }
+ return QString::null;
+ }
+
+ case AnchorWithText:
+ {
+ QString moduleName;
+ QString keyName;
+ CReferenceManager::Type type;
+ CReferenceManager::decodeHyperlink(activeAnchor(), moduleName, keyName, type);
+
+ if (CSwordModuleInfo* module = backend()->findModuleByName(moduleName))
+ {
+ boost::scoped_ptr<CSwordKey> key( CSwordKey::createInstance(module) );
+ key->key( keyName );
+
+ //TODO: This is a BAD HACK, we have to fnd a better solution to manage the settings now
+ CSwordBackend::FilterOptions filterOptions;
+ filterOptions.footnotes = false;
+ filterOptions.strongNumbers = false;
+ filterOptions.morphTags = false;
+ filterOptions.lemmas = false;
+ filterOptions.scriptureReferences = false;
+ filterOptions.textualVariants = false;
+
+ CPointers::backend()->setFilterOptions(filterOptions);
+
+ return QString(key->strippedText()).append("\n(")
+ .append(key->key())
+ .append(", ")
+ .append(key->module()->name())
+ .append(")");
+ /* ("%1\n(%2, %3)")
+ .arg()
+ .arg(key->key())
+ .arg(key->module()->name());*/
+ }
+ return QString::null;
+ }
+ default:
+ return QString::null;
+ }
+ return QString();
+}
+
+// Puts html text and javascript into QWebView
+void BtHtmlReadDisplay::setText( const QString& newText )
+{
+ QString jsText = newText;
+ jsText.replace(body,jsBegin+javascript+jsEnd+body);
+
+ // Disconnect any previous connect and connect to slot that loads the javascript object
+ QWebFrame* frame = mainFrame();
+ disconnect(frame,SIGNAL(javaScriptWindowObjectCleared()),0,0);
+ bool ok = connect(frame,SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(loadJSObject()));
+ Q_ASSERT(ok);
+
+ // Send text to the html viewer
+ m_view->setHtml(jsText);
+}
+
+// See if any text is selected
+bool BtHtmlReadDisplay::hasSelection()
+{
+ if (selectedText().isEmpty())
+ return false;
+ return true;
+}
+
+// Reimplementation
+// Returns the BtHtmlReadDisplayView object
+QWidget* BtHtmlReadDisplay::view()
+{
+ return m_view;
+}
+
+// Select all text in the viewer
+void BtHtmlReadDisplay::selectAll()
+{
+ m_jsObject->setBodyEditable(true);
+ m_view->triggerPageAction( QWebPage::MoveToStartOfDocument, true );
+ m_view->triggerPageAction( QWebPage::SelectEndOfDocument, true );
+ m_jsObject->setBodyEditable(false);
+}
+
+// Scroll QWebView to the correct location as specified by the anchor
+void BtHtmlReadDisplay::moveToAnchor( const QString& anchor )
+{
+ slotGoToAnchor(anchor);
+}
+
+// Scroll the QWebView to the correct location specified by anchor
+void BtHtmlReadDisplay::slotGoToAnchor(const QString& anchor)
+{
+ m_jsObject->moveToAnchor(anchor);
+}
+
+// Save the Lemma (Strongs number) attribute
+void BtHtmlReadDisplay::setLemma(const QString& lemma)
+{
+ m_nodeInfo[ CDisplay::Lemma ] = lemma;
+}
+
+// Open the Find text dialog
+void BtHtmlReadDisplay::openFindTextDialog()
+{
+ CMDIArea* mdiArea = parentWindow()->mdi();
+ showBtHtmlFindText(mdiArea);
+}
+
+// Send "completed" signal when the text is finished loading into the viewer
+void BtHtmlReadDisplay::slotLoadFinished(bool)
+{
+ emit completed();
+}
+
+// For debugging javascript
+#if 0
+void BtHtmlReadDisplay::javaScriptConsoleMessage (const QString& message, int lineNumber, const QString& sourceID )
+{
+}
+#endif
+
+
+
+
+// ----------------- BtHtmlReadDisplayView -------------------------------------
+
+BtHtmlReadDisplayView::BtHtmlReadDisplayView(BtHtmlReadDisplay* displayWidget, QWidget* parent)
+ : QWebView(parent), m_display(displayWidget)
+{
+}
+
+BtHtmlReadDisplayView::~BtHtmlReadDisplayView()
+ {
+ setPage(0);
+ }
+
+// Create the right mouse context menus
+void BtHtmlReadDisplayView::contextMenuEvent(QContextMenuEvent* event)
+{
+ if (QMenu* popup = m_display->installedPopup())
+ {
+ popup->exec(event->globalPos());
+ }
+}
+
+// Reimplementation from QWidget
+void BtHtmlReadDisplayView::dropEvent( QDropEvent* e )
+{
+ if (e->mimeData()->hasFormat("BibleTime/Bookmark"))
+ {
+ //see docs for BTMimeData and QMimeData
+ const QMimeData* mimedata = e->mimeData();
+ if (mimedata != 0)
+ {
+ const BTMimeData* btmimedata = qobject_cast<const BTMimeData*>(mimedata);
+ if (btmimedata != 0)
+ {
+ BookmarkItem item = (qobject_cast<const BTMimeData*>(e->mimeData()))->bookmark();
+ m_display->connectionsProxy()->emitReferenceDropped(item.key());
+ e->acceptProposedAction();
+ return;
+ }
+ }
+ };
+ //don't accept the action!
+ e->ignore();
+}
+
+// Reimplementation from QWebView
+void BtHtmlReadDisplayView::dragEnterEvent( QDragEnterEvent* e )
+{
+ if (e->mimeData()->hasFormat("BibleTime/Bookmark"))
+ {
+ e->acceptProposedAction();
+ return;
+ }
+ //don't accept the action!
+ e->ignore();
+}
+
+// Reimplementation from QWebView
+void BtHtmlReadDisplayView::dragMoveEvent( QDragMoveEvent* e )
+{
+ if (e->mimeData()->hasFormat("BibleTime/Bookmark"))
+ {
+ e->acceptProposedAction();
+ return;
+ }
+ //don't accept the action!
+ e->ignore();
+}
+
diff --git a/src/frontend/display/bthtmlreaddisplay.h b/src/frontend/display/bthtmlreaddisplay.h
new file mode 100644
index 0000000..99a91cf
--- /dev/null
+++ b/src/frontend/display/bthtmlreaddisplay.h
@@ -0,0 +1,118 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef BTHTMLREADDISPLAY_H
+#define BTHTMLREADDISPLAY_H
+
+//BibleTime includes
+#include "bthtmljsobject.h"
+#include "creaddisplay.h"
+
+//Qt includes
+//Added by qt3to4:
+#include <QDragEnterEvent>
+#include <QDropEvent>
+#include <QTimerEvent>
+#include <QWebView>
+#include <QWebPage>
+#include <QWebFrame>
+#include <QPoint>
+
+class BtHtmlReadDisplayView;
+class QScrollArea;
+class QWidget;
+class QString;
+class BtHtmlReadDisplay;
+
+
+/** The implementation for the HTML read display.
+ * @author The BibleTime team
+ */
+class BtHtmlReadDisplay : public QWebPage, public CReadDisplay {
+ Q_OBJECT
+public:
+ //reimplemented functions from CDisplay
+ // Returns the right text part in the specified format.
+ virtual const QString text( const CDisplay::TextType format = CDisplay::HTMLText, const CDisplay::TextPart part = CDisplay::Document );
+
+ // Sets the new text for this display widget.
+ virtual void setText( const QString& newText );
+ virtual bool hasSelection();
+
+ // Reimplementation.
+ virtual void selectAll();
+ virtual void moveToAnchor( const QString& anchor );
+ virtual void openFindTextDialog();
+ virtual QMap<CDisplay::NodeInfoType, QString> getCurrentNodeInfo()
+ {
+ return m_nodeInfo;
+ }
+ QWidget* view();
+ void setLemma(const QString& lemma);
+
+public slots:
+ void loadJSObject();
+ void slotLoadFinished(bool);
+
+signals:
+ void completed();
+
+protected:
+ friend class CDisplay;
+ BtHtmlReadDisplay( CReadWindow* readWindow, QWidget* parent = 0 );
+ virtual ~BtHtmlReadDisplay();
+ void slotGoToAnchor(const QString& anchor);
+ struct DNDData
+ {
+ bool mousePressed;
+ bool isDragging;
+ QString selection;
+ QPoint startPos;
+ enum DragType
+ {
+ Link,
+ Text
+ } dragType;
+ }
+ m_dndData;
+
+ QMap<NodeInfoType, QString> m_nodeInfo;
+ int m_magTimerId;
+
+// For debugging javascript
+// void javaScriptConsoleMessage (const QString & message, int lineNumber, const QString & sourceID );
+
+private:
+ void initJavascript();
+ BtHtmlReadDisplayView* m_view;
+ BtHtmlJsObject* m_jsObject;
+ QString m_currentAnchorCache;
+
+};
+
+
+class BtHtmlReadDisplayView : public QWebView, public CPointers
+{
+ Q_OBJECT
+protected:
+ friend class BtHtmlReadDisplay;
+ void contextMenuEvent(QContextMenuEvent* event);
+ BtHtmlReadDisplayView(BtHtmlReadDisplay* display, QWidget* parent);
+ ~BtHtmlReadDisplayView();
+
+private:
+ BtHtmlReadDisplay* m_display;
+ void dropEvent( QDropEvent* e );
+ void dragEnterEvent( QDragEnterEvent* e );
+ void dragMoveEvent( QDragMoveEvent* e );
+};
+
+#endif
diff --git a/src/frontend/display/cdisplay.cpp b/src/frontend/display/cdisplay.cpp
new file mode 100644
index 0000000..9333bd9
--- /dev/null
+++ b/src/frontend/display/cdisplay.cpp
@@ -0,0 +1,208 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cdisplay.h"
+
+#include "bthtmlreaddisplay.h"
+typedef BtHtmlReadDisplay HTMLREADDISPLAY;
+
+#include "cplainwritedisplay.h"
+#include "chtmlwritedisplay.h"
+
+#include "backend/managers/creferencemanager.h"
+
+#include "util/ctoolclass.h"
+
+
+//Qt includes
+#include <QClipboard>
+#include <QMenu>
+#include <QTimer>
+#include <QDebug>
+#include <QApplication>
+#include <QFileDialog>
+
+//KDE includes
+
+
+CDisplayConnections::CDisplayConnections( CDisplay* display ) : m_display(display) {}
+
+void CDisplayConnections::selectAll() {
+ m_display->selectAll();
+}
+
+void CDisplayConnections::saveAsHTML() {
+ m_display->save(CDisplay::HTMLText, CDisplay::Document);
+}
+
+void CDisplayConnections::saveAsPlain() {
+ m_display->save(CDisplay::PlainText, CDisplay::Document);
+}
+
+/** Emits the signal. */
+void CDisplayConnections::emitReferenceClicked( const QString& module, const QString& key) {
+ qDebug("CDisplayConnections::emitReferenceClicked");
+ qDebug() << "Module: " << module << " key: " << key;
+ emit referenceClicked( module, key );
+}
+
+/** Emits the signal. */
+void CDisplayConnections::emitReferenceDropped( const QString& key) {
+ emit referenceDropped(key);
+}
+
+/** Emits the signal. */
+void CDisplayConnections::emitTextChanged() {
+ emit textChanged();
+}
+
+void CDisplayConnections::copyAll() {
+ m_display->copy(CDisplay::PlainText, CDisplay::Document);
+}
+
+/** No descriptions */
+void CDisplayConnections::copySelection() {
+ qWarning("copyign the selected text");
+ m_display->copy(CDisplay::PlainText, CDisplay::SelectedText);
+}
+
+void CDisplayConnections::printAll(CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions) {
+ m_display->print(CDisplay::Document, displayOptions, filterOptions);
+}
+
+void CDisplayConnections::printAnchorWithText(CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions) {
+ m_display->print(CDisplay::AnchorWithText, displayOptions, filterOptions);
+}
+
+void CDisplayConnections::copyAnchorOnly() {
+ m_display->copy(CDisplay::PlainText, CDisplay::AnchorOnly);
+}
+
+void CDisplayConnections::copyAnchorTextOnly() {
+ m_display->copy(CDisplay::PlainText, CDisplay::AnchorTextOnly);
+}
+
+void CDisplayConnections::copyAnchorWithText() {
+ m_display->copy(CDisplay::PlainText, CDisplay::AnchorWithText);
+}
+
+void CDisplayConnections::saveAnchorWithText() {
+ m_display->save(CDisplay::PlainText, CDisplay::AnchorWithText);
+}
+
+void CDisplayConnections::clear() {
+ m_display->setText(QString::null);
+}
+
+void CDisplayConnections::zoomIn() {
+ m_display->zoomIn();
+}
+
+void CDisplayConnections::zoomOut() {
+ m_display->zoomOut();
+}
+
+void CDisplayConnections::openFindTextDialog() {
+ m_display->openFindTextDialog();
+}
+
+
+/*----------------------*/
+
+CReadDisplay* CDisplay::createReadInstance( CReadWindow* readWindow, QWidget* parent )
+{
+ return new HTMLREADDISPLAY(readWindow, parent);
+}
+
+CWriteDisplay* CDisplay::createWriteInstance( CWriteWindow* writeWindow, const CWriteDisplay::WriteDisplayType& type, QWidget* parent ) {
+ // qWarning("CDisplay::createWriteInstance");
+ if (type == PlainTextDisplay) {
+ return new CPlainWriteDisplay(writeWindow, parent);
+ }
+ else {
+ return new CHTMLWriteDisplay(writeWindow, parent);
+ };
+}
+
+
+CDisplay::CDisplay(CDisplayWindow* parent) :
+m_parentWindow(parent),
+m_connections( new CDisplayConnections( this ) ),
+m_popup(0) {}
+
+CDisplay::~CDisplay() {
+ delete m_connections;
+}
+
+bool CDisplay::copy( const CDisplay::TextType format, const CDisplay::TextPart part ) {
+ QApplication::clipboard()->setText( this->text(format, part) );
+ return true;
+}
+
+bool CDisplay::save( const CDisplay::TextType format, const CDisplay::TextPart part ) {
+ // qWarning("CDisplay::save( const CDisplay::TextType format, const CDisplay::TextPart part )");
+ const QString content = text(format, part);
+ QString filter = QString::null;
+
+ switch (format) {
+ case HTMLText:
+ filter = QObject::tr("HTML files") + QString(" (*.html *.htm);;") + QObject::tr("All files") + QString(" (*.*)");
+ break;
+ case PlainText:
+ filter = QObject::tr("Text files") + QString(" (*.txt);;") + QObject::tr("All files") + QString(" (*.*)");
+ break;
+ }
+
+ const QString filename = QFileDialog::getSaveFileName(0, QObject::tr("Save document ..."), "", filter);
+
+ if (!filename.isEmpty()) {
+ CToolClass::savePlainFile(filename, content);
+ }
+ return true;
+}
+
+/** Emits the signal which used when a reference was clicked. */
+void CDisplay::emitReferenceClicked( const QString& reference ) {
+ QString module, key;
+ CReferenceManager::Type type;
+ CReferenceManager::decodeHyperlink(reference, module, key, type);
+ if (module.isEmpty()) {
+ module = CReferenceManager::preferredModule( type );
+ }
+ m_connections->emitReferenceClicked(module, key);
+}
+
+/** Used when a reference was dropped onto the widget. */
+void CDisplay::emitReferenceDropped( const QString& reference ) {
+ QString module;
+ QString key;
+ CReferenceManager::Type type;
+ CReferenceManager::decodeHyperlink(reference, module, key, type);
+ m_connections->emitReferenceDropped(key);
+}
+
+/** Returns the connections obect used for signas and slots. */
+CDisplayConnections* CDisplay::connectionsProxy() const {
+ return m_connections;
+}
+
+CDisplayWindow* CDisplay::parentWindow() const {
+ return m_parentWindow;
+}
+
+/** Installs the popup which should be opened when the right mouse button was pressed. */
+void CDisplay::installPopup( QMenu* popup ) {
+ m_popup = popup;
+}
+
+/** Returns the popup menu which was set by installPopupMenu() */
+QMenu* CDisplay::installedPopup() {
+ return m_popup;
+}
+
diff --git a/src/frontend/display/cdisplay.h b/src/frontend/display/cdisplay.h
new file mode 100644
index 0000000..59a6a37
--- /dev/null
+++ b/src/frontend/display/cdisplay.h
@@ -0,0 +1,186 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CDISPLAY_H
+#define CDISPLAY_H
+
+//BibleTime includes
+#include "util/cpointers.h"
+#include "backend/managers/cswordbackend.h"
+
+//Qt includes
+#include <QMap>
+
+
+class CDisplayConnections;
+class CReadWindow;
+class CWriteWindow;
+
+class CDisplayWindow;
+class CReadDisplay;
+class CWriteDisplay;
+
+class QMenu;
+
+/** The base class for all display widgets.
+ * @author The BibleTime team
+ */
+class CDisplay : public CPointers {
+public:
+ enum WriteDisplayType {
+ HTMLDisplay = 0,
+ PlainTextDisplay
+ };
+
+ static CReadDisplay* createReadInstance(CReadWindow* readWindow, QWidget* parent = 0);
+ static CWriteDisplay* createWriteInstance( CWriteWindow* writeWindow, const WriteDisplayType& type = PlainTextDisplay, QWidget* parent = 0 );
+
+ enum TextType {
+ HTMLText, /* Used for HTML markup */
+ PlainText /* Plain text without links etc. */
+ };
+ enum TextPart {
+ Document, /* All text */
+ SelectedText, /* Only the selected text */
+ AnchorOnly,
+ AnchorTextOnly,
+ AnchorWithText
+ };
+
+ /**
+ * Copies the given text with the specified format into the applications clipboard.
+ */
+ virtual bool copy( const CDisplay::TextType format, const CDisplay::TextPart part );
+ /**
+ * Saves the given text with the specified format into the applications clipboard.
+ */
+ virtual bool save( const CDisplay::TextType format, const CDisplay::TextPart part );
+
+ //the pure virtual methods of this base class
+
+ /** Returns the text in the given format.
+ *
+ */
+ virtual const QString text( const CDisplay::TextType format = CDisplay::HTMLText, const CDisplay::TextPart part = CDisplay::Document ) = 0;
+ /**
+ * Sets the new text for this display widget.
+ */
+ virtual void setText( const QString& newText ) = 0;
+ /**
+ * Returns true if the display widget has a selection. Otherwise false.
+ */
+ virtual bool hasSelection() = 0;
+ /**
+ * Returns the view of this display widget.
+ */
+ virtual QWidget* view() = 0;
+ /**
+ * Selects the document text.
+ */
+ virtual void selectAll() = 0;
+ /**
+ * Returns the connections obect used for signas and slots.
+ */
+ virtual CDisplayConnections* connectionsProxy() const;
+ /**
+ * Returns the parent window used for this display widget.
+ */
+ CDisplayWindow* parentWindow() const;
+ virtual void print( const CDisplay::TextPart, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions) = 0;
+ /**
+ * Installs the popup which should be opened when the right mouse button was pressed.
+ */
+ void installPopup( QMenu* popup );
+ /**
+ * Returns the popup menu which was set by installPopupMenu()
+ */
+ QMenu* installedPopup();
+
+ virtual void zoomIn() {}
+ virtual void zoomOut() {}
+ virtual void openFindTextDialog() {}
+
+ enum NodeInfoType {
+ Lemma
+ };
+
+
+ virtual QMap<NodeInfoType, QString> getCurrentNodeInfo() {
+ return QMap<NodeInfoType, QString>();
+ }
+
+protected:
+ /**
+ * Used when a reference was dropped onto the widget.
+ */
+ void emitReferenceDropped( const QString& reference );
+ /**
+ * Emits the signal which used when a reference was clicked.
+ */
+ void emitReferenceClicked( const QString& reference );
+
+protected:
+ CDisplay(CDisplayWindow* parent);
+ virtual ~CDisplay();
+
+private:
+ CDisplayWindow* m_parentWindow;
+ CDisplayConnections* m_connections;
+ QMenu* m_popup;
+};
+
+class CDisplayConnections : public QObject {
+ Q_OBJECT
+public:
+ CDisplayConnections( CDisplay* parent );
+
+public slots:
+ virtual void selectAll();
+ void emitReferenceClicked( const QString& module, const QString& key);
+ void emitReferenceDropped( const QString& key );
+ void emitTextChanged();
+
+ //stuff which works in every CDisplay
+ void saveAsPlain();
+ void saveAsHTML();
+ void saveAnchorWithText();
+
+ void printAll(CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions);
+ void printAnchorWithText(CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions);
+
+ void copySelection();
+ void copyAll();
+ void copyAnchorWithText();
+ void copyAnchorTextOnly();
+ void copyAnchorOnly();
+
+ void clear();
+
+ void zoomIn();
+ void zoomOut();
+
+ void openFindTextDialog();
+
+signals:
+ void referenceClicked(const QString& module, const QString& key);
+ void referenceDropped(const QString& key);
+ void textChanged();
+
+private:
+ CDisplay* m_display;
+
+ struct {
+ QString module;
+ QString key;
+ } m_referenceClickedCache;
+};
+
+#endif
diff --git a/src/frontend/display/chtmlwritedisplay.cpp b/src/frontend/display/chtmlwritedisplay.cpp
new file mode 100644
index 0000000..4b9246e
--- /dev/null
+++ b/src/frontend/display/chtmlwritedisplay.cpp
@@ -0,0 +1,285 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#include "chtmlwritedisplay.h"
+#include "btfontsizewidget.h"
+#include "btcolorwidget.h"
+#include "frontend/displaywindow/cwritewindow.h"
+#include "frontend/displaywindow/btactioncollection.h"
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+
+#include <QMenu>
+#include <QToolTip>
+#include <QTextEdit>
+#include <QFontComboBox>
+#include <QMenu>
+#include <QToolBar>
+
+class BtActionCollection;
+
+CHTMLWriteDisplay::CHTMLWriteDisplay(CWriteWindow* parentWindow, QWidget* parent)
+: CPlainWriteDisplay(parentWindow,parent), m_fontFamilyChooser(0),
+ m_fontSizeChooser(0), m_colorChooser(0)
+{
+ m_actions.bold = 0;
+ m_actions.italic = 0;
+ m_actions.underline = 0;
+ m_actions.selectAll = 0;
+
+ setAcceptRichText(true);
+ setAcceptDrops(true);
+ viewport()->setAcceptDrops(true);
+}
+
+CHTMLWriteDisplay::~CHTMLWriteDisplay()
+{
+}
+
+void CHTMLWriteDisplay::setText( const QString& newText )
+{
+ QTextEdit::setHtml(newText);
+}
+
+const QString CHTMLWriteDisplay::plainText()
+{
+ return QTextEdit::toPlainText();
+}
+
+void CHTMLWriteDisplay::toggleBold(bool)
+{
+ setFontWeight( m_actions.bold->isChecked() ? QFont::Bold : QFont::Normal );
+}
+
+void CHTMLWriteDisplay::toggleItalic(bool)
+{
+ setFontItalic( m_actions.italic->isChecked() );
+}
+
+void CHTMLWriteDisplay::toggleUnderline(bool)
+{
+ setFontUnderline( m_actions.underline->isChecked() );
+}
+
+
+void CHTMLWriteDisplay::alignLeft(bool set)
+{
+ if (set && (alignment() != Qt::AlignLeft))
+ {
+ setAlignment(Qt::AlignLeft);
+ slotAlignmentChanged(Qt::AlignLeft);
+ }
+}
+
+void CHTMLWriteDisplay::alignCenter(bool set)
+{
+ if (set && (alignment() != Qt::AlignHCenter))
+ {
+ setAlignment(Qt::AlignHCenter);
+ slotAlignmentChanged(Qt::AlignHCenter);
+ }
+}
+
+void CHTMLWriteDisplay::alignRight(bool set)
+{
+ if (set && (alignment() != Qt::AlignRight))
+ {
+ setAlignment(Qt::AlignRight);
+ slotAlignmentChanged(Qt::AlignRight);
+ }
+}
+
+/** The text's alignment changed. Enable the right buttons. */
+void CHTMLWriteDisplay::slotAlignmentChanged( int a )
+{
+ bool alignLeft = false;
+ bool alignCenter = false;
+ bool alignRight = false;
+
+ if (a & Qt::AlignLeft)
+ {
+ alignLeft = true;
+ }
+ else if ((a & Qt::AlignHCenter) || (a & Qt::AlignCenter))
+ {
+ alignCenter = true;
+ }
+ else if (a & Qt::AlignRight)
+ {
+ alignRight = true;
+ }
+ else
+ {
+ alignLeft = true;
+ qWarning("unknown alignment %i", a);
+ }
+
+ m_actions.alignLeft->setChecked( alignLeft );
+ m_actions.alignCenter->setChecked( alignCenter );
+ m_actions.alignRight->setChecked( alignRight );
+}
+
+void CHTMLWriteDisplay::changeFontSize(int newSize)
+{
+ setFontPointSize((qreal)newSize);
+}
+
+/** Is called when a new color was selected. */
+void CHTMLWriteDisplay::slotColorSelected( const QColor& c)
+{
+ setTextColor( c );
+}
+
+/** Is called when a text with another color was selected. */
+void CHTMLWriteDisplay::slotColorChanged(const QColor& c)
+{
+ m_colorChooser->setColor(c);
+}
+
+void CHTMLWriteDisplay::slotFontChanged( const QFont& font )
+{
+ m_fontFamilyChooser->setCurrentFont(font);
+ m_fontSizeChooser->setFontSize( font.pointSize() );
+
+ m_actions.bold->setChecked( font.bold() );
+ m_actions.italic->setChecked( font.italic() );
+ m_actions.underline->setChecked( font.underline() );
+}
+
+void CHTMLWriteDisplay::slotFontFamilyChoosen(const QFont& font)
+{
+ setFontFamily(font.family());
+}
+
+void CHTMLWriteDisplay::setupToolbar(QToolBar * bar, BtActionCollection * actions)
+{
+ //--------------------font chooser-------------------------
+ m_fontFamilyChooser = new QFontComboBox(this);
+ actions->addAction(CResMgr::displaywindows::writeWindow::fontFamily::actionName, m_fontFamilyChooser);
+ m_fontFamilyChooser->setToolTip( tr("Font") );
+ bar->addWidget(m_fontFamilyChooser);
+ bool ok = connect(m_fontFamilyChooser, SIGNAL(currentFontChanged(const QFont&)),
+ this, SLOT(slotFontFamilyChoosen(const QFont&)));
+ Q_ASSERT(ok);
+
+ //--------------------font size chooser-------------------------
+ m_fontSizeChooser = new BtFontSizeWidget(this);
+ m_fontSizeChooser->setToolTip( tr("Font size") );
+ bar->addWidget(m_fontSizeChooser);
+ ok = connect(m_fontSizeChooser, SIGNAL(fontSizeChanged(int)), this, SLOT(changeFontSize(int)));
+ Q_ASSERT(ok);
+
+ //--------------------color button-------------------------
+ m_colorChooser = new BtColorWidget();
+ m_colorChooser->setToolTip(tr("Font color"));
+ bar->addWidget(m_colorChooser);
+ ok = connect(m_colorChooser, SIGNAL(changed(const QColor&)), this, SLOT(slotColorSelected(const QColor&)));
+ Q_ASSERT(ok);
+
+ bar->addSeparator();
+
+ //--------------------bold toggle-------------------------
+ m_actions.bold = new QAction(
+ util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::writeWindow::boldText::icon),
+ tr("Bold"),
+ actions);
+ m_actions.bold->setCheckable(true);
+ m_actions.bold->setShortcut(CResMgr::displaywindows::writeWindow::boldText::accel);
+ actions->addAction(CResMgr::displaywindows::writeWindow::boldText::actionName, m_actions.bold);
+ m_actions.bold->setToolTip( tr("Bold") );
+ connect(m_actions.bold, SIGNAL(toggled(bool)), this, SLOT(toggleBold(bool)));
+
+ bar->addAction(m_actions.bold);
+
+ //--------------------italic toggle-------------------------
+ m_actions.italic = new QAction(
+ util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::writeWindow::italicText::icon),
+ tr("Italic"),
+ actions );
+ m_actions.italic->setCheckable(true);
+ m_actions.bold->setShortcut(CResMgr::displaywindows::writeWindow::italicText::accel);
+ actions->addAction(CResMgr::displaywindows::writeWindow::italicText::actionName, m_actions.italic);
+ connect(m_actions.italic, SIGNAL(toggled(bool)), this, SLOT(toggleItalic(bool)));
+ m_actions.italic->setToolTip( tr("Italic") );
+ bar->addAction(m_actions.italic);
+
+ //--------------------underline toggle-------------------------
+ m_actions.underline = new QAction(
+ util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::writeWindow::underlinedText::icon),
+ tr("Underline"),
+ actions );
+ m_actions.underline->setCheckable(true);
+ m_actions.underline->setShortcut(CResMgr::displaywindows::writeWindow::underlinedText::accel);
+ actions->addAction(CResMgr::displaywindows::writeWindow::underlinedText::actionName, m_actions.underline);
+ connect(m_actions.underline, SIGNAL(toggled(bool)), this, SLOT(toggleUnderline(bool)));
+ m_actions.underline->setToolTip( tr("Underline") );
+ bar->addAction(m_actions.underline);
+
+ //seperate formatting from alignment buttons
+ bar->addSeparator();
+
+ //--------------------align left toggle-------------------------
+ m_actions.alignLeft = new QAction(
+ util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::writeWindow::alignLeft::icon),
+ tr("Left"), actions);
+ m_actions.alignLeft->setCheckable(true);
+ m_actions.alignLeft->setShortcut(CResMgr::displaywindows::writeWindow::alignLeft::accel);
+ actions->addAction(CResMgr::displaywindows::writeWindow::alignLeft::actionName, m_actions.alignLeft);
+ connect(m_actions.alignLeft, SIGNAL(toggled(bool)), this, SLOT(alignLeft(bool)));
+ m_actions.alignLeft->setToolTip( tr("Align left") );
+ bar->addAction(m_actions.alignLeft);
+
+ //--------------------align center toggle-------------------------
+ m_actions.alignCenter = new QAction(
+ util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::writeWindow::alignCenter::icon),
+ tr("Center"), actions);
+ m_actions.alignCenter->setCheckable(true);
+ m_actions.alignCenter->setShortcut(CResMgr::displaywindows::writeWindow::alignCenter::accel);
+ actions->addAction(CResMgr::displaywindows::writeWindow::alignCenter::actionName, m_actions.alignCenter);
+ connect(m_actions.alignCenter, SIGNAL(toggled(bool)), this, SLOT(alignCenter(bool)));
+ m_actions.alignCenter->setToolTip( tr("Center") );
+ bar->addAction(m_actions.alignCenter);
+
+ //--------------------align right toggle-------------------------
+ m_actions.alignRight = new QAction(
+ util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::writeWindow::alignRight::icon),
+ tr("Right"), actions);
+ m_actions.alignRight->setCheckable(true);
+ m_actions.alignRight->setShortcut(CResMgr::displaywindows::writeWindow::alignRight::accel);
+ actions->addAction(CResMgr::displaywindows::writeWindow::alignRight::actionName, m_actions.alignRight);
+ connect(m_actions.alignRight, SIGNAL(toggled(bool)), this, SLOT(alignRight(bool)));
+ m_actions.alignRight->setToolTip( tr("Align right") );
+ bar->addAction(m_actions.alignRight);
+
+ connect(this, SIGNAL(currentFontChanged(const QFont&)), SLOT(slotFontChanged(const QFont&)));
+ connect(this, SIGNAL(currentAlignmentChanged(int)), SLOT(slotAlignmentChanged(int)));
+ connect(this, SIGNAL(currentColorChanged(const QColor&)), SLOT(slotColorChanged(const QColor&)));
+
+ //set initial values for toolbar items
+ slotFontChanged( font() );
+ slotAlignmentChanged( alignment() );
+ slotColorChanged( textColor() );
+}
+
+/** Reimplementation to show a popup menu if the right mouse button was clicked. */
+QMenu* CHTMLWriteDisplay::createPopupMenu( const QPoint& )
+{
+ if (!m_actions.selectAll)
+ {
+ m_actions.selectAll = new QAction(tr("Select all"), this);
+ connect(m_actions.selectAll, SIGNAL(triggered(bool)), SLOT(selectAll()));
+ }
+
+ QMenu* popup = new QMenu(this);
+ popup->setTitle(tr("HTML editor window"));
+ popup->addAction(m_actions.selectAll);
+ return popup;
+}
diff --git a/src/frontend/display/chtmlwritedisplay.h b/src/frontend/display/chtmlwritedisplay.h
new file mode 100644
index 0000000..155966a
--- /dev/null
+++ b/src/frontend/display/chtmlwritedisplay.h
@@ -0,0 +1,106 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CHTMLWRITEDISPLAY_H
+#define CHTMLWRITEDISPLAY_H
+
+//BibleTime includes
+#include "cplainwritedisplay.h"
+
+class CWriteWindow;
+class QMenu;
+class QWidget;
+class QToolBar;
+class QAction;
+class QFontComboBox;
+class BtFontSizeWidget;
+class BtColorWidget;
+class BtActionCollection;
+
+/** The WYSIWYG implementation of the write display interface.
+ * @author The BibleTime team
+ */
+class CHTMLWriteDisplay : public CPlainWriteDisplay
+{
+ Q_OBJECT
+public:
+ /**
+ * Sets the new text for this display widget. (CPlainWriteDisplay).
+ */
+ virtual void setText( const QString& newText );
+ /**
+ * Returns the text of this edit widget. (CPlainWriteDisplay).
+ */
+ virtual const QString plainText();
+
+ /**
+ * Creates the necessary action objects and puts them on the toolbar.
+ * (CPlainWriteDisplay)
+ */
+ virtual void setupToolbar(QToolBar * bar, BtActionCollection * actionCollection);
+
+protected:
+ friend class CDisplay;
+ CHTMLWriteDisplay(CWriteWindow* parentWindow, QWidget* parent);
+ ~CHTMLWriteDisplay();
+ /**
+ * Reimplementation to show a popup menu if the right mouse button was clicked.
+ * (CPlainWriteDisplay)
+ */
+ virtual QMenu* createPopupMenu( const QPoint& pos );
+
+protected slots:
+ void toggleBold(bool);
+ void toggleItalic(bool);
+ void toggleUnderline(bool);
+
+ void alignLeft(bool);
+ void alignCenter(bool);
+ void alignRight(bool);
+
+ void changeFontSize(int);
+
+ void slotFontChanged( const QFont& );
+ void slotFontFamilyChoosen(const QFont&);
+
+ /**
+ * The text's alignment changed. Enable the right buttons.
+ */
+ void slotAlignmentChanged( int );
+ /**
+ * Is called when a new color was selected.
+ */
+ void slotColorSelected( const QColor& );
+ /**
+ * Is called when a text with another color was selected.
+ */
+ void slotColorChanged( const QColor& );
+
+private:
+ struct
+ {
+ QAction* bold;
+ QAction* italic;
+ QAction* underline;
+
+ QAction* alignLeft;
+ QAction* alignCenter;
+ QAction* alignRight;
+
+ //popup menu
+ QAction* selectAll;
+ }
+ m_actions;
+
+ QFontComboBox* m_fontFamilyChooser;
+ BtFontSizeWidget* m_fontSizeChooser;
+ BtColorWidget* m_colorChooser;
+};
+
+#endif
diff --git a/src/frontend/display/cplainwritedisplay.cpp b/src/frontend/display/cplainwritedisplay.cpp
new file mode 100644
index 0000000..3880f35
--- /dev/null
+++ b/src/frontend/display/cplainwritedisplay.cpp
@@ -0,0 +1,160 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cplainwritedisplay.h"
+#include "frontend/displaywindow/btactioncollection.h"
+#include "frontend/cdragdrop.h"
+#include "frontend/displaywindow/cdisplaywindow.h"
+#include "frontend/displaywindow/cwritewindow.h"
+
+#include "backend/keys/cswordkey.h"
+
+#include <boost/scoped_ptr.hpp>
+
+//Qt includes
+#include <QDragEnterEvent>
+#include <QDropEvent>
+#include <QDragMoveEvent>
+#include <QMenu>
+
+
+CPlainWriteDisplay::CPlainWriteDisplay(CWriteWindow* parentWindow, QWidget* parent) : QTextEdit(parentWindow ? parentWindow : parent), CWriteDisplay(parentWindow) {
+ setAcceptRichText(false);
+ setAcceptDrops(true);
+ viewport()->setAcceptDrops(true);
+
+ connect(this, SIGNAL(textChanged()),
+ connectionsProxy(), SLOT(emitTextChanged()));
+}
+
+CPlainWriteDisplay::~CPlainWriteDisplay() {}
+
+/** Reimplementation. */
+void CPlainWriteDisplay::selectAll() {
+ QTextEdit::selectAll();
+}
+
+void CPlainWriteDisplay::setText( const QString& newText ) {
+ //make sure the text has been converted to show \n instead of <br/>
+ QString text = newText;
+// text.replace("\n<br /><!-- BT newline -->\n", "\n");
+ text.replace("<br />", "\n"); //inserted by BT or the Qt textedit widget
+
+ QTextEdit::setText(text);
+}
+
+bool CPlainWriteDisplay::hasSelection() {
+ //TODO: test this
+ return textCursor().hasSelection();
+}
+
+QWidget* CPlainWriteDisplay::view() {
+ qDebug("CPlainWriteDisplay::view()");
+ return this;
+}
+
+const QString CPlainWriteDisplay::text( const CDisplay::TextType /*format*/, const CDisplay::TextPart /*part*/) {
+ return QString::null;
+}
+
+void CPlainWriteDisplay::print( const CDisplay::TextPart, CSwordBackend::DisplayOptions, CSwordBackend::FilterOptions) {
+}
+
+/** Sets the current status of the edit widget. */
+void CPlainWriteDisplay::setModified( const bool modified ) {
+ document()->setModified(modified);
+}
+
+/** Reimplementation. */
+bool CPlainWriteDisplay::isModified() const {
+ return document()->isModified();
+}
+
+
+/** Returns the text of this edit widget. */
+const QString CPlainWriteDisplay::plainText() {
+ QString ret = QTextEdit::toPlainText();
+
+ //in plain text mode the text just contains newlines, convert them into <br/> before we return the text for display in a HTML widget
+ ret.replace("\n", "<br />");
+
+ return ret;
+}
+
+/** Reimplementation from QTextEdit. Provides an popup menu for the given position. */
+QMenu* CPlainWriteDisplay::createPopupMenu( const QPoint& /*pos*/ ) {
+ return installedPopup();
+}
+//
+///** Reimplementation from QTextEdit. Provides an popup menu for the given position. */
+//QMenu* CPlainWriteDisplay::createPopupMenu( ) {
+// return installedPopup();
+//}
+
+/** Creates the necessary action objects and puts them on the toolbar. */
+void CPlainWriteDisplay::setupToolbar(QToolBar*, BtActionCollection*) {}
+
+/** Reimplementation to insert the text of a dragged reference into the edit view. */
+void CPlainWriteDisplay::dragEnterEvent( QDragEnterEvent* e ) {
+ //if (CDragDropMgr::canDecode(e)) {
+ if (e->mimeData()->hasFormat("BibleTime/Bookmark") || e->mimeData()->hasFormat("text/plain")) {
+ e->acceptProposedAction();
+ }
+ else {
+ //e->accept(false);
+ e->ignore();
+ }
+}
+
+/** Reimplementation to insert the text of a dragged reference into the edit view. */
+void CPlainWriteDisplay::dragMoveEvent( QDragMoveEvent* e ) {
+ if (e->mimeData()->hasFormat("BibleTime/Bookmark") || e->mimeData()->hasFormat("text/plain")) {
+ //placeCursor(e->pos());
+ setTextCursor(cursorForPosition(e->pos()));
+ ensureCursorVisible();
+ e->acceptProposedAction();
+ }
+ else {
+ //e->accept(false);
+ e->ignore();
+ }
+}
+
+/** Reimplementation to manage drops of our drag and drop objects. */
+void CPlainWriteDisplay::dropEvent( QDropEvent* e )
+{
+ //qDebug("CPlainWriteDisplay::dropEvent");
+ const BTMimeData* mimedata = qobject_cast<const BTMimeData*>(e->mimeData());
+
+ if ( mimedata && mimedata->hasFormat("BibleTime/Bookmark") ) {
+ //qDebug("format was bookmark");
+ e->acceptProposedAction();
+
+ BTMimeData::ItemList items = mimedata->bookmarks();
+ BTMimeData::ItemList::iterator it;
+ for (it = items.begin(); it != items.end(); ++it) {
+
+ CSwordModuleInfo* module = backend()->findModuleByName((*it).module());
+ boost::scoped_ptr<CSwordKey> key( CSwordKey::createInstance(module) );
+ key->key( (*it).key() );
+ QString moduleText = key->strippedText();
+
+ const QString text = QString::fromLatin1("%1\n(%2, %3)\n").arg(moduleText).arg((*it).key()).arg((*it).module());
+
+ setTextCursor(cursorForPosition(e->pos()));
+ textCursor().insertText( text );
+ }
+ }
+ else if ( e->mimeData()->hasFormat("text/plain")) {
+ //qDebug("format was plain text");
+ e->acceptProposedAction();
+ setTextCursor(cursorForPosition(e->pos()));
+ textCursor().insertText( e->mimeData()->text() );
+ }
+}
diff --git a/src/frontend/display/cplainwritedisplay.h b/src/frontend/display/cplainwritedisplay.h
new file mode 100644
index 0000000..eca0a3a
--- /dev/null
+++ b/src/frontend/display/cplainwritedisplay.h
@@ -0,0 +1,100 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CPLAINWRITEDISPLAY_H
+#define CPLAINWRITEDISPLAY_H
+
+//Bibletime include files
+#include "cwritedisplay.h"
+
+//Qt includes
+#include <QTextEdit>
+
+
+class CHTMLWriteDisplay;
+
+class QWidget;
+class QMenu;
+class QDragMoveEvent;
+class QDropEvent;
+class QDragEnterEvent;
+class BtActionCollection;
+
+/** The write display implementation for plain source code editing.
+ * @author The BibleTime team
+ */
+class CPlainWriteDisplay : public QTextEdit, public CWriteDisplay {
+public:
+ /**
+ * Reimplementation.
+ */
+ virtual void selectAll();
+ /**
+ * Sets the new text for this display widget.
+ */
+ virtual void setText( const QString& newText );
+ /**
+ * Returns true if the display widget has a selection. Otherwise false.
+ */
+ virtual bool hasSelection();
+ /**
+ * Returns the view of this display widget.
+ */
+ virtual QWidget* view();
+ virtual const QString text( const CDisplay::TextType format = CDisplay::HTMLText, const CDisplay::TextPart part = CDisplay::Document );
+ virtual void print( const CDisplay::TextPart, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions );
+ /**
+ * Reimplementation (CWriteDisplay).
+ */
+ virtual bool isModified() const;
+ /**
+ * Sets the current status of the edit widget (CWriteDisplay).
+ */
+ virtual void setModified( const bool modified );
+ /**
+ * Returns the text of this edit widget (CWriteDisplay).
+ */
+ virtual const QString plainText();
+ /**
+ * Creates the necessary action objects and puts them on the toolbar (CWriteDisplay).
+ */
+ virtual void setupToolbar(QToolBar*, BtActionCollection*);
+
+protected:
+ friend class CDisplay;
+ friend class CHTMLWriteDisplay;
+
+ CPlainWriteDisplay(CWriteWindow* parentWindow, QWidget* parent);
+ virtual ~CPlainWriteDisplay();
+ /**
+ * Reimplementation from QTextEdit. Provides an popup menu for the given position.
+ */
+ virtual QMenu* createPopupMenu( const QPoint& pos );
+// /**
+// * Reimplementation from QTextEdit. Provides an popup menu.
+// */
+// virtual QMenu* createPopupMenu();
+ /**
+ * Reimplementation from QTextEdit to manage drops of our drag and drop objects.
+ */
+ virtual void dropEvent( QDropEvent* e );
+ /**
+ * Reimplementation from QTextEdit to insert the text of a dragged reference into the edit view.
+ */
+ virtual void dragEnterEvent( QDragEnterEvent* e );
+ /**
+ * Reimplementation from QTextEdit to insert the text of a dragged reference into the edit view.
+ */
+ virtual void dragMoveEvent( QDragMoveEvent* e );
+
+};
+
+#endif
diff --git a/src/frontend/display/creaddisplay.cpp b/src/frontend/display/creaddisplay.cpp
new file mode 100644
index 0000000..383d332
--- /dev/null
+++ b/src/frontend/display/creaddisplay.cpp
@@ -0,0 +1,112 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+//BibleTime includes
+#include "creaddisplay.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/drivers/cswordbiblemoduleinfo.h"
+#include "backend/drivers/cswordlexiconmoduleinfo.h"
+#include "backend/drivers/cswordbookmoduleinfo.h"
+#include "backend/keys/cswordkey.h"
+#include "backend/keys/cswordversekey.h"
+#include "backend/keys/cswordtreekey.h"
+#include "backend/keys/cswordldkey.h"
+
+#include "frontend/displaywindow/cdisplaywindow.h"
+#include "frontend/displaywindow/creadwindow.h"
+
+#include "frontend/cexportmanager.h"
+
+#include <boost/scoped_ptr.hpp>
+
+//KDE includes
+
+
+CReadDisplay::CReadDisplay(CReadWindow* readWindow) :
+CDisplay(readWindow),
+m_activeAnchor(QString::null),
+m_useMouseTracking(true) {}
+
+CReadDisplay::~CReadDisplay() {}
+
+/** Returns the current active anchor. */
+const QString& CReadDisplay::activeAnchor() {
+ return m_activeAnchor;
+}
+
+/** Sets the current anchor to the parameter. */
+void CReadDisplay::setActiveAnchor( const QString& anchor ) {
+ m_activeAnchor = anchor;
+}
+
+
+/** Returns true if the display has an active anchor. */
+bool CReadDisplay::hasActiveAnchor() {
+ return !activeAnchor().isEmpty();
+}
+
+
+void CReadDisplay::print(const CDisplay::TextPart type, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions) {
+ CDisplayWindow* window = parentWindow();
+ CSwordKey* const key = window->key();
+ CSwordModuleInfo* module = key->module();
+
+
+ CExportManager mgr(QObject::tr("Print keys"),false, QString::null, parentWindow()->filterOptions(), parentWindow()->displayOptions());
+
+ switch (type) {
+ case Document: {
+ if (module->type() == CSwordModuleInfo::Bible) {
+ CSwordVerseKey* vk = dynamic_cast<CSwordVerseKey*>(key);
+
+ CSwordVerseKey startKey(*vk);
+ startKey.Verse(1);
+
+ CSwordVerseKey stopKey(*vk);
+
+ CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(module);
+ if (bible) {
+ stopKey.Verse( bible->verseCount( bible->bookNumber(startKey.book()), startKey.Chapter() ) );
+ }
+
+ mgr.printKey(module, startKey.key(), stopKey.key(), displayOptions, filterOptions);
+ }
+ else if (module->type() == CSwordModuleInfo::Lexicon || module->type() == CSwordModuleInfo::Commentary ) {
+ mgr.printKey(module, key->key(), key->key(), displayOptions, filterOptions);
+ }
+ else if (module->type() == CSwordModuleInfo::GenericBook) {
+ CSwordTreeKey* tree = dynamic_cast<CSwordTreeKey*>(key);
+
+ CSwordTreeKey startKey(*tree);
+ // while (startKey.previousSibling()) { // go to first sibling on this level!
+ // }
+
+ CSwordTreeKey stopKey(*tree);
+ // if (CSwordBookModuleInfo* book = dynamic_cast<CSwordBookModuleInfo*>(module)) {
+ // while ( stopKey.nextSibling() ) { //go to last displayed sibling!
+ // }
+ // }
+ mgr.printKey(module, startKey.key(), stopKey.key(), displayOptions, filterOptions);
+ }
+ }
+
+ case AnchorWithText: {
+ if (hasActiveAnchor()) {
+ mgr.printByHyperlink( activeAnchor(), displayOptions, filterOptions );
+ }
+ }
+
+ default:
+ break;
+ }
+}
+
diff --git a/src/frontend/display/creaddisplay.h b/src/frontend/display/creaddisplay.h
new file mode 100644
index 0000000..f4a00c4
--- /dev/null
+++ b/src/frontend/display/creaddisplay.h
@@ -0,0 +1,73 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CREADDISPLAY_H
+#define CREADDISPLAY_H
+
+#include "cdisplay.h"
+#include "backend/managers/cswordbackend.h"
+
+#include <QString>
+
+/**The base class for all read-only widgets like KHTMLView.
+ *@author The BibleTime team
+ */
+
+class CReadDisplay : public CDisplay {
+public:
+ /**
+ * Returns true if the display has an active anchor.
+ */
+ bool hasActiveAnchor();
+ /**
+ * Returns the current active anchor.
+ */
+ const QString& activeAnchor();
+ /**
+ * Moves the widget to the given anchor.
+ */
+ virtual void moveToAnchor( const QString& ) = 0;
+ virtual void print(const CDisplay::TextPart, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions);
+
+ void setMouseTracking(const bool trackingEnabled) {
+ m_useMouseTracking = trackingEnabled;
+ };
+ bool getMouseTracking() const {
+ return m_useMouseTracking;
+ };
+
+protected: // Protected methods
+ friend class BtHtmlReadDisplay;
+ friend class BtHtmlReadDisplayView;
+ friend class BtHtmlJsObject;
+ friend class CDisplay;
+ friend class CHTMLReadDisplay;
+ friend class CHTMLReadDisplayView;
+
+ CReadDisplay( CReadWindow* readWindow );
+ ~CReadDisplay();
+
+ /**
+ * Sets the current anchor to the parameter.
+ */
+ void setActiveAnchor( const QString& );
+
+private: // Public attributes
+ /**
+ * The member which hols the current anchor.
+ */
+
+ QString m_activeAnchor;
+
+ bool m_useMouseTracking;
+};
+
+#endif
diff --git a/src/frontend/display/cwritedisplay.cpp b/src/frontend/display/cwritedisplay.cpp
new file mode 100644
index 0000000..ddd9d8f
--- /dev/null
+++ b/src/frontend/display/cwritedisplay.cpp
@@ -0,0 +1,21 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+//BibleTime includes
+#include "cwritedisplay.h"
+
+#include "frontend/displaywindow/cwritewindow.h"
+
+
+CWriteDisplay::CWriteDisplay( CWriteWindow* writeWindow ) : CDisplay(writeWindow) {}
+
+CWriteDisplay::~CWriteDisplay() {}
+
diff --git a/src/frontend/display/cwritedisplay.h b/src/frontend/display/cwritedisplay.h
new file mode 100644
index 0000000..eaa2d9d
--- /dev/null
+++ b/src/frontend/display/cwritedisplay.h
@@ -0,0 +1,51 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CWRITEDISPLAY_H
+#define CWRITEDISPLAY_H
+
+#include "cdisplay.h"
+
+class QToolBar;
+class BtActionCollection;
+
+
+/**The base class for all read/write-display classes.
+ *@author The BibleTime team
+ */
+
+class CWriteDisplay : public CDisplay {
+protected:
+ friend class CDisplay;
+ friend class CPlainWriteDisplay;
+ CWriteDisplay( CWriteWindow* writeWindow );
+ ~CWriteDisplay();
+
+public: // Public methods
+ /**
+ * Sets the current modified status of the widget.
+ */
+ virtual void setModified( const bool modified ) = 0;
+ /**
+ * Returns true if the current text was modified.
+ */
+ virtual bool isModified() const = 0;
+ /**
+ * Returns the text of this edit widget.
+ */
+ virtual const QString plainText() = 0;
+ /**
+ * Creates the necessary action objects and puts them on the toolbar.
+ */
+ virtual void setupToolbar( QToolBar* bar, BtActionCollection* actionCollection ) = 0;
+};
+
+#endif
diff --git a/src/frontend/displaywindow/btactioncollection.cpp b/src/frontend/displaywindow/btactioncollection.cpp
new file mode 100644
index 0000000..f71709a
--- /dev/null
+++ b/src/frontend/displaywindow/btactioncollection.cpp
@@ -0,0 +1,38 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btactioncollection.h"
+
+BtActionCollection::BtActionCollection(QObject* parent)
+ : QObject(parent)
+{
+}
+
+BtActionCollection::~BtActionCollection()
+{
+}
+
+QAction* BtActionCollection::action(const QString& name)
+{
+ Q_ASSERT(m_actions[name] != 0);
+ return m_actions[name];
+}
+
+void BtActionCollection::addAction(const QString& name, QAction* action)
+{
+ Q_ASSERT(action != 0);
+// Q_ASSERT(m_actions[name] == 0); // TODO - replacing actions is ok???
+ m_actions[name] = action;
+}
+
+void BtActionCollection::addAction(const QString &name, const QObject *receiver)
+{
+}
+
+
diff --git a/src/frontend/displaywindow/btactioncollection.h b/src/frontend/displaywindow/btactioncollection.h
new file mode 100644
index 0000000..23ee1cf
--- /dev/null
+++ b/src/frontend/displaywindow/btactioncollection.h
@@ -0,0 +1,32 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+#ifndef BT_ACTION_COLLECTION_S
+#define BT_ACTION_COLLECTION_S
+
+#include <QObject>
+#include <QMap>
+
+class QString;
+class QAction;
+
+class BtActionCollection : public QObject
+{
+ Q_OBJECT
+public:
+ BtActionCollection(QObject* parent);
+ ~BtActionCollection();
+ void addAction(const QString& name, QAction* action);
+ void addAction(const QString &name, const QObject *receiver);
+ QAction* action(const QString& name);
+
+private:
+ QMap<QString, QAction*> m_actions;
+};
+
+#endif
diff --git a/src/frontend/displaywindow/bttoolbarpopupaction.cpp b/src/frontend/displaywindow/bttoolbarpopupaction.cpp
new file mode 100644
index 0000000..907a779
--- /dev/null
+++ b/src/frontend/displaywindow/bttoolbarpopupaction.cpp
@@ -0,0 +1,51 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "bttoolbarpopupaction.h"
+#include <QMenu>
+#include <QToolButton>
+#include <QAction>
+
+// This class provides a toolbar widget that has a icon plus a right side down arrow
+// The icon is typically set to a back or forward arrow and the down arrow has a popup
+// menu when clicked. The menu is typicallly populated with history actions.
+BtToolBarPopupAction::BtToolBarPopupAction(const QIcon& icon, const QString& text, QObject* parent)
+ : QWidgetAction(parent), m_icon(icon), m_text(text)
+{
+ m_menu = new QMenu();
+}
+
+BtToolBarPopupAction::~BtToolBarPopupAction()
+{
+ delete m_menu;
+}
+
+QMenu* BtToolBarPopupAction::popupMenu() const
+{
+ return m_menu;
+}
+
+QWidget* BtToolBarPopupAction::createWidget(QWidget* parent)
+{
+ m_button = new QToolButton(parent);
+ setIcon(m_icon);
+ setToolTip(m_text);
+ m_button->setDefaultAction(this);
+ m_button->setPopupMode(QToolButton::MenuButtonPopup);
+ m_button->setMenu(m_menu);
+ bool ok = connect(m_button, SIGNAL(pressed()), this, SLOT(buttonPressed()));
+ Q_ASSERT(ok);;
+ return m_button;
+}
+
+void BtToolBarPopupAction::buttonPressed()
+{
+ emit triggered();
+}
+
diff --git a/src/frontend/displaywindow/bttoolbarpopupaction.h b/src/frontend/displaywindow/bttoolbarpopupaction.h
new file mode 100644
index 0000000..63ed491
--- /dev/null
+++ b/src/frontend/displaywindow/bttoolbarpopupaction.h
@@ -0,0 +1,45 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+#ifndef BT_TOOLBAR_POPUP_ACTION_H
+#define BT_TOOLBAR_POPUP_ACTION_H
+
+#include <QWidgetAction>
+
+class QMenu;
+class QString;
+class QIcon;
+class QToolButton;
+
+// This class manages the toolbar display for going forward and backward in history.
+class BtToolBarPopupAction : public QWidgetAction
+{
+ Q_OBJECT
+public:
+
+ BtToolBarPopupAction(const QIcon& icon, const QString& text, QObject* parent);
+ ~BtToolBarPopupAction();
+ QMenu* popupMenu() const;
+
+signals:
+ void triggered();
+
+protected:
+ QWidget* createWidget(QWidget* parent);
+
+private slots:
+ void buttonPressed();
+
+private:
+ QMenu* m_menu;
+ QToolButton* m_button;
+ QIcon m_icon;
+ QString m_text;
+};
+
+#endif
diff --git a/src/frontend/displaywindow/cbiblereadwindow.cpp b/src/frontend/displaywindow/cbiblereadwindow.cpp
new file mode 100644
index 0000000..15354fa
--- /dev/null
+++ b/src/frontend/displaywindow/cbiblereadwindow.cpp
@@ -0,0 +1,480 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#include "cbiblereadwindow.h"
+#include "btactioncollection.h"
+
+#include "ccommentaryreadwindow.h"
+#include "cbuttons.h"
+
+#include "backend/keys/cswordversekey.h"
+#include "backend/drivers/cswordbiblemoduleinfo.h"
+
+#include "frontend/profile/cprofilewindow.h"
+#include "frontend/cexportmanager.h"
+#include "backend/config/cbtconfig.h"
+#include "frontend/cmdiarea.h"
+#include "frontend/display/creaddisplay.h"
+#include "frontend/keychooser/ckeychooser.h"
+
+#include "util/ctoolclass.h"
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+
+#include <math.h>
+
+//Qt includes
+#include <QWidget>
+#include <QTimer>
+#include <QEvent>
+#include <QApplication>
+#include <QMenu>
+#include <QMdiSubWindow>
+#include <QAction>
+#include <QMenu>
+#include <QMenu>
+
+using namespace Profile;
+
+CBibleReadWindow::CBibleReadWindow(QList<CSwordModuleInfo*> moduleList, CMDIArea* parent)
+ : CLexiconReadWindow(moduleList, parent)
+{
+ qDebug("CBibleReadWindow::CBibleReadWindow");
+}
+
+CBibleReadWindow::~CBibleReadWindow() {}
+
+void CBibleReadWindow::applyProfileSettings( CProfileWindow* const settings ) {
+ CLexiconReadWindow::applyProfileSettings(settings);
+
+ const int count = displaySettingsButton()->menuItemCount();
+ int result = settings->windowSettings();
+ for (int i = count-1; i>=1; i--) {
+ if (result-(int)pow((double)2,i-1)>= 0) { //2^i was added before, so item with index i is set
+ result -= (int)pow((double)2,i-1);
+ displaySettingsButton()->setItemStatus(i,true);
+ }
+ else {
+ displaySettingsButton()->setItemStatus(i,false);
+ }
+ }
+ displaySettingsButton()->setChanged();
+}
+
+void CBibleReadWindow::storeProfileSettings( CProfileWindow* const settings ) {
+ CLexiconReadWindow::storeProfileSettings(settings);
+
+ const int count = displaySettingsButton()->menuItemCount();
+ int result = 0;
+ //now check every item
+ for (int i = 1; i < count; i++) { //first item is a title
+ if (displaySettingsButton()->itemStatus(i)) //item is checked
+ result += (int)pow((double)2,i-1);//add 2^i (the i. digit in binary)
+ }
+ settings->setWindowSettings(result);
+}
+
+
+/** Reimplementation. */
+void CBibleReadWindow::insertKeyboardActions( BtActionCollection* const a ) {
+
+ QAction* qaction;
+
+ qaction = new QAction(tr("Next book"), a);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::nextBook::accel);
+ a->addAction("nextBook", qaction);
+
+ qaction = new QAction(tr("Previous book"), a);
+ qaction->setShortcut( CResMgr::displaywindows::bibleWindow::previousBook::accel);
+ a->addAction("previousBook", qaction);
+
+ qaction = new QAction(tr("Next chapter"), a);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::nextChapter::accel);
+ a->addAction("nextChapter", qaction);
+
+ qaction = new QAction(tr("Previous chapter"), a);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::previousChapter::accel);
+ a->addAction("previousChapter", qaction);
+
+ qaction = new QAction(tr("Next verse"), a);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::nextVerse::accel);
+ a->addAction("nextVerse", qaction);
+
+ qaction = new QAction(tr("Previous verse"), a);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::previousVerse::accel);
+ a->addAction("previousVerse", qaction);
+
+
+ //popup menu items
+ // new KAction(tr("Select all"), KStdAccel::selectAll(), a, "selectAll");
+
+ //copy menu items
+ // new KAction(tr("Copy reference only"), KShortcut(0), a, "copyReferenceOnly");
+ // new KAction(tr("Text of reference"), KShortcut(0), a, "copyTextOfReference");
+ // new KAction(tr("Reference with text"), KShortcut(0), a, "copyReferenceWithText");
+ qaction = new QAction(tr("Copy chapter"), a);
+ a->addAction("copyChapter", qaction);
+ // new KAction(tr("Copy selected text"), KStdAccel::copy(), a, "copySelectedText");
+
+ //save menu
+ // new KAction(tr("Reference with text"), KShortcut(0), a, "saveReferenceWithText");
+ qaction = new QAction(tr("Save chapter as plain text"), a);
+ a->addAction("saveChapterAsPlainText", qaction);
+
+ qaction = new QAction(tr("Save chapter as HTML"), a);
+ a->addAction("saveChapterAsHTML", qaction);
+ // new KAction(tr("Reference with text"), KShortcut(0), a, "saveReferenceWithText");
+
+ //print
+ qaction = new QAction(tr("Print chapter"), a);
+ qaction->setShortcut(QKeySequence::Print);
+ a->addAction("printChapter", qaction);
+}
+
+void CBibleReadWindow::initActions() {
+ qDebug("CBibleReadWindow::initActions");
+
+ BtActionCollection* ac = actionCollection();
+ CBibleReadWindow::insertKeyboardActions(ac);
+ CLexiconReadWindow::initActions(); //make sure the predefined actions are available
+
+ //cleanup, not a clean oo-solution
+ ac->action("nextEntry")->setEnabled(false);
+ ac->action("previousEntry")->setEnabled(false);
+
+ QAction* qaction;
+
+ qaction = new QAction(tr("Next book"), ac);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::nextBook::accel);
+ QObject::connect(qaction, SIGNAL(triggered()), this, SLOT(nextBook()) );
+ ac->addAction("nextBook", qaction);
+
+ qaction = new QAction(tr("Previous book"), ac);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::previousBook::accel);
+ QObject::connect(qaction, SIGNAL(triggered()), this, SLOT(previousBook()) );
+ ac->addAction("previousBook", qaction);
+
+ qaction = new QAction(tr("Next chapter"), ac);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::nextChapter::accel);
+ QObject::connect(qaction, SIGNAL(triggered()), this, SLOT(nextChapter()) );
+ ac->addAction("nextChapter", qaction);
+
+ qaction = new QAction(tr("Previous chapter"),ac);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::previousChapter::accel);
+ QObject::connect(qaction, SIGNAL(triggered()), this, SLOT(previousChapter()) );
+ ac->addAction("previousChapter", qaction);
+
+ qaction = new QAction(tr("Next verse"), ac);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::nextVerse::accel);
+ QObject::connect(qaction, SIGNAL(triggered()), this, SLOT(nextVerse()) );
+ ac->addAction("nextVerse", qaction);
+
+ qaction = new QAction(tr("Previous verse"), ac);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::previousVerse::accel);
+ QObject::connect(qaction, SIGNAL(triggered()), this, SLOT(previousVerse()) );
+ ac->addAction("previousVerse", qaction);
+
+ m_actions.selectAll = qobject_cast<QAction*>(ac->action("selectAll"));
+ Q_ASSERT(m_actions.selectAll);
+
+ m_actions.findText = qobject_cast<QAction*>(ac->action("findText"));
+ Q_ASSERT(m_actions.findText);
+
+ m_actions.findStrongs = new QAction(
+// QIcon(CResMgr::displaywindows::general::findStrongs::icon),
+ tr("Strong's search"),
+ ac
+ );
+ m_actions.findStrongs->setShortcut(CResMgr::displaywindows::general::findStrongs::accel);
+ m_actions.findStrongs->setToolTip(tr("Find all occurences of the Strong number currently under the mouse cursor"));
+ QObject::connect(m_actions.findStrongs, SIGNAL(triggered()), this, SLOT(openSearchStrongsDialog()) );
+ ac->addAction(CResMgr::displaywindows::general::findStrongs::actionName, m_actions.findStrongs);
+
+ m_actions.copy.referenceOnly = new QAction(tr("Reference only"), ac );
+ QObject::connect(m_actions.copy.referenceOnly, SIGNAL(triggered()), displayWidget()->connectionsProxy(), SLOT(copyAnchorOnly()));
+ ac->addAction("copyReferenceOnly", m_actions.copy.referenceOnly);
+
+ m_actions.copy.referenceTextOnly = new QAction(tr("Text of reference"), ac);
+ QObject::connect(m_actions.copy.referenceTextOnly, SIGNAL(triggered()), displayWidget()->connectionsProxy(), SLOT(copyAnchorTextOnly()) );
+ ac->addAction("copyTextOfReference", m_actions.copy.referenceTextOnly);
+
+ m_actions.copy.referenceAndText = new QAction(tr("Reference with text"), ac);
+ QObject::connect(m_actions.copy.referenceAndText, SIGNAL(triggered()), displayWidget()->connectionsProxy(), SLOT(copyAnchorWithText()) );
+ ac->addAction( "copyReferenceWithText", m_actions.copy.referenceAndText);
+
+ m_actions.copy.chapter = new QAction(tr("Chapter"), ac);
+ QObject::connect(m_actions.copy.chapter, SIGNAL(triggered()), this, SLOT(copyDisplayedText()) );
+ ac->addAction("copyChapter", m_actions.copy.chapter);
+
+ m_actions.copy.selectedText = qobject_cast<QAction*>(ac->action("copySelectedText"));
+ Q_ASSERT(m_actions.copy.selectedText);
+
+ m_actions.save.referenceAndText = new QAction(tr("Reference with text"), ac );
+ QObject::connect(m_actions.save.referenceAndText, SIGNAL(triggered()), displayWidget()->connectionsProxy(), SLOT(saveAnchorWithText()) );
+ ac->addAction("saveReferenceWithText", m_actions.save.referenceAndText);
+
+ m_actions.save.chapterAsPlain = new QAction(tr("Chapter as plain text"), ac);
+ QObject::connect(m_actions.save.chapterAsPlain, SIGNAL(triggered()), this, SLOT(saveChapterPlain()) );
+ ac->addAction("saveChapterAsPlainText", m_actions.save.chapterAsPlain);
+
+ m_actions.save.chapterAsHTML = new QAction(tr("Chapter as HTML"), ac);
+ QObject::connect(m_actions.save.chapterAsHTML, SIGNAL(triggered()), this, SLOT(saveChapterHTML()) );
+ ac->addAction("saveChapterAsHTML", m_actions.save.chapterAsHTML);
+
+ m_actions.print.reference = new QAction(tr("Reference with text"), ac);
+ QObject::connect(m_actions.print.reference, SIGNAL(triggered()), this, SLOT(printAnchorWithText()) );
+ ac->addAction("saveReferenceWithText", m_actions.print.reference);
+
+ m_actions.print.chapter = new QAction(tr("Chapter"), ac);
+ QObject::connect(m_actions.print.chapter, SIGNAL(triggered()), this, SLOT(printAll()) );
+ ac->addAction("printChapter", m_actions.print.chapter);
+
+// CBTConfig::setupAccelSettings(CBTConfig::bibleWindow, ac);
+}
+
+void CBibleReadWindow::initConnections() {
+ CLexiconReadWindow::initConnections();
+}
+
+void CBibleReadWindow::initToolbars() {
+ CLexiconReadWindow::initToolbars();
+}
+
+void CBibleReadWindow::initView() {
+ CLexiconReadWindow::initView();
+
+ parentWidget()->installEventFilter( this );
+}
+
+/** Reimplementation. */
+void CBibleReadWindow::setupPopupMenu() {
+ popup()->setTitle(tr("Bible window"));
+ popup()->setIcon(CToolClass::getIconForModule(modules().first()) );
+ popup()->addAction(m_actions.findText);
+ popup()->addAction(m_actions.findStrongs);
+ popup()->addAction(m_actions.selectAll);
+
+ popup()->addSeparator();
+
+ m_actions.copyMenu = new QMenu(tr("Copy..."), popup());
+ m_actions.copyMenu->addAction(m_actions.copy.referenceOnly);
+ m_actions.copyMenu->addAction(m_actions.copy.referenceTextOnly);
+ m_actions.copyMenu->addAction(m_actions.copy.referenceAndText);
+ m_actions.copyMenu->addAction(m_actions.copy.chapter);
+
+ m_actions.copyMenu->addSeparator();
+
+ m_actions.copyMenu->addAction(m_actions.copy.selectedText);
+ popup()->addMenu(m_actions.copyMenu);
+
+ m_actions.saveMenu = new QMenu(tr("Save..."), popup());
+ m_actions.saveMenu->addAction(m_actions.save.referenceAndText);
+ m_actions.saveMenu->addAction(m_actions.save.chapterAsPlain);
+ m_actions.saveMenu->addAction(m_actions.save.chapterAsHTML);
+ // Save raw HTML action for debugging purposes
+ if (qApp->property("--debug").toBool()) {
+ QAction* debugAction = new QAction("Raw HTML", this);
+ QObject::connect(debugAction, SIGNAL(triggered()), this, SLOT(saveRawHTML()));
+ m_actions.saveMenu->addAction(debugAction);
+ } // end of Save Raw HTML
+ popup()->addMenu(m_actions.saveMenu);
+
+ m_actions.printMenu = new QMenu(tr("Print..."), popup());
+ m_actions.printMenu->addAction(m_actions.print.reference);
+ m_actions.printMenu->addAction(m_actions.print.chapter);
+ popup()->addMenu(m_actions.printMenu);
+}
+
+/** Reimplemented. */
+void CBibleReadWindow::updatePopupMenu() {
+ qWarning("CBibleReadWindow::updatePopupMenu()");
+
+ //enable the action depending on the supported module features
+// bool hasStrongs = false;
+// QList<CSwordModuleInfo*> mods = modules();
+// for (QList<CSwordModuleInfo*>::iterator it = mods.begin(); it != mods.end(); ++it) {
+// if ( (*it)->has( CSwordModuleInfo::strongNumbers ) ) {
+// hasStrongs = true;
+// break;
+// }
+// }
+//
+// m_actions.findStrongs->setEnabled( hasStrongs );
+ m_actions.findStrongs->setEnabled( displayWidget()->getCurrentNodeInfo()[CDisplay::Lemma] != QString::null );
+
+
+ m_actions.copy.referenceOnly->setEnabled( ((CReadDisplay*)displayWidget())->hasActiveAnchor() );
+ m_actions.copy.referenceTextOnly->setEnabled( ((CReadDisplay*)displayWidget())->hasActiveAnchor() );
+ m_actions.copy.referenceAndText->setEnabled( ((CReadDisplay*)displayWidget())->hasActiveAnchor() );
+ m_actions.copy.selectedText->setEnabled( ((CReadDisplay*)displayWidget())->hasSelection() );
+
+ m_actions.save.referenceAndText->setEnabled( ((CReadDisplay*)displayWidget())->hasActiveAnchor() );
+
+ m_actions.print.reference->setEnabled( ((CReadDisplay*)displayWidget())->hasActiveAnchor() );
+}
+
+/** Moves to the next book. */
+void CBibleReadWindow::nextBook() {
+ if (verseKey()->next(CSwordVerseKey::UseBook)) {
+ keyChooser()->setKey(key());
+ }
+}
+
+/** Moves one book behind. */
+void CBibleReadWindow::previousBook() {
+ if (verseKey()->previous(CSwordVerseKey::UseBook)) {
+ keyChooser()->setKey(key());
+ }
+}
+
+/** Moves to the next book. */
+void CBibleReadWindow::nextChapter() {
+ if (verseKey()->next(CSwordVerseKey::UseChapter)) {
+ keyChooser()->setKey(key());
+ }
+}
+
+/** Moves one book behind. */
+void CBibleReadWindow::previousChapter() {
+ if (verseKey()->previous(CSwordVerseKey::UseChapter)) {
+ keyChooser()->setKey(key());
+ }
+}
+
+/** Moves to the next book. */
+void CBibleReadWindow::nextVerse() {
+ if (verseKey()->next(CSwordVerseKey::UseVerse)) {
+ keyChooser()->setKey(key());
+ }
+}
+
+/** Moves one book behind. */
+void CBibleReadWindow::previousVerse() {
+ if (verseKey()->previous(CSwordVerseKey::UseVerse)) {
+ keyChooser()->setKey(key());
+ }
+}
+
+/** rapper around key() to return the right type of key. */
+CSwordVerseKey* CBibleReadWindow::verseKey() {
+ CSwordVerseKey* k = dynamic_cast<CSwordVerseKey*>(CDisplayWindow::key());
+ Q_ASSERT(k);
+
+ return k;
+}
+
+/** Copies the current chapter into the clipboard. */
+void CBibleReadWindow::copyDisplayedText() {
+ CSwordVerseKey dummy(*verseKey());
+ dummy.Verse(1);
+
+ CSwordVerseKey vk(*verseKey());
+ vk.LowerBound(dummy);
+
+ CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(modules().first());
+ dummy.Verse(bible->verseCount(dummy.book(), dummy.Chapter()));
+ vk.UpperBound(dummy);
+
+ CExportManager mgr(tr("Copy chapter to clipboard ..."), false, tr("Copying"), filterOptions(), displayOptions());
+ mgr.copyKey(&vk, CExportManager::Text, true);
+}
+
+/** Saves the chapter as valid HTML page. */
+void CBibleReadWindow::saveChapterHTML() {
+ //saves the complete chapter to disk
+ CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(modules().first());
+ Q_ASSERT(bible);
+ if (!bible) //shouldn't happen
+ return;
+
+ CSwordVerseKey dummy(*verseKey());
+ dummy.Verse(1);
+
+ CSwordVerseKey vk(*verseKey());
+ vk.LowerBound(dummy);
+
+ dummy.Verse(bible->verseCount(dummy.book(), dummy.Chapter()));
+ vk.UpperBound(dummy);
+
+ CExportManager mgr(tr("Saving chapter ..."), true, tr("Saving"), filterOptions(), displayOptions());
+ mgr.saveKey(&vk, CExportManager::HTML, true);
+}
+
+/** Saves the chapter as valid HTML page. */
+void CBibleReadWindow::saveChapterPlain() {
+ //saves the complete chapter to disk
+
+ CSwordVerseKey vk(*verseKey());
+ CSwordVerseKey dummy(*verseKey());
+
+ dummy.Verse(1);
+ vk.LowerBound(dummy);
+
+ CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(modules().first());
+ dummy.Verse(bible->verseCount(dummy.book(), dummy.Chapter()));
+ vk.UpperBound(dummy);
+
+ CExportManager mgr(tr("Saving chapter ..."), true, tr("Saving"), filterOptions(),displayOptions());
+ mgr.saveKey(&vk, CExportManager::Text, true);
+}
+
+void CBibleReadWindow::reload(CSwordBackend::SetupChangedReason reason) {
+ CLexiconReadWindow::reload(reason);
+
+ if (m_modules.count() == 0) {
+ close();
+ return;
+ }
+
+ //refresh the book lists
+// qDebug("lang is %s",backend()->booknameLanguage().latin1());
+ verseKey()->setLocale( backend()->booknameLanguage().toLatin1() );
+ keyChooser()->refreshContent();
+
+// CBTConfig::setupAccelSettings(CBTConfig::readWindow, actionCollection()); //setup the predefined actions
+// CBTConfig::setupAccelSettings(CBTConfig::bibleWindow, actionCollection());
+}
+
+/** No descriptions */
+bool CBibleReadWindow::eventFilter( QObject* o, QEvent* e) {
+ const bool ret = CLexiconReadWindow::eventFilter(o,e);
+
+ // Q_ASSERT(o->inherits("CDisplayWindow"));
+ // qWarning("class: %s", o->className());
+ if (e && (e->type() == QEvent::FocusIn)) { //sync other windows to this active
+
+ /* This is a hack to work around a KHTML problem (similair to the Drag&Drop problem we had):
+ * If new HTML content is loaded from inside a kHTML event handler
+ * the widget's state will be confused, i.e. it's scrolling without having
+ * the mousebutton clicked.
+ *
+ * This is not really in a KHTML event handler but works anyway.
+ * Sometime KDE/Qt is hard to use ...
+ */
+ QTimer::singleShot(0, this, SLOT(syncWindows()));
+ }
+
+ return ret;
+}
+
+void CBibleReadWindow::lookupSwordKey( CSwordKey* newKey ) {
+ CLexiconReadWindow::lookupSwordKey(newKey);
+ syncWindows();
+}
+
+void CBibleReadWindow::syncWindows() {
+ foreach (QMdiSubWindow* subWindow, mdi()->subWindowList()) {
+ CDisplayWindow* w = dynamic_cast<CDisplayWindow*>(subWindow->widget());
+ if (w && w->syncAllowed()) {
+ w->lookupKey( key()->key() );
+ }
+ }
+}
diff --git a/src/frontend/displaywindow/cbiblereadwindow.h b/src/frontend/displaywindow/cbiblereadwindow.h
new file mode 100644
index 0000000..e044463
--- /dev/null
+++ b/src/frontend/displaywindow/cbiblereadwindow.h
@@ -0,0 +1,144 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CBIBLEREADWINDOW_H
+#define CBIBLEREADWINDOW_H
+
+//BibleTime includes
+#include "clexiconreadwindow.h"
+
+
+
+class CTransliterationButton;
+class CSwordKey;
+class CSwordVerseKey;
+
+class BtActionCollection;
+class QAction;
+class QMenu;
+
+class QObject;
+class QEvent;
+
+
+
+/**The read display window for Bibles.
+ *@author The BibleTime team
+ */
+
+class CBibleReadWindow : public CLexiconReadWindow {
+ Q_OBJECT
+public:
+ CBibleReadWindow(QList<CSwordModuleInfo*> modules, CMDIArea* parent);
+ virtual ~CBibleReadWindow();
+ /**
+ * Store the settings of this window in the given CProfileWindow object.
+ */
+ virtual void storeProfileSettings( Profile::CProfileWindow* const settings );
+ /**
+ * Store the settings of this window in the given profile window.
+ */
+ virtual void applyProfileSettings( Profile::CProfileWindow* const settings );
+ /**
+ * Reimplementation.
+ */
+ static void insertKeyboardActions( BtActionCollection* const a );
+
+protected:
+ virtual void initActions();
+ virtual void initToolbars();
+ virtual void initConnections();
+ virtual void initView();
+ /**
+ * Reimplementation.
+ */
+ virtual void setupPopupMenu();
+ /**
+ * Reimplemented.
+ */
+ virtual void updatePopupMenu();
+ /** Event filter.
+ * Reimplementation of the event filter to filter out events like focus in.
+ */
+ virtual bool eventFilter( QObject* o, QEvent* e);
+
+ struct {
+ QAction* selectAll;
+ QAction* findText;
+ QAction* findStrongs;
+
+ QMenu* copyMenu;
+ struct {
+ QAction* referenceOnly;
+ QAction* referenceTextOnly;
+ QAction* referenceAndText;
+ QAction* chapter;
+ QAction* selectedText;
+ }
+ copy;
+
+ QMenu* saveMenu;
+ struct {
+ QAction* referenceAndText;
+ QAction* chapterAsPlain;
+ QAction* chapterAsHTML;
+ }
+ save;
+
+ QMenu* printMenu;
+ struct {
+ QAction* reference;
+ QAction* chapter;
+ }
+ print;
+ }
+ m_actions;
+
+
+public slots:
+ void nextBook();
+ void previousBook();
+ void nextChapter();
+ void previousChapter();
+ void nextVerse();
+ void previousVerse();
+ /**
+ * Refreshes the content of this display window and the content of the keychooser.
+ */
+ virtual void reload(CSwordBackend::SetupChangedReason reason);
+
+protected slots: // Protected slots
+ /**
+ * Copies the current chapter into the clipboard.
+ */
+ void copyDisplayedText();
+ /**
+ * Saves the chapter as valid HTML page.
+ */
+ void saveChapterHTML();
+ /**
+ * Saves the chapter as valid HTML page.
+ */
+ void saveChapterPlain();
+ virtual void lookupSwordKey( CSwordKey* newKey );
+ void syncWindows();
+
+private:
+ friend class CCommentaryReadWindow;
+ /**
+ * Wrapper around key() to return the right type of key.
+ */
+ CSwordVerseKey* verseKey();
+
+ // CTransliterationButton* m_transliterationButton;
+};
+
+#endif
diff --git a/src/frontend/displaywindow/cbookreadwindow.cpp b/src/frontend/displaywindow/cbookreadwindow.cpp
new file mode 100644
index 0000000..657238f
--- /dev/null
+++ b/src/frontend/displaywindow/cbookreadwindow.cpp
@@ -0,0 +1,195 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#include "cbookreadwindow.h"
+#include "bttoolbarpopupaction.h"
+#include "btactioncollection.h"
+
+#include "cmodulechooserbar.h"
+#include "cbuttons.h"
+
+#include "backend/keys/cswordtreekey.h"
+
+#include "frontend/display/cdisplay.h"
+#include "frontend/keychooser/cbooktreechooser.h"
+#include "frontend/profile/cprofilewindow.h"
+#include "backend/config/cbtconfig.h"
+
+#include "util/ctoolclass.h"
+#include "util/cresmgr.h"
+
+#include <QSplitter>
+#include <QToolBar>
+#include <QMenu>
+#include <QAction>
+
+using namespace Profile;
+
+CBookReadWindow::CBookReadWindow(QList<CSwordModuleInfo*> modules, CMDIArea* parent) : CLexiconReadWindow(modules, parent) {}
+
+CBookReadWindow::~CBookReadWindow() {}
+
+void CBookReadWindow::applyProfileSettings( CProfileWindow* profileWindow )
+{
+ CLexiconReadWindow::applyProfileSettings(profileWindow);
+
+ const bool enable = static_cast<bool>( profileWindow->windowSettings() );
+ if (enable) {
+ m_treeAction->activate(QAction::Trigger);
+ }
+}
+
+void CBookReadWindow::storeProfileSettings( CProfileWindow* profileWindow )
+{
+ CLexiconReadWindow::storeProfileSettings(profileWindow);
+
+ //store information about our show tree structure button
+ profileWindow->setWindowSettings( static_cast<int>( m_treeAction->isChecked() ) );
+}
+
+void CBookReadWindow::initActions()
+{
+ CLexiconReadWindow::initActions();
+ BtActionCollection* ac = actionCollection();
+ //cleanup, not a clean oo-solution
+ Q_ASSERT(ac->action("nextEntry"));
+ Q_ASSERT(ac->action("previousEntry"));
+ ac->action("nextEntry")->setEnabled(false);
+ ac->action("previousEntry")->setEnabled(false);
+
+ m_treeAction = new QAction(
+ QIcon(CResMgr::displaywindows::bookWindow::toggleTree::icon),
+ tr("Toggle tree view"),
+ ac
+ );
+ m_treeAction->setCheckable(true);
+ m_treeAction->setShortcut(CResMgr::displaywindows::bookWindow::toggleTree::accel);
+ QObject::connect(m_treeAction, SIGNAL(triggered()), this, SLOT(treeToggled()) );
+ ac->addAction("toggleTree", m_treeAction);
+
+// CBTConfig::setupAccelSettings(CBTConfig::bookWindow, ac);
+}
+
+void CBookReadWindow::insertKeyboardActions( BtActionCollection* const a )
+{
+ QAction* qaction;
+
+ qaction = new QAction(
+ QIcon(CResMgr::displaywindows::bookWindow::toggleTree::icon),
+ tr("Toggle tree view"),
+ a
+ );
+ qaction->setCheckable(true);
+ qaction->setShortcut(CResMgr::displaywindows::bookWindow::toggleTree::accel);
+ a->addAction("toggleTree", qaction);
+
+ // new QAction(tr("Copy reference only"), KShortcut(0), a, "copyReferenceOnly");
+ qaction = new QAction(tr("Copy entry with text"), a);
+ a->addAction("copyEntryWithText", qaction);
+ // new QAction(tr("Copy selected text"), KShortcut(0), a, "copySelectedText");
+ qaction = new QAction(tr("Save entry as plain text"), a);
+ a->addAction("saveEntryAsPlainText", qaction);
+ qaction = new QAction(tr("Save entry as HTML"),a);
+ a->addAction("saveEntryAsHTML", qaction);
+ // new QAction(tr("Print reference only"), KShortcut(0), a, "printReferenceOnly");
+ qaction = new QAction(tr("Print entry with text"), a);
+ a->addAction("printEntryWithText", qaction);
+
+}
+
+/** No descriptions */
+void CBookReadWindow::initConnections()
+{
+ CLexiconReadWindow::initConnections();
+
+ connect(m_treeChooser, SIGNAL(keyChanged(CSwordKey*)), this, SLOT(lookupSwordKey(CSwordKey*)));
+ connect(m_treeChooser, SIGNAL(keyChanged(CSwordKey*)), keyChooser(), SLOT(updateKey(CSwordKey*)));
+ connect(keyChooser(), SIGNAL(keyChanged(CSwordKey*)), m_treeChooser, SLOT(updateKey(CSwordKey*)));
+}
+
+/** Init the view */
+void CBookReadWindow::initView()
+{
+ QSplitter* splitter = new QSplitter(this);
+
+ setMainToolBar( new QToolBar(this) );
+ addToolBar(mainToolBar());
+ //addDockWindow(mainToolBar());
+
+ m_treeChooser = new CBookTreeChooser(modules(), key(), splitter);
+ setDisplayWidget( CDisplay::createReadInstance(this, splitter) );
+
+ setKeyChooser( CKeyChooser::createInstance(modules(), key(), mainToolBar()) );
+
+ setModuleChooserBar( new CModuleChooserBar(modules(), modules().first()->type(), this) );
+ moduleChooserBar()->setButtonLimit(1);
+ addToolBar(moduleChooserBar());
+ //addDockWindow( moduleChooserBar() );
+
+ setButtonsToolBar( new QToolBar(this) );
+ //addDockWindow( buttonsToolBar() );
+ setDisplaySettingsButton( new CDisplaySettingsButton( &displayOptions(), &filterOptions(), modules(), buttonsToolBar()) );
+ addToolBar(buttonsToolBar());
+ m_treeChooser->hide();
+
+ //splitter->setResizeMode(m_treeChooser, QSplitter::Stretch);
+ setCentralWidget( splitter );
+ setWindowIcon(CToolClass::getIconForModule(modules().first()));
+}
+
+void CBookReadWindow::initToolbars()
+{
+ Q_ASSERT(m_treeAction);
+ Q_ASSERT(m_actions.backInHistory);
+
+ mainToolBar()->addAction(m_actions.backInHistory);
+ mainToolBar()->addAction(m_actions.forwardInHistory);
+
+ mainToolBar()->addWidget(keyChooser());
+
+ buttonsToolBar()->addAction(m_treeAction);
+ m_treeAction->setChecked(false);
+
+ buttonsToolBar()->addWidget(displaySettingsButton());
+
+ QAction* action = qobject_cast<QAction*>(actionCollection()->action(
+ CResMgr::displaywindows::general::search::actionName ));
+ if (action) {
+ buttonsToolBar()->addAction(action);
+ }
+
+ //#if KDE_VERSION_MINOR < 1
+ //action->plugAccel( accel() );
+ //#endif
+}
+
+/** Is called when the action was executed to toggle the tree view. */
+void CBookReadWindow::treeToggled()
+{
+ if (m_treeAction->isChecked()) {
+ m_treeChooser->show();
+ }
+ else {
+ m_treeChooser->hide();
+ }
+}
+
+/** Reimplementation to take care of the tree chooser. */
+void CBookReadWindow::modulesChanged()
+{
+ CLexiconReadWindow::modulesChanged();
+ m_treeChooser->setModules(modules());
+}
+
+void CBookReadWindow::setupPopupMenu()
+{
+ CLexiconReadWindow::setupPopupMenu();
+}
diff --git a/src/frontend/displaywindow/cbookreadwindow.h b/src/frontend/displaywindow/cbookreadwindow.h
new file mode 100644
index 0000000..eaa0c15
--- /dev/null
+++ b/src/frontend/displaywindow/cbookreadwindow.h
@@ -0,0 +1,69 @@
+/*********
+*
+* This file is part of BibleTime's BtActionCollection code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime BtActionCollection code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CBOOKREADWINDOW_H
+#define CBOOKREADWINDOW_H
+
+//BibleTime includes
+#include "clexiconreadwindow.h"
+
+
+class QAction;
+class CBookTreeChooser;
+class BtActionCollection;
+
+
+/**
+ * @author The BibleTime team
+ */
+class CBookReadWindow : public CLexiconReadWindow {
+ Q_OBJECT
+public:
+ static void insertKeyboardActions( BtActionCollection* const a );
+
+ CBookReadWindow(QList<CSwordModuleInfo*> modules, CMDIArea* parent);
+
+ virtual ~CBookReadWindow();
+ /**
+ * Store the settings of this window in the given CProfileWindow object.
+ */
+ virtual void storeProfileSettings( Profile::CProfileWindow* profileWindow );
+ /**
+ * Store the settings of this window in the given profile window.
+ */
+ virtual void applyProfileSettings( Profile::CProfileWindow* profileWindow );
+
+protected:
+ virtual void initActions();
+ virtual void initToolbars();
+ virtual void initConnections();
+ virtual void initView();
+
+ virtual void setupPopupMenu();
+
+ protected slots: // Protected slots
+ /**
+ * Reimplementation to take care of the tree chooser.
+ */
+ virtual void modulesChanged();
+
+private:
+ QAction* m_treeAction;
+ CBookTreeChooser* m_treeChooser;
+
+private slots: // Private slots
+ /**
+ * Is called when the action was executed to toggle the tree view.
+ */
+ void treeToggled();
+};
+
+#endif
diff --git a/src/frontend/displaywindow/cbuttons.cpp b/src/frontend/displaywindow/cbuttons.cpp
new file mode 100644
index 0000000..582e5de
--- /dev/null
+++ b/src/frontend/displaywindow/cbuttons.cpp
@@ -0,0 +1,191 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//BibleTime includes
+#include "cbuttons.h"
+
+#include "util/cresmgr.h"
+#include "util/cpointers.h"
+#include "util/directoryutil.h"
+
+//Qt includes
+#include <QString>
+#include <QToolTip>
+#include <QToolButton>
+#include <QHash>
+#include <QMenu>
+
+//KDE includes
+
+
+
+
+CDisplaySettingsButton::CDisplaySettingsButton(CSwordBackend::DisplayOptions *displaySettings, CSwordBackend::FilterOptions *moduleSettings, const QList<CSwordModuleInfo*>& useModules,QWidget *parent )
+: QToolButton(parent) {
+ // qWarning("CDisplaySettingsButton::CDisplaySettingsButton");
+ QToolButton::setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::displaySettings::icon));
+
+ m_displaySettings = displaySettings;
+ m_moduleSettings = moduleSettings;
+ m_modules = useModules;
+
+ m_popup = new QMenu(this);
+ setMenu(m_popup);
+ setPopupMode(QToolButton::InstantPopup);
+ setToolTip(tr("Display options"));
+
+ connect(m_popup, SIGNAL(triggered(QAction*)), this, SLOT(optionToggled(QAction*)));
+ populateMenu();
+}
+
+void CDisplaySettingsButton::reset(const QList<CSwordModuleInfo*>& useModules) {
+ m_modules = useModules;
+ populateMenu();
+ //disable the settings button if no options are available
+ if (!populateMenu()) {
+ setEnabled(false);
+ setToolTip(tr("Display settings: No options available"));
+ }
+ else {
+ setEnabled(true);
+ setToolTip(tr("Display settings"));
+ }
+}
+
+
+void CDisplaySettingsButton::optionToggled(QAction* /*action*/) {
+ qDebug("display settings option toggled");
+ //Take each Action and set the corresponding setting.
+ //Using QAction (QObject) property and OptionType enum is a dirty way to do this.
+ //See populateMenu().
+ foreach (QAction* act, m_popup->actions()) {
+ int optionType = act->property("OptionType").toInt();
+ bool checked = act->isChecked();
+ switch(optionType) {
+ case Linebreak:
+ m_displaySettings->lineBreaks = checked;
+ break;
+ case Versenum:
+ m_displaySettings->verseNumbers = checked;
+ break;
+ case Variant:
+ m_moduleSettings->textualVariants = checked;
+ break;
+ case Vowel:
+ m_moduleSettings->hebrewPoints = checked;
+ break;
+ case Accents:
+ m_moduleSettings->greekAccents = checked;
+ break;
+ case Cantillation:
+ m_moduleSettings->hebrewCantillation = checked;
+ break;
+ case Headings:
+ m_moduleSettings->headings = checked;
+ break;
+ case Morphseg:
+ m_moduleSettings->morphSegmentation = checked;
+ break;
+ case Xref:
+ m_moduleSettings->scriptureReferences = checked;
+ break;
+ case WordsofJ:
+ m_moduleSettings->redLetterWords = checked;
+ break;
+ }
+ }
+
+ emit sigChanged();
+}
+
+/** No descriptions */
+int CDisplaySettingsButton::populateMenu() {
+ int ret = 0;
+
+ m_popup->clear();
+
+ // See also optionToggled()
+
+ ret += addMenuEntry(tr("Use linebreaks after each verse"), Linebreak, &m_displaySettings->lineBreaks, (m_modules.first()->type() == CSwordModuleInfo::Bible));
+
+ //show the verse numbers option only for bible modules
+ ret += addMenuEntry(tr("Show verse numbers"), Versenum, &m_displaySettings->verseNumbers, (m_modules.first()->type() == CSwordModuleInfo::Bible));
+
+ ret += addMenuEntry(tr("Show headings"), Headings, &m_moduleSettings->headings,
+ isOptionAvailable(CSwordModuleInfo::headings));
+
+ ret += addMenuEntry(tr("Highlight words of Jesus"), WordsofJ, &m_moduleSettings->redLetterWords,
+ isOptionAvailable(CSwordModuleInfo::redLetterWords ));
+
+ ret += addMenuEntry(tr("Show Hebrew vowel points"), Vowel, &m_moduleSettings->hebrewPoints,
+ isOptionAvailable(CSwordModuleInfo::hebrewPoints ));
+
+ ret += addMenuEntry(tr("Show Hebrew cantillation marks"), Cantillation, &m_moduleSettings->hebrewCantillation,
+ isOptionAvailable(CSwordModuleInfo::hebrewCantillation ));
+
+ ret += addMenuEntry(tr("Show Greek accents"), Accents, &m_moduleSettings->greekAccents,
+ isOptionAvailable(CSwordModuleInfo::greekAccents ));
+
+ ret += addMenuEntry(tr("Use alternative textual variant"), Variant, &m_moduleSettings->textualVariants,
+ isOptionAvailable(CSwordModuleInfo::textualVariants ));
+
+ ret += addMenuEntry(tr("Show scripture cross-references"), Xref, &m_moduleSettings->scriptureReferences,
+ isOptionAvailable(CSwordModuleInfo::scriptureReferences ));
+
+ ret += addMenuEntry(tr("Show morph segmentation"), Morphseg, &m_moduleSettings->morphSegmentation,
+ isOptionAvailable(CSwordModuleInfo::morphSegmentation ));
+
+ return ret;
+}
+
+/** Adds an entry to m_popup. */
+int CDisplaySettingsButton::addMenuEntry( const QString name, OptionType type, const int* option, const bool available) {
+ int ret = 0;
+
+ if (available) {
+ QAction* a = m_popup->addAction(name);
+ //see optionToggled()
+ a->setProperty("OptionType", type);
+ a->setCheckable(true);
+ a->setChecked(*option);
+ ret = 1;
+ }
+
+ return ret;
+}
+
+bool CDisplaySettingsButton::isOptionAvailable( const CSwordModuleInfo::FilterTypes option ) {
+ bool ret = false;
+ QList<CSwordModuleInfo*>::iterator end_it = m_modules.end();
+ for (QList<CSwordModuleInfo*>::iterator it(m_modules.begin()); it != end_it; ++it) {
+ ret = ret || (*it)->has(option);
+ }
+ return ret;
+}
+
+/** Returns the number of usable menu items in the settings menu. */
+int CDisplaySettingsButton::menuItemCount() {
+ return m_popup->actions().count();
+}
+
+/** Sets the item at position pos to the state given as 2nd paramter. */
+void CDisplaySettingsButton::setItemStatus( const int index, const bool checked ) {
+ QAction* action = m_popup->actions().at(index);
+ action->setChecked(checked);
+}
+
+/** Returns the status of the item at position "index" */
+bool CDisplaySettingsButton::itemStatus( const int index ) {
+ return m_popup->actions().at(index)->isChecked();
+}
+
+/** Sets the status to changed. The signal changed will be emitted. */
+void CDisplaySettingsButton::setChanged() {
+ emit sigChanged();
+}
diff --git a/src/frontend/displaywindow/cbuttons.h b/src/frontend/displaywindow/cbuttons.h
new file mode 100644
index 0000000..6d94c53
--- /dev/null
+++ b/src/frontend/displaywindow/cbuttons.h
@@ -0,0 +1,77 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CBUTTONS_H
+#define CBUTTONS_H
+
+//BibleTime includes
+#include "backend/managers/cswordbackend.h"
+class CSwordModuleInfo;
+
+//QT includes
+#include <QHash>
+#include <QToolButton>
+
+class QMenu;
+
+/** This class manages the display options of the selected modules.
+ * @author The BibleTime team
+ */
+class CDisplaySettingsButton : public QToolButton {
+ Q_OBJECT
+public:
+
+ CDisplaySettingsButton(CSwordBackend::DisplayOptions *displaySettings, CSwordBackend::FilterOptions *settings, const QList<CSwordModuleInfo*>& useModules, QWidget *parent=0);
+ void reset(const QList<CSwordModuleInfo*>& useModules);
+ /**
+ * Sets the item at position pos to the satet given as 2nd paramter.
+ */
+ void setItemStatus( const int pos, const bool checked );
+ /**
+ * Returns the number of usable menu items in the setttings menu.
+ */
+ int menuItemCount();
+ /**
+ * Returns the status of the item at position "index"
+ */
+ bool itemStatus( const int index );
+ /**
+ * Sets the status to changed. The signal changed will be emitted.
+ */
+ void setChanged();
+
+signals:
+ void sigChanged(void);
+
+protected slots:
+ void optionToggled(QAction* action);
+
+protected:
+
+ /** This enum marks the option types for a display. Used internally.*/
+ enum OptionType {Linebreak, Versenum, Headings, WordsofJ, Vowel, Cantillation, Accents,
+ Variant, Xref, Morphseg};
+
+ CSwordBackend::FilterOptions* m_moduleSettings;
+ CSwordBackend::DisplayOptions* m_displaySettings;
+ CSwordBackend::FilterOptions m_available;
+ QList<CSwordModuleInfo*> m_modules;
+
+ QHash<QString, int> m_dict;
+
+ QMenu* m_popup;
+
+ int populateMenu();
+ bool isOptionAvailable( const CSwordModuleInfo::FilterTypes option);
+ int addMenuEntry( const QString name, OptionType type, const int* option, const bool available);
+};
+
+#endif
diff --git a/src/frontend/displaywindow/ccommentaryreadwindow.cpp b/src/frontend/displaywindow/ccommentaryreadwindow.cpp
new file mode 100644
index 0000000..9228c2d
--- /dev/null
+++ b/src/frontend/displaywindow/ccommentaryreadwindow.cpp
@@ -0,0 +1,198 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//BibleTime includes
+#include "ccommentaryreadwindow.h"
+#include "btactioncollection.h"
+
+#include "frontend/profile/cprofilewindow.h"
+#include "backend/config/cbtconfig.h"
+#include "frontend/keychooser/ckeychooser.h"
+#include "frontend/display/cdisplay.h"
+#include "frontend/display/creaddisplay.h"
+
+#include "backend/keys/cswordversekey.h"
+
+#include "util/ctoolclass.h"
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+
+#include <QMenu>
+#include <QAction>
+#include <QIcon>
+#include <QToolBar>
+
+using namespace Profile;
+
+CCommentaryReadWindow::CCommentaryReadWindow(QList<CSwordModuleInfo*> modules, CMDIArea* parent) : CLexiconReadWindow(modules, parent) {}
+
+void CCommentaryReadWindow::insertKeyboardActions( BtActionCollection* const a ) {
+
+ QAction* qaction;
+
+ qaction = new QAction(tr("Next book"), a);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::nextBook::accel);
+ a->addAction("nextBook", qaction);
+
+ qaction = new QAction(tr("Previous book"), a);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::previousBook::accel);
+ a->addAction( "previousBook", qaction);
+
+ qaction = new QAction(tr("Next chapter"), a);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::nextChapter::accel);
+ a->addAction("nextChapter", qaction);
+
+ qaction = new QAction(tr("Previous chapter"), a);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::previousChapter::accel);
+ a->addAction("previousChapter", qaction);
+
+ qaction = new QAction(tr("Next verse"), a);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::nextVerse::accel);
+ a->addAction("nextVerse", qaction);
+
+ qaction = new QAction(tr("Previous verse"), a);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::previousVerse::accel);
+ a->addAction("previousVerse", qaction);
+
+}
+
+void CCommentaryReadWindow::applyProfileSettings( CProfileWindow* profileWindow ) {
+ CLexiconReadWindow::applyProfileSettings(profileWindow);
+ if (profileWindow->windowSettings()) {
+ m_syncButton->setChecked(true);
+ }
+}
+
+void CCommentaryReadWindow::storeProfileSettings( CProfileWindow* profileWindow ) {
+ CLexiconReadWindow::storeProfileSettings(profileWindow);
+ profileWindow->setWindowSettings( m_syncButton->isChecked() );
+}
+
+void CCommentaryReadWindow::initToolbars() {
+ CLexiconReadWindow::initToolbars();
+
+ m_syncButton = new QAction(
+ QIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::commentaryWindow::syncWindow::icon)),
+ tr("Synchronize"),
+ actionCollection()
+ );
+ m_syncButton->setCheckable(true);
+ m_syncButton->setShortcut(CResMgr::displaywindows::commentaryWindow::syncWindow::accel);
+ m_syncButton->setToolTip(tr("Synchronize the displayed entry of this work with the active Bible window"));
+ actionCollection()->addAction(CResMgr::displaywindows::commentaryWindow::syncWindow::actionName, m_syncButton);
+ buttonsToolBar()->addAction(m_syncButton);
+}
+
+/** Reimplementation to handle the keychooser refresh. */
+void CCommentaryReadWindow::reload(CSwordBackend::SetupChangedReason reason) {
+ CLexiconReadWindow::reload(reason);
+
+ //refresh the book lists
+ verseKey()->setLocale( backend()->booknameLanguage().toLatin1() );
+ keyChooser()->refreshContent();
+}
+
+/** rapper around key() to return the right type of key. */
+CSwordVerseKey* CCommentaryReadWindow::verseKey() {
+ CSwordVerseKey* k = dynamic_cast<CSwordVerseKey*>(CDisplayWindow::key());
+ Q_ASSERT(k);
+ return k;
+}
+
+void CCommentaryReadWindow::initActions() {
+ CLexiconReadWindow::initActions(); //make sure the predefined actions are available
+
+ BtActionCollection* ac = actionCollection();
+
+ //cleanup, not a clean oo-solution
+ ac->action("nextEntry")->setEnabled(false);
+ ac->action("previousEntry")->setEnabled(false);
+
+ QAction* qaction;
+
+ qaction = new QAction(tr("Next book"), ac);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::nextBook::accel);
+ QObject::connect(qaction, SIGNAL(triggered()), this, SLOT(nextBook()) );
+ ac->addAction("nextBook", qaction);
+
+ qaction = new QAction(tr("Previous book"), ac);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::previousBook::accel);
+ QObject::connect(qaction, SIGNAL(triggered()), this, SLOT(previousBook()) );
+ ac->addAction("previousBook", qaction);
+
+ qaction = new QAction(tr("Next chapter"), ac);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::nextChapter::accel);
+ QObject::connect(qaction, SIGNAL(triggered()), this, SLOT(nextChapter()) );
+ ac->addAction("nextChapter", qaction);
+
+ qaction = new QAction(tr("Previous chapter"), ac);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::previousChapter::accel);
+ QObject::connect(qaction, SIGNAL(triggered()), this, SLOT(previousChapter()) );
+ ac->addAction("previousChapter", qaction);
+
+ qaction = new QAction(tr("Next verse"), ac);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::nextVerse::accel);
+ QObject::connect(qaction, SIGNAL(triggered()), this, SLOT(nextVerse()) );
+ ac->addAction("nextVerse", qaction);
+
+ qaction = new QAction(tr("Previous verse"), ac);
+ qaction->setShortcut(CResMgr::displaywindows::bibleWindow::previousVerse::accel);
+ QObject::connect(qaction, SIGNAL(triggered()), this, SLOT(previousVerse()) );
+ ac->addAction("previousVerse", qaction);
+
+// CBTConfig::setupAccelSettings(CBTConfig::commentaryWindow, actionCollection());
+}
+
+/** Moves to the next book. */
+void CCommentaryReadWindow::nextBook() {
+ if (verseKey()->next(CSwordVerseKey::UseBook))
+ keyChooser()->setKey(key());
+}
+
+/** Moves one book behind. */
+void CCommentaryReadWindow::previousBook() {
+ if (verseKey()->previous(CSwordVerseKey::UseBook))
+ keyChooser()->setKey(key());
+}
+
+/** Moves to the next book. */
+void CCommentaryReadWindow::nextChapter() {
+ if (verseKey()->next(CSwordVerseKey::UseChapter))
+ keyChooser()->setKey(key());
+}
+
+/** Moves one book behind. */
+void CCommentaryReadWindow::previousChapter() {
+ if (verseKey()->previous(CSwordVerseKey::UseChapter))
+ keyChooser()->setKey(key());
+}
+
+/** Moves to the next book. */
+void CCommentaryReadWindow::nextVerse() {
+ if (verseKey()->next(CSwordVerseKey::UseVerse))
+ keyChooser()->setKey(key());
+}
+
+/** Moves one book behind. */
+void CCommentaryReadWindow::previousVerse() {
+ if (verseKey()->previous(CSwordVerseKey::UseVerse))
+ keyChooser()->setKey(key());
+}
+
+bool CCommentaryReadWindow::syncAllowed() const {
+ return m_syncButton->isChecked();
+}
+
+
+/*!
+ \fn CCommentaryReadWindow::setupPopupMenu()
+ */
+void CCommentaryReadWindow::setupPopupMenu() {
+ CLexiconReadWindow::setupPopupMenu();
+}
diff --git a/src/frontend/displaywindow/ccommentaryreadwindow.h b/src/frontend/displaywindow/ccommentaryreadwindow.h
new file mode 100644
index 0000000..1bac735
--- /dev/null
+++ b/src/frontend/displaywindow/ccommentaryreadwindow.h
@@ -0,0 +1,72 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CCOMMENTARYREADWINDOW_H
+#define CCOMMENTARYREADWINDOW_H
+
+//BibleTime includes
+#include "cbiblereadwindow.h"
+
+//Qt includes
+//#include <qwidget.h>
+
+
+class QAction;
+class CSwordVerseKey;
+class BtActionCollection;
+
+/**
+ *@author The BibleTime team
+ */
+
+class CCommentaryReadWindow : public CLexiconReadWindow {
+ Q_OBJECT
+public:
+ /**
+ * Reimplementation.
+ */
+ static void insertKeyboardActions( BtActionCollection* const a );
+
+ CCommentaryReadWindow(QList<CSwordModuleInfo*> modules, CMDIArea* parent);
+ /**
+ * Store the settings of this window in the given CProfileWindow object.
+ */
+ virtual void storeProfileSettings( Profile::CProfileWindow* profileWindow );
+ /**
+ * Store the settings of this window in the given profile window.
+ */
+ virtual void applyProfileSettings( Profile::CProfileWindow* profileWindow );
+ virtual bool syncAllowed() const;
+
+public slots: // Public slots
+ void nextBook();
+ void previousBook();
+ void nextChapter();
+ void previousChapter();
+ void nextVerse();
+ void previousVerse();
+ /**
+ * Reimplementation to handle the keychooser refresh.
+ */
+ virtual void reload(CSwordBackend::SetupChangedReason);
+
+protected:
+ virtual void initActions();
+ virtual void initToolbars();
+
+private:
+ QAction* m_syncButton;
+ CSwordVerseKey* verseKey();
+protected:
+ virtual void setupPopupMenu();
+};
+
+#endif
diff --git a/src/frontend/displaywindow/cdisplaywindow.cpp b/src/frontend/displaywindow/cdisplaywindow.cpp
new file mode 100644
index 0000000..59fccab
--- /dev/null
+++ b/src/frontend/displaywindow/cdisplaywindow.cpp
@@ -0,0 +1,497 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cdisplaywindow.h"
+#include "bttoolbarpopupaction.h"
+#include "btactioncollection.h"
+
+#include "cmodulechooserbar.h"
+#include "cbuttons.h"
+#include "backend/keys/cswordkey.h"
+#include "frontend/keychooser/ckeychooser.h"
+#include "frontend/keychooser/bthistory.h"
+#include "frontend/display/cdisplay.h"
+#include "frontend/cmdiarea.h"
+#include "frontend/profile/cprofilewindow.h"
+#include "backend/config/cbtconfig.h"
+#include "frontend/searchdialog/csearchdialog.h"
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+
+#include <QWidget>
+#include <QCloseEvent>
+#include <QStringList>
+#include <QDebug>
+#include <QMenu>
+
+using namespace Profile;
+
+CDisplayWindow::CDisplayWindow(QList<CSwordModuleInfo*> modules, CMDIArea *parent)
+ : QMainWindow(parent),
+ m_mdi(parent),
+ m_filterOptions(),
+ m_displayOptions(),
+ m_displaySettingsButton(0),
+ m_keyChooser(0),
+ m_swordKey(0),
+ m_isReady(false),
+ m_moduleChooserBar(0),
+ m_mainToolBar(0),
+ m_popupMenu(0),
+ m_displayWidget(0)
+{
+ qDebug("CDisplayWindow::CDisplayWindow");
+ setAttribute(Qt::WA_DeleteOnClose); //we want to destroy this window when it is closed
+ parent->addSubWindow(this);
+ m_actionCollection = new BtActionCollection(this);
+ setModules(modules);
+
+ // Connect this to the backend module list changes
+ connect(CPointers::backend(), SIGNAL(sigSwordSetupChanged(CSwordBackend::SetupChangedReason)), SLOT(reload(CSwordBackend::SetupChangedReason)));
+ //KMainWindow::setAttribute(Qt::WA_DeleteOnClose); //what about QMdiSubWindow?
+}
+
+CDisplayWindow::~CDisplayWindow() {
+ delete m_swordKey;
+ m_swordKey = 0;
+}
+
+CMDIArea* CDisplayWindow::mdi() const {
+ return m_mdi;
+}
+
+/** Returns the right window caption. */
+const QString CDisplayWindow::windowCaption() {
+ if (!m_modules.count()) {
+ return QString::null;
+ }
+
+ return QString(key()->key()).append(" (").append(m_modules.join(" | ")).append(")");
+}
+
+/** Returns the used modules as a QPtrList */
+QList<CSwordModuleInfo*> CDisplayWindow::modules() {
+ QList<CSwordModuleInfo*> mods;
+
+ for (QStringList::iterator it = m_modules.begin(); it != m_modules.end(); ++it) {
+ Q_ASSERT(backend()->findModuleByName(*it));
+ if (CSwordModuleInfo* m = backend()->findModuleByName(*it)) {
+ mods.append(m);
+ }
+ }
+
+ return mods;
+}
+
+/** Set the window caption. */
+void CDisplayWindow::setCaption( const QString& ) {
+ QWidget::setWindowTitle( windowCaption() );
+ m_mdi->emitWindowCaptionChanged();
+}
+
+void CDisplayWindow::insertKeyboardActions( BtActionCollection* a ) {
+ qDebug() << "CDisplayWindow::insertKeyboardActions: ac: " << a;
+
+ QAction* actn = new QAction(QIcon(), tr("Zoom in"), 0);
+ actn->setShortcut(QKeySequence::ZoomIn);
+ a->addAction("zoomIn", actn);
+ //a->addAction(KStandardAction::ZoomIn, "zoomIn", 0, 0);
+ actn = new QAction(QIcon(), tr("Zoom out"), 0);
+ actn->setShortcut(QKeySequence::ZoomOut);
+ a->addAction("zoomIn", actn);
+ //a->addAction(KStandardAction::ZoomOut, "zoomOut", 0, 0);
+ actn = new QAction(QIcon(), tr("Close"), 0);
+ actn->setShortcut(QKeySequence::Close);
+ a->addAction("closeWindow", actn);
+ //a->addAction(KStandardAction::Close, "closeWindow", 0, 0);
+ actn = new QAction(QIcon(), tr("Select all"), 0);
+ actn->setShortcut(QKeySequence::SelectAll);
+ a->addAction("selectAll", actn);
+ //a->addAction(KStandardAction::SelectAll, "selectAll", 0, 0);
+ actn = new QAction(QIcon(), tr("Copy"), 0);
+ actn->setShortcut(QKeySequence::Copy);
+ a->addAction("copySelectedText", actn);
+ //a->addAction(KStandardAction::Copy, "copySelectedText", 0, 0);
+ actn = new QAction(QIcon(), tr("Find..."), 0);
+ actn->setShortcut(QKeySequence::Find);
+ a->addAction("findText", actn);
+ //a->addAction(KStandardAction::Find, "findText", 0, 0);
+
+ BtToolBarPopupAction* action = new BtToolBarPopupAction(
+ QIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::general::backInHistory::icon)),
+ tr("Back in history"),
+ a
+ );
+ action->setShortcut(CResMgr::displaywindows::general::backInHistory::accel);
+ a->addAction(CResMgr::displaywindows::general::backInHistory::actionName, action);
+
+ action = new BtToolBarPopupAction(
+ QIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::general::forwardInHistory::icon)),
+ tr("Forward in history"),
+ a
+ );
+ action->setShortcut(CResMgr::displaywindows::general::forwardInHistory::accel);
+ a->addAction(CResMgr::displaywindows::general::forwardInHistory::actionName, action);
+}
+
+void CDisplayWindow::initActions()
+{
+ qDebug("CDisplayWindow::initActions");
+
+ BtActionCollection* ac = actionCollection();
+
+ QAction* kaction = new QAction(
+ QIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::general::search::icon)),
+ tr("Open the search dialog with the works of this window"),
+ ac
+ );
+ kaction->setShortcut(CResMgr::displaywindows::general::search::accel);
+ QObject::connect(kaction, SIGNAL(triggered()), this, SLOT(slotSearchInModules()));
+ ac->addAction(CResMgr::displaywindows::general::search::actionName, kaction);
+
+ CDisplayConnections* conn = displayWidget()->connectionsProxy();
+
+ QAction* actn = new QAction(QIcon(), tr("Zoom in"), ac);
+ actn->setShortcut(QKeySequence::ZoomIn);
+ QObject::connect(actn, SIGNAL(triggered()), conn, SLOT(zoomIn()));
+ ac->addAction("zoomIn", actn);
+ addAction(actn);
+ //a->addAction(KStandardAction::ZoomIn, "zoomIn", 0, 0);
+ actn = new QAction(QIcon(), tr("Zoom out"), ac);
+ actn->setShortcut(QKeySequence::ZoomOut);
+ QObject::connect(actn, SIGNAL(triggered()), conn, SLOT(zoomOut()));
+ ac->addAction("zoomOut", actn);
+ addAction(actn);
+ //a->addAction(KStandardAction::ZoomOut, "zoomOut", 0, 0);
+ actn = new QAction(QIcon(), tr("Close"), ac);
+ actn->setShortcut(QKeySequence::Close);
+ QObject::connect(actn, SIGNAL(triggered()), this, SLOT(close()));
+ ac->addAction("closeWindow", actn);
+ addAction(actn);
+ //a->addAction(KStandardAction::Close, "closeWindow", 0, 0);
+ actn = new QAction(QIcon(), tr("Select all"), ac);
+ actn->setShortcut(QKeySequence::SelectAll);
+ QObject::connect(actn, SIGNAL(triggered()), conn, SLOT(selectAll()));
+ ac->addAction("selectAll", actn);
+ addAction(actn);
+ //a->addAction(KStandardAction::SelectAll, "selectAll", 0, 0);
+ actn = new QAction(QIcon(), tr("Copy"), ac);
+ actn->setShortcut(QKeySequence::Copy);
+ QObject::connect(actn, SIGNAL(triggered()), conn, SLOT(copySelection()));
+ ac->addAction("copySelectedText", actn);
+ addAction(actn);
+ //a->addAction(KStandardAction::Copy, "copySelectedText", 0, 0);
+ actn = new QAction(QIcon(), tr("Find..."), ac);
+ actn->setShortcut(QKeySequence::Find);
+ QObject::connect(actn, SIGNAL(triggered()), conn, SLOT(openFindTextDialog()));
+ ac->addAction("findText", actn);
+ addAction(actn);
+ //a->addAction(KStandardAction::Find, "findText", 0, 0);
+
+ BtToolBarPopupAction* popupaction = new BtToolBarPopupAction(
+ QIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::general::backInHistory::icon)),
+ tr("Back in history"),
+ ac
+ );
+ bool ok = QObject::connect(popupaction, SIGNAL(triggered()), keyChooser()->history(), SLOT(back()));
+ Q_ASSERT(ok);
+ ac->addAction(CResMgr::displaywindows::general::backInHistory::actionName, popupaction);
+
+ popupaction = new BtToolBarPopupAction(
+ QIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::general::forwardInHistory::icon)),
+ tr("Forward in history"),
+ ac
+ );
+ ok = QObject::connect(popupaction, SIGNAL(triggered()), keyChooser()->history(), SLOT(fw()) );
+ Q_ASSERT(ok);
+ ac->addAction(CResMgr::displaywindows::general::forwardInHistory::actionName, popupaction);
+
+}
+
+/** Refresh the settings of this window. */
+void CDisplayWindow::reload(CSwordBackend::SetupChangedReason) {
+ //first make sure all used Sword modules are still present
+ QMutableStringListIterator it(m_modules);
+ while (it.hasNext()) {
+ if (!backend()->findModuleByName(it.next())) {
+ it.remove();
+ }
+ }
+
+ if (m_modules.count() == 0){
+ close();
+ return;
+ }
+
+ if (keyChooser()) keyChooser()->setModules( modules(), false );
+
+ if (m_moduleChooserBar) { //necessary for edit windows which have now chooser bar
+ m_moduleChooserBar->setModules(modules());
+ }
+ modulesChanged();
+ lookup();
+}
+
+/** Returns the filter options used by this window. */
+CSwordBackend::FilterOptions& CDisplayWindow::filterOptions() {
+ return m_filterOptions;
+}
+
+/** Returns the display options used by this display window. */
+CSwordBackend::DisplayOptions& CDisplayWindow::displayOptions() {
+ return m_displayOptions;
+}
+
+/** Sets the new display options for this window. */
+void CDisplayWindow::setDisplayOptions( const CSwordBackend::DisplayOptions& displayOptions ) {
+ m_displayOptions = displayOptions;
+}
+
+/** Sets the new filter options of this window. */
+void CDisplayWindow::setFilterOptions( CSwordBackend::FilterOptions& filterOptions ) {
+ m_filterOptions = filterOptions;
+}
+
+/** Returns true if the widget is ready for use. */
+bool CDisplayWindow::isReady() const {
+ return m_isReady;
+}
+
+/** Set the ready status */
+void CDisplayWindow::setReady( const bool& ready ) {
+ m_isReady = ready;
+}
+
+/** Returns true if the window may be closed. */
+bool CDisplayWindow::queryClose() {
+ return true;
+}
+
+/** Returns the keychooser widget of this display window. */
+CKeyChooser* CDisplayWindow::keyChooser() const {
+ return m_keyChooser;
+}
+
+/** Sets the keychooser widget for this display window. */
+void CDisplayWindow::setKeyChooser( CKeyChooser* ck ) {
+ m_keyChooser = ck;
+}
+
+/** Returns the key of this display window. */
+CSwordKey* CDisplayWindow::key() const {
+ Q_ASSERT( m_swordKey );
+ return m_swordKey;
+}
+
+/** Sets the new sword key. */
+void CDisplayWindow::setKey( CSwordKey* key ) {
+ Q_ASSERT( key );
+ m_swordKey = key;
+}
+
+void CDisplayWindow::modulesChanged() {
+ if (moduleChooserBar()) { //necessary for write windows
+ setModules( m_moduleChooserBar->getModuleList() );
+ }
+
+ if (!modules().count()) {
+ close();
+ }
+ else {
+ if (displaySettingsButton()) {
+ displaySettingsButton()->reset(modules());
+ }
+
+ key()->module(modules().first());
+ keyChooser()->setModules(modules());
+ }
+}
+
+/** Returns the module chooser bar. */
+CModuleChooserBar* CDisplayWindow::moduleChooserBar() const {
+ return m_moduleChooserBar;
+}
+
+/** Sets the module chooser bar. */
+void CDisplayWindow::setModuleChooserBar( CModuleChooserBar* bar ) {
+ if (m_moduleChooserBar) {
+ disconnect(m_moduleChooserBar, SIGNAL(sigChanged()), this, SLOT(modulesChanged()));
+ }
+
+ //if a new bar should be set!
+ if (bar) {
+ m_moduleChooserBar = bar;
+ connect(bar, SIGNAL(sigChanged()), SLOT(modulesChanged()));
+ }
+}
+
+/** Sets the modules. */
+void CDisplayWindow::setModules( const QList<CSwordModuleInfo*>& newModules ) {
+ qDebug("CDisplayWindow::setModules");
+ m_modules.clear();
+
+ foreach (CSwordModuleInfo* mod, newModules) {
+ m_modules.append(mod->name());
+ }
+}
+
+/** Initialize the window. Call this method from the outside, because calling this in the constructor is not possible! */
+bool CDisplayWindow::init() {
+ qDebug("CDisplayWindow::init");
+ initView();
+ setMinimumSize( 100,100 );
+
+ setCaption(windowCaption());
+ //setup focus stuff.
+ setFocusPolicy(Qt::ClickFocus);
+ parentWidget()->setFocusPolicy(Qt::ClickFocus);
+ initActions();
+ initToolbars();
+ initConnections();
+ setupPopupMenu();
+
+ m_filterOptions = CBTConfig::getFilterOptionDefaults();
+ m_displayOptions = CBTConfig::getDisplayOptionDefaults();
+ if (displaySettingsButton()) {
+ displaySettingsButton()->reset(modules());
+ }
+
+ setReady(true);
+ return true;
+}
+
+/** Returns the main toolbar. */
+QToolBar* CDisplayWindow::mainToolBar() const {
+ return m_mainToolBar;
+}
+
+/** Returns the main toolbar. */
+QToolBar* CDisplayWindow::buttonsToolBar() const {
+ return m_buttonsToolBar;
+}
+
+/** Sets the main toolbar. */
+void CDisplayWindow::setMainToolBar( QToolBar* bar ) {
+ m_mainToolBar = bar;
+}
+
+/** Sets the main toolbar. */
+void CDisplayWindow::setButtonsToolBar( QToolBar* bar ) {
+ m_buttonsToolBar = bar;
+}
+
+/** Returns the display settings button */
+CDisplaySettingsButton* CDisplayWindow::displaySettingsButton() const {
+ return m_displaySettingsButton;
+}
+
+/** Sets the display settings button. */
+void CDisplayWindow::setDisplaySettingsButton( CDisplaySettingsButton* button ) {
+ if (m_displaySettingsButton)
+ disconnect(m_displaySettingsButton, SIGNAL( sigChanged() ),this, SLOT(lookup() ));
+
+ m_displaySettingsButton = button;
+ connect(m_displaySettingsButton, SIGNAL(sigChanged()),this, SLOT(lookup()));
+}
+
+/** Lookup the current key. Used to refresh the display. */
+void CDisplayWindow::lookup() {
+ lookupSwordKey( key() );
+}
+
+void CDisplayWindow::lookupModKey( const QString& moduleName, const QString& keyName ) {
+ if (!isReady()) {
+ return;
+ }
+
+ CSwordModuleInfo* m = backend()->findModuleByName(moduleName);
+ Q_ASSERT(m);
+ if (!m) {
+ return;
+ }
+
+ //ToDo: check for containsRef compat
+ if (m && modules().contains(m)) {
+ key()->key(keyName);
+ keyChooser()->setKey(key()); //the key chooser does send an update signal
+ }
+ else { //given module not displayed in this window
+ //if the module is displayed in another display window we assume a wrong drop
+ //create a new window for the given module
+ QList<CSwordModuleInfo*> mList;
+ mList.append(m);
+ mdi()->emitCreateDisplayWindow(mList, keyName);
+ }
+}
+
+void CDisplayWindow::lookupKey( const QString& keyName ) {
+ /* This function is called for example after a bookmark was dropped on this window
+ */
+ Q_ASSERT(modules().first());
+
+ //qDebug("CDisplayWindow::lookup: %s", keyName.latin1());
+ lookupModKey(modules().first()->name(), keyName);
+}
+
+/** Update the status of the popup menu entries. */
+void CDisplayWindow::updatePopupMenu() {}
+
+
+///** Returns the installed popup menu. */
+QMenu* CDisplayWindow::popup() {
+ // qWarning("CReadWindow::popup()");
+ if (!m_popupMenu) {
+ m_popupMenu = new QMenu(this);
+ connect(m_popupMenu, SIGNAL(aboutToShow()), this, SLOT(updatePopupMenu()));
+ if (displayWidget()) {
+ displayWidget()->installPopup(m_popupMenu);
+ }
+ /* else {
+ qWarning("CDisplayWindow:: can't instal popup menu");
+ }*/
+ }
+ return m_popupMenu;
+}
+
+/** Returns the display widget used by this implementation of CDisplayWindow. */
+CDisplay* CDisplayWindow::displayWidget() const {
+ Q_ASSERT(m_displayWidget);
+ return m_displayWidget;
+}
+
+/** Sets the display widget used by this display window. */
+void CDisplayWindow::setDisplayWidget( CDisplay* newDisplay ) {
+ m_displayWidget = newDisplay;
+}
+
+void CDisplayWindow::closeEvent(QCloseEvent* e) {
+ if (!queryClose()) {
+ e->ignore();
+ }
+ else {
+ e->accept();
+ }
+}
+
+void CDisplayWindow::slotSearchInModules() {
+ Search::CSearchDialog::openDialog(modules());
+}
+
+void CDisplayWindow::printAll() {
+ m_displayWidget->connectionsProxy()->printAll( m_displayOptions, m_filterOptions);
+}
+
+void CDisplayWindow::printAnchorWithText() {
+ m_displayWidget->connectionsProxy()->printAnchorWithText( m_displayOptions, m_filterOptions);
+}
+
+BtActionCollection* CDisplayWindow::actionCollection()
+{
+ return m_actionCollection;
+}
diff --git a/src/frontend/displaywindow/cdisplaywindow.h b/src/frontend/displaywindow/cdisplaywindow.h
new file mode 100644
index 0000000..1eb7d06
--- /dev/null
+++ b/src/frontend/displaywindow/cdisplaywindow.h
@@ -0,0 +1,264 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CDISPLAYWINDOW_H
+#define CDISPLAYWINDOW_H
+
+//BibleTime includes
+#include "util/cpointers.h"
+
+class CSwordModuleInfo;
+#include "backend/managers/cswordbackend.h"
+
+#include "frontend/profile/cprofilewindow.h"
+
+//Qt includes
+#include <QStringList>
+#include <QMainWindow>
+
+//Forward declarations
+class CMDIArea;
+class CReadWindow;
+class CWriteWindow;
+class CDisplaySettingsButton;
+class CDisplay;
+class CKeyChooser;
+class CModuleChooserBar;
+class QCloseEvent;
+
+class QToolBar;
+class QCloseEvent;
+class QMenu;
+class BtActionCollection;
+
+/** The base class for all display windows of BibleTime.
+ * @author The BibleTime team
+ */
+
+class CDisplayWindow : public QMainWindow, public CPointers {
+ Q_OBJECT
+public:
+ enum WriteWindowType {
+ HTMLWindow = 1,
+ PlainTextWindow = 2
+ };
+
+ /**
+ * Insert the keyboard accelerators of this window into the given KAccel object.
+ */
+ // static void insertKeyboardActions( KAccel* const accel );
+ static void insertKeyboardActions( BtActionCollection* const a );
+
+ CMDIArea* mdi() const;
+ /**
+ * Returns the right window caption.
+ */
+ const QString windowCaption();
+ /**
+ * Returns the used modules as a QPtrList
+ */
+ QList<CSwordModuleInfo*> modules();
+ /**
+ * Store the settings of this window in the given CProfileWindow object.
+ */
+ virtual void storeProfileSettings( Profile::CProfileWindow* profileWindow ) = 0;
+ /**
+ * Store the settings of this window in the given profile window.
+ */
+ virtual void applyProfileSettings( Profile::CProfileWindow* profileWindow ) = 0;
+ /**
+ * Set the window caption.
+ */
+ virtual void setCaption( const QString& );
+ /**
+ * Sets the new filter options of this window.
+ */
+ void setFilterOptions( CSwordBackend::FilterOptions& filterOptions );
+ /**
+ * Sets the new display options for this window.
+ */
+ void setDisplayOptions( const CSwordBackend::DisplayOptions& displayOptions );
+ /**
+ * Returns the display options used by this display window.
+ */
+ CSwordBackend::DisplayOptions& displayOptions();
+ /**
+ * Returns the filter options used by this window.
+ */
+ CSwordBackend::FilterOptions& filterOptions();
+ /**
+ * Set the ready status
+ */
+ void setReady( const bool& ready );
+ /**
+ * Returns true if the widget is ready for use.
+ */
+ bool isReady() const;
+ /**
+ * Returns true if the window may be closed.
+ */
+ virtual bool queryClose();
+ /**
+ * Returns the keychooser widget of this display window.
+ */
+ CKeyChooser* keyChooser() const;
+ /**
+ * Sets the new sword key.
+ */
+ void setKey( CSwordKey* key );
+ /**
+ * Returns the key of this display window.
+ */
+ CSwordKey* key() const;
+ /**
+ * Initialize the window. Call this method from the outside, because calling this in the constructor is not possible!
+ */
+ virtual bool init();
+ /**
+ * Sets the main toolbar.
+ */
+ void setMainToolBar( QToolBar* bar );
+ /**
+ * Sets the buttons toolbar.
+ */
+ void setButtonsToolBar( QToolBar* bar );
+ /**
+ * Returns the main toolbar.
+ */
+ QToolBar* mainToolBar() const;
+ /**
+ * Returns the buttons toolbar.
+ */
+ QToolBar* buttonsToolBar() const;
+ /**
+ * Initialize the toolbars
+ */
+ virtual void initToolbars() = 0;
+ /**
+ * Returns the display settings button
+ */
+ CDisplaySettingsButton* displaySettingsButton() const;
+ /**
+ * Sets the display settings button.
+ */
+ void setDisplaySettingsButton( CDisplaySettingsButton* button );
+ virtual void setupPopupMenu() = 0;
+ /**
+ * Returns the display widget used by this implementation of CDisplayWindow.
+ */
+ virtual CDisplay* displayWidget() const;
+ /**
+ * Sets the display widget used by this display window.
+ */
+ virtual void setDisplayWidget( CDisplay* newDisplay );
+
+ /** Returns whether syncs to the active window are allowed at this time for this display window
+ * @return boolean value whether sync is allowed
+ */
+ virtual bool syncAllowed() const {
+ return false;
+ };
+
+ BtActionCollection* actionCollection();
+
+public slots:
+ /**
+ * Lookup the specified key in the given module. If the module is not chosen withing
+ * this display window create a new displaywindow with the right module in it.
+ */
+ virtual void lookupModKey( const QString& module, const QString& key );
+ /**
+ * Lookup the key in the chosen modules.
+ */
+ virtual void lookupKey( const QString& key );
+ /**
+ * Refresh the settings of this window.
+ */
+ virtual void reload(CSwordBackend::SetupChangedReason reason);
+
+protected:
+ friend class CMDIArea;
+ friend class CBibleReadWindow;
+
+ CDisplayWindow(QList<CSwordModuleInfo*> modules, CMDIArea* parent);
+ virtual ~CDisplayWindow();
+ /**
+ * Initializes the intern keyboard actions.
+ */
+ virtual void initActions();
+ /**
+ * Sets the keychooser widget for this display window.
+ */
+ void setKeyChooser( CKeyChooser* ck );
+ /**
+ * Returns the module chooser bar.
+ */
+ CModuleChooserBar* moduleChooserBar() const;
+ /**
+ * Lookup the given key.
+ */
+ virtual void lookupSwordKey( CSwordKey* ) = 0;
+ /**
+ * Sets the module chooser bar.
+ */
+ void setModuleChooserBar( CModuleChooserBar* bar );
+ /**
+ * Sets the modules.
+ */
+ void setModules( const QList<CSwordModuleInfo*>& modules );
+ /**
+ * Initializes the signal / slot connections of this display window.
+ */
+ virtual void initConnections() = 0;
+ /**
+ * Initialize the view of this display window.
+ */
+ virtual void initView() = 0;
+ /**
+ * Returns the installed popup menu.
+ */
+ QMenu* popup();
+ virtual void closeEvent(QCloseEvent* e);
+
+protected slots:
+ virtual void modulesChanged();
+ /**
+ * Lookup the current key. Used to refresh the display.
+ */
+ void lookup();
+ virtual void updatePopupMenu();
+
+ void slotSearchInModules();
+
+ void printAll();
+ void printAnchorWithText();
+
+
+private:
+ BtActionCollection* m_actionCollection;
+ CMDIArea* m_mdi;
+
+ //we may only cache the module names bacause after a backend relaod the pointers are invalid!
+ QStringList m_modules;
+
+ CSwordBackend::FilterOptions m_filterOptions;
+ CSwordBackend::DisplayOptions m_displayOptions;
+
+ CDisplaySettingsButton* m_displaySettingsButton;
+ CKeyChooser* m_keyChooser;
+ CSwordKey* m_swordKey;
+ bool m_isReady;
+ CModuleChooserBar* m_moduleChooserBar;
+ QToolBar* m_mainToolBar;
+ QToolBar* m_buttonsToolBar;
+ QMenu* m_popupMenu;
+ CDisplay* m_displayWidget;
+};
+
+#endif
diff --git a/src/frontend/displaywindow/cdisplaywindowfactory.cpp b/src/frontend/displaywindow/cdisplaywindowfactory.cpp
new file mode 100644
index 0000000..d386ecf
--- /dev/null
+++ b/src/frontend/displaywindow/cdisplaywindowfactory.cpp
@@ -0,0 +1,57 @@
+//
+// C++ Implementation: cdisplaywindowfactory
+//
+// Description:
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 2007
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "cdisplaywindowfactory.h"
+
+#include "creadwindow.h"
+#include "cbiblereadwindow.h"
+#include "ccommentaryreadwindow.h"
+#include "clexiconreadwindow.h"
+#include "cbookreadwindow.h"
+#include "cwritewindow.h"
+#include "cplainwritewindow.h"
+#include "chtmlwritewindow.h"
+
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "frontend/cmdiarea.h"
+
+
+CReadWindow* CDisplayWindowFactory::createReadInstance(QList<CSwordModuleInfo*> modules, CMDIArea* parent)
+{
+ qDebug("CDisplayWindowFactory::createReadInstance");
+ switch (modules.first()->type()) {
+ case CSwordModuleInfo::Bible:
+ return new CBibleReadWindow(modules, parent);
+ case CSwordModuleInfo::Commentary:
+ return new CCommentaryReadWindow(modules, parent);
+ case CSwordModuleInfo::Lexicon:
+ return new CLexiconReadWindow(modules, parent);
+ case CSwordModuleInfo::GenericBook:
+ return new CBookReadWindow(modules, parent);
+ default:
+ qWarning("unknown module type");
+ break;
+ }
+ return 0;
+}
+
+
+CWriteWindow* CDisplayWindowFactory::createWriteInstance(QList<CSwordModuleInfo*> modules, CMDIArea* parent, const CDisplayWindow::WriteWindowType type)
+{
+ if (type == CDisplayWindow::HTMLWindow) {
+ return new CHTMLWriteWindow(modules, parent);
+ }
+ else {
+ return new CPlainWriteWindow(modules, parent);
+ }
+ return 0;
+}
diff --git a/src/frontend/displaywindow/cdisplaywindowfactory.h b/src/frontend/displaywindow/cdisplaywindowfactory.h
new file mode 100644
index 0000000..4bc4372
--- /dev/null
+++ b/src/frontend/displaywindow/cdisplaywindowfactory.h
@@ -0,0 +1,34 @@
+//
+// C++ Interface: cdisplaywindowfactory
+//
+// Description:
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 2007
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CDISPLAYWINDOWFACTORY_H
+#define CDISPLAYWINDOWFACTORY_H
+
+#include "cdisplaywindow.h"
+
+class CSwordModuleInfo;
+
+
+class CReadWindow;
+class CWriteWindow;
+class CMDIArea;
+
+class CDisplayWindowFactory
+{
+public:
+ static CReadWindow* createReadInstance(QList<CSwordModuleInfo*> modules, CMDIArea* parent);
+ static CWriteWindow* createWriteInstance(QList<CSwordModuleInfo*> modules, CMDIArea* parent, const CDisplayWindow::WriteWindowType type = CDisplayWindow::HTMLWindow);
+
+private:
+ CDisplayWindowFactory();
+};
+
+#endif
diff --git a/src/frontend/displaywindow/chtmlwritewindow.cpp b/src/frontend/displaywindow/chtmlwritewindow.cpp
new file mode 100644
index 0000000..7e97aa6
--- /dev/null
+++ b/src/frontend/displaywindow/chtmlwritewindow.cpp
@@ -0,0 +1,163 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#include "chtmlwritewindow.h"
+#include "btactioncollection.h"
+
+//frontend includes
+#include "frontend/keychooser/ckeychooser.h"
+#include "frontend/profile/cprofilewindow.h"
+#include "frontend/display/cwritedisplay.h"
+#include "frontend/display/chtmlwritedisplay.h"
+
+#include "backend/keys/cswordkey.h"
+
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+
+//Qt includes
+#include <QToolBar>
+#include <QMessageBox>
+#include <QAction>
+
+using namespace Profile;
+
+CHTMLWriteWindow::CHTMLWriteWindow(QList<CSwordModuleInfo*> modules, CMDIArea* parent)
+: CPlainWriteWindow(modules, parent) {}
+
+CHTMLWriteWindow::~CHTMLWriteWindow() {}
+
+void CHTMLWriteWindow::initView() {
+ CWriteDisplay* writeDisplay = CDisplay::createWriteInstance(this, CDisplay::HTMLDisplay);
+ Q_ASSERT(writeDisplay);
+ setDisplayWidget( writeDisplay );
+ setCentralWidget( displayWidget()->view() );
+
+ setMainToolBar( new QToolBar(this) );
+ addToolBar(mainToolBar());
+
+ setKeyChooser( CKeyChooser::createInstance(modules(), key(), mainToolBar()) );
+ mainToolBar()->addWidget(keyChooser());
+}
+
+void CHTMLWriteWindow::initConnections() {
+ CWriteWindow::initConnections();
+
+ connect(keyChooser(), SIGNAL(keyChanged(CSwordKey*)), this, SLOT(lookupSwordKey(CSwordKey*)));
+ connect(displayWidget()->connectionsProxy(), SIGNAL(textChanged()), this, SLOT(textChanged()) );
+}
+
+void CHTMLWriteWindow::initToolbars() {
+ //setup the main toolbar
+ m_actions.syncWindow = new QAction(
+ util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::commentaryWindow::syncWindow::icon),
+ tr("Sync with active Bible"),
+ actionCollection()
+ );
+ m_actions.syncWindow->setCheckable(true);
+ m_actions.syncWindow->setShortcut(CResMgr::displaywindows::commentaryWindow::syncWindow::accel);
+ m_actions.syncWindow->setToolTip(tr("Synchronize (show the same verse) with the active Bible window"));
+ actionCollection()->addAction(CResMgr::displaywindows::commentaryWindow::syncWindow::actionName, m_actions.syncWindow);
+ mainToolBar()->addAction(m_actions.syncWindow);
+
+ m_actions.saveText = new QAction(
+ util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::writeWindow::saveText::icon),
+ tr("Save text"),
+ actionCollection()
+ );
+ m_actions.saveText->setShortcut(CResMgr::displaywindows::writeWindow::saveText::accel);
+ m_actions.saveText->setToolTip( tr("Save text") );
+ QObject::connect(m_actions.saveText, SIGNAL(triggered()), this, SLOT( saveCurrentText() ) );
+ actionCollection()->addAction(CResMgr::displaywindows::writeWindow::saveText::actionName, m_actions.saveText);
+ mainToolBar()->addAction(m_actions.saveText);
+
+
+ m_actions.deleteEntry = new QAction(
+ util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::writeWindow::deleteEntry::icon),
+ tr("Delete current entry"),
+ actionCollection()
+ );
+ m_actions.deleteEntry->setShortcut(CResMgr::displaywindows::writeWindow::deleteEntry::accel);
+ m_actions.deleteEntry->setToolTip( tr("Delete current entry (no undo)") );
+ QObject::connect(m_actions.deleteEntry, SIGNAL(triggered()), this, SLOT( deleteEntry() ) );
+ actionCollection()->addAction(CResMgr::displaywindows::writeWindow::deleteEntry::actionName, m_actions.deleteEntry);
+ mainToolBar()->addAction(m_actions.deleteEntry);
+
+ m_actions.restoreText = new QAction(
+ util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::writeWindow::restoreText::icon),
+ tr("Restore original text"),
+ actionCollection()
+ );
+ m_actions.restoreText->setShortcut(CResMgr::displaywindows::writeWindow::restoreText::accel);
+ m_actions.restoreText->setToolTip( tr("Restore original text, new text will be lost") );
+ QObject::connect(m_actions.restoreText, SIGNAL(triggered()), this, SLOT( restoreText() ) );
+ actionCollection()->addAction(CResMgr::displaywindows::writeWindow::restoreText::actionName, m_actions.restoreText);
+ mainToolBar()->addAction(m_actions.restoreText);
+
+ //html formatting toolbar
+ QToolBar* bar = new QToolBar(this);
+ ((CWriteDisplay*)displayWidget())->setupToolbar( bar, actionCollection() );
+ addToolBar(bar);
+}
+
+void CHTMLWriteWindow::storeProfileSettings( CProfileWindow* profileWindow ) {
+ CWriteWindow::storeProfileSettings(profileWindow);
+ profileWindow->setWindowSettings( m_actions.syncWindow->isChecked() );
+}
+
+void CHTMLWriteWindow::applyProfileSettings( CProfileWindow* profileWindow ) {
+ CWriteWindow::applyProfileSettings(profileWindow);
+ if (profileWindow->windowSettings()) {
+ m_actions.syncWindow->setChecked(true);
+ }
+}
+
+/** Is called when the current text was changed. */
+void CHTMLWriteWindow::textChanged() {
+ m_actions.saveText->setEnabled( ((CWriteDisplay*)displayWidget())->isModified() );
+ m_actions.restoreText->setEnabled( ((CWriteDisplay*)displayWidget())->isModified() );
+}
+
+/** Loads the original text from the module. */
+void CHTMLWriteWindow::restoreText() {
+ lookupSwordKey(key());
+ ((CWriteDisplay*)displayWidget())->setModified(false);
+ textChanged();
+}
+
+bool CHTMLWriteWindow::syncAllowed() const {
+ return m_actions.syncWindow->isChecked();
+}
+
+/** Saves the text for the current key. Directly writes the changed text into the module. */
+void CHTMLWriteWindow::saveCurrentText( const QString& /*key*/ ) {
+ QString t = ((CHTMLWriteDisplay*)displayWidget())->toHtml();
+ //since t is a complete HTML page at the moment, strip away headers and footers of a HTML page
+ QRegExp re("(?:<html.*>.+<body.*>)", Qt::CaseInsensitive); //remove headers, case insensitive
+ re.setMinimal(true);
+ t.replace(re, "");
+ t.replace(QRegExp("</body></html>", Qt::CaseInsensitive), "");//remove footer
+
+ const QString& oldKey = this->key()->key();
+ if( modules().first()->isWritable() ) {
+ modules().first()->write(this->key(), t );
+ this->key()->key( oldKey );
+
+ ((CWriteDisplay*)displayWidget())->setModified(false);
+ textChanged();
+ }
+ else {
+ QMessageBox::critical( this, tr("Module not writable"),
+ QString::fromLatin1("<qt><b>%1</b><br />%2</qt>")
+ .arg( tr("Module is not writable.") )
+ .arg( tr("Either the module may not be edited, or you do not have write permission.") ) );
+ }
+}
diff --git a/src/frontend/displaywindow/chtmlwritewindow.h b/src/frontend/displaywindow/chtmlwritewindow.h
new file mode 100644
index 0000000..9c50957
--- /dev/null
+++ b/src/frontend/displaywindow/chtmlwritewindow.h
@@ -0,0 +1,75 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CHTMLWRITEWINDOW_H
+#define CHTMLWRITEWINDOW_H
+
+//BibleTime includes
+#include "cplainwritewindow.h"
+
+class QAction;
+
+
+/** The WYSIWYG implementation of the editor.
+ * @author The BibleTime team
+ */
+class CHTMLWriteWindow : public CPlainWriteWindow {
+ Q_OBJECT
+public:
+ CHTMLWriteWindow(QList<CSwordModuleInfo*> modules, CMDIArea* parent);
+ virtual ~CHTMLWriteWindow();
+
+ /**
+ * Store the settings of this window in the given CProfileWindow object.
+ */
+ virtual void storeProfileSettings( Profile::CProfileWindow* );
+ /**
+ * Store the settings of this window in the given profile window.
+ */
+ virtual void applyProfileSettings( Profile::CProfileWindow* );
+
+ virtual bool syncAllowed() const;
+
+protected: // Protected methods
+ /**
+ * Initialize the state of this widget.
+ */
+ virtual void initView();
+ virtual void initConnections();
+ virtual void initToolbars();
+ virtual CDisplayWindow::WriteWindowType writeWindowType() {
+ return CDisplayWindow::HTMLWindow;
+ };
+
+protected slots:
+ /**
+ * Is called when the current text was changed.
+ */
+ virtual void textChanged();
+ /**
+ * Loads the original text from the module.
+ */
+ virtual void restoreText();
+ /**
+ * Saves the text for the current key. Directly writes the changed text into the module.
+ */
+ virtual void saveCurrentText( const QString& );
+private:
+ struct {
+ QAction* saveText;
+ QAction* restoreText;
+ QAction* deleteEntry;
+ QAction* syncWindow;
+ }
+ m_actions;
+};
+
+#endif
diff --git a/src/frontend/displaywindow/clexiconreadwindow.cpp b/src/frontend/displaywindow/clexiconreadwindow.cpp
new file mode 100644
index 0000000..703e40c
--- /dev/null
+++ b/src/frontend/displaywindow/clexiconreadwindow.cpp
@@ -0,0 +1,367 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+//BibleTime includes
+#include "clexiconreadwindow.h"
+#include "btactioncollection.h"
+
+#include "cmodulechooserbar.h"
+#include "cbuttons.h"
+#include "bttoolbarpopupaction.h"
+
+#include "backend/keys/cswordkey.h"
+#include "backend/keys/cswordldkey.h"
+
+#include "backend/config/cbtconfig.h"
+#include "frontend/cexportmanager.h"
+#include "frontend/display/cdisplay.h"
+#include "frontend/display/creaddisplay.h"
+#include "frontend/display/bthtmlreaddisplay.h"
+#include "frontend/keychooser/ckeychooser.h"
+#include "frontend/keychooser/bthistory.h"
+
+#include "util/ctoolclass.h"
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+
+#include <QMenu>
+#include <QApplication>
+#include <QFile>
+#include <QFileDialog>
+#include <QAction>
+
+CLexiconReadWindow::CLexiconReadWindow(QList<CSwordModuleInfo*> moduleList, CMDIArea* parent)
+ : CReadWindow(moduleList, parent)
+{
+ qDebug("CLexiconReadWindow::CLexiconReadWindow");
+ moduleList.first();
+ setKey( CSwordKey::createInstance(moduleList.first()) );
+}
+
+CLexiconReadWindow::~CLexiconReadWindow() {}
+
+void CLexiconReadWindow::insertKeyboardActions( BtActionCollection* const a )
+{
+ qDebug("CLexiconReadWindow::insertKeyboardActions");
+ QAction* kaction;
+ kaction = new QAction( tr("Next entry"), a);
+ kaction->setShortcut(CResMgr::displaywindows::lexiconWindow::nextEntry::accel);
+ a->addAction("nextEntry", kaction);
+
+ kaction = new QAction( tr("Previous entry"), a);
+ kaction->setShortcut( CResMgr::displaywindows::lexiconWindow::previousEntry::accel);
+ a->addAction("previousEntry", kaction);
+
+ kaction = new QAction(tr("Copy reference only"), a);
+ a->addAction("copyReferenceOnly", kaction);
+
+ kaction = new QAction(tr("Copy selected text"), a);
+ a->addAction("copySelectedText", kaction);
+
+ kaction = new QAction(tr("Save entry as HTML"), a);
+ a->addAction("saveHtml", kaction);
+
+ kaction = new QAction(tr("Print reference only"), a);
+ a->addAction("printReferenceOnly", kaction);
+}
+
+void CLexiconReadWindow::initActions()
+{
+ qDebug("CLexiconReadWindow::initActions");
+
+ BtActionCollection* ac = actionCollection();
+ CLexiconReadWindow::insertKeyboardActions(ac);
+ CReadWindow::initActions();
+
+ m_actions.backInHistory = dynamic_cast<BtToolBarPopupAction*>(
+ ac->action(CResMgr::displaywindows::general::backInHistory::actionName) );
+ Q_ASSERT(m_actions.backInHistory);
+
+ m_actions.forwardInHistory = dynamic_cast<BtToolBarPopupAction*>(
+ ac->action(CResMgr::displaywindows::general::forwardInHistory::actionName) );
+ Q_ASSERT(m_actions.forwardInHistory);
+
+ QAction* kaction;
+
+ kaction = new QAction(tr("Next entry"), ac );
+ kaction->setShortcut( CResMgr::displaywindows::lexiconWindow::nextEntry::accel);
+ QObject::connect(kaction, SIGNAL(triggered()), this, SLOT( nextEntry() ) );
+ ac->addAction("nextEntry", kaction);
+
+ kaction = new QAction(tr("Previous entry"), ac );
+ kaction->setShortcut( CResMgr::displaywindows::lexiconWindow::previousEntry::accel);
+ QObject::connect(kaction, SIGNAL(triggered()), this, SLOT( previousEntry() ) );
+ ac->addAction("previousEntry", kaction);
+
+ m_actions.selectAll = qobject_cast<QAction*>(ac->action("selectAll"));
+ //TODO: Q_ASSERT(m_actions.selectAll);
+
+ m_actions.findText = qobject_cast<QAction*>(ac->action("findText"));
+ //TODO: Q_ASSERT(m_actions.findText);
+
+ m_actions.findStrongs = new QAction(
+// QIcon(CResMgr::displaywindows::general::findStrongs::icon),
+ tr("Strong's Search"),
+ ac
+ );
+ m_actions.findStrongs->setShortcut(CResMgr::displaywindows::general::findStrongs::accel);
+ QObject::connect(m_actions.findStrongs, SIGNAL(triggered()), this, SLOT(openSearchStrongsDialog()) );
+ ac->addAction(CResMgr::displaywindows::general::findStrongs::actionName, m_actions.findStrongs);
+
+ m_actions.copy.reference = new QAction(tr("Reference only"), ac );
+ QObject::connect(m_actions.copy.reference, SIGNAL(triggered()), displayWidget()->connectionsProxy(), SLOT(copyAnchorOnly()) );
+ ac->addAction("copyReferenceOnly", m_actions.copy.reference);
+
+ m_actions.copy.entry = new QAction(tr("Entry with text"), ac );
+ QObject::connect(m_actions.copy.entry, SIGNAL(triggered()), displayWidget()->connectionsProxy(), SLOT(copyAll()) );
+ ac->addAction("copyEntryWithText", m_actions.copy.entry);
+
+ Q_ASSERT(ac->action("copySelectedText"));
+ m_actions.copy.selectedText = qobject_cast<QAction*>(ac->action("copySelectedText"));
+
+ m_actions.save.entryAsPlain = new QAction(tr("Entry as plain text"), ac );
+ QObject::connect(m_actions.save.entryAsPlain, SIGNAL(triggered()), this, SLOT(saveAsPlain()) );
+ ac->addAction("saveEntryAsPlain", m_actions.save.entryAsPlain);
+
+ m_actions.save.entryAsHTML = new QAction(tr("Entry as HTML"), ac );
+ QObject::connect(m_actions.save.entryAsHTML, SIGNAL(triggered()), this, SLOT(saveAsHTML()));
+ ac->addAction("saveEntryAsHTML", m_actions.save.entryAsHTML);
+
+ m_actions.print.reference = new QAction(tr("Reference only"), ac);
+ QObject::connect(m_actions.print.reference, SIGNAL(triggered()), this, SLOT(printAnchorWithText()));
+ ac->addAction("printReferenceOnly", m_actions.print.reference);
+
+ m_actions.print.entry = new QAction(tr("Entry with text"), ac);
+ QObject::connect(m_actions.print.entry, SIGNAL(triggered()), this, SLOT(printAll()));
+ ac->addAction("printEntryWithText", m_actions.print.entry);
+
+ // init with the user defined settings
+ qDebug("call CBTConfig::setupAccelSettings(CBTConfig::lexiconWindow, ac); and end CLexiconReadWindow::initActions");
+// CBTConfig::setupAccelSettings(CBTConfig::lexiconWindow, ac);
+}
+
+/** No descriptions */
+void CLexiconReadWindow::initConnections()
+{
+ qDebug("CLexiconReadWindow::initConnections");
+ Q_ASSERT(keyChooser());
+
+ connect(keyChooser(), SIGNAL(keyChanged(CSwordKey*)), this, SLOT(lookupSwordKey(CSwordKey*)));
+ connect(keyChooser()->history(), SIGNAL(historyChanged(bool, bool)), this, SLOT(slotUpdateHistoryButtons(bool, bool)));
+
+ //connect the history actions to the right slots
+ bool ok = connect(
+ m_actions.backInHistory->popupMenu(), SIGNAL(aboutToShow()),
+ this, SLOT(slotFillBackHistory())
+ );
+ Q_ASSERT(ok);
+ ok = connect(
+ m_actions.backInHistory->popupMenu(), SIGNAL(triggered(QAction*)),
+ keyChooser()->history(), SLOT(move(QAction*))
+ );
+ Q_ASSERT(ok);
+ ok = connect(
+ m_actions.forwardInHistory->popupMenu(), SIGNAL(aboutToShow()),
+ this, SLOT(slotFillForwardHistory())
+ );
+ Q_ASSERT(ok);
+ ok = connect(
+ m_actions.forwardInHistory->popupMenu(), SIGNAL(triggered(QAction*)),
+ keyChooser()->history(), SLOT(move(QAction*))
+ );
+ Q_ASSERT(ok);
+
+}
+
+void CLexiconReadWindow::initView()
+{
+ qDebug("CLexiconReadWindow::initView");
+ setDisplayWidget( CDisplay::createReadInstance(this) );
+ setMainToolBar( new QToolBar(this) );
+ addToolBar(mainToolBar());
+ setKeyChooser( CKeyChooser::createInstance(modules(), key(), mainToolBar()) );
+ mainToolBar()->addWidget(keyChooser());
+ setModuleChooserBar( new CModuleChooserBar(modules(), modules().first()->type(), this) );
+ moduleChooserBar()->adjustSize();
+ addToolBar(moduleChooserBar());
+ setButtonsToolBar( new QToolBar(this) );
+ addToolBar(buttonsToolBar());
+ setWindowIcon(CToolClass::getIconForModule(modules().first()));
+ setCentralWidget( displayWidget()->view() );
+}
+
+void CLexiconReadWindow::initToolbars()
+{
+ //main toolbar
+ Q_ASSERT(m_actions.backInHistory);
+ mainToolBar()->addAction(m_actions.backInHistory); //1st button
+ mainToolBar()->addAction(m_actions.forwardInHistory); //2nd button
+
+ //buttons toolbar
+ QAction* action = qobject_cast<QAction*>(actionCollection()->action(
+ CResMgr::displaywindows::general::search::actionName));
+ Q_ASSERT( action );
+ if (action) {
+ buttonsToolBar()->addAction(action);
+ }
+ setDisplaySettingsButton( new CDisplaySettingsButton( &displayOptions(), &filterOptions(), modules(), buttonsToolBar()) );
+
+ //TODO: find the right place for the button
+ buttonsToolBar()->addWidget(displaySettingsButton());
+}
+
+void CLexiconReadWindow::setupPopupMenu()
+{
+ popup()->setTitle(tr("Lexicon window"));
+ popup()->setIcon(CToolClass::getIconForModule(modules().first()));
+ popup()->addAction(m_actions.findText);
+ popup()->addAction(m_actions.findStrongs);
+ popup()->addAction(m_actions.selectAll);
+ popup()->addSeparator();
+
+ m_actions.copyMenu = new QMenu(tr("Copy..."), popup());
+
+ m_actions.copyMenu->addAction(m_actions.copy.reference);
+ m_actions.copyMenu->addAction(m_actions.copy.entry);
+ m_actions.copyMenu->addSeparator();
+ m_actions.copyMenu->addAction(m_actions.copy.selectedText);
+ popup()->addMenu(m_actions.copyMenu);
+
+ m_actions.saveMenu = new QMenu(
+ tr("Save..."),
+ popup()
+ );
+ m_actions.saveMenu->addAction(m_actions.save.entryAsPlain);
+ m_actions.saveMenu->addAction(m_actions.save.entryAsHTML);
+
+ // Save raw HTML action for debugging purposes
+ if (qApp->property("--debug").toBool()) {
+ QAction* debugAction = new QAction("Raw HTML", this);
+ QObject::connect(debugAction, SIGNAL(triggered()), this, SLOT(saveRawHTML()));
+ m_actions.saveMenu->addAction(debugAction);
+ } // end of Save Raw HTML
+
+ popup()->addMenu(m_actions.saveMenu);
+
+ m_actions.printMenu = new QMenu(
+ tr("Print..."),
+ popup()
+ );
+ m_actions.printMenu->addAction(m_actions.print.reference);
+ m_actions.printMenu->addAction(m_actions.print.entry);
+ popup()->addMenu(m_actions.printMenu);
+}
+
+/** Reimplemented. */
+void CLexiconReadWindow::updatePopupMenu()
+{
+ //enable the action depending on the supported module features
+
+ m_actions.findStrongs->setEnabled( displayWidget()->getCurrentNodeInfo()[CDisplay::Lemma] != QString::null );
+
+ m_actions.copy.reference->setEnabled( ((CReadDisplay*)displayWidget())->hasActiveAnchor() );
+ m_actions.copy.selectedText->setEnabled( displayWidget()->hasSelection() );
+
+ m_actions.print.reference->setEnabled( ((CReadDisplay*)displayWidget())->hasActiveAnchor() );
+}
+
+/** No descriptions */
+void CLexiconReadWindow::nextEntry()
+{
+ keyChooser()->setKey(ldKey()->NextEntry());
+}
+
+/** No descriptions */
+void CLexiconReadWindow::previousEntry()
+{
+ keyChooser()->setKey(ldKey()->PreviousEntry());
+}
+
+/** Reimplementation to return the right key. */
+CSwordLDKey* CLexiconReadWindow::ldKey()
+{
+ return dynamic_cast<CSwordLDKey*>(CDisplayWindow::key());
+}
+
+/** This function saves the entry as html using the CExportMgr class. */
+void CLexiconReadWindow::saveAsHTML() {
+ CExportManager mgr(tr("Saving entry ..."), true, tr("Saving"), filterOptions(), displayOptions());
+ mgr.saveKey(key(), CExportManager::HTML, true);
+}
+
+/** Saving the raw HTML for debugging purposes */
+void CLexiconReadWindow::saveRawHTML()
+{
+ //qDebug("CLexiconReadWindow::saveRawHTML");
+ QString savefilename = QFileDialog::getSaveFileName();
+ if (savefilename.isEmpty()) return;
+ QFile file(savefilename);
+ BtHtmlReadDisplay* disp = dynamic_cast<BtHtmlReadDisplay*>(displayWidget());
+ if (disp) {
+ if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ qDebug("could not open file");
+ return;
+ }
+ QString source = disp->text();
+ file.write(source.toUtf8());
+ //qDebug() << "wrote" << bytes << "bytes";
+ file.close();
+ file.flush();
+ } else {
+ qDebug("No htmlreaddisplay widget!");
+ }
+
+}
+
+/** This function saves the entry as html using the CExportMgr class. */
+void CLexiconReadWindow::saveAsPlain()
+{
+ CExportManager mgr(tr("Saving entry ..."), true, tr("Saving"), filterOptions(), displayOptions());
+ mgr.saveKey(key(), CExportManager::Text, true);
+}
+
+void CLexiconReadWindow::slotFillBackHistory()
+{
+ qDebug("CLexiconReadWindow::slotFillBackHistory");
+
+ QMenu* menu = m_actions.backInHistory->popupMenu();
+ menu->clear();
+
+ //TODO: take the history list and fill the menu
+ QListIterator<QAction*> it(keyChooser()->history()->getBackList());
+ while (it.hasNext()) {
+ menu->addAction(it.next());
+ }
+}
+
+void CLexiconReadWindow::slotFillForwardHistory()
+{
+ qDebug("CLexiconReadWindow::slotFillForwardHistory");
+
+ QMenu* menu = m_actions.forwardInHistory->popupMenu();
+ menu->clear();
+ //TODO: take the history list and fill the menu using addAction
+ QListIterator<QAction*> it(keyChooser()->history()->getFwList());
+ while (it.hasNext()) {
+ menu->addAction(it.next());
+ }
+}
+
+
+void CLexiconReadWindow::slotUpdateHistoryButtons(bool backEnabled, bool fwEnabled)
+{
+ qDebug("CLexiconReadWindow::slotUpdateHistoryButtons");
+ Q_ASSERT(m_actions.backInHistory);
+ Q_ASSERT(keyChooser());
+
+ m_actions.backInHistory->setEnabled( backEnabled );
+ m_actions.forwardInHistory->setEnabled( fwEnabled );
+}
diff --git a/src/frontend/displaywindow/clexiconreadwindow.h b/src/frontend/displaywindow/clexiconreadwindow.h
new file mode 100644
index 0000000..cea9096
--- /dev/null
+++ b/src/frontend/displaywindow/clexiconreadwindow.h
@@ -0,0 +1,118 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CLEXICONREADWINDOW_H
+#define CLEXICONREADWINDOW_H
+
+//BibleTime includes
+#include "creadwindow.h"
+#include "frontend/keychooser/ckeychooser.h"
+class BtToolBarPopupAction;
+
+class CSwordKey;
+class CSwordLDKey;
+
+class KToolBarPopupAction;
+class BtActionCollection;
+class QAction;
+class QMenu;
+
+/**
+ *@author The BibleTime team
+ */
+
+class CLexiconReadWindow : public CReadWindow {
+ Q_OBJECT
+public:
+ CLexiconReadWindow(QList<CSwordModuleInfo*> modules, CMDIArea* parent);
+ virtual ~CLexiconReadWindow();
+ /**
+ * Store the settings of this window in the given CProfileWindow object.
+ */
+ // virtual void storeProfileSettings( CProfileWindow* profileWindow );
+ /**
+ * Store the settings of this window in the given profile window.
+ */
+ // virtual void applyProfileSettings( CProfileWindow* profileWindow );
+ /**
+ * Reimplementation.
+ */
+ // static void insertKeyboardActions( KAccel* a );
+ static void insertKeyboardActions( BtActionCollection* const a );
+
+protected:
+ virtual void initActions();
+ virtual void initToolbars();
+ virtual void initConnections();
+ virtual void initView();
+ virtual void updatePopupMenu();
+ virtual void setupPopupMenu();
+
+
+ struct ActionsStruct {
+ BtToolBarPopupAction* backInHistory;
+ BtToolBarPopupAction* forwardInHistory;
+
+ QAction* selectAll;
+ QAction* findText;
+ QAction* findStrongs;
+
+ QMenu* copyMenu;
+ struct {
+ QAction* reference;
+ QAction* entry;
+ QAction* selectedText;
+ }
+ copy;
+
+ QMenu* saveMenu;
+ struct {
+ QAction* reference;
+ QAction* entryAsPlain;
+ QAction* entryAsHTML;
+ }
+ save;
+
+ QMenu* printMenu;
+ struct {
+ QAction* reference;
+ QAction* entry;
+ }
+ print;
+ }
+ m_actions;
+
+private:
+ /**
+ * Reimplementation to return the right key.
+ */
+ CSwordLDKey* ldKey();
+
+protected slots: // Protected slots
+ void previousEntry();
+ void nextEntry();
+ /**
+ * This function saves the entry as html using the CExportMgr class.
+ */
+ void saveAsHTML();
+ /**
+ * This function saves the entry as plain text using the CExportMgr class.
+ */
+ void saveAsPlain();
+ void saveRawHTML();
+
+ void slotFillBackHistory();
+ void slotFillForwardHistory();
+
+ void slotUpdateHistoryButtons(bool backEnabled, bool fwEnabled);
+};
+
+#endif
diff --git a/src/frontend/displaywindow/cmodulechooserbar.cpp b/src/frontend/displaywindow/cmodulechooserbar.cpp
new file mode 100644
index 0000000..fc891ad
--- /dev/null
+++ b/src/frontend/displaywindow/cmodulechooserbar.cpp
@@ -0,0 +1,127 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cmodulechooserbar.h"
+
+#include "cmodulechooserbutton.h"
+
+#include <QList>
+#include <QDebug>
+#include <QAction>
+#include <QToolBar>
+
+CModuleChooserBar::CModuleChooserBar(QList<CSwordModuleInfo*> useModules, CSwordModuleInfo::ModuleType type, QWidget *parent)
+ : QToolBar(parent),
+ m_moduleType(type),
+ m_idCounter(0),
+ m_buttonLimit(-1) //-1 means no limit
+{
+ //insert buttons if useModules != 0
+ QList<CSwordModuleInfo*>::iterator end_it = useModules.end();
+ for (QList<CSwordModuleInfo*>::iterator it(useModules.begin()); it != end_it; ++it) {
+ if ((m_buttonLimit != -1) && ( m_buttonLimit <= (int)m_buttonList.count()) ) { //we reached the button limit
+ break;
+ }
+ addButton( *it );
+ }
+
+ // We can add a button to choose an additional module
+ if ( (m_buttonLimit == -1) || (m_buttonLimit > (int)m_buttonList.count()) ) {
+ addButton(0); //add a button without module set
+ }
+}
+
+CModuleChooserButton* CModuleChooserBar::addButton( CSwordModuleInfo* const module )
+{
+ CModuleChooserButton* b = new CModuleChooserButton(module, m_moduleType, ++m_idCounter, this);
+ QAction* a = addWidget(b);
+ m_buttonList.append(b);
+ connect( b, SIGNAL(sigAddButton()), this, SLOT(addButton()) );
+ connect( b, SIGNAL(sigRemoveButton(const int)), this, SLOT(removeButton(const int)) );
+ connect( b, SIGNAL(sigChanged()), SIGNAL(sigChanged()) );
+ connect( b, SIGNAL(sigChanged()), SLOT(updateMenuItems()) );
+ a->setVisible(true);
+ updateMenuItems(); //make sure the items are up to date with the newest module list
+ return b;
+}
+
+void CModuleChooserBar::addButton( ) {
+ addButton(0);
+}
+
+//change current with next and remove
+/** Removes a button from the toolbar */
+void CModuleChooserBar::removeButton( const int ID ) {
+ QMutableListIterator<CModuleChooserButton*> it(m_buttonList);
+ while (it.hasNext()) {
+ CModuleChooserButton* b = it.next();
+ if (b->getId() == ID) { //found the right button to remove
+ it.remove();
+ b->deleteLater();
+ break;
+ }
+ }
+ emit sigChanged();
+ updateMenuItems(); //make sure the items are up to date with the newest module list
+}
+
+/** Returns a list of selected modules. */
+QList<CSwordModuleInfo*> CModuleChooserBar::getModuleList() {
+ QList<CSwordModuleInfo*> list;
+ foreach (CModuleChooserButton* b, m_buttonList)
+ {
+ if (b->module()) list.append( b->module() );
+ }
+ return list;
+}
+
+//change current with remove
+/** Sets the number of the maximum count of buttons. */
+void CModuleChooserBar::setButtonLimit(const int limit) {
+ m_buttonLimit = limit;
+ if (limit == -1) //no need to delete buttons
+ return;
+
+ const int tooMuch = m_buttonList.size() - limit;
+ for (int i = 0; i < tooMuch; ++i) {
+ CModuleChooserButton* b = m_buttonList.takeLast();
+ b->deleteLater();
+ }
+
+ updateMenuItems();
+}
+
+/** Sets the modules which are chosen in this module chooser bar. */
+void CModuleChooserBar::setModules( QList<CSwordModuleInfo*> useModules ) {
+ setButtonLimit(0);
+ setButtonLimit(-1); //these two lines clear the bar
+
+ if (!useModules.count()) return;
+
+ QList<CSwordModuleInfo*>::iterator end_it = useModules.end();
+ for (QList<CSwordModuleInfo*>::iterator it(useModules.begin()); it != end_it; ++it) {
+ if ( (m_buttonLimit != -1) && (m_buttonLimit <= (int)m_buttonList.count()) ) {
+ break;
+ }
+ addButton( *it );
+ }
+
+ if ( (m_buttonLimit == -1) || (m_buttonLimit > (int)m_buttonList.count()) ) {
+ addButton(0);//add button without module set
+ }
+
+ updateMenuItems();
+}
+
+void CModuleChooserBar::updateMenuItems() {
+ resize(sizeHint());
+ update(); //seems to be neccessary to enforce display of the layout changes when a button was removed or added
+ foreach (CModuleChooserButton* b, m_buttonList)
+ b->updateMenuItems();
+}
diff --git a/src/frontend/displaywindow/cmodulechooserbar.h b/src/frontend/displaywindow/cmodulechooserbar.h
new file mode 100644
index 0000000..d21fcb9
--- /dev/null
+++ b/src/frontend/displaywindow/cmodulechooserbar.h
@@ -0,0 +1,77 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CMODULECHOOSERBAR_H
+#define CMODULECHOOSERBAR_H
+
+//BibleTime includes
+#include "backend/drivers/cswordmoduleinfo.h"
+
+#include "util/cpointers.h"
+
+//Qt includes
+#include <QList>
+#include <QToolBar>
+
+class CModuleChooserButton;
+class QWidget;
+
+/**
+ * @author The BibleTime team
+ */
+class CModuleChooserBar : public QToolBar {
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ CModuleChooserBar(QList<CSwordModuleInfo*> useModules, CSwordModuleInfo::ModuleType type, QWidget *parent=0);
+ /**
+ * Returns a list of selected modules.
+ */
+ QList<CSwordModuleInfo*> getModuleList();
+ /**
+ * Sets the number of the maximum count of buttons.
+ */
+ void setButtonLimit( const int limit);
+ /**
+ * Sets the modules which are chosen in this module chooser bar.
+ */
+ void setModules( QList<CSwordModuleInfo*> modules );
+
+signals:
+ void sigChanged();
+
+protected:
+ /**
+ * Adds a button to the toolbar
+ */
+ CModuleChooserButton* addButton( CSwordModuleInfo* const module );
+
+protected slots: // Protected slots
+ /*
+ * This slot calls the addButton function above to add a button.
+ */
+ void addButton();
+ /**
+ * Removes a button from the toolbar
+ */
+ void removeButton( const int ID );
+ /** */
+ void updateMenuItems();
+
+private:
+ CSwordModuleInfo::ModuleType m_moduleType;
+ int m_idCounter;
+ int m_buttonLimit;
+ QList<CModuleChooserButton*> m_buttonList;
+
+};
+
+#endif
diff --git a/src/frontend/displaywindow/cmodulechooserbutton.cpp b/src/frontend/displaywindow/cmodulechooserbutton.cpp
new file mode 100644
index 0000000..dd5a9ee
--- /dev/null
+++ b/src/frontend/displaywindow/cmodulechooserbutton.cpp
@@ -0,0 +1,211 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cmodulechooserbutton.h"
+
+#include "cmodulechooserbar.h"
+
+#include "backend/managers/cswordbackend.h"
+
+#include "backend/config/cbtconfig.h"
+
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+
+//Qt includes
+#include <QString>
+#include <QToolTip>
+#include <QHash>
+#include <QToolButton>
+#include <QMenu>
+#include <QtDebug>
+
+CModuleChooserButton::CModuleChooserButton(CSwordModuleInfo* useModule,CSwordModuleInfo::ModuleType type, const int id, CModuleChooserBar *parent)
+ : QToolButton(parent),
+ m_id(id), m_popup(0), m_moduleChooserBar(parent)
+{
+ m_moduleType = type;
+ m_module = useModule;
+ m_hasModule = (m_module) ? true : false;
+
+ setIcon( util::filesystem::DirectoryUtil::getIcon(iconName()) );
+ setPopupMode(QToolButton::InstantPopup);
+
+ populateMenu();
+}
+
+CModuleChooserButton::~CModuleChooserButton() {
+ qDeleteAll(m_submenus);
+ m_submenus.clear();
+ delete m_popup; //not necessary, because has "this" as parent?
+}
+
+/** Returns the icon used for the current status. */
+const QString CModuleChooserButton::iconName() {
+ switch (m_moduleType) {
+ case CSwordModuleInfo::Bible:
+ return (m_hasModule) ? CResMgr::modules::bible::icon_unlocked : CResMgr::modules::bible::icon_add;
+ case CSwordModuleInfo::Commentary:
+ return (m_hasModule) ? CResMgr::modules::commentary::icon_unlocked : CResMgr::modules::commentary::icon_add;
+ case CSwordModuleInfo::Lexicon:
+ return m_hasModule ? CResMgr::modules::lexicon::icon_unlocked : CResMgr::modules::lexicon::icon_add;
+ case CSwordModuleInfo::GenericBook:
+ return m_hasModule ? CResMgr::modules::book::icon_unlocked : CResMgr::modules::book::icon_add;
+ default: //return as default the bible icon
+ return CResMgr::modules::bible::icon_unlocked;
+ }
+}
+
+CSwordModuleInfo* CModuleChooserButton::module() {
+ foreach (QMenu* popup, m_submenus) {
+ foreach (QAction* action, popup->actions()) {
+ if ( action->isChecked() ) { //idAt -> , isItemChecked -> QAction::isChecked
+ QString mod = action->text(); //popup->text(popup->idAt(i)); //text ->
+ mod.remove(QChar('&')); //remove hotkey indicators
+ return backend()->findModuleByName( mod.left(mod.indexOf(" ")) );
+ }
+ }
+ }
+ return 0; //"none" selected
+}
+
+/** Returns the id used for this button. */
+int CModuleChooserButton::getId() const {
+ return m_id;
+}
+
+/** Is called after a module was selected in the popup */
+void CModuleChooserButton::moduleChosen( QAction* action ) {
+
+ QListIterator<QMenu*> it(m_submenus);
+ while (it.hasNext()) {
+ QMenu* popup = it.next();
+ foreach (QAction* a, popup->actions()) {
+ a->setChecked(false);
+ }
+ action->setChecked(true);
+ }
+
+ m_noneAction->setChecked(false); //uncheck the "none" item
+ if (action->text().remove(QChar('&')) == tr("NONE")) { // note: this is for m_popup, the toplevel!
+ if (m_hasModule) {
+ emit sigRemoveButton(m_id);
+ return;
+ }
+ }
+ else {
+ if (!m_hasModule) {
+ emit sigAddButton();
+ }
+
+ m_hasModule = true;
+ m_module = module();
+
+ setIcon( util::filesystem::DirectoryUtil::getIcon(iconName()) );
+ emit sigChanged();
+
+ if (m_module) {
+ setToolTip( tr("Select a work") + " [" + m_module->name() + "]" );
+ }
+ else {
+ setToolTip( tr("Select an additional work") );
+ }
+ }
+}
+
+/** No descriptions */
+void CModuleChooserButton::populateMenu() {
+ qDeleteAll(m_submenus);
+ m_submenus.clear();
+ delete m_popup;
+ m_popup = new QMenu(this);
+
+ if (m_module) {
+ this->setToolTip( tr("Select a work") + " [" + m_module->name() + "]" );
+ }
+ else {
+ this->setToolTip( tr("Select an additional work") );
+ }
+
+ m_noneAction = m_popup->addAction(tr("NONE"));
+ m_noneAction->setCheckable(true);
+ if (!m_module) m_noneAction->setChecked(true);
+
+ m_popup->addSeparator();
+ connect(m_popup, SIGNAL(triggered(QAction*)), this, SLOT(moduleChosen(QAction*)));
+ setMenu(m_popup);
+
+
+ // ******* Add languages and modules ********
+
+ // Filters: add only non-hidden and right type
+ BTModuleTreeItem::HiddenOff hiddenFilter;
+ TypeFilter typeFilter(m_moduleType);
+ QList<BTModuleTreeItem::Filter*> filters;
+ if (!CBTConfig::get(CBTConfig::bookshelfShowHidden)) {
+ filters.append(&hiddenFilter);
+ }
+ filters.append(&typeFilter);
+ BTModuleTreeItem root(filters, BTModuleTreeItem::LangMod);
+ // add all items recursively
+ addItemToMenu(&root, m_popup);
+
+}
+
+void CModuleChooserButton::addItemToMenu(BTModuleTreeItem* item, QMenu* menu)
+{
+ foreach (BTModuleTreeItem* i, item->children()) {
+
+ if (i->type() == BTModuleTreeItem::Language) {
+ // argument menu was m_popup, create and add a new lang menu to it
+ QMenu* langMenu = new QMenu(i->text(), this);
+ menu->addMenu(langMenu);
+ m_submenus.append(langMenu);
+ connect(langMenu, SIGNAL(triggered(QAction*)), this, SLOT(moduleChosen(QAction*)));
+ // add the module items to the lang menu
+ addItemToMenu(i, langMenu);
+ }
+ else {
+ // item must be module, create and add it to the lang menu
+ QString name(i->text());
+ name.append(" ").append(i->moduleInfo()->isLocked() ? tr("[locked]") : QString::null);
+ QAction* modItem = new QAction(name, menu);
+ modItem->setCheckable(true);
+ if ( m_module && i->text() == m_module->name()) modItem->setChecked(true);
+ menu->addAction(modItem);
+ }
+ }
+}
+
+void CModuleChooserButton::updateMenuItems() {
+ QString moduleName;
+ CSwordModuleInfo* module = 0;
+ QList<CSwordModuleInfo*> chosenModules = m_moduleChooserBar->getModuleList();
+
+ //for ( QMenu* popup = m_submenus.first(); popup; popup = m_submenus.next() ) {
+ QListIterator<QMenu*> it(m_submenus);
+ while (it.hasNext()) {
+ QMenu* popup = it.next();
+ foreach (QAction* action, popup->actions()) {
+ moduleName = action->text();
+ moduleName.remove(QChar('&')); //remove Hotkey indicator
+ module = backend()->findModuleByName( moduleName.left(moduleName.lastIndexOf(" ")) );
+
+ //Q_ASSERT(module);
+ if (!module) qWarning("Can't find module with name %s", moduleName.toLatin1().data());
+
+ bool alreadyChosen = chosenModules.contains( module );
+ if (m_module) {
+ alreadyChosen = alreadyChosen && (m_module->name() != moduleName);
+ }
+ //grey it out, it was chosen already
+ action->setEnabled(!alreadyChosen);
+ }
+ }
+}
diff --git a/src/frontend/displaywindow/cmodulechooserbutton.h b/src/frontend/displaywindow/cmodulechooserbutton.h
new file mode 100644
index 0000000..7715bf3
--- /dev/null
+++ b/src/frontend/displaywindow/cmodulechooserbutton.h
@@ -0,0 +1,82 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CMODULECHOOSERBUTTON_H
+#define CMODULECHOOSERBUTTON_H
+
+//BibleTime includes
+class CSwordModuleInfo;
+#include "backend/btmoduletreeitem.h"
+#include "util/cpointers.h"
+
+//Qt includes
+#include <QToolButton>
+#include <QList>
+
+class QMenu;
+class CModuleChooserBar;
+
+/** The CModuleChooserButton displays a list of submenus sorted by language which contain the possible modules
+ * which can be displayed together with the first one.
+ * @author The BibleTime team
+ */
+class CModuleChooserButton : public QToolButton, public CPointers {
+ Q_OBJECT
+public:
+
+ /** Filter out modules of wrong type. See populateMenu() and BTModuleTreeItem. */
+ struct TypeFilter : public BTModuleTreeItem::Filter {
+ TypeFilter(CSwordModuleInfo::ModuleType t) {m_mType = t;}
+ bool filter(CSwordModuleInfo* mi) { return (mi->type() == m_mType); }
+ CSwordModuleInfo::ModuleType m_mType;
+ };
+
+ CModuleChooserButton(CSwordModuleInfo* useModule, CSwordModuleInfo::ModuleType type, const int id, CModuleChooserBar *parent);
+ ~CModuleChooserButton();
+
+ CSwordModuleInfo* module();
+ /**
+ * Returns the id used for this button.
+ */
+ int getId() const;
+ void updateMenuItems();
+
+protected:
+ /** Populates the menu with language submenus and module items. */
+ void populateMenu();
+ /** Adds items to the menu recursively. */
+ void addItemToMenu(BTModuleTreeItem* item, QMenu* menu);
+
+private:
+ /**
+ * Returns the icon used for the current status.
+ */
+ const QString iconName();
+
+ bool m_hasModule;
+ int m_id;
+ QAction* m_noneAction;
+ CSwordModuleInfo::ModuleType m_moduleType;
+ CSwordModuleInfo* m_module;
+
+ QMenu* m_popup;
+ QList<QMenu*> m_submenus;
+
+ CModuleChooserBar* m_moduleChooserBar;
+
+
+private slots:
+ void moduleChosen(QAction* action );
+
+signals:
+ void sigRemoveButton(const int ID);
+ void sigAddButton();
+ void sigChanged();
+};
+#endif
diff --git a/src/frontend/displaywindow/cplainwritewindow.cpp b/src/frontend/displaywindow/cplainwritewindow.cpp
new file mode 100644
index 0000000..9f12020
--- /dev/null
+++ b/src/frontend/displaywindow/cplainwritewindow.cpp
@@ -0,0 +1,183 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cplainwritewindow.h"
+#include "btactioncollection.h"
+
+#include "frontend/display/cwritedisplay.h"
+
+#include "frontend/keychooser/ckeychooser.h"
+#include "frontend/profile/cprofilewindow.h"
+#include "backend/config/cbtconfig.h"
+
+#include "backend/keys/cswordkey.h"
+
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+
+#include <QRegExp>
+#include <QToolBar>
+#include <QMessageBox>
+#include <QDebug>
+#include <QAction>
+
+using namespace Profile;
+
+CPlainWriteWindow::CPlainWriteWindow(QList<CSwordModuleInfo*> moduleList, CMDIArea* parent) :
+ CWriteWindow(moduleList, parent)
+{
+ setKey( CSwordKey::createInstance(moduleList.first()) );
+}
+
+
+CPlainWriteWindow::~CPlainWriteWindow() {}
+
+/** Initialize the state of this widget. */
+void CPlainWriteWindow::initView() {
+ // qWarning("CPlainWriteWindow::initView()");
+ setDisplayWidget( CDisplay::createWriteInstance(this) );
+ setCentralWidget( displayWidget()->view() );
+
+ setMainToolBar( new QToolBar(this) );
+ addToolBar(mainToolBar());
+ addToolBarBreak();
+
+ setKeyChooser( CKeyChooser::createInstance(modules(), key(), mainToolBar()) );
+ mainToolBar()->addWidget(keyChooser());
+}
+
+void CPlainWriteWindow::initToolbars() {
+ m_actions.syncWindow = new QAction(
+ //KIcon(CResMgr::displaywindows::commentaryWindow::syncWindow::icon),
+ util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::commentaryWindow::syncWindow::icon),
+ tr("Sync with active Bible"),
+ actionCollection()
+ );
+ m_actions.syncWindow->setCheckable(true);
+ m_actions.syncWindow->setShortcut(CResMgr::displaywindows::commentaryWindow::syncWindow::accel);
+ m_actions.syncWindow->setToolTip(tr("Synchronize (show the same verse) with the active Bible window"));
+ mainToolBar()->addAction(m_actions.syncWindow);
+ actionCollection()->addAction(CResMgr::displaywindows::commentaryWindow::syncWindow::actionName, m_actions.syncWindow);
+
+
+ m_actions.saveText = new QAction(
+ //KIcon(CResMgr::displaywindows::writeWindow::saveText::icon),
+ util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::writeWindow::saveText::icon),
+ tr("Save text"),
+ actionCollection()
+ );
+ m_actions.saveText->setShortcut(CResMgr::displaywindows::writeWindow::saveText::accel);
+ QObject::connect(m_actions.saveText, SIGNAL(triggered()), this, SLOT(saveCurrentText()));
+ m_actions.saveText->setToolTip( tr("Save text") );
+ actionCollection()->addAction(CResMgr::displaywindows::writeWindow::saveText::actionName, m_actions.saveText);
+ mainToolBar()->addAction(m_actions.saveText);
+
+
+ m_actions.deleteEntry = new QAction(
+ //KIcon(CResMgr::displaywindows::writeWindow::deleteEntry::icon),
+ util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::writeWindow::deleteEntry::icon),
+ tr("Delete current entry"),
+ actionCollection()
+ );
+ m_actions.deleteEntry->setShortcut(CResMgr::displaywindows::writeWindow::deleteEntry::accel);
+ QObject::connect(m_actions.deleteEntry, SIGNAL(triggered()), this, SLOT(deleteEntry()) );
+ m_actions.deleteEntry->setToolTip( tr("Delete current entry (no undo)") );
+ actionCollection()->addAction(CResMgr::displaywindows::writeWindow::deleteEntry::actionName, m_actions.deleteEntry);
+ mainToolBar()->addAction(m_actions.deleteEntry);
+
+
+ m_actions.restoreText = new QAction(
+ //KIcon(CResMgr::displaywindows::writeWindow::restoreText::icon),
+ util::filesystem::DirectoryUtil::getIcon(CResMgr::displaywindows::writeWindow::restoreText::icon),
+ tr("Restore original text"),
+ actionCollection()
+ );
+ m_actions.restoreText->setShortcut(CResMgr::displaywindows::writeWindow::restoreText::accel);
+ QObject::connect(m_actions.restoreText, SIGNAL(triggered()), this, SLOT(restoreText()) );
+ m_actions.restoreText->setToolTip( tr("Restore original text, new text will be lost") );
+ actionCollection()->addAction(CResMgr::displaywindows::writeWindow::restoreText::actionName, m_actions.restoreText);
+ mainToolBar()->addAction(m_actions.restoreText);
+}
+
+void CPlainWriteWindow::initConnections() {
+ CWriteWindow::initConnections();
+ QObject::connect(keyChooser(), SIGNAL(keyChanged(CSwordKey*)), this, SLOT(lookupSwordKey(CSwordKey*)));
+ QObject::connect(displayWidget()->connectionsProxy(), SIGNAL(textChanged()), this, SLOT(textChanged()) );
+}
+
+void CPlainWriteWindow::storeProfileSettings( CProfileWindow* profileWindow ) {
+ CWriteWindow::storeProfileSettings(profileWindow);
+ profileWindow->setWindowSettings( m_actions.syncWindow->isChecked() );
+}
+
+void CPlainWriteWindow::applyProfileSettings( CProfileWindow* profileWindow ) {
+ CWriteWindow::applyProfileSettings(profileWindow);
+ if (profileWindow->windowSettings()) {
+ m_actions.syncWindow->setChecked(true);
+ }
+}
+
+/** Saves the text for the current key. Directly writes the changed text into the module. */
+void CPlainWriteWindow::saveCurrentText( const QString& /*key*/ ) {
+ QString t = ((CWriteDisplay*)displayWidget())->plainText();
+ //since t is a complete HTML page at the moment, strip away headers and footers of a HTML page
+ QRegExp re("(?:<html.*>.+<body.*>)", Qt::CaseInsensitive); //remove headers, case insensitive
+ re.setMinimal(true);
+ t.replace(re, "");
+ t.replace(QRegExp("</body></html>", Qt::CaseInsensitive), "");//remove footer
+
+ const QString& oldKey = this->key()->key();
+ if( modules().first()->isWritable() ) {
+ modules().first()->write(this->key(), t );
+ this->key()->key( oldKey );
+
+ ((CWriteDisplay*)displayWidget())->setModified(false);
+ textChanged();
+ }
+ else {
+ QMessageBox::critical( this, tr("Module not writable"),
+ QString::fromLatin1("<qt><B>%1</B><BR>%2</qt>")
+ .arg( tr("Module is not writable.") )
+ .arg( tr("Either the module may not be edited, or "
+ "you do not have write permission.") ) );
+ }
+}
+
+/** Loads the original text from the module. */
+void CPlainWriteWindow::restoreText() {
+ lookupSwordKey(key());
+ ((CWriteDisplay*)displayWidget())->setModified(false);
+ textChanged();
+}
+
+/** Is called when the current text was changed. */
+void CPlainWriteWindow::textChanged() {
+ m_actions.saveText->setEnabled( ((CWriteDisplay*)displayWidget())->isModified() );
+ m_actions.restoreText->setEnabled( ((CWriteDisplay*)displayWidget())->isModified() );
+}
+
+/** Deletes the module entry and clears the edit widget, */
+void CPlainWriteWindow::deleteEntry() {
+ modules().first()->deleteEntry( key() );
+ lookupSwordKey( key() );
+ ((CWriteDisplay*)displayWidget())->setModified(false);
+}
+
+/** Setups the popup menu of this display widget. */
+void CPlainWriteWindow::setupPopupMenu() {}
+
+bool CPlainWriteWindow::syncAllowed() const {
+ return m_actions.syncWindow->isChecked();
+}
+
+void CPlainWriteWindow::initActions() {
+}
+
+void CPlainWriteWindow::insertKeyboardActions( BtActionCollection* const ) {
+}
diff --git a/src/frontend/displaywindow/cplainwritewindow.h b/src/frontend/displaywindow/cplainwritewindow.h
new file mode 100644
index 0000000..1ed4215
--- /dev/null
+++ b/src/frontend/displaywindow/cplainwritewindow.h
@@ -0,0 +1,96 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CPLAINWRITEWINDOW_H
+#define CPLAINWRITEWINDOW_H
+
+//BibleTime includes
+#include "cwritewindow.h"
+
+
+class QAction;
+class BtActionCollection;
+
+class QString;
+
+/** The write window class which offers a plain editor for source code editing.
+ * @author The BibleTime team
+ */
+class CPlainWriteWindow : public CWriteWindow {
+ Q_OBJECT
+public:
+ CPlainWriteWindow( QList<CSwordModuleInfo*> modules, CMDIArea* parent);
+ virtual ~CPlainWriteWindow();
+
+ /**
+ * Store the settings of this window in the given CProfileWindow object.
+ */
+ virtual void storeProfileSettings( Profile::CProfileWindow* profileWindow );
+ /**
+ * Store the settings of this window in the given profile window.
+ */
+ virtual void applyProfileSettings( Profile::CProfileWindow* profileWindow );
+
+ /**
+ * Setups the popup menu of this display widget.
+ */
+ virtual void setupPopupMenu();
+ virtual bool syncAllowed() const;
+
+protected: // Protected methods
+ /**
+ * Initialize the state of this widget.
+ */
+ virtual void initView();
+ virtual void initConnections();
+ virtual void initToolbars();
+ virtual CDisplayWindow::WriteWindowType writeWindowType() {
+ return CDisplayWindow::PlainTextWindow;
+ };
+
+ /**
+ * Initializes the intern keyboard actions.
+ */
+ virtual void initActions();
+ /**
+ * Insert the keyboard accelerators of this window into the given KAccel object.
+ */
+ static void insertKeyboardActions( BtActionCollection* const a );
+
+private:
+ struct {
+ QAction* saveText;
+ QAction* deleteEntry;
+ QAction* restoreText;
+ QAction* syncWindow;
+ }
+ m_actions;
+
+protected slots: // Protected slots
+ /**
+ * Saves the text for the current key. Directly writes the changed text into the module.
+ */
+ virtual void saveCurrentText( const QString& );
+ /**
+ * Is called when the current text was changed.
+ */
+ virtual void textChanged();
+ /**
+ * Loads the original text from the module.
+ */
+ virtual void restoreText();
+ /**
+ * Deletes the module entry and clears the edit widget.
+ */
+ virtual void deleteEntry();
+};
+
+#endif
diff --git a/src/frontend/displaywindow/creadwindow.cpp b/src/frontend/displaywindow/creadwindow.cpp
new file mode 100644
index 0000000..d446d30
--- /dev/null
+++ b/src/frontend/displaywindow/creadwindow.cpp
@@ -0,0 +1,205 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//BibleTime includes
+#include "creadwindow.h"
+#include "btactioncollection.h"
+
+#include "frontend/display/bthtmlreaddisplay.h"
+typedef BtHtmlReadDisplay HTMLREADDISPLAY;
+
+#include "backend/rendering/centrydisplay.h"
+#include "backend/rendering/cdisplayrendering.h"
+#include "backend/keys/cswordkey.h"
+#include "backend/keys/cswordversekey.h"
+
+#include "frontend/cexportmanager.h"
+#include "frontend/cmdiarea.h"
+#include "frontend/profile/cprofilewindow.h"
+#include "frontend/searchdialog/csearchdialog.h"
+
+#include <QResizeEvent>
+#include <QMdiSubWindow>
+#include <QDebug>
+
+using namespace Profile;
+
+CReadWindow::CReadWindow(QList<CSwordModuleInfo*> modules, CMDIArea* parent)
+ : CDisplayWindow(modules,parent),
+ m_displayWidget(0)
+{
+ qDebug("CReadWindow::CReadWindow");
+ // installEventFilter(this);
+}
+
+CReadWindow::~CReadWindow() {
+ // qWarning("destructor of CReadWindow");
+}
+
+/** Sets the display widget of this display window. */
+void CReadWindow::setDisplayWidget( CDisplay* newDisplay ) {
+ Q_ASSERT(dynamic_cast<CReadDisplay*>(newDisplay));
+ CDisplayWindow::setDisplayWidget(newDisplay);
+ if (m_displayWidget) {
+ disconnect(m_displayWidget->connectionsProxy(), SIGNAL(referenceClicked(const QString&, const QString&)), this, SLOT(lookupModKey(const QString&, const QString&)));
+ disconnect(m_displayWidget->connectionsProxy(), SIGNAL(referenceDropped(const QString&)), this, SLOT(lookupKey(const QString&)));
+
+ HTMLREADDISPLAY* v = dynamic_cast<HTMLREADDISPLAY*>(m_displayWidget);
+ if (v) {
+ QObject::disconnect(v, SIGNAL(completed()), this, SLOT(slotMoveToAnchor()) );
+ }
+
+ }
+
+ m_displayWidget = (CReadDisplay*)newDisplay;
+ connect(
+ m_displayWidget->connectionsProxy(),
+ SIGNAL(referenceClicked(const QString&, const QString&)),
+ this,
+ SLOT(lookupModKey(const QString&, const QString&))
+ );
+
+ connect(
+ m_displayWidget->connectionsProxy(),
+ SIGNAL(referenceDropped(const QString&)),
+ this,
+ SLOT(lookupKey(const QString&))
+ );
+ HTMLREADDISPLAY* v = dynamic_cast<HTMLREADDISPLAY*>(m_displayWidget);
+ if (v)
+ {
+ QObject::connect(v, SIGNAL(completed()), this, SLOT(slotMoveToAnchor()) );
+ }
+}
+
+/** Lookup the given entry. */
+void CReadWindow::lookupSwordKey( CSwordKey* newKey ) {
+ qDebug() << "CReadWindow::lookup newKey" << newKey->key();
+ Q_ASSERT(newKey);
+
+ using namespace Rendering;
+
+// Q_ASSERT(isReady() && newKey && modules().first());
+ if (!isReady() || !newKey || modules().empty() || !modules().first()) {
+ return;
+ }
+
+ if (key() != newKey) {
+ key()->key(newKey->key());
+ }
+
+ //next-TODO: how about options?
+ Q_ASSERT(modules().first()->getDisplay());
+ CEntryDisplay* display = modules().first()->getDisplay();
+ if (display) { //do we have a display object?
+ displayWidget()->setText(
+ display->text(
+ modules(),
+ newKey->key(),
+ displayOptions(),
+ filterOptions()
+ )
+ );
+ }
+
+ setCaption( windowCaption() );
+
+ // moving to anchor happens in slotMoveToAnchor which catches the completed() signal from KHTMLPart
+
+ qDebug() << "CReadWindow::lookup end, key is :" << newKey->key();
+}
+
+void CReadWindow::slotMoveToAnchor()
+{
+ qDebug("CReadWindow::slotMoveToAnchor");
+ ((CReadDisplay*)displayWidget())->moveToAnchor( Rendering::CDisplayRendering::keyToHTMLAnchor(key()->key()) );
+}
+
+/** Store the settings of this window in the given CProfileWindow object. */
+void CReadWindow::storeProfileSettings(CProfileWindow * const settings) {
+ QRect rect;
+ rect.setX(parentWidget()->x());
+ rect.setY(parentWidget()->y());
+ rect.setWidth(width());
+ rect.setHeight(height());
+ settings->setGeometry(rect);
+
+ // settings->setScrollbarPositions( m_htmlWidget->view()->horizontalScrollBar()->value(), m_htmlWidget->view()->verticalScrollBar()->value() );
+ settings->setType(modules().first()->type());
+ settings->setMaximized(isMaximized() || parentWidget()->isMaximized());
+ settings->setFocus( (this == dynamic_cast<CReadWindow*>(mdi()->activeSubWindow()) ) ); //set property to true if this window is the active one.
+
+ if (key()) {
+ sword::VerseKey* vk = dynamic_cast<sword::VerseKey*>(key());
+ QString oldLang;
+ if (vk) {
+ oldLang = QString(vk->getLocale());
+ vk->setLocale("en"); //save english locale names as default!
+ }
+ settings->setKey( key()->key() );
+ if (vk) {
+ vk->setLocale(oldLang.toLatin1());
+ }
+ }
+
+ QStringList mods;
+
+ QList<CSwordModuleInfo*> allMods = modules();
+ QList<CSwordModuleInfo*>::iterator end_it = allMods.end();
+ for (QList<CSwordModuleInfo*>::iterator it(allMods.begin()); it != end_it; ++it) {
+ mods.append((*it)->name());
+ }
+ settings->setModules(mods);
+}
+
+void CReadWindow::applyProfileSettings(CProfileWindow * const settings) {
+ // parentWidget()->setUpdatesEnabled(false);
+ setUpdatesEnabled(false);
+
+ if (settings->maximized()) { //maximize this window
+ // Use parentWidget() to call showMaximized. Otherwise we'd get lot's of X11 errors
+ parentWidget()->showMaximized();
+ }
+ else {
+ const QRect rect = settings->geometry();
+ parentWidget()->resize(rect.width(), rect.height());
+ parentWidget()->move(rect.x(), rect.y());
+ }
+
+ setUpdatesEnabled(true);
+}
+
+void CReadWindow::insertKeyboardActions( BtActionCollection* const ) {}
+
+/** No descriptions */
+void CReadWindow::copyDisplayedText() {
+ CExportManager mgr(QString::null);
+ mgr.copyKey(key(), CExportManager::Text, true);
+}
+
+
+/*!
+ \fn CReadWindow::resizeEvent(QResizeEvent* e)
+ */
+void CReadWindow::resizeEvent(QResizeEvent* /*e*/) {
+ if (displayWidget()) {
+ ((CReadDisplay*)displayWidget())->moveToAnchor(Rendering::CDisplayRendering::keyToHTMLAnchor(key()->key()));
+ }
+}
+
+void CReadWindow::openSearchStrongsDialog() {
+// qWarning("looking for lemma %s", displayWidget()->getCurrentNodeInfo()[CDisplay::Lemma].latin1() );
+ QString searchText = QString::null;
+
+ if (displayWidget()->getCurrentNodeInfo()[CDisplay::Lemma] != QString::null) {
+ searchText.append("strong:").append(displayWidget()->getCurrentNodeInfo() [CDisplay::Lemma]);
+ }
+
+ Search::CSearchDialog::openDialog( modules(), searchText, 0 );
+}
diff --git a/src/frontend/displaywindow/creadwindow.h b/src/frontend/displaywindow/creadwindow.h
new file mode 100644
index 0000000..3630b58
--- /dev/null
+++ b/src/frontend/displaywindow/creadwindow.h
@@ -0,0 +1,79 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CREADWINDOW_H
+#define CREADWINDOW_H
+
+//BibleTime includes
+#include "cdisplaywindow.h"
+
+#include "frontend/display/cdisplay.h"
+#include "frontend/display/creaddisplay.h"
+
+
+class BtActionCollection;
+class QResizeEvent;
+
+
+/** The base class for all read-only display windows.
+ * @author The BibleTime team
+ */
+
+class CReadWindow : public CDisplayWindow {
+ Q_OBJECT
+public:
+ // static void insertKeyboardActions( KAccel* const a );
+ static void insertKeyboardActions( BtActionCollection* const a );
+
+ CReadWindow(QList<CSwordModuleInfo*> modules, CMDIArea* parent);
+ virtual ~CReadWindow();
+ /**
+ * Store the settings of this window in the given CProfileWindow object.
+ */
+ virtual void storeProfileSettings(Profile::CProfileWindow * const settings);
+ /**
+ * Store the settings of this window in the given CProfileWindow object.
+ */
+ virtual void applyProfileSettings(Profile::CProfileWindow * const settings);
+
+protected: // Protected methods
+ /**
+ * Sets the display widget of this display window.
+ */
+ virtual void setDisplayWidget( CDisplay* newDisplay );
+ /**
+ */
+ virtual void resizeEvent(QResizeEvent* e);
+
+protected slots:
+ /**
+ * Load the text using the key
+ */
+ virtual void lookupSwordKey( CSwordKey* );
+ /**
+ * Catch the signal when the KHTMLPart has finished the layout (anchors are not ready before that).
+ */
+ virtual void slotMoveToAnchor();
+
+ /**
+ * Update the status of the popup menu entries.
+ */
+ virtual void copyDisplayedText();
+ /** Open the search dialog with the strong info of the last clicked word.
+ *
+ */
+ void openSearchStrongsDialog();
+
+private:
+ CReadDisplay* m_displayWidget;
+};
+
+#endif
diff --git a/src/frontend/displaywindow/cwritewindow.cpp b/src/frontend/displaywindow/cwritewindow.cpp
new file mode 100644
index 0000000..0c58bf7
--- /dev/null
+++ b/src/frontend/displaywindow/cwritewindow.cpp
@@ -0,0 +1,161 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+#include "cwritewindow.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/keys/cswordversekey.h"
+
+#include "frontend/keychooser/ckeychooser.h"
+#include "frontend/profile/cprofilewindow.h"
+#include "frontend/display/cwritedisplay.h"
+
+
+#include <QMessageBox>
+
+
+using namespace Profile;
+
+CWriteWindow::CWriteWindow(QList<CSwordModuleInfo*> modules, CMDIArea* parent)
+: CDisplayWindow(modules, parent), m_writeDisplay(0) {}
+
+CWriteWindow::~CWriteWindow() {}
+
+
+void CWriteWindow::insertKeyboardActions( BtActionCollection* const ) {}
+
+void CWriteWindow::initConnections() {
+ Q_ASSERT(keyChooser());
+ QObject::connect(keyChooser(), SIGNAL(beforeKeyChange(const QString&)), this, SLOT(beforeKeyChange(const QString&)));
+}
+
+void CWriteWindow::initActions() {}
+
+
+void CWriteWindow::storeProfileSettings(CProfileWindow * const settings) {
+
+ settings->setWriteWindowType( writeWindowType() );
+
+ QRect rect;
+ rect.setX(parentWidget()->x());
+ rect.setY(parentWidget()->y());
+ rect.setWidth(width());
+ rect.setHeight(height());
+ settings->setGeometry(rect);
+
+ // settings->setScrollbarPositions( m_htmlWidget->view()->horizontalScrollBar()->value(), m_htmlWidget->view()->verticalScrollBar()->value() );
+ settings->setType(modules().first()->type());
+ settings->setMaximized(isMaximized() || parentWidget()->isMaximized());
+
+ if (key()) {
+ sword::VerseKey* vk = dynamic_cast<sword::VerseKey*>(key());
+ QString oldLang;
+ if (vk) {
+ oldLang = QString::fromLatin1(vk->getLocale());
+ vk->setLocale("en"); //save english locale names as default!
+ }
+ settings->setKey( key()->key() );
+ if (vk) {
+ vk->setLocale(oldLang.toLatin1());
+ }
+ }
+
+ QStringList mods;
+ QList<CSwordModuleInfo*> allMods = modules();
+ QList<CSwordModuleInfo*>::iterator end_it = allMods.end();
+ for (QList<CSwordModuleInfo*>::iterator it(allMods.begin()); it != end_it; ++it) {
+ mods.append((*it)->name());
+ }
+ settings->setModules(mods);
+}
+
+void CWriteWindow::applyProfileSettings(CProfileWindow * const settings) {
+ setUpdatesEnabled(false);
+
+ if (settings->maximized()) {
+ parentWidget()->showMaximized();
+ }
+ else {
+ const QRect rect = settings->geometry();
+ parentWidget()->resize(rect.width(), rect.height());
+ parentWidget()->move(rect.x(), rect.y());
+ //setGeometry( settings->geometry() );
+ }
+ // displayWidget()->view()->horizontalScrollBar()->setValue( settings->scrollbarPositions().horizontal );
+ // m_htmlWidget->view()->verticalScrollBar()->setValue( settings->scrollbarPositions().vertical );
+
+ setUpdatesEnabled(true);
+}
+
+void CWriteWindow::setDisplayWidget( CDisplay* display ) {
+ Q_ASSERT(dynamic_cast<CWriteDisplay*>(display));
+ CDisplayWindow::setDisplayWidget((CWriteDisplay*)display);
+ m_writeDisplay = (CWriteDisplay*)display;
+}
+
+void CWriteWindow::lookupSwordKey( CSwordKey* newKey ) {
+ //set the raw text to the display widget
+ if (!newKey)
+ return;
+
+ if (key() != newKey) { //set passage of newKey to key() if they're different, otherwise we'd get mixed up if we look up newkey which may have a different module set
+ key()->key(newKey->key());
+ }
+
+ if ( modules().count() ) {
+ displayWidget()->setText( key()->rawText() );
+ }
+ setCaption( windowCaption() );
+}
+
+bool CWriteWindow::queryClose() {
+ //save the text if it has changed
+ if (m_writeDisplay->isModified()) {
+ switch (QMessageBox::question( this, tr("Save Text?"), tr("Save text before closing?"), QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::Yes) ) {
+ case QMessageBox::Yes: //save and close
+ saveCurrentText();
+ m_writeDisplay->setModified( false );
+ return true;
+ case QMessageBox::No: //don't save and close
+ return true;
+ default: // cancel, don't close
+ return false;
+ }
+ }
+ return true;
+}
+
+void CWriteWindow::beforeKeyChange(const QString& key) {
+ Q_ASSERT(displayWidget());
+ Q_ASSERT(keyChooser());
+ if (!isReady()) return;
+
+ //If the text changed and we'd do a lookup ask the user if the text should be saved
+ if (modules().first() && ((CWriteDisplay*)displayWidget())->isModified()) {
+
+ switch (QMessageBox::question( this, tr("Save Text?"), tr("Save changed text?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes) ) {
+ case QMessageBox::Yes: { //save the changes
+ saveCurrentText( key );
+ break;
+ }
+ default: {// set modified to false so it won't ask again
+ ((CWriteDisplay*)displayWidget())->setModified(false);
+ break;
+ }
+ }
+ }
+}
+
+void CWriteWindow::saveCurrentText() {
+ if(key()) {
+ saveCurrentText(key()->key());
+ }
+}
+
diff --git a/src/frontend/displaywindow/cwritewindow.h b/src/frontend/displaywindow/cwritewindow.h
new file mode 100644
index 0000000..c3b47c2
--- /dev/null
+++ b/src/frontend/displaywindow/cwritewindow.h
@@ -0,0 +1,72 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CWRITEWINDOW_H
+#define CWRITEWINDOW_H
+
+//BibleTime includes
+#include "cdisplaywindow.h"
+
+
+class CWriteDisplay;
+class QString;
+class BtActionCollection;
+
+/**The base class for all write-only display windows.
+ *@author The BibleTime team
+ */
+
+class CWriteWindow : public CDisplayWindow {
+ Q_OBJECT
+public:
+ static void insertKeyboardActions( BtActionCollection* const a );
+
+ CWriteWindow(QList<CSwordModuleInfo*> modules, CMDIArea* parent);
+ virtual ~CWriteWindow();
+ /**
+ * Store the settings of this window in the given CProfileWindow object.
+ */
+ virtual void storeProfileSettings(Profile::CProfileWindow * const settings);
+ /**
+ * Store the settings of this window in the given CProfileWindow object.
+ */
+ virtual void applyProfileSettings(Profile::CProfileWindow * const settings);
+ virtual void initConnections();
+ virtual void initActions();
+
+public slots:
+ /**
+ * Look up the given key and display the text. In our case we offer to edit the text.
+ */
+ virtual void lookupSwordKey( CSwordKey* key );
+
+
+protected: // Protected methods
+ /**
+ * Saves the given text as text of the given key. Use this function
+ * as backend in each write window implementation.
+ */
+ void setDisplayWidget( CDisplay* display );
+ virtual CDisplayWindow::WriteWindowType writeWindowType() = 0;
+ virtual bool queryClose();
+ virtual void saveCurrentText( const QString& key ) = 0;
+
+protected slots:
+ /** Save text to the module
+ */
+ void saveCurrentText();
+ /**
+ */
+ virtual void beforeKeyChange(const QString&);
+
+private:
+ CWriteDisplay* m_writeDisplay;
+};
+
+#endif
diff --git a/src/frontend/htmldialogs/btaboutdialog.cpp b/src/frontend/htmldialogs/btaboutdialog.cpp
new file mode 100644
index 0000000..5e0bc91
--- /dev/null
+++ b/src/frontend/htmldialogs/btaboutdialog.cpp
@@ -0,0 +1,251 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btaboutdialog.h"
+
+#include "util/directoryutil.h"
+
+#include "swversion.h"
+
+// Forwards
+static QString make_body(const QString& content);
+static QString make_bold(const QString& content);
+static QString make_br();
+static QString make_center(const QString& content);
+static QString make_head(const QString& content);
+static QString make_html(const QString& content);
+static QString make_file_icon(const QString& icon);
+static QString make_link(const QString& link, const QString& text);
+static QString make_version();
+
+
+// Implements the Help > About dialog box
+
+BtAboutDialog::BtAboutDialog(QWidget *parent, Qt::WindowFlags wflags )
+ : BtTabHtmlDialog (tr("About BibleTime"), 5, parent, wflags)
+{
+ resize(550,340);
+ init_lic_tab();
+ init_sword_tab();
+ init_qt_tab();
+ init_contributors_tab();
+ init_bt_tab();
+}
+
+BtAboutDialog::~BtAboutDialog()
+{
+}
+
+void BtAboutDialog::init_bt_tab()
+{
+ selectTab(0);
+ setTabText("BibleTime" );
+ QString content;
+ content = make_file_icon("bibletime");
+ content += "&nbsp;&nbsp;";
+ content += make_bold("BibleTime " + make_version());
+ content = make_center(content) + make_br();
+ content += tr("BibleTime is an easy to use but powerful Bible study tool.");
+ content += make_br() + make_br();
+ content += tr("We are looking for developers and translators.");
+ content += " ";
+ content += tr("If you would like to join our team, please send an email to info@bibletime.info.");
+ content += make_br() + make_br();
+ content += tr("(c)1999-2009, The BibleTime Team");
+ content += make_br();
+ content += make_link("http://www.bibletime.info","http://www.bibletime.info");
+ QString bibletime = make_html(make_head("") + make_body(content));
+ setHtml(bibletime);
+}
+
+void BtAboutDialog::init_contributors_tab()
+{
+ selectTab(1);
+ setTabText(tr("Contributors"));
+ QString content;
+ content += make_bold(tr("The following people contributed to BibleTime:")) + make_br();
+ // sorted alphabetically (last name)
+ content += "<ul>";
+ content += "<li>Thomas Abthorpe (" + tr("documentation and translation manager") + ")</li>";
+ content += "<li>Joachim Ansorg (" + tr("project founder, developer") + ")</li>";
+ content += "<li>David Blue (" + tr("designer") + ")</li>";
+ content += "<li>Tim Brodie (" + tr("developer") + ")</li>";
+ content += "<li>Timothy R. Butler (" + tr("designer") + ")</li>";
+ content += "<li>Jim Campbell (" + tr("developer") + ")</li>";
+ content += "<li>Lee Carpenter (" + tr("developer") + ")</li>";
+ content += "<li>Jeremy Erickson (" + tr("packager") + ")</li>";
+ content += "<li>Troy A. Griffitts (" + tr("creator of The Sword Project") + ")</li>";
+ content += "<li>Martin Gruner (" + tr("project manager, developer") + ")</li>";
+ content += "<li>Thomas Hagedorn (" + tr("domain sponsor") + ")</li>";
+ content += "<li>Bob Harman (" + tr("howto") + ")</li>";
+ content += "<li>Gary Holmlund (" + tr("developer") + ")</li>";
+ content += "<li>Nikolay Igotti (" + tr("developer") + ")</li>";
+ content += "<li>Eeli Kaikkonnen (" + tr("developer") + ")</li>";
+ content += "<li>Chris Kujawa (" + tr("developer") + ")</li>";
+ content += "<li>Mark Lybarger (" + tr("developer") + ")</li>";
+ content += "<li>Luke Mauldin (" + tr("developer") + ")</li>";
+ content += "<li>James Ots (" + tr("designer") + ")</li>";
+ content += "<li>Fred Saalbach (" + tr("documentation") + ")</li>";
+ content += "<li>Gary Sims (" + tr("developer") + ")</li>";
+ content += "<li>Wolfgang Stradner (" + tr("tester, usability expert") + ")</li>";
+ content += "<li>Thorsten Uhlmann (" + tr("developer") + ")</li>";
+ content += "<li>David White (" + tr("developer") + ")</li>";
+ content += "<li>Mark Zealey (" + tr("developer") + ")</li>";
+ content += "</ul>";
+
+ content += make_bold(tr("The following people translated BibleTime into their language:")) + make_br();
+ // sorted alphabetically (last name)
+ content += "<ul>";
+ content += "<li>Horatiu Alexe</li>";
+ content += "<li>Chun-shek Chan</li>";
+ content += "<li>Ilpo Kantonen</li>";
+ content += "<li>Pavel Laukko</li>";
+ content += "<li>Piotr Markiewicz</li>";
+ content += "<li>G&eacute;za Nov&aacute;k</li>";
+ content += "<li>Gabriel P&eacute;rez</li>";
+ content += "<li>Igor Plisco</li>";
+ content += "<li>Jaak Ristioja</li>";
+ content += "<li>Igor Rykhlin</li>";
+ content += "<li>Vlad Savitsky</li>";
+ content += "<li>Johan van der Lingen</li>";
+ content += "<li>Jean Van Schaftingen</li>";
+ content += "<li>Dmitry Yurevich</li>";
+ content += "<li>Esteban Zeller</li>";
+ content += "</ul>";
+ content += make_br();
+ content += tr("Some names may be missing, please email bibletime-translations@lists.sourceforge.net if you notice errors or omissions.");
+
+ QString contributors = make_html(make_head("") + make_body(content));
+ setHtml(contributors);
+}
+
+
+void BtAboutDialog::init_sword_tab()
+{
+ selectTab(2);
+ setTabText("Sword" );
+
+ QString version( sword::SWVersion::currentVersion.getText());
+ QString content = make_br() + make_br();
+ content += make_center(make_bold(tr("SWORD library version %1").arg(version)));
+ content += make_br();
+
+ content += tr("BibleTime makes use of the SWORD Project. The SWORD Project is the CrossWire Bible Society's free Bible software project. Its purpose is to create cross-platform open-source tools-- covered by the GNU General Public License-- that allow programmers and Bible societies to write new Bible software more quickly and easily.");
+ content += make_br() + make_br();
+ content += tr("The SWORD Project") + make_br();
+ content += make_link("http://www.crosswire.org/sword/index.jsp","www.crosswire.org/sword/index.jsp");
+
+ setHtml(content);
+
+}
+
+void BtAboutDialog::init_qt_tab()
+{
+ selectTab(3);
+ setTabText("Qt");
+ QString content;
+ content += make_br() + make_br();
+ content += make_center(make_bold("Qt"));
+ content += make_br();
+ content += tr("This program uses Qt Open Source Edition version %1.").arg(qVersion());
+ //content += qVersion();
+ content += make_br() + make_br();
+ content += tr("Qt Open Source Edition is intended for the development of Open Source applications.");
+ content += " ";
+ content += tr("Qt is a C++ toolkit for cross-platform application development.");
+ content += make_br() + make_br();
+ content += tr("Please see ");
+ content += make_link("http://qtsoftware.com/company/model/","qtsoftware.com/company/model");
+ content += tr(" for an overview of Qt licensing.");
+ QString qt = make_html(make_head("") + make_body(content));
+ setHtml(qt);
+}
+
+void BtAboutDialog::init_lic_tab()
+{
+ selectTab(4);
+ setTabText(tr("License"));
+
+ QByteArray text;
+ text += tr("BibleTime is released under the GPL license.");
+ text += " ";
+ text += tr("You can download and use (but not distribute) the program for personal, private, public or commercial purposes without restrictions.");
+ text += " ";
+ text += tr("You can give away or distribute the program if you also distribute the corresponding source code.");
+ text += "<br><br>";
+ //text += tr("It is allowed to distribute software under GPL for a small fee, but it must be accompanied with the complete source code, and the fact that it is freely available with no cost must not be hidden.");
+ //text += "<br><br>";
+ text += tr("The complete legally binding license is below.");
+
+ QFile licFile(util::filesystem::DirectoryUtil::getLicenseDir().path() + "/license.html");
+ if (licFile.open(QFile::ReadOnly))
+ {
+ QByteArray html;
+ while (!licFile.atEnd())
+ {
+ QByteArray line = licFile.readLine();
+ html = html + line;
+ }
+ licFile.close();
+ html.replace("TRANSLATED TEXT", text);
+ setHtml(QString(html));
+ }
+}
+
+
+
+// Helper functions
+
+static QString make_center(const QString& content)
+{
+ return "<center>" + content + "</center>";
+}
+
+static QString make_br()
+{
+ return "<br>";
+}
+
+static QString make_bold(const QString& content)
+{
+ return "<b>" + content + "</b>";
+}
+
+static QString make_html(const QString& content)
+{
+ return "<html>" + content + "</html>";
+}
+
+static QString make_head(const QString& content)
+{
+ return "<head>" + content + "</head>";
+}
+
+static QString make_body(const QString& content)
+{
+ return "<body>" + content + "</body>";
+}
+
+static QString make_link(const QString& link, const QString& text)
+{
+ return "<a href=\"" + link + "\">" + text +"</a>";
+}
+
+static QString make_version()
+{
+// return "";
+ return BT_VERSION;
+}
+
+static QString make_file_icon(const QString& icon)
+{
+ QString dir = "<img src=file://" + util::filesystem::DirectoryUtil::getIconDir().path();
+ return dir + "/" + icon +".png >";
+}
+
diff --git a/src/frontend/htmldialogs/btaboutdialog.h b/src/frontend/htmldialogs/btaboutdialog.h
new file mode 100644
index 0000000..067cad7
--- /dev/null
+++ b/src/frontend/htmldialogs/btaboutdialog.h
@@ -0,0 +1,29 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTABOUTDIALOG_H
+#define BTABOUTDIALOG_H
+
+#include "bttabhtmldialog.h"
+
+class BtAboutDialog : public BtTabHtmlDialog
+{
+ Q_OBJECT
+
+ public:
+ BtAboutDialog(QWidget *parent=0, Qt::WindowFlags wflags = Qt::Dialog);
+ ~BtAboutDialog();
+ void init_bt_tab();
+ void init_contributors_tab();
+ void init_sword_tab();
+ void init_qt_tab();
+ void init_lic_tab();
+};
+
+#endif
diff --git a/src/frontend/htmldialogs/bttabhtmldialog.cpp b/src/frontend/htmldialogs/bttabhtmldialog.cpp
new file mode 100644
index 0000000..f8a83f7
--- /dev/null
+++ b/src/frontend/htmldialogs/bttabhtmldialog.cpp
@@ -0,0 +1,140 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "bttabhtmldialog.h" // See this file for more documentation of BtTabHtmlDialog
+#include "util/dialogutil.h"
+#include "util/directoryutil.h"
+
+#include <QDialog>
+#include <QDialogButtonBox>
+#include <QVBoxLayout>
+#include <QWebView>
+#include <QMenu>
+#include <QTabWidget>
+#include <QDesktopServices>
+#include <QContextMenuEvent>
+
+BtTabHtmlDialog::BtTabHtmlDialog
+ (const QString& title, int tabs, QWidget *parent, Qt::WindowFlags wflags )
+ : QDialog(parent, wflags), m_webView(0), m_tabWidget(0), m_tabs(tabs)
+{
+ //Set the flag to destroy when closed
+ setAttribute(Qt::WA_DeleteOnClose);
+ setWindowTitle(title);
+ resize(400, 300);
+
+ QVBoxLayout *vboxLayout = new QVBoxLayout(this);
+ if (tabs == 0)
+ {
+ m_webView = new BtWebView(this);
+ init_connections(m_webView);
+ vboxLayout->addWidget(m_webView);
+ m_webView->setHtml("Hi");
+ }
+ else
+ {
+ m_tabWidget = new QTabWidget(this);
+ vboxLayout->addWidget(m_tabWidget);
+ for (int i=0; i<tabs; i++)
+ {
+ QWebView* webView = new BtWebView(this);
+ init_connections(webView);
+ webView->setObjectName("View" + QString::number(i));
+ webView->setHtml(" ");
+ m_tabWidget->addTab(webView,"Tab" + QString::number(i));
+ m_tabWidget->show();
+ }
+ }
+
+ QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, this);
+ util::prepareDialogBox(buttonBox);
+ vboxLayout->addWidget(buttonBox);
+
+ bool ok;
+ ok = connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ Q_ASSERT(ok);
+ ok = connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+ Q_ASSERT(ok);
+}
+
+BtTabHtmlDialog::~BtTabHtmlDialog()
+{
+}
+
+void BtTabHtmlDialog::init_connections(QWebView* webView)
+{
+ webView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
+ bool ok = connect(webView, SIGNAL(linkClicked(QUrl)), this, SLOT(linkClicked(QUrl)));
+ Q_ASSERT(ok);
+}
+
+void BtTabHtmlDialog::linkClicked(const QUrl url)
+{
+ QDesktopServices::openUrl(url);
+}
+
+void BtTabHtmlDialog::selectTab(int tab)
+{
+ Q_ASSERT(tab >= 0 && tab < m_tabWidget->count());
+ m_tabWidget->setCurrentIndex(tab);
+}
+
+QWebView* BtTabHtmlDialog::webView()
+{
+ QWebView* webview = 0;
+ if (m_tabs == 0)
+ webview = m_webView;
+ else
+ {
+ QWidget* widget = m_tabWidget->currentWidget();
+ QString name = widget->objectName();
+ webview = qobject_cast<QWebView*>(widget);
+ }
+ Q_ASSERT(webview != 0);
+ return webview;
+}
+
+void BtTabHtmlDialog::setHtml(const QString& html, const QUrl& baseUrl)
+{
+ QUrl url = baseUrl;
+ if (url == QUrl())
+ {
+ QString dir = "file://" + util::filesystem::DirectoryUtil::getIconDir().path();
+ url.setUrl(dir);
+ }
+ webView()->setHtml(html,url);
+}
+
+void BtTabHtmlDialog::setUrl(const QUrl& url)
+{
+ webView()->setUrl(url);
+}
+
+void BtTabHtmlDialog::setTabText(const QString& tabName)
+{
+ Q_ASSERT(m_tabs != 0); // There are no tabs to name
+ int index = m_tabWidget->currentIndex();
+ m_tabWidget->setTabText(index,tabName);
+}
+
+// ******************* BtWebView *******************
+
+BtWebView::BtWebView(QWidget* parent)
+ : QWebView(parent), m_popup(0)
+{
+ m_popup = new QMenu(this);
+ QAction* copyAction = pageAction(QWebPage::Copy);
+ m_popup->addAction(copyAction);
+}
+
+void BtWebView::contextMenuEvent(QContextMenuEvent* event)
+{
+ m_popup->exec(event->globalPos());
+}
+
diff --git a/src/frontend/htmldialogs/bttabhtmldialog.h b/src/frontend/htmldialogs/bttabhtmldialog.h
new file mode 100644
index 0000000..2b40f12
--- /dev/null
+++ b/src/frontend/htmldialogs/bttabhtmldialog.h
@@ -0,0 +1,87 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTTABDIALOG_H
+#define BTTABDIALOG_H
+
+#include <QDialog>
+#include <QString>
+#include <QUrl>
+#include <QWebView>
+
+class QTabWidget;
+class QMenu;
+
+// This class creates a dialog with zero or more tabs. For zero tabs it is
+// just a single QWebView inside the dialog. For 1 or more tabs, each tab
+// contains a separate QWebView. Each QWebView can have either plain text or
+// html text. The class will automatically delete itself when closed.
+// The class can either be directly called or subclassed. The dialog is not modal.
+
+// Typical direct usage:
+//
+// Zero tabs
+// BtTabHtmlDialog* dlg = new BtTabHtmlDialog("My Title", 0, parent);
+// dlg->setHtml(htmlText);
+// dlg->show();
+//
+// or
+//
+// Two tabs
+// BtTabHtmlDialog* dlg = new BtTabHtmlDialog("My Title", 2, parent);
+// dlg->selectTab(0);
+// dlg->setTabText(nameOfTab0);
+// dlg->setHtml(htmlText0);
+// dlg->selectTab(1);
+// dlg->setTabText(nameOfTab1);
+// dlg->setHtml(htmlText1);
+// dlg->show();
+
+
+class BtTabHtmlDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ BtTabHtmlDialog(const QString& title, int numberTabs, QWidget *parent=0, Qt::WindowFlags wflags = Qt::Dialog);
+ ~BtTabHtmlDialog();
+ void selectTab(int tab);
+ void setTabText(const QString& tabName);
+
+// See QWebView::setHtml()
+ void setHtml(const QString& html, const QUrl& baseUrl=QUrl());
+
+// See QWebView::setUrl()
+ void setUrl(const QUrl& url);
+
+private slots:
+ void linkClicked(const QUrl url);
+
+private:
+ void init_connections(QWebView* webView);
+ QWebView* webView();
+
+ QWebView* m_webView;
+ QTabWidget* m_tabWidget;
+ int m_tabs;
+};
+
+
+class BtWebView : public QWebView
+{
+public:
+ BtWebView(QWidget* parent=0);
+
+protected:
+ void contextMenuEvent(QContextMenuEvent* event);
+
+private:
+ QMenu* m_popup;
+};
+
+#endif
diff --git a/src/frontend/keychooser/bthistory.cpp b/src/frontend/keychooser/bthistory.cpp
new file mode 100644
index 0000000..7eae47f
--- /dev/null
+++ b/src/frontend/keychooser/bthistory.cpp
@@ -0,0 +1,130 @@
+//
+// C++ Implementation: BTHistory
+//
+// Description:
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 2007
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#include "bthistory.h"
+
+#include "backend/keys/cswordkey.h"
+
+
+#include <QAction>
+#include <QList>
+
+#include <QDebug>
+
+
+BTHistory::BTHistory(QWidget* parent)
+ : m_historyList(),
+ m_index(-1),
+ m_inHistoryFunction(false)
+{
+ setParent(parent);
+ Q_ASSERT(class_invariant());
+}
+
+void BTHistory::add(CSwordKey* newKey) {
+ qDebug("BTHistory::add");
+ Q_ASSERT(newKey);
+ // Add new key Action after current index if we were not using the history functions,
+ // if it's not a duplicate and if it's not empty.
+ if (!m_inHistoryFunction && ((m_index < 0) || (newKey->key() != m_historyList.at(m_index)->text()) ))
+ {
+ if (!newKey->key().isEmpty()) {
+ m_historyList.insert(++m_index, new QAction(newKey->key(), this));
+ }
+ // TODO: history limit?
+ sendChangedSignal();
+ }
+ Q_ASSERT(class_invariant());
+}
+
+void BTHistory::move(QAction* historyItem)
+{
+ qDebug("BTHistory::move");
+ //Q_ASSERT(historyItem);
+ Q_ASSERT(m_historyList.count());
+
+ m_inHistoryFunction = true;
+ //find the action in the list
+ m_index = m_historyList.indexOf(historyItem);
+ //move to the selected item in the list, it will be the current item
+ QString newKey = m_historyList.at(m_index)->text();
+ emit historyMoved(newKey); // signal to "outsiders"; key has been changed
+ sendChangedSignal();
+
+ m_inHistoryFunction = false;
+ Q_ASSERT(class_invariant());
+}
+
+void BTHistory::back()
+{
+ qDebug("BTHistory::back");
+ if ( m_index >= 1) {
+ move(m_historyList.at(m_index-1));
+ }
+ Q_ASSERT(class_invariant());
+}
+
+void BTHistory::fw()
+{
+ qDebug("BTHistory::fw");
+ if (m_index < (m_historyList.size()-1)) {
+ move(m_historyList.at(m_index+1));
+ }
+ Q_ASSERT(class_invariant());
+}
+
+QList<QAction*> BTHistory::getBackList()
+{
+ qDebug("BTHistory::getBackList");
+
+ QList<QAction*> list;
+ for (int i = m_index-1; i >= 0; --i) {
+ list.append(m_historyList.at(i));
+ }
+
+ qDebug() << "return:" << list;
+ Q_ASSERT(class_invariant());
+ return list;
+}
+
+QList<QAction*> BTHistory::getFwList()
+{
+ qDebug("BTHistory::getFwList");
+
+ QList<QAction*> list;
+ //qDebug() << "historyList.size:" << m_historyList.size();
+ for (int i = m_index+1; i < m_historyList.size(); ++i) {
+ //qDebug() << "i:" << i;
+ list.append(m_historyList.at(i));
+ }
+ qDebug() << "return:" << list;
+
+ Q_ASSERT(class_invariant());
+ return list;
+}
+
+void BTHistory::sendChangedSignal()
+{
+ bool backEnabled = m_index > 0; //there are items in the back list
+ bool fwEnabled = m_historyList.size() > m_index+1; //there are items in the fw list
+ emit historyChanged(backEnabled, fwEnabled);
+ Q_ASSERT(class_invariant());
+}
+
+bool BTHistory::class_invariant()
+{
+ for (int i = 0; i < m_historyList.size(); ++i) {
+ if (!m_historyList.at(i) || m_historyList.at(i)->text().isEmpty()) return false;
+ }
+ if (!(m_index >= -1 && m_index < m_historyList.size())) return false;
+ return true;
+}
diff --git a/src/frontend/keychooser/bthistory.h b/src/frontend/keychooser/bthistory.h
new file mode 100644
index 0000000..34e5fdb
--- /dev/null
+++ b/src/frontend/keychooser/bthistory.h
@@ -0,0 +1,80 @@
+//
+// C++ Interface: BTHistory
+//
+// Description:
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 2007
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#ifndef BTHISTORY_H
+#define BTHISTORY_H
+
+#include <QList>
+#include <QObject>
+
+
+class CSwordKey;
+class QAction;
+class QWidget;
+
+class BTHistory: public QObject
+{
+ Q_OBJECT
+
+public:
+ BTHistory(QWidget* parent);
+ ~BTHistory() {};
+
+ /**
+ * Return a list of Actions behind the current point, the first of the history list will be the
+ * last in the returned list and vice versa.
+ */
+ QList<QAction*> getBackList();
+ /**
+ * Return a list of Actions after the current point.
+ */
+ QList<QAction*> getFwList();
+
+public slots:
+ /**
+ * Add a new key to the history.
+ */
+ void add(CSwordKey* newKey);
+ /**
+ * Move the current point in history list.
+ */
+ void move(QAction*);
+ /**
+ * Go back one step in history.
+ */
+ void back();
+ /**
+ * Go forward one step in history.
+ */
+ void fw();
+
+signals:
+ /**
+ * Signal will be sent when the history has been changed (added, moved)
+ */
+ void historyChanged(bool backEnabled, bool fwEnabled);
+ /**
+ * Signal will be sent when the current point in history has moved
+ */
+ void historyMoved(QString& newKey);
+
+private:
+
+ void sendChangedSignal();
+ bool class_invariant();
+
+ QList<QAction*> m_historyList;
+ int m_index; //pointer to the current item; -1==empty, 0==first etc.
+ bool m_inHistoryFunction; //to prevent recursive behaviour
+};
+
+#endif
diff --git a/src/frontend/keychooser/cbookkeychooser.cpp b/src/frontend/keychooser/cbookkeychooser.cpp
new file mode 100644
index 0000000..411bf26
--- /dev/null
+++ b/src/frontend/keychooser/cbookkeychooser.cpp
@@ -0,0 +1,278 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+#include "cbookkeychooser.h"
+
+#include "bthistory.h"
+
+#include "backend/keys/cswordtreekey.h"
+#include "backend/drivers/cswordbookmoduleinfo.h"
+#include "backend/config/cbtconfig.h"
+
+//Qt includes
+#include <QWidget>
+#include <QHBoxLayout>
+#include <QList>
+#include <QDebug>
+
+QMap<QObject*, int> boxes;
+
+CBookKeyChooser::CBookKeyChooser(QList<CSwordModuleInfo*> modules, CSwordKey *key, QWidget *parent)
+ : CKeyChooser(modules, key, parent), m_layout(0)
+{
+
+ setModules(modules, false);
+ m_key = dynamic_cast<CSwordTreeKey*>(key);
+ if (!m_modules.count()) {
+ m_key = 0;
+ }
+
+ setModules(modules, true);
+ setKey(key);
+
+ adjustFont();
+ connect(this, SIGNAL(keyChanged(CSwordKey*)), history(), SLOT(add(CSwordKey*)) );
+}
+
+CBookKeyChooser::~CBookKeyChooser() {}
+
+void CBookKeyChooser::setKey(CSwordKey* newKey)
+{
+ setKey(newKey, true);
+}
+
+/** Sets a new key to this keychooser */
+void CBookKeyChooser::setKey(CSwordKey* newKey, const bool emitSignal)
+{
+ if (m_key != newKey) { //set the internal key to the new one
+ m_key = dynamic_cast<CSwordTreeKey*>(newKey);
+ }
+
+ QString oldKey = m_key->key(); //string backup of key
+
+ if (oldKey.isEmpty()) { //don't set keys equal to "/", always use a key which may have content
+ m_key->firstChild();
+ oldKey = m_key->key();
+ }
+
+ const int oldOffset = m_key->getOffset(); //backup key position
+
+ QStringList siblings; //split up key
+ if (m_key && !oldKey.isEmpty()) {
+ siblings = oldKey.split('/', QString::SkipEmptyParts);
+ }
+
+ int depth = 0;
+ int index = 0;
+
+ m_key->root(); //start iteration at root node
+
+ while( m_key->firstChild() && (depth < siblings.count()) ) {
+ QString key = m_key->key();
+ index = (depth == 0) ? -1 : 0;
+
+ bool found = false;
+
+ do { //look for matching sibling
+ ++index;
+ found = (m_key->getLocalNameUnicode() == siblings[depth]);
+ }
+ while (!found && m_key->nextSibling());
+
+ if (found)
+ key = m_key->key(); //found: change key to this level
+ else
+ m_key->key(key); //not found: restore old key
+
+ setupCombo(key, depth, index);
+
+ //last iteration: check to see if another box can be filled with child entries
+ if (depth == siblings.count()-1 && m_key->hasChildren())
+ {
+ m_key->firstChild();
+ setupCombo(m_key->key(), ++depth, 0);
+ }
+
+ depth++;
+ }
+
+ //clear the combos which were not filled
+ for (; depth < m_modules.first()->depth(); ++depth) {
+ CKeyChooserWidget* chooser = m_chooserWidgets.at(depth);
+ if (chooser) chooser->reset(0,0,false);
+ }
+
+ if (oldKey.isEmpty()) {
+ m_key->root();
+ }
+ else {
+ //m_key->key(oldKey);
+ m_key->setOffset(oldOffset);
+ }
+
+ if (emitSignal) emit keyChanged(m_key);
+}
+
+/** Returns the key of this kechooser. */
+CSwordKey* CBookKeyChooser::key()
+{
+ return m_key;
+}
+
+/** Sets another module to this keychooser */
+void CBookKeyChooser::setModules(const QList<CSwordModuleInfo*>& modules, const bool refresh)
+{
+ m_modules.clear();
+
+ // for (modules.first(); modules.current(); modules.next()) {
+ QList<CSwordModuleInfo*>::const_iterator end_it = modules.end();
+ for (QList<CSwordModuleInfo*>::const_iterator it(modules.begin()); it != end_it; ++it) {
+ if ( (*it)->type() == CSwordModuleInfo::GenericBook ) {
+ if (CSwordBookModuleInfo* book = dynamic_cast<CSwordBookModuleInfo*>(*it)) {
+ m_modules.append(book);
+ }
+ }
+ }
+
+ //refresh the number of combos
+ if (refresh && m_modules.count() && m_key) {
+ if (!m_layout) {
+ m_layout = new QHBoxLayout(this);
+ m_layout->setSpacing(0);
+ m_layout->setContentsMargins(0,0,0,0);
+ }
+
+ qDeleteAll(m_chooserWidgets);
+ m_chooserWidgets.clear();
+
+ for (int i = 0; i < m_modules.first()->depth(); ++i) {
+ // Create an empty keychooser, don't handle next/prev signals
+ CKeyChooserWidget* w = new CKeyChooserWidget(0, false, this);
+ m_chooserWidgets.append( w );
+
+ //don't allow a too high width, try to keep as narrow as possible
+ //to aid users with smaller screen resolutions
+ int totalWidth = 200; //only 1 level
+ if (m_modules.first()->depth() > 1) {
+ if (m_modules.first()->depth() > 3)
+ totalWidth = 400; //4+ levels
+ else
+ totalWidth = 300; //2-3 levels
+ }
+
+ int maxWidth = (int) ((float) totalWidth / (float) m_modules.first()->depth());
+
+ w->comboBox()->setMaximumWidth(maxWidth);
+ w->comboBox()->setCurrentIndex(0);
+
+ connect(w, SIGNAL(changed(int)), SLOT(keyChooserChanged(int)));
+ connect(w, SIGNAL(focusOut(int)), SLOT(keyChooserChanged(int)));
+
+ m_layout->addWidget(w);
+ boxes[w] = i;
+
+ w->show();
+ }
+
+ //set the tab order of the key chooser widgets
+
+ CKeyChooserWidget* chooser = 0;
+ CKeyChooserWidget* chooser_prev = 0;
+ const int count = m_chooserWidgets.count();
+ for (int i = 0; i < count; ++i) {
+ chooser = m_chooserWidgets.at(i);
+ Q_ASSERT(chooser);
+
+ if (chooser && chooser_prev) {
+ QWidget::setTabOrder(chooser_prev, chooser);
+ }
+
+ chooser_prev = chooser;
+ }
+ QWidget::setTabOrder(chooser, 0);
+
+ updateKey(m_key);
+ adjustFont(); // only when refresh is set.
+ }
+}
+
+/** No descriptions */
+void CBookKeyChooser::adjustFont()
+{
+ //Make sure the entries are displayed correctly.
+ QListIterator<CKeyChooserWidget*> it(m_chooserWidgets);
+ while (it.hasNext()) {
+ it.next()->comboBox()->setFont( CBTConfig::get( m_modules.first()->language() ).second );
+ }
+}
+
+/** Refreshes the content. */
+void CBookKeyChooser::refreshContent()
+{
+ if (m_key) {
+ updateKey( m_key ); //refresh with current key
+ }
+}
+
+void CBookKeyChooser::setupCombo(const QString key, const int depth, const int currentItem)
+{
+ CKeyChooserWidget* chooserWidget = m_chooserWidgets.at(depth);
+
+ CSwordTreeKey tmpKey(*m_key);
+ tmpKey.key(key);
+ tmpKey.parent();
+ tmpKey.firstChild();
+
+ QStringList items;
+ if (depth > 0) items << QString::null; //insert an empty item at the top
+
+ do {
+ items << tmpKey.getLocalNameUnicode();
+ }
+ while (tmpKey.nextSibling());
+
+ if (chooserWidget) chooserWidget->reset(items,currentItem,false);
+}
+
+/** A keychooser changed. Update and emit a signal if necessary. */
+void CBookKeyChooser::keyChooserChanged(int /*newIndex*/)
+{
+ const int activeID = boxes[const_cast<QObject*>(sender())]; //no so good code!
+
+ QStringList items;
+ CKeyChooserWidget* chooser;
+
+ for (int i = 0; i < m_chooserWidgets.count(); ++i) {
+ chooser = m_chooserWidgets.at(i);
+ const QString currentText = (chooser && chooser->comboBox()) ? chooser->comboBox()->currentText() : QString::null;
+
+ if (currentText.isEmpty() || i > activeID) {
+ break;
+ }
+
+ items << currentText;
+ }
+
+ QString newKey("/");
+ newKey.append(items.join("/"));
+
+ m_key->key(newKey);
+ setKey(m_key);
+}
+
+/** Updates the keychoosers for the given key but emit no signal. */
+void CBookKeyChooser::updateKey(CSwordKey* key)
+{
+ setKey(key, false);
+}
+
+void CBookKeyChooser::setKey(QString& newKey)
+{
+ m_key->key(newKey);
+ setKey(m_key);
+}
diff --git a/src/frontend/keychooser/cbookkeychooser.h b/src/frontend/keychooser/cbookkeychooser.h
new file mode 100644
index 0000000..80dd03f
--- /dev/null
+++ b/src/frontend/keychooser/cbookkeychooser.h
@@ -0,0 +1,86 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CBOOKKEYCHOOSER_H
+#define CBOOKKEYCHOOSER_H
+
+//BibleTime includes
+#include "ckeychooser.h"
+#include "ckeychooserwidget.h"
+
+#include <QList>
+
+class CSwordKey;
+class CSwordBookModuleInfo;
+class CSwordTreeKey;
+
+namespace sword {
+ class TreeKeyIdx;
+}
+
+/** The keychooser implementation for books.
+ * @author The BibleTime team
+ */
+class CBookKeyChooser : public CKeyChooser {
+ Q_OBJECT
+public:
+ CBookKeyChooser(QList<CSwordModuleInfo*> modules, CSwordKey *key=0, QWidget *parent=0);
+ ~CBookKeyChooser();
+ /**
+ * Refreshes the content.
+ */
+ virtual void refreshContent();
+ /**
+ * Sets another module to this keychooser
+ */
+ virtual void setModules(const QList<CSwordModuleInfo*>& modules, const bool refresh = false);
+ /**
+ * Returns the key of this keychooser
+ */
+ virtual CSwordKey* key();
+ /**
+ * Sets a new key to this keychooser
+ */
+ virtual void setKey(CSwordKey*);
+ /**
+ * Sets a new key to this keychooser
+ */
+ void setKey(CSwordKey*, const bool emitSignal);
+
+
+public slots: // Public slots
+ /**
+ * Updates the keychoosers for the given key but emit no signal.
+ */
+ void updateKey(CSwordKey*);
+
+protected: // Protected methods
+ /**
+ * Fills the combo given by depth with the items from the key having depth "depth".
+ * The parent sibling is given by key.
+ */
+ void setupCombo(const QString key, const int depth, const int currentItem);
+ /** No descriptions */
+ virtual void adjustFont();
+
+protected slots:
+ /**
+ * A keychooser changed. Update and emit a signal if necessary.
+ */
+ void keyChooserChanged(int);
+ virtual void setKey(QString& newKey);
+
+private:
+ QList<CKeyChooserWidget*> m_chooserWidgets;
+ QList<CSwordBookModuleInfo*> m_modules;
+ CSwordTreeKey *m_key;
+ QHBoxLayout* m_layout;
+};
+
+#endif
diff --git a/src/frontend/keychooser/cbooktreechooser.cpp b/src/frontend/keychooser/cbooktreechooser.cpp
new file mode 100644
index 0000000..7297d76
--- /dev/null
+++ b/src/frontend/keychooser/cbooktreechooser.cpp
@@ -0,0 +1,200 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+#include "cbooktreechooser.h"
+
+#include "bthistory.h"
+
+#include "backend/keys/cswordtreekey.h"
+#include "backend/drivers/cswordbookmoduleinfo.h"
+#include "backend/config/cbtconfig.h"
+
+#include <QHBoxLayout>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+#include <QHeaderView>
+#include <QApplication>
+
+#include <QDebug>
+
+CBookTreeChooser::CBookTreeChooser(QList<CSwordModuleInfo*> modules, CSwordKey *key, QWidget *parent)
+: CKeyChooser(modules, key, parent),
+m_key( dynamic_cast<CSwordTreeKey*>(key) ) {
+
+ setModules(modules, false);
+
+ //if there is no module there is no key either
+ if (!modules.count()) {
+ m_modules.clear();
+ m_key = 0;
+ }
+
+ //now setup the keychooser widgets
+ m_treeView = new QTreeWidget(this);
+
+ QHBoxLayout* layout = new QHBoxLayout(this);
+ layout->setSpacing(0);
+ layout->setContentsMargins(0,0,0,0);
+ layout->addWidget(m_treeView);
+ m_treeView->header()->hide();
+
+ //when user selects the item whe must react
+ connect(m_treeView, SIGNAL(currentItemChanged ( QTreeWidgetItem*, QTreeWidgetItem*)), SLOT(itemActivated(QTreeWidgetItem*)));
+
+ setKey(key);
+ adjustFont();
+ connect(this, SIGNAL(keyChanged(CSwordKey*)), history(), SLOT(add(CSwordKey*)) );
+}
+
+CBookTreeChooser::~CBookTreeChooser() {}
+
+/** Sets a new key to this keychooser. Inherited from ckeychooser. */
+void CBookTreeChooser::setKey(CSwordKey* key) {
+ setKey(key, false);
+}
+
+/** Sets a new key to this keychooser. Inherited from ckeychooser. */
+void CBookTreeChooser::setKey(CSwordKey* newKey, const bool emitSignal) {
+ qDebug("CBookTreeChooser::setKey");
+
+ if (m_key != newKey ) {
+ m_key = dynamic_cast<CSwordTreeKey*>(newKey);
+ }
+
+ const QString key = m_key->key(); //key as text, path
+
+ QTreeWidgetItem* matching_item = m_treeView->topLevelItem(0);
+
+ QTreeWidgetItemIterator it(m_treeView);
+ while (*it) {
+ if ((*it)->text(1) == key)
+ {
+ matching_item = (*it);
+ break;
+ }
+ ++it;
+ }
+
+ m_treeView->setCurrentItem( matching_item );
+ m_treeView->scrollToItem(matching_item);
+
+ if (emitSignal) {
+ emit keyChanged(m_key);
+ }
+}
+
+/** Returns the key of this keychooser. Inherited from ckeychooser.*/
+CSwordKey* CBookTreeChooser::key() {
+ return m_key;
+}
+
+/** Sets another module to this keychooser. Inherited from ckeychooser (therefore
+the list of modules instead of one). */
+void CBookTreeChooser::setModules(const QList<CSwordModuleInfo*>& modules, const bool refresh) {
+
+ //Add given modules into private list
+ m_modules.clear();
+ QList<CSwordModuleInfo*>::const_iterator end_it = modules.end();
+ for (QList<CSwordModuleInfo*>::const_iterator it(modules.begin()); it != end_it; ++it) {
+ if (CSwordBookModuleInfo* book = dynamic_cast<CSwordBookModuleInfo*>(*it)) {
+ m_modules.append(book);
+ }
+ }
+
+ //if there exists a module and a key, setup the visible tree
+ if (refresh && m_modules.count() && m_key) {
+ const uint offset = m_key->getOffset(); //actually unnecessary, taken care of in setupTree
+ setupTree();
+ m_key->setOffset( offset );
+
+ adjustFont(); //only when refresh is set.
+ }
+}
+
+/** From ckeychooser. */
+void CBookTreeChooser::adjustFont() {
+ //Make sure the entries are displayed correctly.
+ m_treeView->setFont( CBTConfig::get(m_modules.first()->language()).second );
+
+}
+
+
+/** Refreshes the content. Inherited from ckeychooser. */
+void CBookTreeChooser::refreshContent() {
+ if (m_key) {
+ updateKey(m_key); //refresh with current key
+ }
+}
+
+
+//TODO: itemActivated is called too many times. As tested in GDB, the function
+//is called twice with the pointer to the correct book and twice with a null
+//pointer.
+
+/** Slot for signal when item is selected by user. */
+void CBookTreeChooser::itemActivated( QTreeWidgetItem* item ) {
+ qDebug("CBookTreeChooser::itemActivated");
+ //Sometimes Qt calls this function with a null pointer.
+ if (item){
+ m_key->key(item->text(1));
+ //tell possible listeners about the change
+ emit keyChanged(m_key);
+ }
+}
+
+/** Inherited from ckeychooser */
+void CBookTreeChooser::updateKey( CSwordKey* key ) {
+ setKey(key, false);
+}
+
+/** Reimplementation to handle tree creation on show. */
+void CBookTreeChooser::show() {
+ CKeyChooser::show();
+
+ if (!m_treeView->topLevelItemCount()) {
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ setupTree(); //create the tree structure
+ m_treeView->resize(m_treeView->sizeHint());
+ QApplication::restoreOverrideCursor();
+ }
+}
+
+/** Creates the tree structure in the view. */
+void CBookTreeChooser::setupTree() {
+ m_treeView->clear();
+
+ const unsigned long offset = m_key->getOffset();
+
+ m_key->root();
+ addKeyChildren(m_key, m_treeView->invisibleRootItem());
+
+ m_key->setOffset( offset );
+ setKey(m_key, false); //the module may have changed
+}
+
+/** Populates tree widget with items. */
+void CBookTreeChooser::addKeyChildren(CSwordTreeKey* key, QTreeWidgetItem* item) {
+ if (key->hasChildren()) {
+ key->firstChild();
+ do {
+ QStringList columns;
+ columns << key->getLocalNameUnicode() << key->key();
+ QTreeWidgetItem *i = new QTreeWidgetItem(item, columns, QTreeWidgetItem::Type);
+ i->setData(0, Qt::ToolTipRole, key->getLocalNameUnicode());
+ int offset = key->getOffset();
+ addKeyChildren(key, i);
+ key->setOffset(offset);
+ } while (key->nextSibling());
+ }
+}
+
+void CBookTreeChooser::setKey(QString& newKey)
+{
+ m_key->key(newKey);
+ setKey(m_key);
+}
diff --git a/src/frontend/keychooser/cbooktreechooser.h b/src/frontend/keychooser/cbooktreechooser.h
new file mode 100644
index 0000000..455ba01
--- /dev/null
+++ b/src/frontend/keychooser/cbooktreechooser.h
@@ -0,0 +1,87 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CBOOKTREECHOOSER_H
+#define CBOOKTREECHOOSER_H
+
+
+/** The treechooser implementation for books.
+ * @author The BibleTime team
+ */
+//BibleTime includes
+#include "ckeychooser.h"
+#include "ckeychooserwidget.h"
+
+
+class CSwordKey;
+class CSwordBookModuleInfo;
+class CSwordTreeKey;
+
+namespace sword {
+ class TreeKeyIdx;
+}
+
+class QTreeWidget;
+class QTreeWidgetItem;
+
+/** The keychooser implementation for books.
+ * @author The BibleTime team
+ */
+class CBookTreeChooser : public CKeyChooser {
+ Q_OBJECT
+public:
+ CBookTreeChooser(QList<CSwordModuleInfo*> modules, CSwordKey *key=0, QWidget *parent=0);
+ ~CBookTreeChooser();
+ /**
+ * Refreshes the content.
+ */
+ virtual void refreshContent();
+ /**
+ * Sets another module to this keychooser
+ */
+ virtual void setModules(const QList<CSwordModuleInfo*>& modules, const bool refresh = true);
+ /**
+ * Returns the key of this keychooser.
+ */
+ virtual CSwordKey* key();
+ /**
+ * Sets a new key to this keychooser
+ */
+ virtual void setKey(CSwordKey*);
+ void setKey(CSwordKey*, const bool emitSinal);
+
+public slots: // Public slots
+ virtual void updateKey( CSwordKey* );
+ /**
+ * Reimplementation to handle tree creation on show.
+ */
+ virtual void show();
+
+
+protected: // Protected methods
+ /**
+ * Creates the first level of the tree structure.
+ */
+ void setupTree();
+ virtual void adjustFont();
+ void addKeyChildren(CSwordTreeKey* key, QTreeWidgetItem* item);
+
+protected slots: // Protected slots
+ void itemActivated( QTreeWidgetItem* item );
+ void setKey(QString& newKey);
+
+private:
+ QList<CSwordBookModuleInfo*> m_modules;
+ CSwordTreeKey* m_key;
+ QTreeWidget* m_treeView;
+};
+
+#endif
diff --git a/src/frontend/keychooser/ckeychooser.cpp b/src/frontend/keychooser/ckeychooser.cpp
new file mode 100644
index 0000000..f0650d6
--- /dev/null
+++ b/src/frontend/keychooser/ckeychooser.cpp
@@ -0,0 +1,64 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#include "ckeychooser.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/drivers/cswordbiblemoduleinfo.h"
+#include "backend/drivers/cswordcommentarymoduleinfo.h"
+#include "backend/drivers/cswordlexiconmoduleinfo.h"
+
+#include "backend/keys/cswordkey.h"
+
+#include "bthistory.h"
+#include "clexiconkeychooser.h"
+#include "versekeychooser/cbiblekeychooser.h"
+#include "cbookkeychooser.h"
+
+#include <QAction>
+#include <QDebug>
+
+CKeyChooser::CKeyChooser(QList<CSwordModuleInfo*>, CSwordKey *, QWidget *parent)
+ : QWidget(parent),
+ m_history(0)
+{
+ //qDebug("CKeyChooser::CKeyChooser");
+ m_history = new BTHistory(this);
+ QObject::connect(history(), SIGNAL(historyMoved(QString&)), this, SLOT(setKey(QString&)));
+}
+
+CKeyChooser::~CKeyChooser() {}
+
+CKeyChooser* CKeyChooser::createInstance(QList<CSwordModuleInfo*> modules, CSwordKey *key, QWidget *parent) {
+ if (!modules.count()) {
+ return 0;
+ }
+
+ switch ( modules.first()->type() ) {
+ case CSwordModuleInfo::Commentary: //Bibles and commentaries use the same key chooser
+ case CSwordModuleInfo::Bible:
+ return new CBibleKeyChooser(modules,key,parent);
+ break;
+ case CSwordModuleInfo::Lexicon:
+ return new CLexiconKeyChooser(modules,key,parent);
+ case CSwordModuleInfo::GenericBook:
+ return new CBookKeyChooser(modules,key,parent);
+ default:
+ return 0;
+ }
+}
+
+
+BTHistory* CKeyChooser::history()
+{
+ return m_history;
+}
+
diff --git a/src/frontend/keychooser/ckeychooser.h b/src/frontend/keychooser/ckeychooser.h
new file mode 100644
index 0000000..d10a74a
--- /dev/null
+++ b/src/frontend/keychooser/ckeychooser.h
@@ -0,0 +1,115 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CKEYCHOOSER_H
+#define CKEYCHOOSER_H
+
+
+class CSwordModuleInfo;
+
+#include <QWidget>
+
+
+class CSwordKey;
+class QAction;
+
+class BTHistory;
+
+
+/**
+ * The base class for the KeyChooser.
+ * Do not use directly, create a KeyChooser with
+ * @ref #createInstance , this will create the proper one
+ * of the classes that inherit from @ref CKeyChooser
+ *
+ * @author The BibleTime team
+ */
+
+class CKeyChooser : public QWidget {
+ Q_OBJECT
+
+public:
+
+ /**
+ * Creates a proper Instance, either
+ *
+ @ref CLexiconKeyChooser or
+ * @ref CBibleKeyChooser
+ * @param info the @ref CModuleInfo to be represented by the KeyChooser
+ * @param key if not NULL, the @ref CKey the KeyChooser should be set to
+ * @param parent the parent of the widget to create
+ */
+ static CKeyChooser* createInstance(QList<CSwordModuleInfo*> modules, CSwordKey *key, QWidget *parent);
+
+
+public slots:
+ /**
+ * sets the @ref CKey
+ * @param key the key which the widget should be set to
+ */
+ virtual void setKey(CSwordKey* key) = 0;
+ /**
+ * sets the @ref CKey
+ * @param key the key which the widget should be set to
+ */
+ virtual void updateKey(CSwordKey* key) = 0;
+ /**
+ * gets the current @ref CKey
+ *
+ * @return the current @ref CKey
+ */
+ virtual CSwordKey* key() = 0;
+ /**
+ * Sets the module of this keychooser and refreshes the comboboxes
+ */
+ virtual void setModules( const QList<CSwordModuleInfo*>& modules, const bool refresh = true ) = 0;
+ /**
+ * Freshes the content of the different key chooser parts.
+ */
+ virtual void refreshContent() = 0;
+
+ /**
+ * Returns the history object of this keychooser.
+ */
+ BTHistory* history();
+
+signals:
+
+ /**
+ * is emitted if the @ref CKey was changed by the user
+ */
+ void keyChanged(CSwordKey* newKey);
+ /**
+ * Is emitted before the key is changed!
+ */
+ void beforeKeyChange(const QString& key);
+
+protected:
+
+ /**
+ * the constructor - DO NOT USE! -- use @ref #createInstance instead!
+ */
+ CKeyChooser(QList<CSwordModuleInfo*> info, CSwordKey *key=0, QWidget *parent=0);
+ virtual ~CKeyChooser();
+ /**
+ * Set the appropriate font do display the modules
+ */
+ virtual void adjustFont() = 0;
+
+protected slots:
+ virtual void setKey(QString& newKey) = 0;
+
+private:
+ BTHistory* m_history;
+
+};
+
+#endif
diff --git a/src/frontend/keychooser/ckeychooserwidget.cpp b/src/frontend/keychooser/ckeychooserwidget.cpp
new file mode 100644
index 0000000..dd8f7a5
--- /dev/null
+++ b/src/frontend/keychooser/ckeychooserwidget.cpp
@@ -0,0 +1,304 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+//BibleTime includes
+#include "ckeychooserwidget.h"
+
+#include "cscrollerwidgetset.h"
+
+//Qt includes
+#include <QString>
+#include <QWheelEvent>
+#include <QFocusEvent>
+#include <QHBoxLayout>
+#include <QComboBox>
+#include <QLineEdit>
+#include <QDebug>
+
+CKCComboBox::CKCComboBox()
+: QComboBox() {
+ setFocusPolicy(Qt::WheelFocus);
+ if (lineEdit()) {
+ installEventFilter( lineEdit() );
+ }
+}
+
+/** Reimplementation. */
+bool CKCComboBox::eventFilter( QObject *o, QEvent *e ) {
+ if (e->type() == QEvent::FocusOut) {
+ QFocusEvent* f = static_cast<QFocusEvent*>(e);
+
+ if (o == lineEdit() && f->reason() == Qt::TabFocusReason) {
+ int index = findText(currentText());
+ if (index == -1) {
+ index = 0;// return 0 if not found
+ }
+ setCurrentIndex( index );
+ emit focusOut( index );
+
+ return false;
+ }
+ else if (f->reason() == Qt::PopupFocusReason) {
+ return false;
+ }
+ else if (f->reason() == Qt::ActiveWindowFocusReason) {
+ emit activated(currentText());
+ return false;
+ }
+ else if (f->reason() == Qt::MouseFocusReason) {
+ emit activated(currentText());
+ return false;
+ }
+ else if (o == this) {
+ emit activated(currentText());
+ return false;
+ }
+ }
+
+ return QComboBox::eventFilter(o,e);
+}
+
+/** Scrolls in the list if the wheel of the mouse was used. */
+void CKCComboBox::wheelEvent( QWheelEvent* e ) {
+ return QComboBox::wheelEvent(e);
+
+ const signed int change = (int)((float)e->delta()/(float)120);
+ int current = currentIndex();
+
+ if ((current+change >= 0) && (current+change<count()) ) {
+ setCurrentIndex(current+change);
+ e->accept();
+ emit activated( currentIndex() );
+ }
+ else {
+ e->ignore();
+ }
+}
+
+//**********************************************************************************/
+
+CKeyChooserWidget::CKeyChooserWidget(int count, const bool useNextPrevSignals, QWidget *parent ) : QWidget(parent) {
+ m_useNextPrevSignals = useNextPrevSignals;
+
+ for (int index=1; index <= count; index++) {
+ m_list.append( QString::number(index) );
+ }
+ init();
+ reset(m_list,0,false);
+}
+
+CKeyChooserWidget::CKeyChooserWidget(QStringList *list, const bool useNextPrevSignals, QWidget *parent ) : QWidget(parent) {
+ m_useNextPrevSignals = useNextPrevSignals;
+
+ if (list) {
+ m_list = *list; //deep copy the items of list
+ }
+ else {
+ m_list.clear();
+ }
+
+ init();
+ reset(m_list,0,false);
+}
+
+void CKeyChooserWidget::reset(const int count, int index, bool do_emit) {
+ //This prevents the widget from resetting during application load, which
+ //produces undesirable behavior.
+ //if (!updatesEnabled())
+ // return;
+
+ m_list.clear();
+ for (int i=1; i <= count; i++) { //TODO: CHECK
+ m_list.append( QString::number(i) );
+ }
+
+ reset(&m_list,index,do_emit);
+}
+
+void CKeyChooserWidget::reset(QStringList& list, int index, bool do_emit) {
+ //This prevents the widget from resetting during application load, which
+ //produces undesirable behavior.
+ //if (!updatesEnabled())
+ // return;
+
+ m_list = list;
+ reset(&m_list,index,do_emit);
+}
+
+
+void CKeyChooserWidget::reset(QStringList *list, int index, bool do_emit) {
+ //if (isResetting || !updatesEnabled())
+ if (isResetting)
+ return;
+
+ // qWarning("starting insert");
+ isResetting = true;
+
+ oldKey = QString::null;
+
+ // m_comboBox->setUpdatesEnabled(false);
+ //DON'T REMOVE THE HIDE: Otherwise QComboBox's sizeHint() function won't work properly
+ m_comboBox->hide();
+ m_comboBox->clear();
+ if (list) {
+ m_comboBox->insertItems(-1, *list);
+ }
+
+ if (!list || (list && !list->count())) { //nothing in the combobox
+ setEnabled(false);
+ }
+ else if (!isEnabled()) { //was disabled
+ setEnabled(true);
+ }
+
+ if (list->count()) {
+ m_comboBox->setCurrentIndex(index);
+ }
+ if (do_emit) {
+ emit changed(m_comboBox->currentIndex());
+ }
+
+ const QSize dummySize = m_comboBox->sizeHint(); //without this function call the combo box won't be properly sized!
+ //DON'T REMOVE OR MOVE THE show()! Otherwise QComboBox's sizeHint() function won't work properly!
+ m_comboBox->show();
+
+ // m_comboBox->setFont( m_comboBox->font() );
+ // m_comboBox->setUpdatesEnabled(true);
+
+ isResetting = false;
+ // qWarning("inserted");
+}
+
+/** Initializes this widget. We need this function because we have more than one constructor. */
+void CKeyChooserWidget::init() {
+ qDebug("CKeyChooserWidget::init");
+ oldKey = QString::null;
+
+ setFocusPolicy(Qt::WheelFocus);
+
+ m_comboBox = new CKCComboBox();
+ m_comboBox->setAutoCompletion( true );
+ m_comboBox->setEditable(true);
+ m_comboBox->setInsertPolicy(QComboBox::NoInsert);
+ m_comboBox->setFocusPolicy(Qt::WheelFocus);
+
+ m_mainLayout = new QHBoxLayout( this );
+ m_mainLayout->setSpacing(0);
+ m_mainLayout->setContentsMargins(0,0,0,0);
+ m_mainLayout->addWidget(m_comboBox);
+
+ m_scroller = new CScrollerWidgetSet(this);
+
+ m_mainLayout->addWidget( m_scroller );
+ m_mainLayout->addSpacing(0);
+
+ setTabOrder(m_comboBox, 0);
+
+ connect(m_scroller, SIGNAL(scroller_pressed()), SLOT(lock()));
+ connect(m_scroller, SIGNAL(scroller_released()), SLOT(unlock()));
+ connect(m_scroller, SIGNAL(change(int)), SLOT(changeCombo(int)) );
+
+ connect(m_comboBox, SIGNAL(activated(int)), SLOT(slotComboChanged(int)));
+ // connect(m_comboBox, SIGNAL(activated(const QString&)), SLOT(slotReturnPressed(const QString&)));
+ connect(m_comboBox->lineEdit(), SIGNAL(returnPressed()), SLOT(slotReturnPressed()));
+ connect(m_comboBox, SIGNAL(focusOut(int)), SIGNAL(focusOut(int)));
+
+ updatelock = false;
+ isResetting = false;
+}
+
+/** Is called when the return key was presed in the combobox. */
+void CKeyChooserWidget::slotReturnPressed( /*const QString& text*/) {
+ Q_ASSERT(comboBox()->lineEdit());
+ qDebug("return pressed");
+
+ QString text = comboBox()->lineEdit()->text();
+ for (int index = 0; index < comboBox()->count(); ++index) {
+ if (comboBox()->itemText(index) == text) {
+// emit changed(index);
+ emit focusOut(index); // a workaround because focusOut is not checked, the slot connected to changed to check
+ break;
+ }
+ }
+}
+
+/** Is called when the current item of the combo box was changed. */
+void CKeyChooserWidget::slotComboChanged(int index) {
+ qDebug("CKeyChooserWidget::slotComboChanged(int index)");
+ if (!updatesEnabled()) {
+ return;
+ }
+
+ setUpdatesEnabled(false);
+
+ const QString key = comboBox()->itemText( index );
+ if (oldKey.isNull() || (oldKey != key)) {
+ emit changed(index);
+ }
+
+ oldKey = key;
+
+ setUpdatesEnabled(true);
+}
+
+/** Sets the tooltips for the given entries using the parameters as text. */
+void CKeyChooserWidget::setToolTips( const QString comboTip, const QString nextEntryTip, const QString scrollButtonTip, const QString previousEntryTip) {
+ comboBox()->setToolTip(comboTip);
+ m_scroller->setToolTips(nextEntryTip, scrollButtonTip, previousEntryTip);
+}
+
+/** Sets the current item to the one with the given text */
+bool CKeyChooserWidget::setItem( const QString item ) {
+ bool ret = false;
+ const int count = comboBox()->count();
+ for (int i = 0; i < count; ++i) {
+ if (comboBox()->itemText(i) == item) {
+ comboBox()->setCurrentIndex(i);
+ ret = true;
+ break;
+ }
+ }
+ if (!ret)
+ comboBox()->setCurrentIndex(-1);
+ return ret;
+}
+
+/* Handlers for the various scroller widgetset. */
+void CKeyChooserWidget::lock() {
+ updatelock = true;
+ comboBox()->setEditable(false);
+ oldKey = comboBox()->currentText();
+}
+
+void CKeyChooserWidget::unlock() {
+ updatelock = false;
+ comboBox()->setEditable(true);
+ comboBox()->setEditText(comboBox()->itemText(comboBox()->currentIndex()));
+ if (comboBox()->currentText() != oldKey) {
+ emit changed(comboBox()->currentIndex());
+ }
+}
+
+void CKeyChooserWidget::changeCombo(int n) {
+ const int old_index = comboBox()->currentIndex();
+ int new_index = old_index + n;
+
+ //index of highest Item
+ const int max = comboBox()->count()-1;
+ if(new_index > max) new_index = max;
+ if(new_index < 0) new_index = 0;
+
+ if(new_index != old_index) {
+ comboBox()->setCurrentIndex(new_index);
+ if(!updatelock)
+ emit changed(new_index);
+ }
+}
+
diff --git a/src/frontend/keychooser/ckeychooserwidget.h b/src/frontend/keychooser/ckeychooserwidget.h
new file mode 100644
index 0000000..05b0236
--- /dev/null
+++ b/src/frontend/keychooser/ckeychooserwidget.h
@@ -0,0 +1,171 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CKEYCHOOSERWIDGET_H
+#define CKEYCHOOSERWIDGET_H
+
+
+#include <QString>
+#include <QStringList>
+#include <QComboBox>
+
+class QWheelEvent;
+class QHBoxLayout;
+class QWidget;
+class QObject;
+class QEvent;
+
+class CLexiconKeyChooser;
+class CScrollerWidgetSet;
+/*
+* We use this class to conrtol the focus move in the combobox
+* This class is used in the key chooser widgets
+*/
+class CKCComboBox : public QComboBox {
+ Q_OBJECT
+
+public:
+ CKCComboBox();
+ /**
+ * Returns the size this widget would like to have.
+ */
+ // virtual QSize sizeHint() const;
+
+protected:
+ /**
+ * Reimplementation.
+ */
+ virtual bool eventFilter( QObject *o, QEvent *e );
+ /**
+ * Scrolls in the list if the wheel of the mouse was used.
+ */
+ virtual void wheelEvent( QWheelEvent* e);
+
+signals:
+ /**
+ * Emitted when the user moves the focus away from the combo by pressing tab
+ */
+ void focusOut(int itemIndex);
+};
+
+/**
+ * This class implements the KeyCooser Widget, which
+ * consists of a @ref QComboBox, two normal ref @QToolButton
+ * and a enhanced @ref CScrollButton
+ *
+ * @author The BibleTime team
+ */
+class CKeyChooserWidget : public QWidget {
+ Q_OBJECT
+public:
+ /**
+ * the constructor
+ */
+ CKeyChooserWidget(QStringList *list=0, const bool useNextPrevSignals = false, QWidget *parent=0 );
+ /**
+ * the constructor
+ */
+ CKeyChooserWidget(int count=0, const bool useNextPrevSignals = false, QWidget *parent=0 );
+ /**
+ * This function does clear the combobox, then fill in
+ * the StringList, set the ComboBox' current item to index
+ * and if do_emit is true, it will emit @ref #changed
+ *
+ * @param list the stringlist to be inserted
+ * @param index the index that the combobox is to jump to
+ * @param do_emit should we emit @ref #changed(int)
+ */
+ void reset(const int count, int index, bool do_emit);
+ void reset(QStringList& list, int index, bool do_emit);
+ void reset(QStringList *list, int index, bool do_emit);
+ /**
+ * Initializes this widget. We need this function because
+ * we have more than one constructor.
+ */
+ virtual void init();
+ /**
+ *
+ */
+ // virtual void adjustSize();
+ /**
+ * Sets the tooltips for the given entries using the parameters as text.
+ */
+ void setToolTips( const QString comboTip, const QString nextEntry, const QString scrollButton, const QString previousEntry);
+ /**
+ * Sets the current item to the one with the given text
+ */
+ bool setItem( const QString item);
+ /**
+ * Return the combobox of this key chooser widget.
+ */
+ QComboBox* comboBox() {return m_comboBox;};
+
+public slots:
+ /**
+ * is called to lock the combobox
+ */
+ void lock()
+ ;
+ /**
+ * is called to unlock the combobox
+ */
+ void unlock();
+ /**
+ * is called to move the combobox to a certain index
+ * @param index the index to jump to
+ */
+ void changeCombo(int index);
+ void slotComboChanged(int index);
+
+signals:
+ /**
+ * Is emitted if the widget changed, but
+ * only if it is not locked or being reset
+ *
+ * @param the current ComboBox index
+ */
+ void changed(int index);
+ /**
+ * Is emitted if the widget was left with a focus out event.
+ * @param index The new index of the ComboBox
+ */
+ void focusOut(int index);
+
+protected:
+ /**
+ * indicates wheter we are resetting at the moment
+ */
+ bool isResetting;
+ /**
+ *
+ */
+ QString oldKey;
+
+protected slots: // Protected slots
+ /**
+ * Is called when the return key was presed in the combobox.
+ */
+ void slotReturnPressed( /*const QString&*/ );
+
+
+private:
+ friend class CLexiconKeyChooser;
+ QStringList m_list;
+ bool m_useNextPrevSignals;
+ bool updatelock;
+
+ /**
+ * Members should never be public!!
+ */
+ CKCComboBox* m_comboBox;
+ QHBoxLayout *m_mainLayout;
+ CScrollerWidgetSet * m_scroller;
+};
+
+#endif
diff --git a/src/frontend/keychooser/clexiconkeychooser.cpp b/src/frontend/keychooser/clexiconkeychooser.cpp
new file mode 100644
index 0000000..00c02ba
--- /dev/null
+++ b/src/frontend/keychooser/clexiconkeychooser.cpp
@@ -0,0 +1,180 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#include "clexiconkeychooser.h"
+
+#include "bthistory.h"
+#include "ckeychooserwidget.h"
+#include "cscrollbutton.h"
+
+#include "backend/drivers/cswordlexiconmoduleinfo.h"
+#include "backend/keys/cswordldkey.h"
+#include "backend/config/cbtconfig.h"
+#include "util/cresmgr.h"
+
+//STL headers
+#include <algorithm>
+#include <iterator>
+#include <map>
+
+#include <QHBoxLayout>
+
+
+CLexiconKeyChooser::CLexiconKeyChooser(QList<CSwordModuleInfo*> modules, CSwordKey *key, QWidget *parent)
+ : CKeyChooser(modules, key, parent),
+ m_key(dynamic_cast<CSwordLDKey*>(key))
+{
+ setModules(modules, false);
+
+ //we use a layout because the key chooser should be resized to full size
+ m_layout = new QHBoxLayout(this);
+ m_layout->setSpacing(0);
+ m_layout->setContentsMargins(0,0,0,0);
+ m_layout->setDirection(QBoxLayout::LeftToRight);
+ m_layout->setSizeConstraint(QLayout::SetNoConstraint);
+
+ m_widget = new CKeyChooserWidget(0, false, this);
+
+ //don't allow a too high width, try to keep as narrow as possible
+ //to aid users with smaller screen resolutions
+ m_widget->comboBox()->setMaximumWidth(200);
+
+ m_widget->setToolTips(
+ tr("Entries of the current work"),
+ tr("Next entry"),
+ tr("Scroll through the entries of the list. Press the button and move the mouse to increase or decrease the item."),
+ tr("Previous entry")
+ );
+
+ m_layout->addWidget(m_widget,0,Qt::AlignLeft);
+
+ connect(m_widget,SIGNAL(changed(int)),SLOT(activated(int)));
+ connect(m_widget,SIGNAL(focusOut(int)),SLOT(activated(int)));
+
+ setModules(modules, true);
+ setKey(key);
+ connect(this, SIGNAL(keyChanged(CSwordKey*)), history(), SLOT(add(CSwordKey*)) );
+}
+
+CSwordKey* CLexiconKeyChooser::key() {
+ // qWarning("key");
+ return m_key;
+}
+
+void CLexiconKeyChooser::setKey(CSwordKey* key)
+{
+ qDebug("CLexiconKeyChooser::setKey");
+
+ if (!(m_key = dynamic_cast<CSwordLDKey*>(key))) {
+ return;
+ }
+
+ QString newKey = m_key->key();
+ const int index = m_widget->comboBox()->findText(newKey);
+ m_widget->comboBox()->setCurrentIndex(index);
+
+ // qWarning("setKey end");
+ emit keyChanged( m_key);
+}
+
+void CLexiconKeyChooser::activated(int index) {
+ // qWarning("activated");
+ const QString text = m_widget->comboBox()->itemText(index);
+
+ // To prevent from eternal loop, because activated() is emitted again
+ if (m_key && m_key->key() != text) {
+ m_key->key(text);
+ setKey(m_key);
+ }
+ // qWarning("activated end");
+}
+
+inline bool my_cmpEntries(const QString& a, const QString& b) {
+ return a < b;
+}
+
+/** Reimplementation. */
+void CLexiconKeyChooser::refreshContent() {
+ if (m_modules.count() == 1) {
+ m_widget->reset(m_modules.first()->entries(), 0, true);
+ // qWarning("resetted");
+ }
+ else {
+ typedef std::multimap<unsigned int, QStringList*> EntryMap;
+ EntryMap entryMap;
+ QStringList* entries = 0;
+ QListIterator<CSwordLexiconModuleInfo*> mit(m_modules);
+ while (mit.hasNext()) {
+ entries = mit.next()->entries();
+ entryMap.insert( std::make_pair(entries->count(), entries) );
+ }
+
+ QStringList goodEntries; //The string list which contains the entries which are available in all modules
+
+ EntryMap::iterator it = entryMap.begin(); //iterator to go thoigh all selected modules
+ QStringList refEntries = *(it->second); //copy the items for the first time
+ QStringList* cmpEntries = ( ++it )->second; //list for comparision, starts with the second module in the map
+
+ while(it != entryMap.end()) {
+ std::set_intersection(
+ refEntries.begin(), --(refEntries.end()), //--end() is the last valid entry
+ cmpEntries->begin(), --(cmpEntries->end()),
+ std::back_inserter(goodEntries), //append valid entries to the end of goodEntries
+ my_cmpEntries //ci_cmpEntries is the comparision function
+ );
+
+ cmpEntries = ( ++it )->second; //this is a pointer to the string list of a new module
+
+ /*
+ * use the good entries for next comparision,
+ * because the final list can only have the entries of goodEntries as maxiumum
+ */
+ refEntries = goodEntries;
+ };
+
+ m_widget->reset(goodEntries, 0, true); //write down the entries
+ } //end of ELSE
+
+}
+
+/** No descriptions */
+void CLexiconKeyChooser::adjustFont() {
+
+}
+
+/** Sets the module and refreshes the combo boxes */
+void CLexiconKeyChooser::setModules( const QList<CSwordModuleInfo*>& modules, const bool refresh ) {
+
+ while (!m_modules.isEmpty())
+ m_modules.takeFirst(); // not deleting the pointer
+
+ QList<CSwordModuleInfo*>::const_iterator end_it = modules.end();
+ for (QList<CSwordModuleInfo*>::const_iterator it(modules.begin()); it != end_it; ++it) {
+ CSwordLexiconModuleInfo* lexicon = dynamic_cast<CSwordLexiconModuleInfo*>(*it);
+ if (lexicon) {
+ m_modules.append(lexicon);
+ }
+ }
+
+ if (refresh) {
+ refreshContent();
+ // adjustFont();
+ }
+}
+
+/** No descriptions */
+void CLexiconKeyChooser::updateKey(CSwordKey*) {}
+
+void CLexiconKeyChooser::setKey(QString& newKey)
+{
+ m_key->key(newKey);
+ setKey(m_key);
+}
diff --git a/src/frontend/keychooser/clexiconkeychooser.h b/src/frontend/keychooser/clexiconkeychooser.h
new file mode 100644
index 0000000..a75ce37
--- /dev/null
+++ b/src/frontend/keychooser/clexiconkeychooser.h
@@ -0,0 +1,86 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CLEXICONKEYCHOOSER_H
+#define CLEXICONKEYCHOOSER_H
+
+
+#include "ckeychooser.h"
+class CSwordModuleInfo;
+
+
+class CKeyChooserWidget;
+class CSwordLexiconModuleInfo;
+class CSwordLDKey;
+
+class QWidget;
+class QHBoxLayout;
+
+/**
+ * This class implements the KeyChooser for lexicons
+ *
+ * it inhertits @ref CKeyChooser
+ * it uses 1 @ref CKeyChooserWidget to represent the lexicon keys
+ *
+ * @author The BibleTime team
+ */
+class CLexiconKeyChooser : public CKeyChooser {
+ Q_OBJECT
+public:
+ /**
+ * The constructor
+ *
+ * you should not need to use this, use @ref CKeyChooser::createInstance instead
+ */
+ CLexiconKeyChooser(QList<CSwordModuleInfo*> modules, CSwordKey *key=0, QWidget *parent=0);
+
+public slots:
+ /**
+ * see @ref CKeyChooser::getKey
+ * @return Return the key object we use.
+ */
+ virtual CSwordKey* key();
+ /**
+ * see @ref CKeyChooser::setKey
+ */
+ virtual void setKey(CSwordKey* key);
+ /**
+ * used to react to changes in the @ref CKeyChooserWidget
+ *
+ * @param index not used
+ **/
+ virtual void activated(int index);
+ /**
+ * Reimplementation.
+ */
+ virtual void refreshContent();
+ /**
+ * Sets the module and refreshes the combo boxes of this keychooser.
+ */
+ virtual void setModules( const QList<CSwordModuleInfo*>& modules, const bool refresh = true );
+
+protected:
+ CKeyChooserWidget *m_widget;
+ CSwordLDKey* m_key;
+ QList<CSwordLexiconModuleInfo*> m_modules;
+ QHBoxLayout *m_layout;
+
+ virtual void adjustFont();
+
+public slots: // Public slots
+ virtual void updateKey(CSwordKey* key);
+
+protected slots:
+ virtual void setKey(QString& newKey);
+
+};
+
+#endif
diff --git a/src/frontend/keychooser/cscrollbutton.cpp b/src/frontend/keychooser/cscrollbutton.cpp
new file mode 100644
index 0000000..742bc53
--- /dev/null
+++ b/src/frontend/keychooser/cscrollbutton.cpp
@@ -0,0 +1,85 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#include "cscrollbutton.h"
+
+
+#include <stdlib.h>
+#include <math.h>
+
+//Qt includes
+#include <QEvent>
+#include <QApplication>
+#include <QCursor>
+#include <QPoint>
+#include <QMouseEvent>
+#include <QWheelEvent>
+
+CScrollButton::CScrollButton(QWidget *parent) : QToolButton(parent) {
+ setFocusPolicy(Qt::WheelFocus);
+ setCursor(Qt::SplitVCursor );
+
+ m_isLocked = false;
+ connect(this, SIGNAL(pressed() ), SLOT(was_pressed() ));
+ connect(this, SIGNAL(released()), SLOT(was_released()));
+}
+
+bool CScrollButton::isLocked( ) const {
+ return m_isLocked;
+}
+
+void CScrollButton::was_pressed( ) {
+ QApplication::setOverrideCursor(Qt::BlankCursor);
+ m_isLocked = true;
+ lock_Point = get_lock_Point();
+
+ emit lock()
+ ;
+}
+
+void CScrollButton::was_released( ) {
+ QApplication::restoreOverrideCursor();
+ m_isLocked = false;
+
+ emit unlock();
+}
+
+const QPoint CScrollButton::get_lock_Point() const {
+ return mapToGlobal( QPoint( width()/2, height()/2 ) );
+}
+
+void CScrollButton::mouseMoveEvent( QMouseEvent* e ) {
+ if (m_isLocked) {
+ int vchange = (QCursor::pos().y() - lock_Point.y());
+
+ if (abs(vchange) < 10) {
+ vchange = (int)((vchange>0 ? 1 : -1) * pow(abs(vchange), 0.3));
+ }
+ else if (abs(vchange) < 30) {
+ vchange = (int)((vchange>0 ? 1 : -1) * pow(abs(vchange), 0.6));
+ }
+ else if (abs(vchange) < 40) {
+ vchange = (int)((vchange>0 ? 1 : -1) * pow(abs(vchange), 1.2));
+ }
+ else {
+ vchange = (int)((vchange>0 ? 1 : -1) * pow(abs(vchange), 2.0));
+ }
+
+ if (vchange) { //not emit 0
+ emit change_requested( vchange );
+ }
+
+ QCursor::setPos( lock_Point );
+ }
+ else {
+ QToolButton::mouseMoveEvent(e);
+ }
+}
diff --git a/src/frontend/keychooser/cscrollbutton.h b/src/frontend/keychooser/cscrollbutton.h
new file mode 100644
index 0000000..3a38f37
--- /dev/null
+++ b/src/frontend/keychooser/cscrollbutton.h
@@ -0,0 +1,85 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CSRCOLLBUTTON_H
+#define CSRCOLLBUTTON_H
+
+
+#include <QToolButton>
+
+
+class QMouseEvent;
+class QWidget;
+class QMouseEvent;
+class QWheelEvent;
+
+/** This Class implements the direct chooser button used in the KeyChooser Widget
+ * @author The BibleTime team
+ */
+class CScrollButton : public QToolButton {
+ Q_OBJECT
+public:
+ /**
+ * The constructor
+ */
+ CScrollButton(QWidget *parent=0);
+ bool isLocked() const;
+
+signals:
+ /**
+ * is emitted when the button enters locked state
+ */
+ void lock()
+ ;
+ /**
+ * is emitted when the button leaves locked state
+ */
+ void unlock();
+ /**
+ * indicates a change the user made by moving the mouse
+ * @param count the number of items to be changed in the KeyChooser ComboBox
+ */
+ void change_requested(int count);
+
+protected slots:
+ /*
+ * used to process the button press events
+ */
+ void was_pressed();
+ /**
+ * used to process the button release events
+ */
+ void was_released();
+
+protected:
+ /**
+ * Reimplementation from @ref QWidget#mouseMoveEvent - processes
+ * the mouse move events
+ */
+ virtual void mouseMoveEvent( QMouseEvent* e );
+ /**
+ * used to find the lock point - the middle of the button
+ * @return the lock point
+ */
+ const QPoint get_lock_Point() const;
+
+private:
+ /**
+ * Indicates whether the button is in locked state or not
+ */
+ bool m_isLocked;
+ /**
+ * stores the lock point
+ */
+ QPoint lock_Point;
+};
+
+#endif
diff --git a/src/frontend/keychooser/cscrollerwidgetset.cpp b/src/frontend/keychooser/cscrollerwidgetset.cpp
new file mode 100644
index 0000000..3577803
--- /dev/null
+++ b/src/frontend/keychooser/cscrollerwidgetset.cpp
@@ -0,0 +1,87 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+//BibleTime includes
+#include "cscrollbutton.h"
+#include "cscrollerwidgetset.h"
+
+//Qt includes
+#include <QString>
+#include <QToolButton>
+#include <QVBoxLayout>
+#include <QWheelEvent>
+
+const unsigned int WIDTH = 16;
+const unsigned int ARROW_HEIGHT = 12;
+const unsigned int MOVER_HEIGHT = 6;
+
+CScrollerWidgetSet::CScrollerWidgetSet(QWidget *parent) : QWidget(parent) {
+ m_layout = new QVBoxLayout(this);
+ m_layout->setSpacing(0);
+ m_layout->setContentsMargins(0,0,0,0);
+ m_layout->setAlignment(this, Qt::AlignHCenter | Qt::AlignCenter);
+
+ btn_up = new QToolButton(this);
+ btn_up->setArrowType(Qt::UpArrow);
+
+ btn_up->setFixedSize(WIDTH, ARROW_HEIGHT);
+ btn_up->setFocusPolicy(Qt::NoFocus);
+ btn_up->setAutoRaise(true);
+
+ btn_fx = new CScrollButton(this);
+ btn_fx->setFixedSize(WIDTH, MOVER_HEIGHT);
+ btn_fx->setFocusPolicy(Qt::NoFocus);
+
+ btn_down = new QToolButton(this);
+ btn_down->setArrowType(Qt::DownArrow);
+ btn_down->setFixedSize(WIDTH, ARROW_HEIGHT);
+ btn_down->setFocusPolicy(Qt::NoFocus);
+ btn_down->setAutoRaise(true);
+
+ m_layout->addWidget( btn_up,0 );
+ m_layout->addWidget( btn_fx,0 );
+ m_layout->addWidget( btn_down,0 );
+ setMinimumWidth(WIDTH); // Kludge to add some spacing but seems to work.
+
+ connect(btn_fx, SIGNAL(lock()), SLOT(slotLock()));
+ connect(btn_fx, SIGNAL(unlock()), SLOT(slotUnlock()));
+ connect(btn_fx, SIGNAL(change_requested(int)), SLOT(slotScroller(int)));
+ connect(btn_up, SIGNAL(clicked()), SLOT(slotUpClick()));
+ connect(btn_down, SIGNAL(clicked()), SLOT(slotDownClick()));
+}
+
+/** Sets the tooltips for the given entries using the parameters as text. */
+void CScrollerWidgetSet::setToolTips( const QString nextEntryTip, const QString scrollButtonTip, const QString previousEntryTip) {
+ btn_fx->setToolTip(scrollButtonTip);
+ btn_down->setToolTip(nextEntryTip);
+ btn_up->setToolTip(previousEntryTip);
+}
+
+
+void CScrollerWidgetSet::wheelEvent( QWheelEvent* e ) {
+ /**
+ * The problem is, that wheel events do everytime have the delta value 120
+ */
+ const int vchange = ((e->delta() > 0) ? (-1) : (1));
+
+ if (vchange!=0) {//do not emit a change with value 0
+ emit change(vchange);
+ e->accept();
+ }
+ else {
+ e->ignore();
+ }
+}
+
+void CScrollerWidgetSet::slotLock() { emit scroller_pressed(); }
+void CScrollerWidgetSet::slotUnlock() { emit scroller_released(); }
+void CScrollerWidgetSet::slotScroller(int n) { emit change(n); }
+void CScrollerWidgetSet::slotUpClick() { slotScroller(-1); }
+void CScrollerWidgetSet::slotDownClick() { slotScroller(1); }
diff --git a/src/frontend/keychooser/cscrollerwidgetset.h b/src/frontend/keychooser/cscrollerwidgetset.h
new file mode 100644
index 0000000..bd482df
--- /dev/null
+++ b/src/frontend/keychooser/cscrollerwidgetset.h
@@ -0,0 +1,76 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CSCROLLERWIDGETSET_H
+#define CSCROLLERWIDGETSET_H
+
+
+#include <QWidget>
+
+
+class QVBoxLayout;
+class QToolButton;
+class QString;
+
+class CScrollButton;
+
+/**
+ * This class implements the Scroller Widget-set, which
+ * consists of two normal ref @QToolButton and a enhanced @ref CScrollButton
+ *
+ * @author The BibleTime team
+ */
+class CScrollerWidgetSet : public QWidget {
+ Q_OBJECT
+public:
+ /**
+ * the constructor
+ */
+ CScrollerWidgetSet(QWidget *parent=0);
+ /**
+ * Sets the tooltips for the given entries using the parameters as text.
+ */
+ void setToolTips( const QString nextEntry, const QString scrollButton, const QString previousEntry);
+
+signals:
+ /**
+ * is emitted to proceed to some other entry relative to the
+ * current, indicated by the int value
+ */
+ void change(int count);
+
+ /**
+ * These emit when the scroll button is pressed or released
+ */
+ void scroller_pressed();
+ void scroller_released();
+
+protected:
+
+ virtual void wheelEvent( QWheelEvent* e );
+
+ QToolButton* btn_up;
+ QToolButton* btn_down;
+ CScrollButton* btn_fx;
+
+protected slots:
+ void slotLock();
+ void slotUnlock();
+ void slotUpClick();
+ void slotDownClick();
+ void slotScroller(int);
+
+private:
+ QVBoxLayout *m_layout;
+
+};
+
+#endif
diff --git a/src/frontend/keychooser/versekeychooser/btdropdownchooserbutton.cpp b/src/frontend/keychooser/versekeychooser/btdropdownchooserbutton.cpp
new file mode 100644
index 0000000..e4b05c3
--- /dev/null
+++ b/src/frontend/keychooser/versekeychooser/btdropdownchooserbutton.cpp
@@ -0,0 +1,134 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btdropdownchooserbutton.h"
+#include "ckeyreferencewidget.h"
+#include "btversekeymenu.h"
+
+#include <QWheelEvent>
+#include <QDebug>
+
+const unsigned int ARROW_HEIGHT = 12;
+
+BtDropdownChooserButton::BtDropdownChooserButton(CKeyReferenceWidget* ref)
+ : QToolButton(),
+ m_ref(ref)
+{
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+
+ setAutoRaise(true);
+ setArrowType(Qt::NoArrow);
+ setFixedHeight(ARROW_HEIGHT);
+ setFocusPolicy(Qt::NoFocus);
+ setPopupMode(QToolButton::InstantPopup);
+ setStyleSheet("QToolButton{margin:0px;}QToolButton::menu-indicator{subcontrol-position: center center;}");
+
+ BtVerseKeyMenu* m = new BtVerseKeyMenu(this);
+// KAcceleratorManager::setNoAccel(m);
+ setMenu(m);
+ QObject::connect(m, SIGNAL(triggered(QAction*)), this, SLOT(slotMenuTriggered(QAction*)));
+}
+
+
+void BtDropdownChooserButton::mousePressEvent(QMouseEvent* e)
+{
+ //qDebug("BtDropdownChooserButton::mousePressEvent");
+ //recreate the menu
+ menu()->clear();
+ this->newList();
+
+ QToolButton::mousePressEvent(e);
+}
+
+void BtDropdownChooserButton::wheelEvent(QWheelEvent* e)
+{
+ // The problem is, that wheel events do everytime have the delta value 120
+ const int vchange = ((e->delta() > 0) ? (-1) : (1));
+
+ if (vchange!=0) {//do not emit a change with value 0
+ emit stepItem(vchange);
+ e->accept();
+ }
+ else {
+ e->ignore();
+ }
+}
+
+
+//******************Book dropdown button*************************************/
+
+BtBookDropdownChooserButton::BtBookDropdownChooserButton(CKeyReferenceWidget* ref)
+ : BtDropdownChooserButton(ref)
+{
+ setToolTip(tr("Select book"));
+ QObject::connect(this, SIGNAL(stepItem(int)), m_ref, SLOT(slotStepBook(int)));
+}
+
+void BtBookDropdownChooserButton::newList()
+{
+ QMenu* m = menu();
+ QStringList* booklist = ref()->m_module->books();
+ foreach (QString bookname, *booklist) {
+ m->addAction(bookname);
+ }
+}
+
+void BtBookDropdownChooserButton::slotMenuTriggered(QAction* action)
+{
+ qDebug() << "BtBookDropdownChooserButton::slotMenuTriggered" << action->text();
+ m_ref->slotChangeBook(action->text());
+}
+
+
+//****************** Chapter dropdown button *************************************/
+
+BtChapterDropdownChooserButton::BtChapterDropdownChooserButton(CKeyReferenceWidget* ref)
+ : BtDropdownChooserButton(ref)
+{
+ setToolTip(tr("Select chapter"));
+ QObject::connect(this, SIGNAL(stepItem(int)), m_ref, SLOT(slotStepChapter(int)));
+}
+
+void BtChapterDropdownChooserButton::newList()
+{
+ QMenu* m = menu();
+ int count = ref()->m_module->chapterCount(ref()->m_key->book());
+ for (int i = 1; i <= count; i++) {
+ m->addAction(QString::number(i));
+ }
+}
+
+void BtChapterDropdownChooserButton::slotMenuTriggered(QAction* action)
+{
+ m_ref->slotChangeChapter(action->text().toInt());
+}
+
+
+//****************** Verse dropdown button *************************************/
+
+BtVerseDropdownChooserButton::BtVerseDropdownChooserButton(CKeyReferenceWidget* ref)
+ : BtDropdownChooserButton(ref)
+{
+ setToolTip(tr("Select verse"));
+ QObject::connect(this, SIGNAL(stepItem(int)), m_ref, SLOT(slotStepVerse(int)));
+}
+
+void BtVerseDropdownChooserButton::newList()
+{
+ QMenu* m = menu();
+ int count = ref()->m_module->verseCount(ref()->m_key->book(), ref()->m_key->Chapter());
+ for (int i = 1; i <= count; i++) {
+ m->addAction(QString::number(i));
+ }
+}
+
+void BtVerseDropdownChooserButton::slotMenuTriggered(QAction* action)
+{
+ m_ref->slotChangeVerse(action->text().toInt());
+}
diff --git a/src/frontend/keychooser/versekeychooser/btdropdownchooserbutton.h b/src/frontend/keychooser/versekeychooser/btdropdownchooserbutton.h
new file mode 100644
index 0000000..969f5c2
--- /dev/null
+++ b/src/frontend/keychooser/versekeychooser/btdropdownchooserbutton.h
@@ -0,0 +1,79 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTDROPDOWNCHOOSERBUTTON_H
+#define BTDROPDOWNCHOOSERBUTTON_H
+
+
+#include <QToolButton>
+
+class CKeyReferenceWidget;
+
+/**
+* Base class for book/ch/v dropdown list chooser buttons.
+*/
+class BtDropdownChooserButton : public QToolButton
+{
+ Q_OBJECT
+public:
+ BtDropdownChooserButton(CKeyReferenceWidget* ref);
+
+ virtual ~BtDropdownChooserButton() {}
+ /** The item list is constructed here just before the menu is shown.*/
+ virtual void mousePressEvent(QMouseEvent* event);
+ /** Recreates the menu list.*/
+ virtual void newList() = 0;
+ /** Returns the verse reference widget which this button belongs to.*/
+ CKeyReferenceWidget* ref() {return m_ref;}
+public slots:
+ /** When a menu item is selected the key will be changed.*/
+ virtual void slotMenuTriggered(QAction* action) = 0;
+protected:
+ CKeyReferenceWidget* m_ref;
+ void wheelEvent(QWheelEvent* event);
+signals:
+ void stepItem(int step);
+};
+
+/** See BtDropdownChooserButton.*/
+class BtBookDropdownChooserButton : public BtDropdownChooserButton
+{
+ Q_OBJECT
+public:
+ BtBookDropdownChooserButton(CKeyReferenceWidget* ref);
+ ~BtBookDropdownChooserButton() {}
+ virtual void newList();
+public slots:
+ virtual void slotMenuTriggered(QAction* action);
+};
+
+/** See BtDropdownChooserButton.*/
+class BtChapterDropdownChooserButton : public BtDropdownChooserButton
+{
+ Q_OBJECT
+public:
+ BtChapterDropdownChooserButton(CKeyReferenceWidget* ref);
+ ~BtChapterDropdownChooserButton() {}
+ virtual void newList();
+public slots:
+ virtual void slotMenuTriggered(QAction* action);
+};
+
+/** See BtDropdownChooserButton.*/
+class BtVerseDropdownChooserButton : public BtDropdownChooserButton
+{
+ Q_OBJECT
+public:
+ BtVerseDropdownChooserButton(CKeyReferenceWidget* ref);
+ ~BtVerseDropdownChooserButton() {}
+ virtual void newList();
+public slots:
+ virtual void slotMenuTriggered(QAction* action);
+};
+#endif
diff --git a/src/frontend/keychooser/versekeychooser/btversekeymenu.cpp b/src/frontend/keychooser/versekeychooser/btversekeymenu.cpp
new file mode 100644
index 0000000..f8607e4
--- /dev/null
+++ b/src/frontend/keychooser/versekeychooser/btversekeymenu.cpp
@@ -0,0 +1,52 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btversekeymenu.h"
+
+#include <QMenu>
+#include <QTimerEvent>
+#include <QMouseEvent>
+
+#include <QDebug>
+
+BtVerseKeyMenu::BtVerseKeyMenu(QWidget* parent)
+ : QMenu(parent),
+ m_timerId(0),
+ m_firstClickLock(true)
+{
+ qDebug("BtVerseKeyMenu::BtVerseKeyMenu");
+ QObject::connect(this, SIGNAL(aboutToShow()), this, SLOT(startFirstClickDelayTimer()));
+}
+
+void BtVerseKeyMenu::startFirstClickDelayTimer()
+{
+ //qDebug() << "BtVerseKeyMenu::startFirstClickDelayTimer";
+ m_firstClickLock = true;
+ killTimer(m_timerId);
+ m_timerId = startTimer(300);
+}
+
+void BtVerseKeyMenu::timerEvent(QTimerEvent* e)
+{
+ if (e->timerId() == m_timerId) {
+ //qDebug() << "BtVerseKeyMenu::timerEvent";
+ killTimer(m_timerId);
+ m_firstClickLock = false;
+ } else {
+ QMenu::timerEvent(e);
+ }
+}
+
+void BtVerseKeyMenu::mouseReleaseEvent(QMouseEvent* e)
+{
+ //qDebug() << "BtVerseKeyMenu::mouseReleaseEvent";
+ if (m_firstClickLock) return;
+ //qDebug() << "BtVerseKeyMenu::mouseReleaseEvent 2";
+ QMenu::mouseReleaseEvent(e);
+}
diff --git a/src/frontend/keychooser/versekeychooser/btversekeymenu.h b/src/frontend/keychooser/versekeychooser/btversekeymenu.h
new file mode 100644
index 0000000..45d9385
--- /dev/null
+++ b/src/frontend/keychooser/versekeychooser/btversekeymenu.h
@@ -0,0 +1,43 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTVERSEKEYMENU_H
+#define BTVERSEKEYMENU_H
+
+#include <QMenu>
+
+class QMouseEvent;
+class QTimerEvent;
+
+/**
+* Menu for book/ch/v dropdown lists.
+*
+* This is implemented mostly because it needs a delay which prevents unwanted actions after
+* the menu has been shown and mouse button is released over some item.
+*/
+class BtVerseKeyMenu : public QMenu
+{
+ Q_OBJECT
+public:
+ BtVerseKeyMenu(QWidget* parent);
+ ~BtVerseKeyMenu(){}
+protected:
+ virtual void mouseReleaseEvent(QMouseEvent* event);
+ /** Frees the mouse button release after the delay has elapsed.*/
+ virtual void timerEvent(QTimerEvent* event);
+private slots:
+ /** Starts the delay timer for the first mouse button release.*/
+ void startFirstClickDelayTimer();
+
+private:
+ int m_timerId;
+ bool m_firstClickLock;
+};
+
+#endif
diff --git a/src/frontend/keychooser/versekeychooser/cbiblekeychooser.cpp b/src/frontend/keychooser/versekeychooser/cbiblekeychooser.cpp
new file mode 100644
index 0000000..2bc9e77
--- /dev/null
+++ b/src/frontend/keychooser/versekeychooser/cbiblekeychooser.cpp
@@ -0,0 +1,108 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cbiblekeychooser.h"
+
+#include "../bthistory.h"
+#include "ckeyreferencewidget.h"
+#include "../cscrollbutton.h"
+
+#include "backend/keys/cswordversekey.h"
+#include "backend/drivers/cswordbiblemoduleinfo.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+
+#include "util/cresmgr.h"
+
+#include <QHBoxLayout>
+#include <QDebug>
+
+
+CBibleKeyChooser::CBibleKeyChooser(QList<CSwordModuleInfo*> modules, CSwordKey *key, QWidget *parent) :
+ CKeyChooser(modules, key, parent),
+ m_key(dynamic_cast<CSwordVerseKey*>(key))
+{
+ w_ref = 0;
+ setModules(modules, false);
+ if (!m_modules.count()) {
+ qWarning() << "CBibleKeyChooser: module is not a Bible or commentary!";
+ m_key = 0;
+ return;
+ }
+ QHBoxLayout* layout = new QHBoxLayout(this);
+ layout->setSpacing(0);
+ layout->setContentsMargins(0,0,0,0);
+ layout->setDirection( QBoxLayout::LeftToRight );
+
+ w_ref = new CKeyReferenceWidget(dynamic_cast<CSwordBibleModuleInfo*>(m_modules.first()), m_key, this);
+ layout->addWidget(w_ref);
+
+ connect(w_ref,SIGNAL(changed(CSwordVerseKey *)),SLOT(refChanged(CSwordVerseKey *)));
+
+ setKey(m_key); //set the key without changing it, setKey(key()) would change it
+
+ connect(this, SIGNAL(keyChanged(CSwordKey*)), history(), SLOT(add(CSwordKey*)) );
+}
+
+CSwordKey* CBibleKeyChooser::key() {
+ return m_key;
+}
+
+void CBibleKeyChooser::setKey(CSwordKey* key)
+{
+ Q_ASSERT(dynamic_cast<CSwordVerseKey*>(key));
+ if (dynamic_cast<CSwordVerseKey*>(key) == 0) return;
+
+ emit (beforeKeyChange(m_key->key())); //required to make direct setKey calls work from the outside
+ m_key = dynamic_cast<CSwordVerseKey*>(key);
+ w_ref->setKey(m_key);
+ emit keyChanged(m_key);
+}
+
+void CBibleKeyChooser::refChanged(CSwordVerseKey* key)
+{
+ Q_ASSERT(m_key);
+ Q_ASSERT(key);
+
+ if (!updatesEnabled()) return;
+
+ setUpdatesEnabled(false);
+ if (m_key) emit beforeKeyChange(m_key->key());
+ m_key = key;
+ emit keyChanged(m_key);
+
+ setUpdatesEnabled(true);
+}
+
+void CBibleKeyChooser::setModules(const QList<CSwordModuleInfo*>& modules, const bool refresh) {
+ m_modules.clear();
+
+ foreach (CSwordModuleInfo* mod, modules) {
+ if (mod->type() == CSwordModuleInfo::Bible || mod->type() == CSwordModuleInfo::Commentary) {
+ if (CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(mod)) m_modules.append(bible);
+ }
+ }
+
+ // First time this is called we havnt set up w_ref.
+ if (w_ref) w_ref->setModule(dynamic_cast<CSwordBibleModuleInfo*>(m_modules.first()));
+ if (refresh) refreshContent();
+}
+
+void CBibleKeyChooser::refreshContent() {
+ setKey(m_key);
+}
+
+void CBibleKeyChooser::updateKey(CSwordKey* /*key*/) {}
+
+void CBibleKeyChooser::adjustFont() {}
+
+void CBibleKeyChooser::setKey(QString& newKey)
+{
+ m_key->key(newKey);
+ setKey(m_key);
+}
diff --git a/src/frontend/keychooser/versekeychooser/cbiblekeychooser.h b/src/frontend/keychooser/versekeychooser/cbiblekeychooser.h
new file mode 100644
index 0000000..a410354
--- /dev/null
+++ b/src/frontend/keychooser/versekeychooser/cbiblekeychooser.h
@@ -0,0 +1,78 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CBIBLEKEYCHOOSER_H
+#define CBIBLEKEYCHOOSER_H
+
+
+#include "../ckeychooser.h"
+#include "backend/drivers/cswordbiblemoduleinfo.h"
+
+#include <QList>
+
+class QWidget;
+
+class CKeyReferenceWidget;
+class CSwordVerseKey;
+class CSwordBibleModuleInfo;
+
+/** This class implements the KeyChooser for bibles and commentaries
+ *
+ * it inhertits @ref CKeyChooser
+ *
+ * it uses a CKeyReferenceWidget 's to represent the bible keys
+ *
+ * @author The BibleTime team
+ */
+
+class CBibleKeyChooser : public CKeyChooser {
+ Q_OBJECT
+
+public:
+ /**
+ * the constructor
+ * you should not need to use this, use @ref CKeyChooser::createInstance instead
+ */
+ CBibleKeyChooser(QList<CSwordModuleInfo*> modules, CSwordKey *key=0, QWidget *parent=0);
+
+public slots:
+ /**
+ * see @ref CKeyChooser::getKey
+ */
+ CSwordKey* key();
+ /**
+ * see @ref CKeyChooser::setKey
+ */
+ virtual void setKey(CSwordKey *key);
+ /**
+ * Sets the module
+ */
+ virtual void setModules(const QList<CSwordModuleInfo*>& modules, const bool refresh = true);
+ /**
+ * used to react to changes
+ * @param index not used
+ */
+ void refChanged(CSwordVerseKey *key);
+
+ void updateKey(CSwordKey* key);
+ void adjustFont();
+ void refreshContent();
+
+protected slots:
+ virtual void setKey(QString& newKey);
+
+private:
+ CKeyReferenceWidget* w_ref;
+ QList<CSwordBibleModuleInfo*> m_modules;
+ CSwordVerseKey *m_key;
+};
+
+#endif
diff --git a/src/frontend/keychooser/versekeychooser/ckeyreferencewidget.cpp b/src/frontend/keychooser/versekeychooser/ckeyreferencewidget.cpp
new file mode 100644
index 0000000..0815a89
--- /dev/null
+++ b/src/frontend/keychooser/versekeychooser/ckeyreferencewidget.cpp
@@ -0,0 +1,229 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//BibleTime includes
+#include "ckeyreferencewidget.h"
+
+#include "../cscrollerwidgetset.h"
+#include "btdropdownchooserbutton.h"
+
+#include "backend/config/cbtconfig.h"
+
+#include "backend/keys/cswordversekey.h"
+
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+
+//Qt includes
+#include <QString>
+#include <QStringList>
+#include <QEvent>
+#include <QPixmap>
+#include <QApplication>
+#include <QHBoxLayout>
+#include <QToolButton>
+#include <QDebug>
+#include <QLineEdit>
+
+
+
+CKeyReferenceWidget::CKeyReferenceWidget( CSwordBibleModuleInfo *mod, CSwordVerseKey *key, QWidget *parent, const char* /*name*/) :
+ QWidget(parent),
+ m_key(new CSwordVerseKey(mod))
+{
+
+ updatelock = false;
+ m_module = mod;
+
+ setFocusPolicy(Qt::WheelFocus);
+
+ QToolButton* clearRef = new QToolButton(this);
+ clearRef->setIcon(util::filesystem::DirectoryUtil::getIcon("edit_clear_locationbar"));
+ clearRef->setAutoRaise(true);
+ clearRef->setStyleSheet("QToolButton{margin:0px;}");
+ connect(clearRef, SIGNAL(clicked()), SLOT(slotClearRef()) );
+
+ m_bookScroller = new CScrollerWidgetSet(this);
+
+ m_textbox = new QLineEdit( this );
+ m_textbox->setStyleSheet("QLineEdit{margin:0px;}");
+
+ setKey(key); // The order of these two functions is important.
+ setModule();
+
+ m_chapterScroller = new CScrollerWidgetSet(this);
+ m_verseScroller = new CScrollerWidgetSet(this);
+
+ m_bookDropdownButton = new BtBookDropdownChooserButton(this);
+ m_chapterDropdownButton = new BtChapterDropdownChooserButton(this);
+ m_verseDropdownButton = new BtVerseDropdownChooserButton(this);
+
+ QHBoxLayout* dropdownButtonsLayout = new QHBoxLayout();
+ QVBoxLayout* editorAndButtonsLayout = new QVBoxLayout();
+ dropdownButtonsLayout->setContentsMargins(0,0,0,0);
+ editorAndButtonsLayout->setContentsMargins(0,0,0,0);
+ dropdownButtonsLayout->setSpacing(0);
+ editorAndButtonsLayout->setSpacing(0);
+
+ dropdownButtonsLayout->addWidget(m_bookDropdownButton, 2);
+ dropdownButtonsLayout->addWidget(m_chapterDropdownButton,1);
+ dropdownButtonsLayout->addWidget(m_verseDropdownButton,1);
+ editorAndButtonsLayout->addWidget(m_textbox);
+ editorAndButtonsLayout->addLayout(dropdownButtonsLayout);
+
+ QHBoxLayout* m_mainLayout = new QHBoxLayout( this );
+ m_mainLayout->setContentsMargins(0,0,0,0);
+ m_mainLayout->setSpacing(0);
+ m_mainLayout->addWidget(clearRef);
+ m_mainLayout->addWidget(m_bookScroller);
+ m_mainLayout->addLayout(editorAndButtonsLayout);
+ m_mainLayout->addWidget(m_chapterScroller);
+ m_mainLayout->addWidget(m_verseScroller);
+
+
+ setTabOrder(m_textbox, 0);
+
+ QString scrollButtonToolTip(tr("Scroll through the entries of the list. Press the button and move the mouse to increase or decrease the item."));
+ m_bookScroller->setToolTips(
+ tr("Next book"),
+ scrollButtonToolTip,
+ tr("Previous book")
+ );
+ m_chapterScroller->setToolTips(
+ tr("Next chapter"),
+ scrollButtonToolTip,
+ tr("Previous chapter")
+ );
+ m_verseScroller->setToolTips(
+ tr("Next verse"),
+ scrollButtonToolTip,
+ tr("Previous verse")
+ );
+
+ // signals and slots connections
+
+ connect(m_bookScroller, SIGNAL(change(int)), SLOT(slotStepBook(int)));
+ connect(m_bookScroller, SIGNAL(scroller_pressed()), SLOT(slotUpdateLock()));
+ connect(m_bookScroller, SIGNAL(scroller_released()), SLOT(slotUpdateUnlock()));
+ connect(m_textbox, SIGNAL(returnPressed()), SLOT(slotReturnPressed()));
+ connect(m_chapterScroller, SIGNAL(change(int)), SLOT(slotStepChapter(int)));
+ connect(m_chapterScroller, SIGNAL(scroller_pressed()), SLOT(slotUpdateLock()));
+ connect(m_chapterScroller, SIGNAL(scroller_released()), SLOT(slotUpdateUnlock()));
+ connect(m_verseScroller, SIGNAL(change(int)), SLOT(slotStepVerse(int)));
+ connect(m_verseScroller, SIGNAL(scroller_pressed()), SLOT(slotUpdateLock()));
+ connect(m_verseScroller, SIGNAL(scroller_released()), SLOT(slotUpdateUnlock()));
+}
+
+void CKeyReferenceWidget::setModule(CSwordBibleModuleInfo *m)
+{
+ if (m) //can be null
+ {
+ m_module = m;
+ m_key->module(m);
+ }
+}
+
+void CKeyReferenceWidget::slotClearRef( )
+{
+ m_textbox->setText("");
+ m_textbox->setFocus();
+}
+
+void CKeyReferenceWidget::updateText()
+{
+ m_textbox->setText(m_key->key());
+}
+
+bool CKeyReferenceWidget::setKey(CSwordVerseKey *key)
+{
+ if (!key) return false;
+
+ m_key->key(key->key());
+ updateText();
+ return true;
+}
+
+QLineEdit* CKeyReferenceWidget::textbox()
+{
+ return m_textbox;
+}
+
+void CKeyReferenceWidget::slotReturnPressed()
+{
+ m_key->key(m_textbox->text());
+ updateText();
+
+ emit changed(m_key.get());
+}
+
+/* Handlers for the various scroller widgetsets. Do we really want a verse scroller? */
+void CKeyReferenceWidget::slotUpdateLock()
+{
+ updatelock = true;
+ oldKey = m_key->key();
+}
+
+void CKeyReferenceWidget::slotUpdateUnlock()
+{
+ updatelock = false;
+ if (oldKey != m_key->key()) emit changed(m_key.get());
+}
+
+void CKeyReferenceWidget::slotStepBook(int n)
+{
+ n > 0 ? m_key->next( CSwordVerseKey::UseBook ) : m_key->previous( CSwordVerseKey::UseBook );
+ updateText();
+ if (!updatelock) emit changed(m_key.get());
+}
+
+void CKeyReferenceWidget::slotStepChapter(int n)
+{
+ n > 0 ? m_key->next( CSwordVerseKey::UseChapter ) : m_key->previous( CSwordVerseKey::UseChapter );
+ updateText();
+ if (!updatelock) emit changed(m_key.get());
+}
+
+void CKeyReferenceWidget::slotStepVerse(int n)
+{
+ n > 0 ? m_key->next( CSwordVerseKey::UseVerse ) : m_key->previous( CSwordVerseKey::UseVerse );
+ updateText();
+ if (!updatelock) emit changed(m_key.get());
+}
+
+
+void CKeyReferenceWidget::slotChangeVerse(int n)
+{
+ if (m_key->Verse() != n) {
+ m_key->Verse( n );
+ setKey( m_key.get() );
+ }
+ updateText();
+ if (!updatelock) emit changed(m_key.get());
+}
+
+void CKeyReferenceWidget::slotChangeChapter(int n)
+{
+ if (m_key->Chapter() != n) {
+ m_key->Chapter( n );
+ setKey( m_key.get() );
+ }
+ updateText();
+ if (!updatelock) emit changed(m_key.get());
+}
+
+void CKeyReferenceWidget::slotChangeBook(QString bookname)
+{
+ if (m_key->book() != bookname) {
+ m_key->book( bookname );
+ setKey( m_key.get() );
+ }
+ updateText();
+ if (!updatelock) emit changed(m_key.get());
+}
+
diff --git a/src/frontend/keychooser/versekeychooser/ckeyreferencewidget.h b/src/frontend/keychooser/versekeychooser/ckeyreferencewidget.h
new file mode 100644
index 0000000..d6d5eee
--- /dev/null
+++ b/src/frontend/keychooser/versekeychooser/ckeyreferencewidget.h
@@ -0,0 +1,86 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CKEYREFERENCEWIDGET_H
+#define CKEYREFERENCEWIDGET_H
+
+#include "../cscrollerwidgetset.h"
+#include "backend/drivers/cswordbiblemoduleinfo.h"
+
+#include <QWidget>
+
+#include <boost/scoped_ptr.hpp>
+
+
+class CLexiconKeyChooser;
+class CSwordVerseKey;
+class BtDropdownChooserButton;
+
+class QLineEdit;
+
+
+class CKeyReferenceWidget : public QWidget {
+ Q_OBJECT
+public:
+ /**
+ * the constructor
+ */
+ CKeyReferenceWidget(CSwordBibleModuleInfo *, CSwordVerseKey*, QWidget *parent=0, const char *name=0);
+ bool setKey(CSwordVerseKey* key);
+ QLineEdit* textbox();
+ void setModule(CSwordBibleModuleInfo *m = 0);
+
+signals:
+ void changed(CSwordVerseKey* key);
+
+protected:
+ void updateText();
+
+protected slots: // Protected slots
+ /**
+ * Is called when the return key was presed in the textbox.
+ */
+ void slotReturnPressed();
+
+ void slotClearRef();
+
+ void slotUpdateLock();
+ void slotUpdateUnlock();
+ void slotStepBook(int);
+ void slotStepChapter(int);
+ void slotStepVerse(int);
+ void slotChangeBook(QString bookname);
+ void slotChangeChapter(int chapter);
+ void slotChangeVerse(int verse);
+
+private:
+ friend class CLexiconKeyChooser;
+ friend class BtDropdownChooserButton;
+ friend class BtBookDropdownChooserButton;
+ friend class BtChapterDropdownChooserButton;
+ friend class BtVerseDropdownChooserButton;
+
+ boost::scoped_ptr<CSwordVerseKey> m_key;
+
+ QLineEdit* m_textbox;
+
+ CScrollerWidgetSet *m_bookScroller;
+ CScrollerWidgetSet *m_chapterScroller;
+ CScrollerWidgetSet *m_verseScroller;
+
+ BtDropdownChooserButton* m_bookDropdownButton;
+ BtDropdownChooserButton* m_chapterDropdownButton;
+ BtDropdownChooserButton* m_verseDropdownButton;
+
+ bool updatelock;
+ QString oldKey;
+ CSwordBibleModuleInfo *m_module;
+};
+
+#endif
diff --git a/src/frontend/mainindex/bookmarks/btbookmarkfolder.cpp b/src/frontend/mainindex/bookmarks/btbookmarkfolder.cpp
new file mode 100644
index 0000000..ac86b0e
--- /dev/null
+++ b/src/frontend/mainindex/bookmarks/btbookmarkfolder.cpp
@@ -0,0 +1,150 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+#include "btbookmarkfolder.h"
+#include "btbookmarkitembase.h"
+#include "btbookmarkitem.h"
+#include "btbookmarkloader.h"
+
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+
+#include <QFileDialog>
+
+#include <QDebug>
+
+BtBookmarkFolder::BtBookmarkFolder(QTreeWidgetItem* parent, QString name)
+ : 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 == 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()
+{
+ return QString();
+}
+
+void BtBookmarkFolder::newSubFolder()
+{
+ if (dynamic_cast<BtBookmarkFolder*>(this)) {
+ BtBookmarkFolder* f = new BtBookmarkFolder(this, QObject::tr("New folder"));
+
+ 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()
+{
+ qDebug() << "BtBookmarkFolder::update()";
+ BtBookmarkItemBase::update();
+ if (isExpanded() && childCount())
+ setIcon(0, util::filesystem::DirectoryUtil::getIcon(CResMgr::mainIndex::openedFolder::icon));
+ else
+ setIcon(0, util::filesystem::DirectoryUtil::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(0, 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/mainindex/bookmarks/btbookmarkfolder.h b/src/frontend/mainindex/bookmarks/btbookmarkfolder.h
new file mode 100644
index 0000000..a659917
--- /dev/null
+++ b/src/frontend/mainindex/bookmarks/btbookmarkfolder.h
@@ -0,0 +1,51 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 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 "btbookmarkitembase.h"
+
+#define CURRENT_SYNTAX_VERSION 1
+
+
+class BtBookmarkFolder : public BtBookmarkItemBase
+{
+public:
+ friend class BtBookmarkLoader;
+ BtBookmarkFolder(QTreeWidgetItem* parent, QString name);
+ ~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();
+};
+
+#endif
diff --git a/src/frontend/mainindex/bookmarks/btbookmarkitem.cpp b/src/frontend/mainindex/bookmarks/btbookmarkitem.cpp
new file mode 100644
index 0000000..84473f7
--- /dev/null
+++ b/src/frontend/mainindex/bookmarks/btbookmarkitem.cpp
@@ -0,0 +1,163 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+#include "btbookmarkitem.h"
+#include "btbookmarkfolder.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/keys/cswordversekey.h"
+#include "frontend/cinputdialog.h"
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+#include "backend/config/cbtconfig.h"
+#include "util/cpointers.h"
+
+#include <QDebug>
+
+#include <boost/scoped_ptr.hpp>
+
+
+BtBookmarkItem::BtBookmarkItem(CSwordModuleInfo* module, QString key, QString& description)
+ :m_description(description),
+ m_moduleName(module ? module->name() : QString::null)
+{
+ if (((module && (module->type() == CSwordModuleInfo::Bible)) || (module->type() == CSwordModuleInfo::Commentary)) ) {
+ CSwordVerseKey vk(0);
+ vk.key(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)
+{
+ update();
+}
+
+CSwordModuleInfo* BtBookmarkItem::module()
+{
+ CSwordModuleInfo* const m = CPointers::backend()->findModuleByName(m_moduleName);
+ return m;
+}
+
+QString BtBookmarkItem::key()
+{
+ const QString englishKeyName = englishKey();
+ if (!module()) {
+ return englishKeyName;
+ }
+
+ QString returnKeyName = englishKeyName;
+ if ((module()->type() == CSwordModuleInfo::Bible) || (module()->type() == CSwordModuleInfo::Commentary)) {
+ CSwordVerseKey vk(0);
+ vk.key(englishKeyName);
+ vk.setLocale(CPointers::backend()->booknameLanguage().toLatin1() );
+
+ returnKeyName = vk.key(); //the returned key is always in the currently set bookname language
+ }
+
+ return returnKeyName;
+}
+
+const QString& BtBookmarkItem::description()
+{
+ return m_description;
+}
+
+void BtBookmarkItem::setDescription(QString text)
+{
+ m_description = text;
+}
+
+QString BtBookmarkItem::toolTip()
+{
+ if (!module()) {
+ return QString::null;
+ }
+
+ CSwordBackend::FilterOptions filterOptions = CBTConfig::getFilterOptionDefaults();
+ filterOptions.footnotes = false;
+ filterOptions.scriptureReferences = false;
+ CPointers::backend()->setFilterOptions(filterOptions);
+
+ QString ret;
+ boost::scoped_ptr<CSwordKey> k( CSwordKey::createInstance(module()) );
+ k->key(this->key());
+
+ const CLanguageMgr::Language* lang = module()->language();
+ CBTConfig::FontSettingsPair fontPair = CBTConfig::get
+ (lang);
+
+ Q_ASSERT(k.get());
+ if (fontPair.first) { //use a special font
+ ret = QString::fromLatin1("<b>%1 (%2)</b><hr>%3")
+ .arg(key())
+ .arg(module()->name())
+ .arg(description())
+ ;
+ }
+ else {
+ ret = QString::fromLatin1("<b>%1 (%2)</b><hr>%3")
+ .arg(key())
+ .arg(module()->name())
+ .arg(description())
+ ;
+ }
+
+ return ret;
+}
+
+bool BtBookmarkItem::enableAction(MenuAction action)
+{
+ if (action == ChangeBookmark || (module() && (action == PrintBookmarks)) || action == DeleteEntries)
+ return true;
+
+ return false;
+}
+
+void BtBookmarkItem::rename()
+{
+ bool ok = false;
+ const QString newDescription = CInputDialog::getText(QObject::tr("Change description ..."), QObject::tr("Enter a new description for the chosen bookmark."), description(), &ok, treeWidget());
+
+ if (ok) {
+ m_description = newDescription;
+ update();
+ }
+}
+
+QString BtBookmarkItem::englishKey() const
+{
+ return m_key;
+}
+
+void BtBookmarkItem::update()
+{
+ qDebug() << "BtBookmarkItem::update";
+ setIcon(0, util::filesystem::DirectoryUtil::getIcon(CResMgr::mainIndex::bookmark::icon));
+
+ const QString title = QString::fromLatin1("%1 (%2)").arg(key()).arg(module() ? module()->name() : QObject::tr("unknown"));
+ setText(0, title);
+ setToolTip(0, toolTip());
+}
+
diff --git a/src/frontend/mainindex/bookmarks/btbookmarkitem.h b/src/frontend/mainindex/bookmarks/btbookmarkitem.h
new file mode 100644
index 0000000..8529e23
--- /dev/null
+++ b/src/frontend/mainindex/bookmarks/btbookmarkitem.h
@@ -0,0 +1,67 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 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 "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(CSwordModuleInfo* module, QString key, QString& description);
+
+ /** Creates a copy. */
+ BtBookmarkItem(const BtBookmarkItem& other);
+
+ ~BtBookmarkItem() {}
+
+ /** Returns the used module, 0 if there is no such module. */
+ CSwordModuleInfo* module();
+
+ /** Returns the used key. */
+ QString key();
+
+ /** Returns the used description. */
+ const QString& description();
+ /** Sets the description text for this bookmark. */
+ virtual void setDescription(QString text);
+
+ /** Returns a tooltip for this bookmark. */
+ virtual QString toolTip();
+
+ /** 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.*/
+ QString englishKey() const;
+
+ QString m_key;
+ QString m_description;
+ QString m_moduleName;
+};
+
+#endif
diff --git a/src/frontend/mainindex/bookmarks/btbookmarkitembase.cpp b/src/frontend/mainindex/bookmarks/btbookmarkitembase.cpp
new file mode 100644
index 0000000..bd5ae13
--- /dev/null
+++ b/src/frontend/mainindex/bookmarks/btbookmarkitembase.cpp
@@ -0,0 +1,41 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btbookmarkitembase.h"
+#include "cbookmarkindex.h"
+
+#include <QTreeWidgetItem>
+#include <QDropEvent>
+
+BtBookmarkItemBase::BtBookmarkItemBase()
+{}
+
+BtBookmarkItemBase::BtBookmarkItemBase(QTreeWidgetItem* parent)
+ : QTreeWidgetItem(parent)
+{}
+
+CBookmarkIndex* BtBookmarkItemBase::bookmarkWidget() const
+{
+ return dynamic_cast<CBookmarkIndex*>(treeWidget());
+}
+
+// void BtBookmarkItemBase::dropped(QDropEvent* e)
+// {
+//
+// }
+//
+// void BtBookmarkItemBase::addPreviousSibling(BtBookmarkItemBase* item)
+// {
+//
+// }
+//
+// void BtBookmarkItemBase::addNextSibling(BtBookmarkItemBase* item)
+// {
+//
+// }
diff --git a/src/frontend/mainindex/bookmarks/btbookmarkitembase.h b/src/frontend/mainindex/bookmarks/btbookmarkitembase.h
new file mode 100644
index 0000000..1e486e6
--- /dev/null
+++ b/src/frontend/mainindex/bookmarks/btbookmarkitembase.h
@@ -0,0 +1,63 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 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 <QString>
+#include <QMimeData>
+#include <QDropEvent>
+
+class CBookmarkIndex;
+
+
+class BtBookmarkItemBase : public QTreeWidgetItem
+{
+public:
+
+ enum MenuAction {
+ NewFolder = 0,
+ ChangeFolder,
+
+ ChangeBookmark,
+ 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() = 0;
+ virtual CBookmarkIndex* bookmarkWidget() const;
+
+ /** 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/mainindex/bookmarks/btbookmarkloader.cpp b/src/frontend/mainindex/bookmarks/btbookmarkloader.cpp
new file mode 100644
index 0000000..3e70dbe
--- /dev/null
+++ b/src/frontend/mainindex/bookmarks/btbookmarkloader.cpp
@@ -0,0 +1,174 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btbookmarkloader.h"
+
+#include "btbookmarkitem.h"
+#include "btbookmarkfolder.h"
+
+#include "util/ctoolclass.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+
+#include <QTreeWidgetItem>
+#include <QDomElement>
+#include <QDomNode>
+#include <QDomDocument>
+#include <QTextStream>
+#include <QFile>
+#include <QIODevice>
+#include <QTextCodec>
+
+#include <QDebug>
+
+#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(parent, QString());
+ 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");
+ }
+ newBookmarkItem->update();
+ newItem = newBookmarkItem;
+ }
+ qDebug() << "BtBookmarkLoader::handleXmlElement: return new item";
+ return newItem;
+}
+
+
+QString BtBookmarkLoader::loadXmlFromFile(QString fileName)
+{
+ if (fileName.isNull()) {
+ fileName = util::filesystem::DirectoryUtil::getUserBaseDir().absolutePath() + "/bookmarks.xml";
+ }
+ QFile file(fileName);
+ if (!file.exists())
+ return QString();
+
+ 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)
+{
+ Q_ASSERT(rootItem);
+ if (fileName.isNull()) {
+ fileName = util::filesystem::DirectoryUtil::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);
+ }
+ CToolClass::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);
+
+ parentElement.appendChild(elem);
+ }
+}
diff --git a/src/frontend/mainindex/bookmarks/btbookmarkloader.h b/src/frontend/mainindex/bookmarks/btbookmarkloader.h
new file mode 100644
index 0000000..3ae0bb6
--- /dev/null
+++ b/src/frontend/mainindex/bookmarks/btbookmarkloader.h
@@ -0,0 +1,47 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 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/directoryutil.h"
+
+#include <QString>
+#include <QList>
+#include <QDomElement>
+
+
+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/mainindex/bookmarks/cbookmarkindex.cpp b/src/frontend/mainindex/bookmarks/cbookmarkindex.cpp
new file mode 100644
index 0000000..7405fd3
--- /dev/null
+++ b/src/frontend/mainindex/bookmarks/cbookmarkindex.cpp
@@ -0,0 +1,850 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//BibleTime includes
+#include "cbookmarkindex.h"
+
+#include "btbookmarkitembase.h"
+#include "btbookmarkitem.h"
+#include "btbookmarkfolder.h"
+#include "btbookmarkloader.h"
+
+#include "backend/managers/creferencemanager.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+
+#include "frontend/searchdialog/csearchdialog.h"
+#include "backend/config/cbtconfig.h"
+#include "frontend/cinfodisplay.h"
+
+#include "frontend/cprinter.h"
+#include "frontend/cdragdrop.h"
+
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+#include "util/ctoolclass.h"
+
+#include <boost/scoped_ptr.hpp>
+
+//Qt includes
+#include <QInputDialog>
+#include <QDragLeaveEvent>
+#include <QDragMoveEvent>
+#include <QDropEvent>
+#include <QHeaderView>
+#include <QTimer>
+#include <QToolTip>
+#include <QList>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+#include <QCursor>
+#include <QMouseEvent>
+#include <QMessageBox>
+#include <QMenu>
+#include <QAction>
+#include <QPaintEvent>
+#include <QPainter>
+#include <QApplication>
+#include <QDrag>
+
+#include <QDebug>
+
+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");
+
+ header()->hide();
+
+ 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.changeBookmark = newQAction(tr("Change bookmark description..."), CResMgr::mainIndex::changeBookmark::icon, 0, this, SLOT(changeBookmark()), 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.changeBookmark);
+ 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);
+
+ //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)
+{
+ QAction* action = new QAction(util::filesystem::DirectoryUtil::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);
+}
+
+
+/**
+* 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)
+{
+ static QPixmap pix;
+ static int halfPixHeight;
+ static bool arrowInitialized = false;
+
+ // Initialize the static variables, including the arrow pixmap
+ if (!arrowInitialized) {
+ arrowInitialized = true;
+ int arrowSize = CToolClass::mWidth(this, 1);
+ QString fileName;
+ if (util::filesystem::DirectoryUtil::getIconDir().exists("pointing_arrow.svg")) {
+ fileName = util::filesystem::DirectoryUtil::getIconDir().filePath("pointing_arrow.svg");
+ } else {
+ if (util::filesystem::DirectoryUtil::getIconDir().exists("pointing_arrow.png")) {
+ fileName = util::filesystem::DirectoryUtil::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);
+ } 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 = CPointers::backend()->findModuleByName(moduleName);
+
+ QTreeWidgetItem* newItem = new BtBookmarkItem(minfo, keyText, description);
+ parentItem->insertChild(indexInParent, newItem);
+ }
+}
+
+
+/** 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::ChangeBookmark:
+ return m_actions.changeBookmark;
+ 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::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(0, QObject::tr("New folder"));
+ //parentFolder->addChild(newFolder);
+ insertTopLevelItem(topLevelItemCount()-1, newFolder);
+ newFolder->update();
+ newFolder->rename();
+ }
+}
+
+/** Opens a dialog to change the current folder. */
+void CBookmarkIndex::changeFolder() {
+ BtBookmarkFolder* i = dynamic_cast<BtBookmarkFolder*>(currentItem());
+ Q_ASSERT(i);
+ if (i) {
+ i->rename();
+ }
+}
+
+/** Changes the current bookmark. */
+void CBookmarkIndex::changeBookmark() {
+ BtBookmarkItem* i = dynamic_cast<BtBookmarkItem*>(currentItem());
+ Q_ASSERT(i);
+
+ if (i) {
+ i->rename();
+ }
+}
+
+/** 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();
+ }
+}
+
+/** 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;
+ }
+ boost::scoped_ptr<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 (QMessageBox::question(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
+ }
+
+}
+
+
+/*
+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::ChangeBookmark:
+ 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());
+ //qDebug("CBookmarkIndex::saveBookmarks end");
+}
+
+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()) {
+ (CPointers::infoDisplay())->setInfo(
+ InfoDisplay::CInfoDisplay::CrossReference,
+ bitem->module()->name() + ":" + bitem->key()
+ );
+ } else {
+ (CPointers::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;
+}
+
diff --git a/src/frontend/mainindex/bookmarks/cbookmarkindex.h b/src/frontend/mainindex/bookmarks/cbookmarkindex.h
new file mode 100644
index 0000000..39e2df3
--- /dev/null
+++ b/src/frontend/mainindex/bookmarks/cbookmarkindex.h
@@ -0,0 +1,182 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 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
+
+//BibleTime includes
+#include "btbookmarkitembase.h"
+
+class CSwordModuleInfo;
+#include "frontend/displaywindow/cdisplaywindow.h"
+
+#include "util/cpointers.h"
+
+//Qt includes
+#include <QTimer>
+#include <QToolTip>
+#include <QList>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+
+class CSearchDialog;
+class CMainIndex;
+class QWidget;
+class QDropEvent;
+class QDragMoveEvent;
+class QDragLeaveEvent;
+class BTMimeData;
+class QMenu;
+class QAction;
+class QPaintEvent;
+
+class QMouseEvent;
+
+/**
+* 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& );
+
+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 changeBookmark();
+
+ /** 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* changeBookmark;
+ 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;
+};
+
+#endif
diff --git a/src/frontend/mainindex/bookshelf/actionenum.h b/src/frontend/mainindex/bookshelf/actionenum.h
new file mode 100644
index 0000000..919e8ac
--- /dev/null
+++ b/src/frontend/mainindex/bookshelf/actionenum.h
@@ -0,0 +1,24 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef ACTIONENUM_H
+#define ACTIONENUM_H
+
+enum IndexAction {
+ EditModule,
+ UnlockModule,
+ HideModules,
+ ShowAllModules,
+ SearchModules,
+ UpdateModules,
+ Grouping,
+ AboutModule
+};
+
+#endif
diff --git a/src/frontend/mainindex/bookshelf/btindexfolder.cpp b/src/frontend/mainindex/bookshelf/btindexfolder.cpp
new file mode 100644
index 0000000..632817e
--- /dev/null
+++ b/src/frontend/mainindex/bookshelf/btindexfolder.cpp
@@ -0,0 +1,19 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btindexfolder.h"
+#include "backend/btmoduletreeitem.h"
+#include "util/directoryutil.h"
+
+BTIndexFolder::BTIndexFolder(BTModuleTreeItem* treeItem, QTreeWidgetItem* parent)
+ : BTIndexItem(parent)
+{
+ setText(0, treeItem->text());
+ setIcon(0, util::filesystem::DirectoryUtil::getIcon(treeItem->iconName()));
+}
diff --git a/src/frontend/mainindex/bookshelf/btindexfolder.h b/src/frontend/mainindex/bookshelf/btindexfolder.h
new file mode 100644
index 0000000..6c8f672
--- /dev/null
+++ b/src/frontend/mainindex/bookshelf/btindexfolder.h
@@ -0,0 +1,30 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTINDEXFOLDER_H
+#define BTINDEXFOLDER_H
+
+#include "btindexitem.h"
+
+#include <QString>
+
+class BTModuleTreeItem;
+
+/**
+ @author The BibleTime team <info@bibletime.info>
+*/
+class BTIndexFolder : public BTIndexItem
+{
+public:
+ BTIndexFolder(BTModuleTreeItem* treeItem, QTreeWidgetItem* p);
+
+ ~BTIndexFolder() {}
+};
+
+#endif
diff --git a/src/frontend/mainindex/bookshelf/btindexitem.cpp b/src/frontend/mainindex/bookshelf/btindexitem.cpp
new file mode 100644
index 0000000..2356f84
--- /dev/null
+++ b/src/frontend/mainindex/bookshelf/btindexitem.cpp
@@ -0,0 +1,19 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btindexitem.h"
+#include "cbookshelfindex.h"
+
+#include <QTreeWidgetItem>
+#include <QTreeWidget>
+
+
+BTIndexItem::BTIndexItem(QTreeWidgetItem* parent)
+ : QTreeWidgetItem(parent)
+{}
diff --git a/src/frontend/mainindex/bookshelf/btindexitem.h b/src/frontend/mainindex/bookshelf/btindexitem.h
new file mode 100644
index 0000000..33d2f7b
--- /dev/null
+++ b/src/frontend/mainindex/bookshelf/btindexitem.h
@@ -0,0 +1,45 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTINDEXITEM_H
+#define BTINDEXITEM_H
+
+#include "actionenum.h"
+
+#include <QTreeWidgetItem>
+#include <QString>
+
+class CMainIndex;
+class QMimeData;
+class QAction;
+
+
+/**
+@author The BibleTime team <info@bibletime.info>
+*/
+class BTIndexItem : public QTreeWidgetItem
+{
+public:
+ /** Those menu actions which are item specific. */
+
+ BTIndexItem(QTreeWidgetItem* parent);
+ virtual ~BTIndexItem() {};
+ /**
+ * Enables the given action if it has the "indexActionType" property which this item supports.
+ * Handles only those actions which may or may not be supported, not those which
+ * are always supported by all items. If the action is not supported in the current state of the
+ * item this function does nothing.
+ */
+ virtual bool enableAction(QAction*) const {return false;}
+
+ //TODO: d'n'd functions so that view can delegate d'n'd to items?
+ virtual bool acceptDrop(const QMimeData*) {return false;}
+};
+
+#endif
diff --git a/src/frontend/mainindex/bookshelf/btindexmodule.cpp b/src/frontend/mainindex/bookshelf/btindexmodule.cpp
new file mode 100644
index 0000000..91a9f2f
--- /dev/null
+++ b/src/frontend/mainindex/bookshelf/btindexmodule.cpp
@@ -0,0 +1,93 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btindexmodule.h"
+
+#include "backend/btmoduletreeitem.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "util/directoryutil.h"
+#include "frontend/cdragdrop.h"
+
+#include <QIcon>
+#include <QString>
+#include <QDebug>
+#include <QAction>
+
+
+
+BTIndexModule::BTIndexModule(BTModuleTreeItem* treeItem, QTreeWidgetItem* previous)
+ : BTIndexItem(previous)
+{
+ //qDebug("BTIndexModule::BTIndexModule");
+ setText(0, treeItem->text()); //set text
+ setIcon(0, util::filesystem::DirectoryUtil::getIcon(treeItem->iconName()) );
+ m_moduleInfo = treeItem->moduleInfo();
+ setToolTip(0, CToolClass::moduleToolTip(moduleInfo()) );
+
+ setFlags(Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled|Qt::ItemIsSelectable);
+ if (!m_moduleInfo->isHidden()) {
+ setFlags(flags()|Qt::ItemIsEnabled);
+ }
+}
+
+
+BTIndexModule::~BTIndexModule()
+{
+}
+
+
+bool BTIndexModule::enableAction(QAction* action) const
+{
+ if (!action->isEnabled()) {
+ IndexAction actionType = (IndexAction)action->property("indexActionType").toInt();
+
+ switch (actionType) {
+ case EditModule:
+ if (moduleInfo()->isWritable()) action->setEnabled(true);
+ break;
+ case UnlockModule:
+ if (moduleInfo()->isEncrypted()) action->setEnabled(true);
+ break;
+ case HideModules:
+ if (!m_moduleInfo->isHidden()) action->setEnabled(true);
+ case UpdateModules:
+ break;
+ case AboutModule:
+ case Grouping:
+ case SearchModules:
+ case ShowAllModules: break;
+ }
+ }
+ return true; //TODO: check, is this correct?
+}
+
+
+bool BTIndexModule::acceptDrop(const QMimeData* data)
+{
+ //TODO: check the module type of the reference, accept only proper type.
+ // Bible accepts biblical references and plain text (for search),
+ // but it could accept a lexicon entry too for search, especially a Strong's entry.
+ // Lexicon could accept lexicon references but also biblical references to find all places where
+ // the verse is referred to. Same with genbooks.
+
+ const BTMimeData* btData = dynamic_cast<const BTMimeData*>(data);
+ if (btData) {
+ return true;
+ }
+ if (data->hasText()) {
+ return true;
+ }
+ return false;
+}
+
+
+CSwordModuleInfo* BTIndexModule::moduleInfo() const
+{
+ return m_moduleInfo;
+}
diff --git a/src/frontend/mainindex/bookshelf/btindexmodule.h b/src/frontend/mainindex/bookshelf/btindexmodule.h
new file mode 100644
index 0000000..cbd711c
--- /dev/null
+++ b/src/frontend/mainindex/bookshelf/btindexmodule.h
@@ -0,0 +1,39 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTINDEXMODULE_H
+#define BTINDEXMODULE_H
+
+#include "btindexitem.h"
+
+#include "util/ctoolclass.h"
+
+class BTModuleTreeItem;
+class CSwordModuleInfo;
+
+class QAction;
+class QMimeData;
+
+
+class BTIndexModule : public BTIndexItem
+{
+public:
+ BTIndexModule(BTModuleTreeItem* treeItem, QTreeWidgetItem* previous);
+
+ ~BTIndexModule();
+
+ virtual bool enableAction(QAction* action) const;
+ virtual bool acceptDrop(const QMimeData* data);
+ CSwordModuleInfo* moduleInfo() const;
+
+private:
+ CSwordModuleInfo* m_moduleInfo;
+};
+
+#endif
diff --git a/src/frontend/mainindex/bookshelf/cbookshelfindex.cpp b/src/frontend/mainindex/bookshelf/cbookshelfindex.cpp
new file mode 100644
index 0000000..1c6db2a
--- /dev/null
+++ b/src/frontend/mainindex/bookshelf/cbookshelfindex.cpp
@@ -0,0 +1,722 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cbookshelfindex.h"
+
+#include "btindexitem.h"
+#include "btindexmodule.h"
+#include "btindexfolder.h"
+#include "chidemodulechooserdialog.h"
+
+#include "backend/btmoduletreeitem.h"
+#include "backend/managers/creferencemanager.h"
+
+#include "frontend/searchdialog/csearchdialog.h"
+#include "backend/config/cbtconfig.h"
+#include "frontend/cinfodisplay.h"
+#include "frontend/btaboutmoduledialog.h"
+#include "frontend/cprinter.h"
+#include "frontend/cdragdrop.h"
+
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+
+//Qt includes
+#include <QDragLeaveEvent>
+#include <QDragMoveEvent>
+#include <QDropEvent>
+#include <QHeaderView> //for hiding the header
+#include <QTimer> // for delayed auto-opening of folders
+#include <QList>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+#include <QInputDialog> // for unlocking key
+#include <QDebug>
+#include <QMenu>
+
+#include <boost/scoped_ptr.hpp>
+
+
+
+CBookshelfIndex::CBookshelfIndex(QWidget *parent)
+ : QTreeWidget(parent),
+ m_searchDialog(0),
+ m_autoOpenFolder(0),
+ m_autoOpenTimer(this)
+{
+ m_grouping = (BTModuleTreeItem::Grouping)CBTConfig::get(CBTConfig::bookshelfGrouping);
+ m_showHidden = CBTConfig::get(CBTConfig::bookshelfShowHidden);
+ setContextMenuPolicy(Qt::CustomContextMenu);
+ initView();
+ initConnections();
+ initTree();
+}
+
+CBookshelfIndex::~CBookshelfIndex() {}
+
+
+
+/** Initializes the view. */
+void CBookshelfIndex::initView()
+{
+// qDebug("CBookshelfIndex::initView");
+
+ header()->hide();
+
+ setFocusPolicy(Qt::WheelFocus);
+ setAcceptDrops( false ); // TODO: accept drops
+ setDragEnabled( true );
+ setDropIndicatorShown( true );
+
+ setItemsExpandable(true);
+ viewport()->setAcceptDrops(false); //TODO: accept drops
+ setRootIsDecorated(false);
+ setAllColumnsShowFocus(true);
+ setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+ //setup the popup menu
+ m_popup = new QMenu(viewport());
+ m_popup->setTitle(tr("Bookshelf"));
+
+ initActions();
+
+// qDebug("CBookshelfIndex::initView end");
+}
+
+void CBookshelfIndex::initActions()
+{
+
+ // Each action has a type attached to it as a dynamic property, see actionenum.h.
+ // Menuitem and its subitems can have the same type.
+ // Actions can have also "singleItemAction" property if
+ // it supports only one item.
+ // See contextMenu() and BTIndexItem for how these properties are used later.
+
+ // Actions are added to the popup menu and also to a list for easy foreach access.
+
+ QMenu* actionMenu = 0;
+ QAction* action = 0;
+
+ // -------------------------Grouping --------------------------------------
+ actionMenu = new QMenu(tr("Grouping"), this);
+ actionMenu->setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::mainIndex::grouping::icon));
+ actionMenu->setProperty("indexActionType", QVariant(Grouping));
+
+ m_groupingGroup = new QActionGroup(this);
+ QObject::connect(m_groupingGroup, SIGNAL(triggered(QAction*)), this, SLOT(actionChangeGrouping(QAction*)) );
+
+ //TODO: set the inital checked state
+ action = newQAction(tr("Category/Language"), CResMgr::mainIndex::grouping::icon, 0, 0, 0, this);
+ action->setCheckable(true);
+ action->setProperty("indexActionType", QVariant(Grouping));
+ action->setProperty("grouping", BTModuleTreeItem::CatLangMod);
+ actionMenu->addAction(action);
+ m_groupingGroup->addAction(action);
+ if (m_grouping == BTModuleTreeItem::CatLangMod) action->setChecked(true);
+ m_actionList.append(action);
+
+ action = newQAction(tr("Category"),CResMgr::mainIndex::grouping::icon, 0, 0, 0, this);
+ action->setCheckable(true);
+ m_groupingGroup->addAction(action);
+ if (m_grouping == BTModuleTreeItem::CatMod) action->setChecked(true);
+ action->setProperty("indexActionType", QVariant(Grouping));
+ action->setProperty("grouping", BTModuleTreeItem::CatMod);
+ actionMenu->addAction(action);
+ m_actionList.append(action);
+
+ action = newQAction(tr("Language/Category"),CResMgr::mainIndex::grouping::icon, 0, 0, 0, this);
+ action->setCheckable(true);
+ m_groupingGroup->addAction(action);
+ if (m_grouping == BTModuleTreeItem::LangCatMod) action->setChecked(true);
+ actionMenu->addAction(action);
+ action->setProperty("indexActionType", QVariant(Grouping));
+ action->setProperty("grouping", BTModuleTreeItem::LangCatMod);
+ m_actionList.append(action);
+
+ action = newQAction(tr("Language"),CResMgr::mainIndex::grouping::icon, 0, 0, 0, this);
+ action->setCheckable(true);
+ m_groupingGroup->addAction(action);
+ if (m_grouping == BTModuleTreeItem::LangMod) action->setChecked(true);
+ actionMenu->addAction(action);
+ action->setProperty("indexActionType", QVariant(Grouping));
+ action->setProperty("grouping", BTModuleTreeItem::LangMod);
+ m_actionList.append(action);
+
+ action = newQAction(tr("Works only"),CResMgr::mainIndex::grouping::icon, 0, 0, 0, this);
+ action->setCheckable(true);
+ m_groupingGroup->addAction(action);
+ if (m_grouping == BTModuleTreeItem::Mod) action->setChecked(true);
+ actionMenu->addAction(action);
+ action->setProperty("indexActionType", QVariant(Grouping));
+ action->setProperty("grouping", BTModuleTreeItem::Mod);
+ m_actionList.append(action);
+
+ action = m_popup->addMenu(actionMenu);
+ action->setProperty("indexActionType", QVariant(Grouping));
+ m_actionList.append(action);
+
+
+ // ------------Hide---------------------
+ action = newQAction(tr("Hide/unhide works..."),CResMgr::mainIndex::search::icon, 0, this, SLOT(actionHideModules()), this);
+ action->setProperty("indexActionType", QVariant(HideModules));
+ //action->setProperty("multiItemAction", QVariant(true));
+ m_popup->addAction(action);
+ m_actionList.append(action);
+
+// -------------------Show hidden---------------------------
+ action = newQAction(tr("Show hidden"),CResMgr::mainIndex::search::icon, 0, 0, 0, this);
+ action->setProperty("indexActionType", QVariant(ShowAllModules));
+ action->setCheckable(true);
+ QObject::connect(action, SIGNAL(toggled(bool)), this, SLOT(actionShowModules(bool)));
+ if (m_showHidden) action->setChecked(true); else action->setChecked(false);
+ m_popup->addAction(action);
+ m_actionList.append(action);
+
+
+ m_popup->addSeparator();
+
+ //------------------------------------------------------------
+ //----------------- Actions for items ------------------------
+
+ // -------------------------Edit module --------------------------------
+ actionMenu = new QMenu(tr("Edit"), this);
+ actionMenu->setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::mainIndex::editModuleMenu::icon) );
+// actionMenu->setDelayed(false);
+ actionMenu->setProperty("indexActionType", QVariant(EditModule));
+ actionMenu->setProperty("singleItemAction", QVariant(true));
+ //m_actionList.append(actionMenu);
+
+ action = newQAction(tr("Plain text..."),CResMgr::mainIndex::editModulePlain::icon, 0, this, SLOT(actionEditModulePlain()), this);
+ actionMenu->addAction(action);
+ m_actionList.append(action);
+ action->setProperty("indexActionType", QVariant(EditModule));
+ action->setProperty("singleItemAction", QVariant(true));
+
+ action = newQAction(tr("HTML..."),CResMgr::mainIndex::editModuleHTML::icon, 0, this, SLOT(actionEditModuleHTML()), this);
+ actionMenu->addAction(action);
+ m_actionList.append(action);
+ action->setProperty("indexActionType", QVariant(EditModule));
+ action->setProperty("singleItemAction", QVariant(true));
+
+ m_actionList.append(m_popup->addMenu(actionMenu));
+
+
+ // ------------------------ Misc actions -------------------------------------
+ action = newQAction(tr("Search..."),CResMgr::mainIndex::search::icon, 0, this, SLOT(actionSearchInModules()), this);
+ action->setProperty("indexActionType", QVariant(SearchModules));
+ action->setProperty("multiItemAction", QVariant(true));
+ m_popup->addAction(action);
+ m_actionList.append(action);
+
+ action = newQAction(tr("Unlock..."),CResMgr::mainIndex::unlockModule::icon, 0, this, SLOT(actionUnlockModule()), this);
+ m_popup->addAction(action);
+ action->setProperty("indexActionType", QVariant(UnlockModule));
+ action->setProperty("singleItemAction", QVariant(true));
+ m_actionList.append(action);
+
+ action = newQAction(tr("About..."),CResMgr::mainIndex::aboutModule::icon, 0, this, SLOT(actionAboutModule()), this);
+ m_popup->addAction(action);
+ action->setProperty("singleItemAction", QVariant(true));
+ action->setProperty("indexActionType", QVariant(AboutModule));
+ m_actionList.append(action);
+
+
+}
+
+/** 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* CBookshelfIndex::newQAction(const QString& text, const QString& pix, const int /*shortcut*/, const QObject* receiver, const char* slot, QObject* parent)
+{
+ QAction* action = new QAction(util::filesystem::DirectoryUtil::getIcon(pix), text, parent);
+ if (receiver && !QString(slot).isEmpty())
+ {
+ QObject::connect(action, SIGNAL(triggered()), receiver, slot);
+ }
+ return action;
+}
+
+/** Initialize the SIGNAL<->SLOT connections */
+void CBookshelfIndex::initConnections()
+{
+ //Connect this to the backend module list changes.
+ bool ok;
+ ok = connect(CPointers::backend(), SIGNAL(sigSwordSetupChanged(CSwordBackend::SetupChangedReason)), SLOT(reloadSword(CSwordBackend::SetupChangedReason)));
+ Q_ASSERT(ok);
+
+ ok = connect(this, SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SLOT(slotExecuted(QTreeWidgetItem*)));
+ Q_ASSERT(ok);
+
+ // Single/double click item activation is style dependend
+ if (style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) == 0)
+ {
+ ok = connect(this, SIGNAL(itemClicked(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_autoOpenTimer, SIGNAL(timeout()), this, SLOT(autoOpenTimeout()));
+ Q_ASSERT(ok);
+
+ ok = connect(this, SIGNAL(itemSelectionChanged()), this, SLOT(slotModifySelection()));
+ Q_ASSERT(ok);
+}
+
+void CBookshelfIndex::slotModifySelection()
+{
+ // This creates recursion if a folder is selected, but not infinite.
+ //qDebug("CBookshelfIndex::slotModifySelection");
+ QList<QTreeWidgetItem*> selection = selectedItems();
+ foreach (QTreeWidgetItem* item, selection) {
+ BTIndexFolder* folder = dynamic_cast<BTIndexFolder*>(item);
+ if (folder) {
+ item->setSelected(false);
+ break;
+ }
+ }
+}
+
+/**
+* Hack to get single click and selection working. See slotExecuted.
+*/
+void CBookshelfIndex::mouseReleaseEvent(QMouseEvent* event) {
+ //qDebug("CBookshelfIndex::mouseReleaseEvent");
+ //qDebug() << event->type() << event->modifiers();
+ if (itemAt(event->pos())) {
+ if (m_frozenModules.contains( itemAt(event->pos())->text(0) )) {
+ //do nothing
+ event->accept();
+ return;
+ }
+ }
+ m_mouseReleaseEventModifiers = event->modifiers();
+ QTreeWidget::mouseReleaseEvent(event);
+
+}
+
+/** Called when an item is clicked with mouse or activated with keyboard. */
+void CBookshelfIndex::slotExecuted( QTreeWidgetItem* i )
+{
+ qDebug("CBookshelfIndex::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;
+ }
+
+ BTIndexItem* btItem = dynamic_cast<BTIndexItem*>(i);
+ if (!btItem) {
+ qWarning("item was not BTIndexItem!");
+ return;
+ }
+
+ if (BTIndexModule* m = dynamic_cast<BTIndexModule*>(i)) { //clicked on a module
+ CSwordModuleInfo* mod = m->moduleInfo();
+ if (!m_frozenModules.contains(mod->name())) {
+ m_frozenModules.insert(mod->name());
+ QList<CSwordModuleInfo*> modules;
+ modules.append(mod);
+ qDebug("will emit createReadDisplayWindow");
+ emit createReadDisplayWindow(modules, QString::null);
+
+ }
+ } else {
+ i->setExpanded( !i->isExpanded() );
+ }
+}
+
+void CBookshelfIndex::unfreezeModules(QList<CSwordModuleInfo*> modules)
+{
+ foreach (CSwordModuleInfo* mInfo, modules) {
+ m_frozenModules.remove(mInfo->name());
+ }
+}
+
+/** Reimplementation. Returns the drag object for the current selection. */
+QMimeData* CBookshelfIndex::dragObject()
+{
+ //TODO: we have to add a mime type "module" if we want to for example enable draggin a module to a displaywindow
+ return 0;
+}
+
+
+/** Reimplementation from QTreeWidget. Returns true if the drag is acceptable for the widget. */
+void CBookshelfIndex::dragEnterEvent( QDragEnterEvent* event )
+{
+ //qDebug("CBookshelfIndex::dragEnterEvent");
+ event->acceptProposedAction();
+}
+
+void CBookshelfIndex::dragMoveEvent( QDragMoveEvent* event )
+{
+ const QPoint pos = event->pos();
+
+ BTIndexItem* i = dynamic_cast<BTIndexItem*>(itemAt(pos));
+ //TODO: implement accepting drop in item
+ if (i && i->acceptDrop(event->mimeData()) ) {
+ event->acceptProposedAction();
+ } else {
+ event->ignore();
+ }
+}
+
+void CBookshelfIndex::dropEvent( QDropEvent* event )
+{
+ const QPoint pos = event->pos();
+
+ BTIndexItem* i = dynamic_cast<BTIndexItem*>(itemAt(pos));
+ //TODO: implement accepting drop in item
+ if (i && i->acceptDrop(event->mimeData()) ) {
+ QMenu* menu = new QMenu(this);
+ QAction* openAction = menu->addAction("Open reference in new subwindow");
+ QAction* searchRefAction = menu->addAction("Search for reference as crossreference");
+ QAction* searchAction = menu->addAction("Search text");
+ QAction* selectedAction = menu->exec(this->mapToGlobal(pos));
+ if (selectedAction == openAction) {;}
+ if (selectedAction == searchAction) {;}
+ if (selectedAction == searchRefAction) {;}
+ event->acceptProposedAction();
+ } else {
+ event->ignore();
+ }
+}
+
+void CBookshelfIndex::changeEvent(QEvent* e)
+{
+ if (e->type() == QEvent::StyleChange) {
+ // Single/double click item activation is style dependend
+ QObject::disconnect(this, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(slotExecuted(QTreeWidgetItem*)));
+ if (style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) == 0) {
+ QObject::connect(this, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(slotExecuted(QTreeWidgetItem*)));
+ }
+ }
+ QTreeWidget::changeEvent(e);
+}
+
+/** No descriptions */
+void CBookshelfIndex::initTree() {
+ qDebug("CBookshelfIndex::initTree");
+
+ //first clean the tree
+ clear();
+ //m_grouping = (BTModuleTreeItem::Grouping)CBTConfig::get(CBTConfig::bookshelfGrouping);
+
+ BTModuleTreeItem::HiddenOff hiddenFilter;
+ QList<BTModuleTreeItem::Filter*> filters;
+ if (!m_showHidden) {
+ filters.append(&hiddenFilter);
+ }
+ BTModuleTreeItem root(filters, m_grouping);
+ addToTree(&root, this->invisibleRootItem());
+}
+
+void CBookshelfIndex::addToTree(BTModuleTreeItem* item, QTreeWidgetItem* widgetItem)
+{
+ foreach (BTModuleTreeItem* i, item->children()) {
+ if (i->type() == BTModuleTreeItem::Module) {
+ addToTree(i, new BTIndexModule(i, widgetItem));
+ }
+ else
+ addToTree(i, new BTIndexFolder(i, widgetItem));
+ }
+ // Possible TODO: if item is Language and it's under Category and Category is Glossaries,
+ // add the second language name - but how to add other language group?
+ // do we have to modify btmoduletreeitem?
+}
+
+
+/** No descriptions */
+void CBookshelfIndex::emitModulesChosen( QList<CSwordModuleInfo*> modules, QString key ) {
+ emit createReadDisplayWindow(modules, key);
+}
+
+
+
+/** Shows the context menu at the given position. */
+void CBookshelfIndex::contextMenu(const QPoint& p) {
+ qDebug("CBookshelfIndex::contextMenu");
+ qDebug() << "list of actions: ";
+ foreach (QAction* action, m_actionList) {
+ qDebug() << action->text();
+ }
+ //setup menu entries depending on current selection
+ QTreeWidgetItem* i = itemAt(p);
+ qDebug() << "item at point: " << i;
+ QList<QTreeWidgetItem *> items = selectedItems();
+ //The item which was clicked may not be selected - but don't add folder
+ if (i && !dynamic_cast<BTIndexFolder*>(i) && !items.contains(i))
+ items.append(i);
+
+ // disable those menu entries which are item dependent,
+ // dis/enable some others
+ qDebug()<<"grouping action type:"<<(int)Grouping;
+ foreach (QAction* action, m_actionList) {
+ IndexAction actionType = (IndexAction)action->property("indexActionType").toInt();
+ qDebug() << "action type:" << actionType;
+ if ( actionType == Grouping ) {
+ qDebug()<<"grouping action, enabling...";
+ action->setEnabled(true);
+ qDebug()<< action->isEnabled();
+ }
+ else if (actionType == ShowAllModules) {
+ //enabled only if there are hidden modules
+ if (!CBTConfig::get(CBTConfig::hiddenModules).empty()) {
+ action->setEnabled(true);
+ } else {
+ action->setEnabled(false);
+ }
+ action->setChecked(m_showHidden);
+
+ }
+ else if (actionType == SearchModules) {
+ action->setText(tr("Search"));
+ if (items.count() > 0)
+ action->setEnabled(true);
+ else action->setEnabled(false);
+ }
+ else if (actionType == HideModules) {
+ //action->setText(tr("Hide"));
+ action->setEnabled(true);
+ }
+ else action->setEnabled(false);
+ }
+
+
+ if (items.count() == 0) {
+ //special handling for no selection: do nothing
+ }
+
+ if (items.count() == 1) {
+ //special handling for one selected item
+ qDebug("there was one selected item");
+ BTIndexItem* btItem = dynamic_cast<BTIndexItem*>(items.at(0));
+
+ if (btItem && !dynamic_cast<BTIndexFolder*>(btItem)) {
+ foreach (QAction* action, m_actionList) {
+ if ( (IndexAction)action->property("indexActionType").toInt() == AboutModule ) {
+ qDebug() << "enabling action" << action->text();
+ action->setEnabled(true);
+ }
+ else if ((IndexAction)action->property("indexActionType").toInt() == SearchModules ) {
+ // Change the text of the menu item to reflect the module name
+ BTIndexModule* modItem = dynamic_cast<BTIndexModule*>(btItem);
+ if (modItem) {
+ CSwordModuleInfo* info = modItem->moduleInfo();
+ action->setText(tr("Search in %1...").arg(info->name()));
+ }
+ }
+ else {
+ qDebug() << "ask item" << items.at(0)->text(0) << "to enable the action" << action->text();
+ btItem->enableAction(action);
+ }
+ qDebug() << "action enabled is: " << action->isEnabled();
+ }
+ }
+ }
+ else { // more than one item
+ foreach (QAction* action, m_actionList) {
+ // Change the text of some menu items to reflect multiple selection
+ if ((IndexAction)action->property("indexActionType").toInt() == SearchModules ) {
+ action->setText(tr("Search in selected..."));
+ }
+ // Enable items
+ foreach(QTreeWidgetItem* item, items) {
+ BTIndexItem* btItem = dynamic_cast<BTIndexItem*>(item);
+ if (btItem && !action->property("singleItemAction").isValid()) {
+ btItem->enableAction(action);
+ }
+ }
+ }
+ }
+
+ //finally, open the popup
+ m_popup->exec(mapToGlobal(p));
+}
+
+void CBookshelfIndex::actionChangeGrouping(QAction* action)
+{
+ BTModuleTreeItem::Grouping grouping = (BTModuleTreeItem::Grouping)action->property("grouping").toInt();
+ m_grouping = grouping;
+ CBTConfig::set(CBTConfig::bookshelfGrouping, grouping);
+ initTree();
+}
+
+
+/** Opens the searchdialog for the selected modules. */
+void CBookshelfIndex::actionSearchInModules() {
+ QList<QTreeWidgetItem *> items = selectedItems();
+ QListIterator<QTreeWidgetItem *> it(items);
+ QList<CSwordModuleInfo*> modules;
+ while(it.hasNext()) {
+ if (BTIndexModule* i = dynamic_cast<BTIndexModule*>(it.next())) {
+ if (i->moduleInfo()) {
+ modules.append(i->moduleInfo());
+ }
+ }
+ }
+
+ if (modules.isEmpty()) { //get a list of useful default modules for the search if no modules were selected
+ CSwordModuleInfo* m = CBTConfig::get(CBTConfig::standardBible);
+ if (m) {
+ modules.append(m);
+ }
+ }
+
+ Search::CSearchDialog::openDialog(modules, QString::null);
+}
+
+/** Unlocks the current module. */
+void CBookshelfIndex::actionUnlockModule() {
+ if (BTIndexModule* i = dynamic_cast<BTIndexModule*>(currentItem())) {
+ bool ok = false;
+ const QString unlockKey =
+ QInputDialog::getText(
+ this,
+ tr("Unlock Work"),
+ tr("Enter the unlock key for this work."),
+ QLineEdit::Normal,
+ i->moduleInfo()->config(CSwordModuleInfo::CipherKey),
+ &ok
+ );
+
+ if (ok) {
+ i->moduleInfo()->unlock( unlockKey );
+ CPointers::backend()->reloadModules(CSwordBackend::OtherChange);
+ }
+ }
+}
+
+void CBookshelfIndex::actionShowModules(bool checked)
+{
+ qDebug("CBookshelfIndex::actionShowModules");
+ m_showHidden = checked;
+ CBTConfig::set(CBTConfig::bookshelfShowHidden, m_showHidden);
+ // show hidden status is changed, notify others who may rebuild their module lists
+ CPointers::backend()->notifyChange(CSwordBackend::HidedModules);
+
+}
+
+void CBookshelfIndex::actionHideModules()
+{
+ qDebug("CBookshelfIndex::actionHideModules");
+ QString current;
+ if (BTIndexModule* i = dynamic_cast<BTIndexModule*>(currentItem())) {
+ current = i->text(0);
+ }
+
+ QString title(tr("Hide/Unhide Works"));
+ QString label(tr("Select the works to be hidden."));
+ CHideModuleChooserDialog* dlg = new CHideModuleChooserDialog(this, title, label, current);
+ connect(dlg, SIGNAL(modulesChanged(QList<CSwordModuleInfo*>)),
+ this, SLOT(setHiddenModules(QList<CSwordModuleInfo*>)));
+ int code = dlg->exec();
+ if (code == QDialog::Accepted) {
+ // notify all who may rebuild their module lists
+ CPointers::backend()->notifyChange(CSwordBackend::HidedModules);
+ }
+}
+
+
+/** Shows information about the current module. */
+void CBookshelfIndex::actionAboutModule() {
+ if (BTIndexModule* i = dynamic_cast<BTIndexModule*>(currentItem())) {
+ BTAboutModuleDialog* dialog = new BTAboutModuleDialog(this, i->moduleInfo());
+ dialog->show();
+ dialog->raise();
+ }
+}
+
+/** Reimplementation. Takes care of movable items. */
+void CBookshelfIndex::startDrag(Qt::DropActions /*supportedActions*/) {
+
+}
+
+/** Reimplementation to support the items dragEnter and dragLeave functions. */
+void CBookshelfIndex::contentsDragMoveEvent( QDragMoveEvent* /*event*/ ) {
+// // qWarning("void CBookshelfIndex:: drag move event ( QDragLeaveEvent* e )");
+// CIndexItemBase* i = dynamic_cast<CIndexItemBase*>( itemAt( contentsToViewport(event->pos())) );
+// if (i) {
+// if (i->allowAutoOpen(event) || (i->acceptDrop(event) && i->isFolder() && i->allowAutoOpen(event) && !i->isOpen() && autoOpen()) ) {
+// if (m_autoOpenFolder != i) {
+// m_autoOpenTimer.stop();
+// }
+//
+// m_autoOpenFolder = i;
+// m_autoOpenTimer.start( 400 );
+// }
+// else {
+// m_autoOpenFolder = 0;
+// }
+// }
+// else {
+// m_autoOpenFolder = 0;
+// }
+//
+// QTreeWidget::contentsDragMoveEvent(event);
+}
+
+
+void CBookshelfIndex::autoOpenTimeout() {
+ m_autoOpenTimer.stop();
+ if (m_autoOpenFolder && !m_autoOpenFolder->isExpanded() && m_autoOpenFolder->childCount()) {
+ m_autoOpenFolder->setExpanded(true);
+ }
+}
+
+/** No descriptions */
+void CBookshelfIndex::contentsDragLeaveEvent( QDragLeaveEvent* /*e*/ ) {
+// m_autoOpenTimer.stop();
+// QTreeWidget::contentsDragLeaveEvent(e);
+}
+
+
+/** Opens an editor window to edit the modules content. */
+void CBookshelfIndex::actionEditModulePlain() {
+ QList<CSwordModuleInfo*> modules;
+ QList<QTreeWidgetItem *> items = selectedItems();
+ QListIterator<QTreeWidgetItem *> it(items);
+ //loop through items
+ while(it.hasNext()) {
+ if (BTIndexModule* i = dynamic_cast<BTIndexModule*>(it.next())) {
+ modules.append(i->moduleInfo());
+ }
+ }
+ if (modules.count() == 1) {
+ emit createWriteDisplayWindow(modules.first(), QString::null, CDisplayWindow::PlainTextWindow);
+ };
+}
+
+/** Opens an editor window to edit the modules content. */
+void CBookshelfIndex::actionEditModuleHTML() {
+ QList<CSwordModuleInfo*> modules;
+ QList<QTreeWidgetItem *> items = selectedItems();
+ QListIterator<QTreeWidgetItem *> it(items);
+ while(it.hasNext()) {
+ if (BTIndexModule* i = dynamic_cast<BTIndexModule*>(it.next())) {
+ modules.append(i->moduleInfo());
+ }
+ }
+
+ if (modules.count() == 1) {
+ emit createWriteDisplayWindow(modules.first(), QString::null, CDisplayWindow::HTMLWindow);
+ }
+}
+
+/** Reloads the main index's Sword dependend things like modules */
+void CBookshelfIndex::reloadSword(CSwordBackend::SetupChangedReason) {
+ //reload the modules
+ qDebug("CBookshelfIndex::reloadSword");
+ initTree();
+}
diff --git a/src/frontend/mainindex/bookshelf/cbookshelfindex.h b/src/frontend/mainindex/bookshelf/cbookshelfindex.h
new file mode 100644
index 0000000..f9e56e7
--- /dev/null
+++ b/src/frontend/mainindex/bookshelf/cbookshelfindex.h
@@ -0,0 +1,207 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CBOOKSHELFINDEX_H
+#define CBOOKSHELFINDEX_H
+
+//BibleTime includes
+#include "btindexitem.h"
+#include "backend/btmoduletreeitem.h"
+class CSwordModuleInfo;
+#include "frontend/displaywindow/cdisplaywindow.h"
+
+#include "util/cpointers.h"
+
+//Qt includes
+#include <QTimer>
+#include <QList>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+
+
+
+class CSearchDialog;
+class CMainIndex;
+class QWidget;
+class QDropEvent;
+class QDragMoveEvent;
+class QDragLeaveEvent;
+class BTMimeData;
+class QMenu;
+class QActionGroup;
+class QMouseEvent;
+class BTModuleTreeItem;
+
+
+
+/**
+* The widget which manages the modules. The modules are put into own,
+* fixed subfolders sorted by category and/or language.
+* @author The BibleTime team
+*/
+class CBookshelfIndex : public QTreeWidget {
+ Q_OBJECT
+
+public:
+ CBookshelfIndex(QWidget *parent);
+ virtual ~CBookshelfIndex();
+
+ void initTree();
+ /**
+ * Opens the searchdialog using the given modules using the given search text.
+ */
+ void emitModulesChosen( QList<CSwordModuleInfo*> modules, QString key );
+
+ /** Helper method for "freezing" modules while opening them in windows. */
+ void unfreezeModules(QList<CSwordModuleInfo*>);
+
+public slots:
+
+ /**
+ * Reloads the main index's Sword dependend things like modules
+ */
+ void reloadSword(CSwordBackend::SetupChangedReason);
+
+ /**
+ * Opens the searchdialog for the selected modules.
+ */
+ void actionSearchInModules();
+
+protected:
+
+ /** Handle mouse clicks.*/
+ virtual void mouseReleaseEvent(QMouseEvent* event);
+
+ /** Empty re-implementation to prevent unwanted opening of folders with some styles.*/
+ virtual void mouseDoubleClickEvent(QMouseEvent*) {}
+
+ /**
+ * Initialize the SIGNAL<->SLOT connections
+ */
+ void initConnections();
+ /**
+ * Reimplementation. Returns the drag object for the current selection.
+ */
+ virtual QMimeData* dragObject();
+ /**
+ * Reimplementation from QTreeWidget (QAbstractItemView). Returns true if the drag is acceptable for the listview.
+ */
+ virtual void dragEnterEvent( QDragEnterEvent* event );
+ virtual void dragMoveEvent( QDragMoveEvent* event );
+ virtual void dropEvent( QDropEvent* event );
+
+ /** Receive style change event to change single/double click activation behaviour. */
+ virtual void changeEvent(QEvent*);
+
+ /**
+ * Reimplementation from QAbstractItemView. Takes care of movable items.
+ */
+ virtual void startDrag(Qt::DropActions supportedActions);
+ /**
+ * TODO: qt4 Reimplementation to support the items dragEnter and dragLeave functions.
+ */
+ virtual void contentsDragMoveEvent( QDragMoveEvent* event );
+ /**
+ * Reimplementation.
+ */
+ virtual void contentsDragLeaveEvent( QDragLeaveEvent* e );
+
+
+protected slots: // Protected slots
+ /**
+ * Called when the selection is changed.
+ */
+ void slotModifySelection();
+ /**
+ * Is called when an item was clicked or activated.
+ */
+ void slotExecuted( QTreeWidgetItem* );
+
+ /**
+ * Shows the context menu at the given position.
+ */
+ void contextMenu(const QPoint&);
+
+ /**
+ * Changes the grouping.
+ */
+ void actionChangeGrouping(QAction* action);
+
+ /**
+ * Shows information about the current module.
+ */
+
+ /**
+ * Show or hide the hidden modules, depending on the action check state.
+ */
+ void actionShowModules(bool checked);
+
+ /**
+ * Set the selected modules hidden.
+ */
+ void actionHideModules();
+
+
+ void actionAboutModule();
+ /**
+ * Unlocks the current module.
+ */
+ void actionUnlockModule();
+ void autoOpenTimeout();
+
+ /**
+ * Opens a plain text editor window to edit the modules content.
+ */
+ void actionEditModulePlain();
+ /**
+ * Opens an HTML editor window to edit the modules content.
+ */
+ void actionEditModuleHTML();
+
+ void addToTree(BTModuleTreeItem* item, QTreeWidgetItem* widgetItem);
+
+
+private:
+ CSearchDialog* m_searchDialog;
+ //ToolTip* m_toolTip;
+ bool m_itemsMovable;
+ QTreeWidgetItem* m_autoOpenFolder;
+ QTimer m_autoOpenTimer;
+ BTModuleTreeItem::Grouping m_grouping; //temporary solution - this should be in config
+ QActionGroup* m_groupingGroup;
+ int m_mouseReleaseEventModifiers;
+ bool m_showHidden;
+ QSet<QString> m_frozenModules;
+
+ /**
+ * Initializes the view.
+ */
+ void initView();
+ void initActions();
+
+ /** Convenience function for creating a new QAction. */
+ QAction* newQAction(const QString& text, const QString& pix, int shortcut, const QObject* receiver, const char* slot, QObject* parent);
+
+ QList<QAction*> m_actionList;
+
+ QMenu* m_popup;
+
+signals:
+ /**
+ * Is emitted when a module should be opened,
+ */
+ void createReadDisplayWindow( QList<CSwordModuleInfo*>, const QString& );
+ /**
+ * Is emitted when a write window should be created.
+ */
+ void createWriteDisplayWindow( CSwordModuleInfo*, const QString&, const CDisplayWindow::WriteWindowType& );
+
+};
+
+#endif
diff --git a/src/frontend/mainindex/bookshelf/chidemodulechooserdialog.cpp b/src/frontend/mainindex/bookshelf/chidemodulechooserdialog.cpp
new file mode 100644
index 0000000..0a923c4
--- /dev/null
+++ b/src/frontend/mainindex/bookshelf/chidemodulechooserdialog.cpp
@@ -0,0 +1,70 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2007 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "chidemodulechooserdialog.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/cswordbackend.h"
+#include "backend/btmoduletreeitem.h"
+
+#include "util/cpointers.h"
+#include "util/cresmgr.h"
+#include "util/ctoolclass.h"
+#include "util/directoryutil.h"
+
+#include <QDialog>
+#include <QButtonGroup>
+#include <QDialogButtonBox>
+#include <QHBoxLayout>
+#include <QSpacerItem>
+#include <QTreeWidget>
+#include <QVBoxLayout>
+#include <QStringList>
+#include <QDebug>
+#include <QHeaderView>
+
+
+CHideModuleChooserDialog::CHideModuleChooserDialog( QWidget* parent, QString title, QString label, QString currentModule)
+ : CModuleChooserDialog(parent, title, label),
+ m_currentModule(currentModule),
+ m_focusItem(0)
+{
+ QObject::connect(this, SIGNAL(modulesChanged(QList<CSwordModuleInfo*>, QTreeWidget*)), this, SLOT(applyHiddenModules(QList<CSwordModuleInfo*>)));
+ init();
+ if (m_focusItem) {
+ treeWidget()->scrollToItem(m_focusItem);
+ }
+}
+
+
+void CHideModuleChooserDialog::initModuleItem(BTModuleTreeItem* btItem, QTreeWidgetItem* widgetItem)
+{
+ widgetItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
+ if (btItem->moduleInfo()->isHidden())
+ widgetItem->setCheckState(0, Qt::Checked);
+ else
+ widgetItem->setCheckState(0, Qt::Unchecked);
+ if (m_currentModule == widgetItem->text(0)) {
+ m_focusItem = widgetItem;
+ }
+}
+
+void CHideModuleChooserDialog::applyHiddenModules(QList<CSwordModuleInfo*> hiddenModules)
+{
+ qDebug("CHideModuleChooserDialog::applyHiddenModules");
+ QList<CSwordModuleInfo*> allModules = CPointers::backend()->moduleList();
+ foreach(CSwordModuleInfo* i, allModules) {
+ if (hiddenModules.contains(i)) {
+ i->setHidden(true);
+ } else {
+ i->setHidden(false);
+ }
+
+ }
+}
diff --git a/src/frontend/mainindex/bookshelf/chidemodulechooserdialog.h b/src/frontend/mainindex/bookshelf/chidemodulechooserdialog.h
new file mode 100644
index 0000000..9fd7e8c
--- /dev/null
+++ b/src/frontend/mainindex/bookshelf/chidemodulechooserdialog.h
@@ -0,0 +1,43 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CHIDEMODULECHOOSERDIALOG_H
+#define CHIDEMODULECHOOSERDIALOG_H
+
+class CSwordModuleInfo;
+
+#include "frontend/cmodulechooserdialog.h"
+
+class QTreeWidgetItem;
+
+class BTModuleTreeItem;
+
+
+
+class CHideModuleChooserDialog : public CModuleChooserDialog
+{
+ Q_OBJECT
+public:
+ CHideModuleChooserDialog(QWidget* parent, QString title, QString label, QString currentModule);
+ ~CHideModuleChooserDialog() {}
+
+protected:
+ virtual void initModuleItem(BTModuleTreeItem* btItem, QTreeWidgetItem* widgetItem);
+protected slots:
+ void applyHiddenModules(QList<CSwordModuleInfo*> hiddenModules);
+
+
+private:
+ QString m_currentModule;
+ QTreeWidgetItem* m_focusItem;
+};
+
+
+
+#endif
diff --git a/src/frontend/mainindex/cmainindex.cpp b/src/frontend/mainindex/cmainindex.cpp
new file mode 100644
index 0000000..04341b0
--- /dev/null
+++ b/src/frontend/mainindex/cmainindex.cpp
@@ -0,0 +1,36 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//BibleTime includes
+#include "cmainindex.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+
+#include "bookshelf/cbookshelfindex.h"
+#include "bookmarks/cbookmarkindex.h"
+
+#include <QTabWidget>
+
+
+CMainIndex::CMainIndex(QWidget *parent) : QTabWidget(parent)
+{
+ setFocusPolicy(Qt::StrongFocus);
+ m_bookmarksPage = new CBookmarkIndex(0);
+ m_bookshelfPage = new CBookshelfIndex(0);
+ addTab(m_bookshelfPage, tr("Bookshelf"));
+ addTab(m_bookmarksPage, tr("Bookmarks"));
+
+ //shortcut some signals from pages to signals of this widget so that outsiders
+ // do not have to use the pages directly
+ QObject::connect(m_bookshelfPage, SIGNAL(createReadDisplayWindow( QList<CSwordModuleInfo*>, const QString& )), this, SIGNAL(createReadDisplayWindow( QList<CSwordModuleInfo*>, const QString& )));
+ QObject::connect(m_bookmarksPage, SIGNAL(createReadDisplayWindow( QList<CSwordModuleInfo*>, const QString& )), this, SIGNAL(createReadDisplayWindow( QList<CSwordModuleInfo*>, const QString& )));
+
+ QObject::connect(m_bookshelfPage, SIGNAL(createWriteDisplayWindow( CSwordModuleInfo*, const QString&, const CDisplayWindow::WriteWindowType& )), this, SIGNAL(createWriteDisplayWindow( CSwordModuleInfo*, const QString&, const CDisplayWindow::WriteWindowType&)));
+
+}
diff --git a/src/frontend/mainindex/cmainindex.h b/src/frontend/mainindex/cmainindex.h
new file mode 100644
index 0000000..b5d217d
--- /dev/null
+++ b/src/frontend/mainindex/cmainindex.h
@@ -0,0 +1,57 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CMAININDEX_H
+#define CMAININDEX_H
+
+#include "frontend/displaywindow/cdisplaywindow.h"
+
+#include <QTabWidget>
+#include <QFocusEvent>
+
+class CBookmarkIndex;
+class CBookshelfIndex;
+class CSwordModuleInfo;
+
+/** The class which manages all bookmarks and modules. The modules are put into own, fixed subfolders sorted by language.
+ * @author The BibleTime team
+ */
+class CMainIndex : public QTabWidget {
+ Q_OBJECT
+
+public:
+ CMainIndex(QWidget *parent);
+ virtual ~CMainIndex() {};
+
+ //void reloadSword();
+
+ CBookshelfIndex* bookshelfIndex() {return m_bookshelfPage;}
+
+signals:
+ /**
+ * Is emitted when a module should be opened,
+ */
+ void createReadDisplayWindow( QList<CSwordModuleInfo*>, const QString& );
+ /**
+ * Is emitted when a write window should be created.
+ */
+ void createWriteDisplayWindow( CSwordModuleInfo*, const QString&, const CDisplayWindow::WriteWindowType& );
+
+protected:
+ /** QWidget method - move focus to the active page widget */
+ virtual void focusInEvent(QFocusEvent*) {currentWidget()->setFocus();}
+
+private:
+
+ CBookmarkIndex* m_bookmarksPage;
+ CBookshelfIndex* m_bookshelfPage;
+
+};
+
+#endif
diff --git a/src/frontend/profile/cprofile.cpp b/src/frontend/profile/cprofile.cpp
new file mode 100644
index 0000000..f6c8be1
--- /dev/null
+++ b/src/frontend/profile/cprofile.cpp
@@ -0,0 +1,433 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cprofile.h"
+#include "util/directoryutil.h"
+
+//Qt includes
+#include <QFile>
+#include <QString>
+#include <QTextStream>
+#include <QDomDocument>
+
+#define CURRENT_SYNTAX_VERSION 3
+
+namespace Profile {
+
+CProfile::CProfile( const QString& file, const QString& name )
+ : m_name(name.isEmpty() ? QObject::tr("unknown") : name),
+ m_filename(file),
+ m_fullscreen(false),
+ m_geometry(10,20,640,480),
+ m_mdiArrangementMode((CMDIArea::MDIArrangementMode)0) //0 is not a valid enum entry, means "unknown"
+{
+ if (!m_filename.isEmpty() && name.isEmpty()) {
+ loadBasics();
+ }
+ else if (m_filename.isEmpty() && !name.isEmpty()) {
+ m_filename = name;
+ m_filename.replace(QRegExp("\\s=#."),"_");
+ m_filename = util::filesystem::DirectoryUtil::getUserSessionsDir().absolutePath() + "/" + m_filename + ".xml";
+ init(m_filename);
+ }
+ else {
+ qWarning("CProfile: empty file name!");
+ }
+}
+
+CProfile::~CProfile() {
+ qDeleteAll(m_profileWindows); //there's no autodelete feature in qt4
+ m_profileWindows.clear(); //delete all CProfileWindows objects
+}
+
+/** Loads the profile from the file given in the constructor. */
+QList<CProfileWindow*> CProfile::load() {
+ QFile file(m_filename);
+ if (!file.exists())
+ {
+ //qWarning() << "Standard profile not found at filename " << m_filename;
+ return QList<CProfileWindow*>();
+ }
+
+ QDomDocument doc;
+ if (file.open(QIODevice::ReadOnly)) {
+ QTextStream t( &file );
+ t.setCodec("UTF-8");
+ doc.setContent(t.readAll());
+ file.close();
+ }
+
+ QDomElement document = doc.documentElement();
+ if( document.tagName() != "BibleTimeProfile" && document.tagName() != "BibleTime" ) { //BibleTime was used in syntax version 1.0
+ qWarning("CProfile::load: Missing BibleTime doc");
+ return m_profileWindows;
+ }
+ if (document.hasAttribute("name")) {
+ m_name = document.attribute("name");
+ }
+
+ //load settings of the main window
+ {
+ // see if there's a section with the name MAINWINDOW
+ QDomElement elem = document.firstChild().toElement();
+ QDomElement mainWindow;
+ while (!elem.isNull()) {
+ if (elem.tagName() == "MAINWINDOW") {
+ mainWindow = elem;
+ break; //found the element
+ }
+ elem = elem.nextSibling().toElement();
+ }
+ if (!mainWindow.isNull()) { //was found
+ setFullscreen( (bool)mainWindow.attribute("fullscreen").toInt());
+
+ QByteArray bstate;
+ bstate += mainWindow.attribute("state");
+ setMainwindowState(QByteArray::fromHex(bstate));
+
+ QDomElement geometry_element = mainWindow.namedItem("GEOMETRY").toElement();
+ QRect rect;
+ if(!geometry_element.isNull()) {
+ if (geometry_element.hasAttribute("x")) {
+ rect.setX(geometry_element.attribute("x").toInt());
+ }
+ if (geometry_element.hasAttribute("y")) {
+ rect.setY(geometry_element.attribute("y").toInt());
+ }
+ if (geometry_element.hasAttribute("width")) {
+ rect.setWidth(geometry_element.attribute("width").toInt());
+ }
+ if (geometry_element.hasAttribute("height")) {
+ rect.setHeight(geometry_element.attribute("height").toInt());
+ }
+ if (geometry_element.hasAttribute("isMaximized")) {
+ this->setMaximized( static_cast<bool>(geometry_element.attribute("isMaximized").toInt()) );
+ }
+ setGeometry(rect);
+ }
+
+ QDomElement mdi_element = mainWindow.namedItem("MDI").toElement();
+ if(!mdi_element.isNull()) {
+ if (mdi_element.hasAttribute("ArrangementMode")) {
+ this->setMDIArrangementMode((CMDIArea::MDIArrangementMode)mdi_element.attribute("ArrangementMode").toInt());
+ }
+ }
+ }
+ }
+
+ m_profileWindows.clear();
+ QDomElement elem = document.firstChild().toElement();
+ while (!elem.isNull()) {
+ CProfileWindow* p = 0;
+ if (elem.tagName() == "BIBLE") {
+ p = new CProfileWindow(CSwordModuleInfo::Bible);
+ }
+ else if (elem.tagName() == "COMMENTARY") {
+ p = new CProfileWindow(CSwordModuleInfo::Commentary);
+ }
+ else if (elem.tagName() == "LEXICON") {
+ p = new CProfileWindow(CSwordModuleInfo::Lexicon);
+ }
+ else if (elem.tagName() == "BOOK") {
+ p = new CProfileWindow(CSwordModuleInfo::GenericBook);
+ }
+
+ if (p) {
+ m_profileWindows.append(p);
+
+ if (elem.hasAttribute("windowSettings")) {
+ p->setWindowSettings( elem.attribute("windowSettings").toInt() );
+ }
+ if (elem.hasAttribute("writeWindowType")) {
+ p->setWriteWindowType( elem.attribute("writeWindowType").toInt() );
+ }
+ if (elem.hasAttribute("hasFocus")) {
+ p->setFocus( static_cast<bool>(elem.attribute("hasFocus").toInt()) );
+ }
+
+ QRect rect;
+
+ QDomElement object = elem.namedItem("GEOMETRY").toElement();
+ if(!object.isNull()) {
+ if (object.hasAttribute("x")) {
+ rect.setX(object.attribute("x").toInt());
+ }
+ if (object.hasAttribute("y")) {
+ rect.setY(object.attribute("y").toInt());
+ }
+ if (object.hasAttribute("width")) {
+ rect.setWidth(object.attribute("width").toInt());
+ }
+ if (object.hasAttribute("height")) {
+ rect.setHeight(object.attribute("height").toInt());
+ }
+ if (object.hasAttribute("isMaximized")) {
+ p->setMaximized( static_cast<bool>(object.attribute("isMaximized").toInt()) );
+ }
+ }
+ p->setGeometry(rect);
+
+ object = elem.namedItem("MODULES").toElement();
+ if(!object.isNull()) {
+ if (object.hasAttribute("list")) {
+ const QString sep = object.hasAttribute("separator") ? object.attribute("separator") : "|";
+ QStringList modules = object.attribute("list").split(sep);
+ p->setModules(modules);
+ }
+ }
+
+ object = elem.namedItem("KEY").toElement();
+ if(!object.isNull()) {
+ if (object.hasAttribute("name"))
+ p->setKey(object.attribute("name"));
+ }
+
+ object = elem.namedItem("SCROLLBARS").toElement();
+ if(!object.isNull()) {
+ int horizontal = 0, vertical = 0;
+ if (object.hasAttribute("horizontal"))
+ horizontal = object.attribute("horizontal").toInt();
+ if (object.hasAttribute("vertical"))
+ vertical = object.attribute("vertical").toInt();
+
+ p->setScrollbarPositions(horizontal, vertical);
+ }
+ }
+ elem = elem.nextSibling().toElement();
+ }
+ return m_profileWindows;
+}
+
+/** Saves the profile to the file given in the constructor. */
+bool CProfile::save(QList<CProfileWindow*> windows) {
+ /** Save the settings using a XML file
+ * Save the CProfileWindow objects using a XML file which name is in m_filename
+ */
+ bool ret = false;
+ QDomDocument doc("DOC");
+ doc.appendChild( doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
+
+ QDomElement content = doc.createElement("BibleTimeProfile");
+ content.setAttribute("syntaxVersion", CURRENT_SYNTAX_VERSION);
+ content.setAttribute("name", m_name);
+ doc.appendChild(content);
+
+ //save mainwindow settings
+ {
+ QDomElement mainWindow = doc.createElement("MAINWINDOW");
+ mainWindow.setAttribute("fullscreen", fullscreen());
+
+ QString sstate = QString(getMainwindowState().toHex());
+ mainWindow.setAttribute("state", sstate);
+
+ QDomElement geometry = doc.createElement("GEOMETRY");
+ mainWindow.appendChild(geometry);
+ const QRect r = this->geometry();
+ geometry.setAttribute("x",r.x());
+ geometry.setAttribute("y",r.y());
+ geometry.setAttribute("width",r.width());
+ geometry.setAttribute("height",r.height());
+ geometry.setAttribute("isMaximized",static_cast<int>(this->maximized()));
+
+ QDomElement mdi = doc.createElement("MDI");
+ mainWindow.appendChild(mdi);
+ mdi.setAttribute("ArrangementMode",static_cast<int>(this->getMDIArrangementMode()));
+
+ content.appendChild(mainWindow);
+ }
+
+ //for (CProfileWindow* p = windows.first(); p; p = windows.next()) {
+ foreach(CProfileWindow* p, windows) {
+ QDomElement window;
+ switch (p->type()) {
+ case CSwordModuleInfo::Bible:
+ window = doc.createElement("BIBLE");
+ break;
+ case CSwordModuleInfo::Commentary:
+ window = doc.createElement("COMMENTARY");
+ break;
+ case CSwordModuleInfo::Lexicon:
+ window = doc.createElement("LEXICON");
+ break;
+ case CSwordModuleInfo::GenericBook:
+ window = doc.createElement("BOOK");
+ break;
+ default:
+ break;
+ }
+ if (window.isNull())
+ break;
+ window.setAttribute("windowSettings", p->windowSettings());
+ window.setAttribute("writeWindowType", p->writeWindowType());
+ window.setAttribute("hasFocus", p->hasFocus());
+
+ //save geomtery
+ const QRect r = p->geometry();
+ QDomElement geometry = doc.createElement("GEOMETRY");
+ geometry.setAttribute("x",r.x());
+ geometry.setAttribute("y",r.y());
+ geometry.setAttribute("width",r.width());
+ geometry.setAttribute("height",r.height());
+ geometry.setAttribute("isMaximized",static_cast<int>(p->maximized()));
+ window.appendChild( geometry );
+
+ QDomElement modules = doc.createElement("MODULES");
+ modules.setAttribute("separator", "|");
+ modules.setAttribute("list", p->modules().join("|"));
+ window.appendChild( modules );
+
+ QDomElement key = doc.createElement("KEY");
+ key.setAttribute("name", p->key());
+ window.appendChild( key );
+
+ QDomElement scrollbars = doc.createElement("SCROLLBARS");
+ scrollbars.setAttribute("horizontal", p->scrollbarPositions().horizontal);
+ scrollbars.setAttribute("vertical", p->scrollbarPositions().vertical);
+ window.appendChild( scrollbars );
+
+ content.appendChild( window );
+ }
+
+ QFile file(m_filename);
+ if ( file.open(QIODevice::WriteOnly) ) {
+ ret = true;
+ QTextStream t( &file );
+ t.setCodec("UTF-8");
+ t << doc.toString();
+ file.close();
+ }
+ else
+ ret = false;
+
+ return ret;
+}
+
+/** Saves the profile to the file given in the constructor. */
+bool CProfile::save() {
+ return save(m_profileWindows);
+}
+
+/** Returns the filename used for this profile. */
+const QString& CProfile::filename() {
+ return m_filename;
+}
+
+/** Returns the name of this profile. */
+const QString& CProfile::name() {
+ return m_name;
+}
+
+/** Initializes the XML for the first time (use to create a new profile) */
+void CProfile::init(const QString file) {
+ const QString oldFile = m_filename;
+ m_filename = file;
+ save(QList<CProfileWindow*>());
+ m_filename = oldFile;
+}
+
+/** Changes the name of this profile. */
+void CProfile::setName( const QString& newName ) {
+ m_name = newName;
+ saveBasics(); //save chanegd name
+}
+
+/** Loads the basic settings requires for proper operation. */
+void CProfile::loadBasics() {
+ QFile file(m_filename);
+ if (!file.exists())
+ return;
+
+ QDomDocument doc;
+ if (file.open(QIODevice::ReadOnly)) {
+ QTextStream t( &file );
+ t.setCodec("UTF-8");
+ doc.setContent(t.readAll());
+ file.close();
+ }
+ QDomElement document = doc.documentElement();
+ if (document.hasAttribute("name"))
+ m_name = document.attribute("name");
+}
+
+void CProfile::saveBasics() {
+ QFile file(m_filename);
+ if (!file.exists())
+ return;
+
+ QDomDocument doc;
+ if (file.open(QIODevice::ReadOnly)) {
+ QTextStream t(&file);
+ t.setCodec("UTF-8");
+ doc.setContent(t.readAll());
+ file.close();
+ }
+
+ QDomElement document = doc.documentElement();
+ document.setAttribute("name", m_name);
+
+ if (file.open(QIODevice::WriteOnly)) {
+ QTextStream t( &file );
+ t.setCodec("UTF-8");
+ t << doc.toString();
+ file.close();
+ }
+}
+
+/** Returns true if the main window was in fullscreen mode as the profile was saved. */
+bool CProfile::fullscreen() const {
+ return m_fullscreen;
+}
+
+/** Set the parameter to true if the main window coveres the full screen size. */
+void CProfile::setFullscreen( const bool fullscreen ) {
+ m_fullscreen = fullscreen;
+}
+
+/** Returns true if the main window was maximized as the profile was saved. */
+bool CProfile::maximized() const {
+ return m_maximized;
+}
+
+/** Set the parameter to true if the main window is maximized. */
+void CProfile::setMaximized( const bool maximized ) {
+ m_maximized = maximized;
+}
+
+/** Returns the geometry of the main window */
+const QRect CProfile::geometry() {
+ return m_geometry;
+}
+
+/** Stes the geoemtry of the main window */
+void CProfile::setGeometry( const QRect rect ) {
+ m_geometry = rect;
+}
+
+void CProfile::setMDIArrangementMode(const CMDIArea::MDIArrangementMode newArrangementMode)
+{
+ m_mdiArrangementMode = newArrangementMode;
+}
+
+CMDIArea::MDIArrangementMode CProfile::getMDIArrangementMode(void)
+{
+ return m_mdiArrangementMode;
+}
+
+void CProfile::setMainwindowState(const QByteArray& state)
+{
+ m_mainwindowState = state;
+}
+
+QByteArray CProfile::getMainwindowState()
+{
+ return m_mainwindowState;
+}
+
+
+} //end of namespace Profile
diff --git a/src/frontend/profile/cprofile.h b/src/frontend/profile/cprofile.h
new file mode 100644
index 0000000..6e375f9
--- /dev/null
+++ b/src/frontend/profile/cprofile.h
@@ -0,0 +1,120 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CPROFILE_H
+#define CPROFILE_H
+
+#include "cprofilewindow.h"
+#include "frontend/cmdiarea.h"
+
+//Qt includes
+#include <QList>
+#include <QByteArray>
+
+namespace Profile {
+
+/** Manages one profile file. Provides functions to save and restore settings of the available display windows.
+ * @author The BibleTime team
+ */
+class CProfile {
+public:
+ CProfile(const QString& fileName, const QString& name = QString::null);
+ ~CProfile();
+
+ /**
+ * Saves the profile to the file given in the constructor.
+ * @param windows The list of windows available in the profile.
+ */
+ bool save( QList<CProfileWindow*> windows );
+ /**
+ * Saves the profile to the file given in the constructor.
+ */
+ bool save();
+ /**
+ * Loads the profile from the file given in the constructor.
+ * @return The list of profiled window which exist in the profile.
+ */
+ QList<CProfileWindow*> load();
+ /**
+ * Returns the name of this profile.
+ */
+ const QString& name();
+ /**
+ * Returns the filename used for this profile.
+ */
+ const QString& filename();
+ /**
+ * Initializes the XML for the first time (use to create a new profile)
+ */
+ void init(const QString);
+ /**
+ * Chnages the name of this profile.
+ */
+ void setName( const QString& );
+ /**
+ * Returns true if the main window was in fullscreen mode as the profile was saved.
+ */
+ bool fullscreen() const;
+ /**
+ * Set the parameter to true if the main window coveres the full screen size.
+ */
+ void setFullscreen( const bool fullscreen );
+ /**
+ * Returns true if the main window was maximized as the profile was saved.
+ */
+ bool maximized() const;
+ /**
+ * Set the parameter to true if the main window is maximized.
+ */
+ void setMaximized( const bool maximized );
+ /**
+ * Sets the geoemtry of the main window
+ */
+ void setGeometry( const QRect rect );
+ /**
+ * Returns the geometry of the main window
+ */
+ const QRect geometry();
+ /**
+ * Sets the MDI arrangement mode
+ */
+ void setMDIArrangementMode(const CMDIArea::MDIArrangementMode);
+ /**
+ * Returns mdi arrangement mode
+ */
+ CMDIArea::MDIArrangementMode getMDIArrangementMode(void);
+ /**
+ * set mainwindow saveState - position of docking windows and toolbar
+ */
+ void setMainwindowState(const QByteArray& state);
+ /**
+ * Return mainwindow saveState - position of docking windows and toolbar
+ */
+ QByteArray getMainwindowState();
+
+private:
+ /**
+ * Loads the basic settings requires for proper operation.
+ */
+ void loadBasics();
+ void saveBasics();
+
+ QList<CProfileWindow*> m_profileWindows;
+ QString m_name;
+ QString m_filename;
+ bool m_fullscreen;
+ bool m_maximized;
+ QRect m_geometry;
+ CMDIArea::MDIArrangementMode m_mdiArrangementMode;
+ QByteArray m_mainwindowState;
+};
+
+} //end of namespace Profile
+
+#endif
diff --git a/src/frontend/profile/cprofilemgr.cpp b/src/frontend/profile/cprofilemgr.cpp
new file mode 100644
index 0000000..783e371
--- /dev/null
+++ b/src/frontend/profile/cprofilemgr.cpp
@@ -0,0 +1,130 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#include "cprofilemgr.h"
+#include "util/directoryutil.h"
+
+//Qt includes
+#include <QDir>
+#include <QFile>
+#include <QList>
+
+
+namespace Profile {
+
+CProfileMgr::CProfileMgr() : m_startupProfile(0) {
+ //m_profiles.setAutoDelete(true);
+
+ m_profilePath = util::filesystem::DirectoryUtil::getUserSessionsDir().absolutePath() + "/";
+
+ QDir d( m_profilePath );
+ QStringList files = d.entryList(QStringList("*.xml"));
+ for ( QStringList::Iterator it = files.begin(); it != files.end(); ++it ) {
+ if ((*it) != "_startup_.xml") {
+ m_profiles.append(new CProfile(m_profilePath + *it));
+ }
+ else {
+ m_startupProfile = new CProfile(m_profilePath + *it);
+ }
+ }
+}
+
+CProfileMgr::~CProfileMgr() {
+ qDeleteAll(m_profiles);
+ m_profiles.clear();
+ delete m_startupProfile;
+}
+
+/** Returns a list of available profiles. */
+const QList<CProfile*>& CProfileMgr::profiles() {
+ return m_profiles;
+}
+
+/** Creates a new profile with the name "name" (first parameter). @return The profile object */
+CProfile* CProfileMgr::create( const QString name ) {
+ CProfile* p = new CProfile(QString::null, name);
+ m_profiles.append(p);
+
+ return p;
+}
+
+/** Removes the profile from the list and from the directory containg the profile files. */
+bool CProfileMgr::remove( CProfile* p )
+{
+ bool ret = false;
+ QFile f( p->filename() );
+ if (f.exists())
+ f.remove();
+
+ int i = m_profiles.indexOf(p);
+ if (i != -1)
+ delete m_profiles.takeAt(i);
+
+ ret = true;
+ return ret;
+}
+
+bool CProfileMgr::remove( const QString& profile)
+{
+ bool ret = false;
+ QListIterator<CProfile*> it(m_profiles);
+ while (it.hasNext()) {
+ CProfile* p = it.next();
+ if (p->name() == profile) {
+ remove(p);
+ ret = true;
+ }
+ }
+ return ret;
+}
+
+/** Returns the profile with the desired name. If there's no such profile 0 is returned. */
+CProfile* CProfileMgr::profile(const QString& name) {
+ QListIterator<CProfile*> it(m_profiles);
+ while (it.hasNext()) {
+ CProfile* p = it.next();
+ if (p && p->name() == name) {
+ return p;
+ }
+ }
+
+ return 0;
+}
+
+/** Returns the startup profile if it exists, otherwise return 0. */
+CProfile* CProfileMgr::startupProfile() {
+ if (!m_startupProfile) {
+ m_startupProfile = new CProfile(QString::null, "_startup_");
+ }
+
+ return m_startupProfile;
+}
+
+/** Refreshes the profiles available on disk. Use this function to update the list of profiles after another instance of CProfileMgr created a new profile. */
+void CProfileMgr::refresh() {
+ qDeleteAll(m_profiles);
+ m_profiles.clear(); //delete all profiles
+ QDir d( m_profilePath );
+ QStringList files = d.entryList(QStringList("*.xml"));
+ for ( QStringList::Iterator it = files.begin(); it != files.end(); ++it ) {
+ CProfile p(m_profilePath + *it);
+ if (p.name() == "_startup_") { //new startup profile
+ if (!m_startupProfile) { //don't put this in the if clause above,it doesn't work!
+ m_startupProfile = new CProfile(m_profilePath + *it);
+ }
+ }
+ else if (!profile(p.name())) { //don't have it already
+ m_profiles.append(new CProfile(m_profilePath + *it));
+ }
+ }
+}
+
+} //end of namespace Profile
diff --git a/src/frontend/profile/cprofilemgr.h b/src/frontend/profile/cprofilemgr.h
new file mode 100644
index 0000000..934d09a
--- /dev/null
+++ b/src/frontend/profile/cprofilemgr.h
@@ -0,0 +1,68 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CPROFILEMGR_H
+#define CPROFILEMGR_H
+
+#include "cprofile.h"
+
+//Qt includes
+#include <QString>
+#include <QList>
+
+namespace Profile {
+/** The manager for profiles.
+ * Provides functions to create, delete, save and load profiles.
+ * @author The BibleTime team
+ */
+class CProfileMgr {
+public:
+ CProfileMgr();
+ ~CProfileMgr();
+
+ /** Creates a new profile with the name "name" (first parameter).
+ * @return The profile object
+ */
+ CProfile* create( const QString name );
+ /**
+ * @return a list of available profiles
+ */
+ const QList<CProfile*>& profiles();
+ /**
+ * Removes the profile from the list and from the directory containg the profile files.
+ */
+ bool remove( CProfile* p );
+ /**
+ * Removes the profile from the list and from the directory containg the profile files.
+ */
+ bool remove( const QString& );
+ /**
+ * Returns the profile with the desired name. If there's no such profile 0 is returned.
+ */
+ CProfile* profile(const QString&);
+ /**
+ * Returns the startup profile if it exists, otherwise return 0.
+ */
+ CProfile* startupProfile();
+ /**
+ * Refreshes the profiles available on disk. Use this function to update the list of profiles after another instance of CProfileMgr created a new profile.
+ */
+ void refresh();
+
+protected:
+ QList<CProfile*> m_profiles;
+ QString m_profilePath;
+ CProfile* m_startupProfile;
+};
+
+} //end of namespace Profile
+
+#endif
diff --git a/src/frontend/profile/cprofilewindow.cpp b/src/frontend/profile/cprofilewindow.cpp
new file mode 100644
index 0000000..f405923
--- /dev/null
+++ b/src/frontend/profile/cprofilewindow.cpp
@@ -0,0 +1,134 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#include "cprofilewindow.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/cswordbackend.h"
+
+
+#include <QString>
+#include <QRect>
+#include <QStringList>
+
+
+namespace Profile {
+
+CProfileWindow::CProfileWindow(CSwordModuleInfo::ModuleType type)
+: m_type(type),
+m_windowGeometry(),
+m_moduleList(),
+m_key(QString::null),
+m_maximized(false),
+m_hasFocus(false),
+m_windowSettings(0),
+m_writeWindowType(0) {
+ m_scrollbarPos.horizontal = 0;
+ m_scrollbarPos.vertical = 0;
+}
+
+CProfileWindow::~CProfileWindow() {}
+
+/** Returns the size of the window including the x,y coordinates. */
+const QRect& CProfileWindow::geometry() const {
+ return m_windowGeometry;
+}
+
+/** Sets the size of the window. */
+void CProfileWindow::setGeometry( const QRect& rect ) {
+ m_windowGeometry = rect;
+}
+
+/** Returns the type of the managed window (bible window, commentary window or lexicon window). */
+CSwordModuleInfo::ModuleType CProfileWindow::type() const {
+ if (m_type != CSwordModuleInfo::Unknown)
+ return m_type;
+ return CSwordModuleInfo::Unknown;
+}
+
+/** Sets the modules. */
+void CProfileWindow::setModules( const QStringList& modules ) {
+ m_moduleList = modules; //copy module pointers into our own list
+}
+
+/** Returns a list of module names which are chosen in the managed window profile. */
+const QStringList& CProfileWindow::modules() const {
+ return m_moduleList;
+}
+
+/** Returns the current key set in the modules. */
+const QString& CProfileWindow::key() const {
+ return m_key;
+}
+
+/** Set the key used in the modules. */
+void CProfileWindow::setKey( const QString& key ) {
+ m_key = key;
+}
+
+/** Sets the current position of the scrollbars. */
+void CProfileWindow::setScrollbarPositions(const int& horizontal, const int& vertical) {
+ // m_scrollbarPos = {x,y};
+ m_scrollbarPos.horizontal = horizontal;
+ m_scrollbarPos.vertical = vertical;
+}
+
+/** Returns tghe position of the scrollbars */
+const CProfileWindow::ScrollbarPos& CProfileWindow::scrollbarPositions() const {
+ return m_scrollbarPos;
+}
+
+/** Sets the type of the used modules. */
+void CProfileWindow::setType(const CSwordModuleInfo::ModuleType& type) {
+ m_type = type;
+}
+
+/** Returns true if the window is maximized. */
+const bool& CProfileWindow::maximized() const {
+ return m_maximized;
+}
+
+/** Sets the windows maximized state to true or false. */
+void CProfileWindow::setMaximized( const bool& maximized ) {
+ m_maximized = maximized;
+}
+
+/** Returns true if the window is maximized. */
+const bool& CProfileWindow::hasFocus() const {
+ return m_hasFocus;
+}
+
+/** Sets the windows maximized state to true or false. */
+void CProfileWindow::setFocus( const bool& hasFocus ) {
+ m_hasFocus = hasFocus;
+}
+
+/** Returns an integer with the window specific settings */
+const int& CProfileWindow::windowSettings() const {
+ return m_windowSettings;
+}
+
+/** Sets the window specific settings. */
+void CProfileWindow::setWindowSettings( const int& settings ) {
+ m_windowSettings = settings;
+}
+
+/** Tells this profile window to represent a write window. */
+void CProfileWindow::setWriteWindowType( const int& writeWindowType ) {
+ m_writeWindowType = writeWindowType;
+}
+
+/** Returns whether this profile window represents a write window. */
+const int& CProfileWindow::writeWindowType() const {
+ return m_writeWindowType;
+}
+
+} //end of namespace Profile
diff --git a/src/frontend/profile/cprofilewindow.h b/src/frontend/profile/cprofilewindow.h
new file mode 100644
index 0000000..090d991
--- /dev/null
+++ b/src/frontend/profile/cprofilewindow.h
@@ -0,0 +1,126 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CPROFILEWINDOW_H
+#define CPROFILEWINDOW_H
+
+class CSwordModuleInfo;
+#include "backend/managers/cswordbackend.h"
+
+//Qt includes
+#include <QString>
+#include <QRect>
+#include <QStringList>
+//#include <QList>
+
+namespace Profile {
+
+/** Contains the settings for one window saved in the profile.
+ * @author The BibleTime team
+ */
+class CProfileWindow {
+public:
+ struct ScrollbarPos {
+ int horizontal; //the position of the horizontal scrollbar
+ int vertical; //the position of the vertical scrollbar
+ };
+
+ CProfileWindow(CSwordModuleInfo::ModuleType type = CSwordModuleInfo::Unknown);
+ ~CProfileWindow();
+ /**
+ * Sets the modules.
+ */
+ void setModules( const QStringList& modules );
+ /**
+ * Returns the type of the managed window (bible window, commentary window or lexicon window).
+ */
+ CSwordModuleInfo::ModuleType type() const;
+ /**
+ * Sets the type of the used modules.
+ */
+ void setType(const CSwordModuleInfo::ModuleType& type);
+ /**
+ * Sets the size of the window.
+ */
+ void setGeometry( const QRect& s );
+ /**
+ * Returns the size of the window including the x,y coordinates.
+ */
+ const QRect& geometry() const;
+ /**
+ * Returns a list of module names which are chosen in the managed window profile.
+ */
+ const QStringList& modules() const;
+ /**
+ * Set the key used in the modules.
+ */
+ void setKey( const QString& );
+ /**
+ * Returns the current key set in the modules.
+ */
+ const QString& key() const;
+ /**
+ * Sets the current position of the scrollbars.
+ */
+ void setScrollbarPositions(const int& x, const int& y);
+ /**
+ * Sets the windows maximized state to true or false.
+ */
+ void setMaximized( const bool& maximized );
+ /**
+ * Sets the windows hasFocus state to true or false.
+ */
+ void setFocus( const bool& hasFocus );
+ /**
+ * Sets the window specific settings.
+ */
+ void setWindowSettings( const int& settings );
+ /**
+ * Returns an integer with the window specific settings
+ */
+ const int& windowSettings() const;
+ /**
+ * Returns true if the window is maximized.
+ */
+ const bool& maximized() const;
+ /**
+ * Returns true if the window has the focus in the MDI area.
+ */
+ const bool& hasFocus() const;
+ /**
+ * Returns tghe position of the scrollbars
+ */
+ const CProfileWindow::ScrollbarPos& scrollbarPositions() const;
+ /**
+ * Returns whether this profile window represents a write window.
+ */
+ const int& writeWindowType() const;
+ /**
+ * Tells this profile window to represent a write window.
+ */
+ void setWriteWindowType( const int& writeWindowType );
+
+private:
+ CSwordModuleInfo::ModuleType m_type;
+ QRect m_windowGeometry;
+ QStringList m_moduleList;
+ QString m_key;
+ ScrollbarPos m_scrollbarPos;
+ bool m_maximized;
+ bool m_hasFocus;
+ int m_windowSettings;
+ int m_writeWindowType;
+};
+
+} //end of namespace Profile
+
+#endif
+
diff --git a/src/frontend/searchdialog/analysis/csearchanalysisdialog.cpp b/src/frontend/searchdialog/analysis/csearchanalysisdialog.cpp
new file mode 100644
index 0000000..d37cb1d
--- /dev/null
+++ b/src/frontend/searchdialog/analysis/csearchanalysisdialog.cpp
@@ -0,0 +1,84 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "csearchanalysisdialog.h"
+#include "csearchanalysisscene.h"
+#include "csearchanalysisview.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "util/dialogutil.h"
+
+#include <QDialog>
+#include <QAbstractButton>
+#include <QDialogButtonBox>
+#include <QVBoxLayout>
+#include <QApplication>
+#include <QDesktopWidget>
+
+namespace Search {
+
+static const int DIALOG_HEIGHT=400;
+static const int DIALOG_BORDER=30;
+
+CSearchAnalysisDialog::CSearchAnalysisDialog( QList<CSwordModuleInfo*> modules, QWidget* parentDialog )
+ : QDialog(parentDialog)
+{
+ initView();
+ m_analysis->reset();
+ m_analysis->analyse(modules);
+
+ // Set initial width based on the search data, but limit to the
+ // width of the desktop
+ int width = m_analysis->width()+DIALOG_BORDER;
+ int desktopWidth = QApplication::desktop()->screenGeometry(this).width();
+ if (width > desktopWidth)
+ width = desktopWidth;
+ resize(width, DIALOG_HEIGHT);
+
+}
+
+/** Initializes this dialog. */
+void CSearchAnalysisDialog::initView()
+{
+
+ QVBoxLayout *vboxLayout = new QVBoxLayout(this);
+
+ m_analysis = new CSearchAnalysisScene(this);
+ m_analysisView = new CSearchAnalysisView(m_analysis, this);
+//// m_analysisView->show();
+ vboxLayout->addWidget(m_analysisView);
+
+ m_buttonBox = new QDialogButtonBox(this);
+ m_buttonBox->setOrientation(Qt::Horizontal);
+ m_buttonBox->setStandardButtons(QDialogButtonBox::Close);
+ m_buttonBox->addButton(QDialogButtonBox::Save);
+ //tr("Save as HTML"),
+ util::prepareDialogBox(m_buttonBox);
+ vboxLayout->addWidget(m_buttonBox);
+
+ bool ok = QObject::connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+ Q_ASSERT(ok);
+ ok = QObject::connect(m_buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(buttonClicked(QAbstractButton*)));
+ Q_ASSERT(ok);
+}
+
+void CSearchAnalysisDialog::buttonClicked(QAbstractButton* button)
+{
+ if (m_buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) {
+ m_analysis->saveAsHTML();
+ }
+}
+
+void CSearchAnalysisDialog::resizeEvent(QResizeEvent* event)
+{
+ QDialog::resizeEvent(event);
+ m_analysis->resizeHeight(height());
+}
+
+}
diff --git a/src/frontend/searchdialog/analysis/csearchanalysisdialog.h b/src/frontend/searchdialog/analysis/csearchanalysisdialog.h
new file mode 100644
index 0000000..c24c554
--- /dev/null
+++ b/src/frontend/searchdialog/analysis/csearchanalysisdialog.h
@@ -0,0 +1,58 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef SEARCHCSEARCHANALYSISDIALOG_H
+#define SEARCHCSEARCHANALYSISDIALOG_H
+
+
+class CSwordModuleInfo;
+
+#include <QDialog>
+#include <QObject>
+
+class QAbstractButton;
+class QDialogButtonBox;
+
+namespace Search {
+
+class CSearchAnalysisView;
+class CSearchAnalysisScene;
+
+
+
+/**
+ @author The BibleTime team <info@bibletime.info>
+*/
+class CSearchAnalysisDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ CSearchAnalysisDialog(QList<CSwordModuleInfo*> modules, QWidget* parentDialog);
+ ~CSearchAnalysisDialog() {}
+
+protected: // Protected methods
+ /**
+ * Initializes this dialog.
+ */
+ void initView();
+ void resizeEvent(QResizeEvent* event);
+
+private slots:
+ void buttonClicked(QAbstractButton* button);
+
+private:
+ CSearchAnalysisScene* m_analysis;
+ CSearchAnalysisView* m_analysisView;
+ QDialogButtonBox* m_buttonBox;
+};
+
+}
+
+#endif
diff --git a/src/frontend/searchdialog/analysis/csearchanalysisitem.cpp b/src/frontend/searchdialog/analysis/csearchanalysisitem.cpp
new file mode 100644
index 0000000..713a98b
--- /dev/null
+++ b/src/frontend/searchdialog/analysis/csearchanalysisitem.cpp
@@ -0,0 +1,169 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "csearchanalysisitem.h"
+#include "csearchanalysisscene.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+
+#include <QGraphicsRectItem>
+#include <QPainter>
+#include <QFont>
+#include <QPen>
+#include <QPoint>
+#include <QRect>
+
+
+namespace Search {
+
+const int SPACE_BETWEEN_PARTS = 5;
+const int RIGHT_BORDER = 15;
+const int LEFT_BORDER = 15;
+const int LOWER_BORDER = 10;
+const int UPPER_BORDER = 10;
+
+const int ITEM_TEXT_SIZE = 8;
+const int LABEL_TEXT_SIZE = 6;
+
+//used for the shift between the bars
+const int BAR_DELTAX = 4;
+const int BAR_DELTAY = 2;
+const int BAR_WIDTH = 2 + (2*BAR_DELTAX); //should be equal or bigger than the label font size
+// Used for the text below the bars
+const int BAR_LOWER_BORDER = 100;
+
+const int LEGEND_INNER_BORDER = 5;
+const int LEGEND_DELTAY = 4;
+const int LEGEND_WIDTH = 85;
+
+CSearchAnalysisItem::CSearchAnalysisItem(const int moduleCount, const QString &bookname, double *scaleFactor, QList<CSwordModuleInfo*>* modules)
+ : QGraphicsRectItem(),
+ m_moduleList( modules ),
+ m_scaleFactor(scaleFactor),
+ m_bookName(bookname),
+ m_moduleCount(moduleCount),
+ m_bufferPixmap(0)
+{
+ m_resultCountArray.resize(m_moduleCount);
+ int index = 0;
+ for (index = 0; index < m_moduleCount; ++index) m_resultCountArray[index] = 0;
+}
+
+CSearchAnalysisItem::~CSearchAnalysisItem()
+{
+ delete m_bufferPixmap;
+}
+
+/** Sets the resultcount of this item for the given module */
+void CSearchAnalysisItem::setCountForModule( const int moduleIndex, const int count) {
+ m_resultCountArray[moduleIndex] = count;
+}
+
+/** Returns the resultcount of this item for the given module */
+int CSearchAnalysisItem::getCountForModule( const int moduleIndex) {
+ return m_resultCountArray[moduleIndex];
+}
+
+
+bool CSearchAnalysisItem::hasHitsInAnyModule() {
+ foreach (const int hits, m_resultCountArray){
+ if (hits) return true;
+ }
+ return false;
+}
+
+/** Reimplementation. Draws the content of this item. */
+void CSearchAnalysisItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*) {
+ QFont f = painter->font();
+ f.setPointSize(ITEM_TEXT_SIZE);
+ painter->setFont(f);
+
+ /**
+ * We have to paint so many bars as we have modules available (we use m_moduleCount)
+ * We paint inside the area which is given by height and width of this rectangle item
+ */
+ int index = 0;
+ int drawn = 0;
+ int Value = 0;
+
+ //find out the biggest value
+ for (index=0;index < m_moduleCount; index++) {
+ if (m_resultCountArray[index] > Value) {
+ Value = m_resultCountArray[index];
+ }
+ };
+
+ while (drawn < m_moduleCount) {
+ for (index = 0; index < m_moduleCount; index++) {
+ if (m_resultCountArray[index] == Value) {
+ QPoint p1((int)rect().x() + (m_moduleCount-drawn-1)*BAR_DELTAX,
+ (int)rect().height() + (int)y() - BAR_LOWER_BORDER - (m_moduleCount-drawn)*BAR_DELTAY);
+ QPoint p2(p1.x() + BAR_WIDTH,
+ p1.y() - (int)( !m_resultCountArray[index] ? 0 : ((m_resultCountArray[index])*(*m_scaleFactor))) );
+ QRect r(p1, p2);
+ painter->fillRect(r, QBrush(CSearchAnalysisScene::getColor(index)) );
+ painter->drawRect(r);
+ drawn++;
+ }
+ }
+ //finds the next smaller value
+ int newValue = 0;
+ for (index=0;index < m_moduleCount; index++)
+ if (m_resultCountArray[index] < Value && m_resultCountArray[index] >= newValue)
+ newValue = m_resultCountArray[index];
+ Value = newValue;
+ }
+ if (!m_bufferPixmap) {
+ m_bufferPixmap = new QPixmap(width(),BAR_LOWER_BORDER);
+ //m_bufferPixmap->resize(width(),BAR_LOWER_BORDER);
+ m_bufferPixmap->fill();
+ QPainter p(m_bufferPixmap);
+ f = p.font();
+ f.setPointSize(ITEM_TEXT_SIZE);
+ p.setFont(f);
+ p.rotate(90);
+ p.drawText(QPoint(5,0), m_bookName);
+ }
+ painter->drawPixmap(QPoint(int(rect().x()),int(rect().height()+y()-BAR_LOWER_BORDER)), *m_bufferPixmap);
+}
+
+/** Returns the width of this item. */
+int CSearchAnalysisItem::width() {
+ return m_moduleCount*(m_moduleCount>1 ? BAR_DELTAX : 0) + BAR_WIDTH;
+}
+
+/** Returns the tooltip for this item. */
+const QString CSearchAnalysisItem::getToolTip() {
+ QString toolTipString = QString("<center><b>%1</b></center><hr/>").arg(m_bookName);
+ toolTipString += "<table cellspacing=\"0\" cellpadding=\"3\" width=\"100%\" height=\"100%\" align=\"center\">";
+
+ //ToDo: Fix that loop
+ int i = 0;
+ QList<CSwordModuleInfo*>::iterator end_it = m_moduleList->end();
+
+ for (QList<CSwordModuleInfo*>::iterator it(m_moduleList->begin()); it != end_it; ++it) {
+ CSwordModuleInfo* info = (*it);
+ const QColor c = CSearchAnalysisScene::getColor(i);
+
+ toolTipString.append(
+ QString("<tr bgcolor=\"white\"><td><b><font color=\"#%1\">%2</font></b></td><td>%3 (%4%)</td></tr>")
+ .arg(QString().sprintf("%02X%02X%02X",c.red(),c.green(),c.blue()))
+ .arg(info ? info->name() : QString::null)
+ .arg( m_resultCountArray[i] )
+ .arg( (info && m_resultCountArray[i])? ((double)m_resultCountArray[i] / (double)info->searchResult().Count())*(double)100 : 0.0, 0, 'g', 2)
+ );
+ ++i;
+ }
+
+ toolTipString += "</table>";
+
+ return toolTipString;
+}
+
+}
diff --git a/src/frontend/searchdialog/analysis/csearchanalysisitem.h b/src/frontend/searchdialog/analysis/csearchanalysisitem.h
new file mode 100644
index 0000000..5926f43
--- /dev/null
+++ b/src/frontend/searchdialog/analysis/csearchanalysisitem.h
@@ -0,0 +1,65 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef SEARCHCSEARCHANALYSISITEM_H
+#define SEARCHCSEARCHANALYSISITEM_H
+
+class CSwordModuleInfo;
+
+#include <QGraphicsRectItem>
+#include <QGraphicsScene>
+
+namespace Search {
+
+/**
+ @author The BibleTime team <info@bibletime.info>
+*/
+class CSearchAnalysisItem : public QGraphicsRectItem
+{
+public:
+
+ CSearchAnalysisItem(const int moduleCount, const QString& bookname, double *scaleFactor, QList<CSwordModuleInfo*>* modules);
+ ~CSearchAnalysisItem();
+ /**
+ * Sets the resultcount of this item
+ */
+ void setCountForModule( const int moduleIndex, const int count);
+
+ /**
+ * Returns the resultcount of this item
+ */
+ int getCountForModule( const int moduleIndex);
+ /**
+ * Does one of the modules contain hits?
+ */
+ bool hasHitsInAnyModule();
+ /**
+ * Returns the width of this item.
+ */
+ virtual int width();
+ /**
+ * Returns the tooltip for this item.
+ */
+ const QString getToolTip();
+
+private:
+ virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*);
+
+ QList<CSwordModuleInfo*>* m_moduleList;
+ double *m_scaleFactor;
+ QString m_bookName;
+ int m_moduleCount;
+ QVector<int> m_resultCountArray;
+ QPixmap* m_bufferPixmap;
+
+};
+
+}
+
+#endif
diff --git a/src/frontend/searchdialog/analysis/csearchanalysislegenditem.cpp b/src/frontend/searchdialog/analysis/csearchanalysislegenditem.cpp
new file mode 100644
index 0000000..be667e0
--- /dev/null
+++ b/src/frontend/searchdialog/analysis/csearchanalysislegenditem.cpp
@@ -0,0 +1,84 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "csearchanalysislegenditem.h"
+#include "csearchanalysisscene.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+
+#include <QPainter>
+#include <QPen>
+#include <QFont>
+
+namespace Search {
+
+const int SPACE_BETWEEN_PARTS = 5;
+const int RIGHT_BORDER = 15;
+const int LEFT_BORDER = 15;
+const int LOWER_BORDER = 10;
+const int UPPER_BORDER = 10;
+
+const int ITEM_TEXT_SIZE = 8;
+const int LABEL_TEXT_SIZE = 6;
+
+//used for the shift between the bars
+const int BAR_DELTAX = 4;
+const int BAR_DELTAY = 2;
+const int BAR_WIDTH = 2 + (2*BAR_DELTAX); //should be equal or bigger than the label font size
+// Used for the text below the bars
+const int BAR_LOWER_BORDER = 100;
+
+const int LEGEND_INNER_BORDER = 5;
+const int LEGEND_DELTAY = 4;
+const int LEGEND_WIDTH = 85;
+
+
+CSearchAnalysisLegendItem::CSearchAnalysisLegendItem(QList<CSwordModuleInfo*> *list )
+ : QGraphicsRectItem()
+{
+ m_moduleList = list;
+}
+
+/** Reimplementation. Draws the content of this item. */
+void CSearchAnalysisLegendItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*) {
+ painter->save();
+
+ //the outer rectangle
+ QPoint p1( (int)(rect().x()), (int)(rect().y()) );
+ QPoint p2( (int)(rect().x()+rect().width()), (int)(rect().y()) + rect().height() );
+ QRect r(p1, p2);
+ r = r.normalized();
+ painter->drawRect(r);
+
+ QFont f = painter->font();
+ f.setPointSize(ITEM_TEXT_SIZE);
+ painter->setFont(f);
+
+ // for (unsigned int index=0; index < m_moduleList->count(); index++){
+ int moduleIndex = 0;
+ QList<CSwordModuleInfo*>::iterator end_it = m_moduleList->end();
+ for (QList<CSwordModuleInfo*>::iterator it(m_moduleList->begin()); it != end_it; ++it) {
+ // the module color indicators
+ QPoint p1( (int)(rect().x()) + LEGEND_INNER_BORDER, (int)(rect().y()) + LEGEND_INNER_BORDER + moduleIndex*(LEGEND_DELTAY + ITEM_TEXT_SIZE) );
+ QPoint p2(p1.x() + ITEM_TEXT_SIZE, p1.y() + ITEM_TEXT_SIZE);
+ QRect r(p1,p2);
+ painter->fillRect(r, QBrush(CSearchAnalysisScene::getColor(moduleIndex)) );
+ r = r.normalized();
+ painter->drawRect(r);
+
+ QPoint p3( p2.x() + LEGEND_INNER_BORDER, p2.y() );
+ painter->drawText(p3, (*it)->name() );
+
+ ++moduleIndex;
+ }
+ painter->restore();
+}
+
+
+}
diff --git a/src/frontend/searchdialog/analysis/csearchanalysislegenditem.h b/src/frontend/searchdialog/analysis/csearchanalysislegenditem.h
new file mode 100644
index 0000000..879f239
--- /dev/null
+++ b/src/frontend/searchdialog/analysis/csearchanalysislegenditem.h
@@ -0,0 +1,35 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef SEARCHCSEARCHANALYSISLEGENDITEM_H
+#define SEARCHCSEARCHANALYSISLEGENDITEM_H
+
+class CSwordModuleInfo;
+
+#include <QGraphicsRectItem>
+
+namespace Search {
+
+/**
+ @author The BibleTime team <info@bibletime.info>
+*/
+class CSearchAnalysisLegendItem : public QGraphicsRectItem
+{
+public:
+ CSearchAnalysisLegendItem(QList<CSwordModuleInfo*>* list );
+
+private:
+ virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*);
+ QList<CSwordModuleInfo*>* m_moduleList;
+
+};
+
+}
+
+#endif
diff --git a/src/frontend/searchdialog/analysis/csearchanalysisscene.cpp b/src/frontend/searchdialog/analysis/csearchanalysisscene.cpp
new file mode 100644
index 0000000..7bc3ab2
--- /dev/null
+++ b/src/frontend/searchdialog/analysis/csearchanalysisscene.cpp
@@ -0,0 +1,292 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "csearchanalysisscene.h"
+#include "csearchanalysisitem.h"
+#include "csearchanalysislegenditem.h"
+
+#include "frontend/searchdialog/csearchdialog.h"
+
+#include "backend/keys/cswordversekey.h"
+#include "util/ctoolclass.h"
+
+#include <QHashIterator>
+#include <QFileDialog>
+#include <QTextCodec>
+#include <QApplication>
+
+
+
+namespace Search {
+
+const int SPACE_BETWEEN_PARTS = 5;
+const int RIGHT_BORDER = 15;
+const int LEFT_BORDER = 15;
+const int LOWER_BORDER = 10;
+const int UPPER_BORDER = 10;
+
+const int ITEM_TEXT_SIZE = 8;
+const int LABEL_TEXT_SIZE = 6;
+
+//used for the shift between the bars
+const int BAR_DELTAX = 4;
+const int BAR_DELTAY = 2;
+const int BAR_WIDTH = 2 + (2*BAR_DELTAX); //should be equal or bigger than the label font size
+// Used for the text below the bars
+const int BAR_LOWER_BORDER = 90;
+
+const int LEGEND_INNER_BORDER = 5;
+const int LEGEND_DELTAY = 4;
+const int LEGEND_WIDTH = 85;
+
+
+CSearchAnalysisScene::CSearchAnalysisScene(QObject *parent )
+ : QGraphicsScene(parent),
+ m_scaleFactor(0.0),
+ m_legend(0)
+{
+ setBackgroundBrush(QBrush(Qt::white));
+ setSceneRect(0,0,1,1);
+}
+
+
+QHash<QString, CSearchAnalysisItem*>* CSearchAnalysisScene::getSearchAnalysisItemList() {
+ // Returns pointer to the search analysis items
+ return &m_itemList;
+}
+
+/** Starts the analysis of the search result. This should be called only once because QCanvas handles the updates automatically. */
+void CSearchAnalysisScene::analyse(QList<CSwordModuleInfo*> modules) {
+ /**
+ * Steps of analysing our search result;
+ * -Create the items for all available books ("Genesis" - "Revelation")
+ * -Iterate through all modules we analyse
+ * -Go through all books of this module
+ * -Find out how many times we found the book
+ * -Set the count to the items which belongs to the book
+ */
+ setModules(modules);
+
+ m_lastPosList.clear();
+ const int numberOfModules = m_moduleList.count();
+ if (!numberOfModules)
+ return;
+ m_legend = new CSearchAnalysisLegendItem(&m_moduleList);
+ addItem(m_legend);
+ m_legend->setRect(LEFT_BORDER, UPPER_BORDER,
+ LEGEND_WIDTH, LEGEND_INNER_BORDER*2 + ITEM_TEXT_SIZE*numberOfModules + LEGEND_DELTAY*(numberOfModules-1) );
+ m_legend->show();
+
+ int xPos = (int)(LEFT_BORDER + m_legend->rect().width() + SPACE_BETWEEN_PARTS);
+ int moduleIndex = 0;
+ m_maxCount = 0;
+ int count = 0;
+ CSwordVerseKey key(0);
+ key.key("Genesis 1:1");
+
+ CSearchAnalysisItem* analysisItem = m_itemList[key.book()];
+ bool ok = true;
+ while (ok && analysisItem) {
+ moduleIndex = 0;
+ QList<CSwordModuleInfo*>::iterator end_it = m_moduleList.end();
+ for (QList<CSwordModuleInfo*>::iterator it(m_moduleList.begin()); it != end_it; ++it) {
+ qApp->processEvents( QEventLoop::AllEvents );
+ if (!m_lastPosList.contains(*it)) {
+ m_lastPosList.insert(*it,0);
+ }
+
+ analysisItem->setCountForModule(moduleIndex, (count = getCount(key.book(), *it)));
+ m_maxCount = (count > m_maxCount) ? count : m_maxCount;
+
+ ++moduleIndex;
+ }
+ if (analysisItem->hasHitsInAnyModule())
+ {
+ analysisItem->setRect(xPos, UPPER_BORDER, analysisItem->rect().width(), analysisItem->rect().height());
+ QString tip = analysisItem->getToolTip();
+ analysisItem->setToolTip(tip);
+ analysisItem->show();
+ xPos += (int)analysisItem->width() + SPACE_BETWEEN_PARTS;
+ }
+ ok = key.next(CSwordVerseKey::UseBook);
+ analysisItem = m_itemList[key.book()];
+ }
+ setSceneRect(0,0, xPos+BAR_WIDTH+(m_moduleList.count()-1)*BAR_DELTAX+RIGHT_BORDER, height() );
+ slotResized();
+}
+
+/** Sets the module list used for the analysis. */
+void CSearchAnalysisScene::setModules(QList<CSwordModuleInfo*> modules) {
+ m_moduleList.clear();
+ foreach (CSwordModuleInfo * mod, modules) {
+ if ( (mod->type() == CSwordModuleInfo::Bible) || (mod->type() == CSwordModuleInfo::Commentary) ) { //a Bible or an commentary
+ m_moduleList.append(mod);
+ }
+ }
+
+ m_itemList.clear();
+ CSearchAnalysisItem* analysisItem = 0;
+ CSwordVerseKey key(0);
+ key.key("Genesis 1:1");
+ do {
+ analysisItem = new CSearchAnalysisItem(m_moduleList.count(), key.book(), &m_scaleFactor, &m_moduleList);
+ addItem(analysisItem);
+ analysisItem->hide();
+ m_itemList.insert(key.book(), analysisItem);
+ }
+ while (key.next(CSwordVerseKey::UseBook));
+ update();
+}
+
+/** Sets back the items and deletes things to cleanup */
+void CSearchAnalysisScene::reset() {
+ m_scaleFactor = 0.0;
+
+ QHashIterator<QString, CSearchAnalysisItem*> it( m_itemList ); // iterator for items
+ while ( it.hasNext() ) {
+ it.next();
+ if (it.value()) it.value()->hide();
+ }
+ m_lastPosList.clear();
+
+ if (m_legend) m_legend->hide();
+
+ delete m_legend;
+ m_legend = 0;
+
+ update();
+}
+
+/** No descriptions */
+void CSearchAnalysisScene::slotResized() {
+ m_scaleFactor = (double)( (double)(height()-UPPER_BORDER-LOWER_BORDER-BAR_LOWER_BORDER-100-(m_moduleList.count()-1)*BAR_DELTAY)
+ /(double)m_maxCount);
+ QHashIterator<QString, CSearchAnalysisItem*> it( m_itemList );
+ while ( it.hasNext() ) {
+ it.next();
+ if (it.value()) {
+ it.value()->setRect(it.value()->rect().x(), UPPER_BORDER, BAR_WIDTH + (m_moduleList.count()-1)*BAR_DELTAX, height()-LOWER_BORDER-BAR_LOWER_BORDER);
+ }
+ }
+ update();
+}
+
+/** This function returns a color for each module */
+QColor CSearchAnalysisScene::getColor(int index) {
+ switch (index) {
+ case 0:
+ return Qt::red;
+ case 1:
+ return Qt::darkGreen;
+ case 2:
+ return Qt::blue;
+ case 3:
+ return Qt::cyan;
+ case 4:
+ return Qt::magenta;
+ case 5:
+ return Qt::darkRed;
+ case 6:
+ return Qt::darkGray;
+ case 7:
+ return Qt::black;
+ case 8:
+ return Qt::darkCyan;
+ case 9:
+ return Qt::darkMagenta;
+ default:
+ return Qt::red;
+ }
+}
+
+/** Returns the count of the book in the module */
+unsigned int CSearchAnalysisScene::getCount( const QString book, CSwordModuleInfo* module ) {
+ sword::ListKey& result = module->searchResult();
+ const int length = book.length();
+ unsigned int i = m_lastPosList[module];
+ unsigned int count = 0;
+ const unsigned int resultCount = result.Count();
+ while (i < resultCount) {
+ if ( strncmp(book.toUtf8(), (const char*)*result.GetElement(i), length) )
+ break;
+ i++;
+ ++count;
+ }
+ m_lastPosList.insert(module,i);
+ return count;
+}
+
+void CSearchAnalysisScene::saveAsHTML() {
+ const QString fileName = QFileDialog::getSaveFileName(0, tr("Save Search Analysis"), QString::null, tr("HTML files (*.html;*.HTML;*.HTM;*.htm)") );
+ if (fileName.isEmpty()) return;
+
+ int count = 0;
+ QString countStr = "";
+ QString m_searchAnalysisHTML = "";
+ QString tableTitle = "";
+ QString tableTotals = "";
+ QString VerseRange = "";
+ const QString txtCSS = QString("<style type=\"text/css\">\ntd {border:1px solid black;}\nth {font-size: 130%; text-align:left; vertical-align:top;}\n</style>\n");
+ const QString metaEncoding = QString("<META http-equiv=Content-Type content=\"text/html; charset=utf-8\">");
+ CSwordVerseKey key(0);
+ sword::ListKey searchResult;
+
+ key.key("Genesis 1:1");
+
+ CSearchAnalysisItem* analysisItem = m_itemList.value( key.book() );
+
+ QString text = "<html>\n<head>\n<title>" + tr("BibleTime Search Analysis") + "</title>\n" + txtCSS + metaEncoding + "</head>\n<body>\n";
+ text += "<table>\n<tr><th>" + tr("Search text :") + "</th><th>" + CSearchDialog::getSearchDialog()->searchText() + "</th></tr>\n";
+
+ tableTitle = "<tr><th align=\"left\">" + tr("Book") + "</th>";
+ tableTotals = "<tr><td align=\"left\">" + tr("Total hits") + "</td>";
+
+ foreach (CSwordModuleInfo* mod, m_moduleList) {
+ tableTitle += QString("<th align=\"left\">") + mod->name() + QString("</th>");
+ searchResult = mod->searchResult();
+ countStr.setNum(searchResult.Count());
+
+ tableTotals += QString("<td align=\"right\">") + countStr + QString("</td>");
+ }
+ tableTitle += QString("</tr>\n");
+ tableTotals += QString("</tr>\n");
+
+ m_searchAnalysisHTML = "";
+ bool ok = true;
+ while (ok) {
+ m_searchAnalysisHTML += QString("<tr><td>") + key.book() + QString("</td>");
+ analysisItem = m_itemList.value( key.book() );
+
+ int moduleIndex = 0;
+ QList<CSwordModuleInfo*>::iterator end_it = m_moduleList.end();
+ for (QList<CSwordModuleInfo*>::iterator it(m_moduleList.begin()); it != end_it; ++it) {
+ count = analysisItem->getCountForModule(moduleIndex);
+ countStr.setNum(count);
+ m_searchAnalysisHTML += QString("<td align=\"right\">") + countStr + QString("</td>");
+
+ ++moduleIndex;
+ }
+ m_searchAnalysisHTML += QString("</tr>\n");
+ ok = key.next(CSwordVerseKey::UseBook);
+ }
+
+ text += QString("<table>\n") + tableTitle + tableTotals + m_searchAnalysisHTML + QString("</table>\n");
+ text += QString("<center>") + tr("Created by <a href=\"http://www.bibletime.info/\">BibleTime</a>") + QString("</center>");
+ text += QString("</body></html>");
+
+ CToolClass::savePlainFile(fileName, text, false, QTextCodec::codecForName("UTF8"));
+}
+
+void CSearchAnalysisScene::resizeHeight(int height)
+{
+ setSceneRect(0,0, sceneRect().width(), height);
+ slotResized();
+}
+
+}
diff --git a/src/frontend/searchdialog/analysis/csearchanalysisscene.h b/src/frontend/searchdialog/analysis/csearchanalysisscene.h
new file mode 100644
index 0000000..755dacf
--- /dev/null
+++ b/src/frontend/searchdialog/analysis/csearchanalysisscene.h
@@ -0,0 +1,88 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef SEARCHCSEARCHANALYSISSCENE_H
+#define SEARCHCSEARCHANALYSISSCENE_H
+
+#include "csearchanalysisitem.h"
+
+class CSwordModuleInfo;
+
+
+#include <QGraphicsScene>
+#include <QColor>
+#include <QMap>
+#include <QHash>
+
+namespace Search {
+
+class CSearchAnalysisLegendItem;
+
+/**
+ @author The BibleTime team <info@bibletime.info>
+*/
+class CSearchAnalysisScene : public QGraphicsScene {
+ Q_OBJECT
+public:
+ CSearchAnalysisScene(QObject* parent);
+
+ virtual ~CSearchAnalysisScene() {}
+
+ /**
+ * Starts the analysis of the search result.
+ * This should be called only once because
+ * QCanvas handles the updates automatically.
+ */
+ void analyse(QList<CSwordModuleInfo*> modules);
+ /**
+ * This function returns a color for each module
+ * @return The color at position index in the list
+ */
+ static QColor getColor(int index);
+ /**
+ * This function returns a pointer to the list of AnalysisItems
+ */
+ QHash<QString, CSearchAnalysisItem*>* getSearchAnalysisItemList();
+ void reset();
+ /**
+ * resize the height of the scene
+ */
+ void resizeHeight(int height);
+
+public slots:
+ void saveAsHTML();
+
+protected slots: // Protected slots
+ /**
+ * No descriptions
+ */
+ void slotResized();
+
+protected:
+ void setModules(QList<CSwordModuleInfo*> modules);
+
+private:
+ /**
+ * Returns the count of the book in the module
+ */
+ unsigned int getCount( const QString book, CSwordModuleInfo* module );
+
+ QList<CSwordModuleInfo*> m_moduleList;
+ QHash<QString, CSearchAnalysisItem*> m_itemList;
+ QMap<CSwordModuleInfo*,unsigned int> m_lastPosList;
+ int m_maxCount;
+ double m_scaleFactor;
+ CSearchAnalysisLegendItem* m_legend;
+
+
+};
+
+}
+
+#endif
diff --git a/src/frontend/searchdialog/analysis/csearchanalysisview.cpp b/src/frontend/searchdialog/analysis/csearchanalysisview.cpp
new file mode 100644
index 0000000..0d58c78
--- /dev/null
+++ b/src/frontend/searchdialog/analysis/csearchanalysisview.cpp
@@ -0,0 +1,50 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "csearchanalysisview.h"
+#include "csearchanalysisscene.h"
+
+#include <QWidget>
+#include <QGraphicsView>
+#include <QResizeEvent>
+
+
+namespace Search {
+
+CSearchAnalysisView::CSearchAnalysisView(CSearchAnalysisScene* scene, QWidget* parent)
+ : QGraphicsView(scene, parent)
+{
+ setFocusPolicy(Qt::WheelFocus);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ resize(sizeHint());
+}
+
+
+/** Returns the sizeHint for this view */
+QSize CSearchAnalysisView::sizeHint() const {
+ return QGraphicsView::sizeHint();
+}
+
+/** No descriptions */
+void CSearchAnalysisView::resizeEvent( QResizeEvent* e) {
+ QGraphicsView::resizeEvent(e);
+ scene()->setSceneRect(0,0, scene()->sceneRect().width(), viewport()->height() );
+}
+
+
+/** Returns the item at position p. If there no item at that point return 0.
+Is needed?
+*/
+//CSearchAnalysisItem* CSearchAnalysisView::itemAt( const QPoint& p )
+//{
+//}
+
+
+
+}
diff --git a/src/frontend/searchdialog/analysis/csearchanalysisview.h b/src/frontend/searchdialog/analysis/csearchanalysisview.h
new file mode 100644
index 0000000..35c4419
--- /dev/null
+++ b/src/frontend/searchdialog/analysis/csearchanalysisview.h
@@ -0,0 +1,54 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef SEARCHCSEARCHANALYSISVIEW_H
+#define SEARCHCSEARCHANALYSISVIEW_H
+
+#include <QGraphicsView>
+#include <QSize>
+
+class QResizeEvent;
+
+namespace Search {
+
+class CSearchAnalysisScene;
+
+/**
+ @author The BibleTime team <info@bibletime.info>
+*/
+class CSearchAnalysisView : public QGraphicsView
+{
+public:
+ CSearchAnalysisView(CSearchAnalysisScene* scene, QWidget* parent);
+
+ ~CSearchAnalysisView() {}
+
+/**
+ * Returns the sizeHint for this view
+ * We give back the size of the parent widgetas default.
+ * This is a reimplementation from QCanvasView::sizeHint().
+ */
+ virtual QSize sizeHint() const;
+
+ /**
+ * Returns the item at position p or 0 if there is no item.
+ */
+ //CSearchAnalysisItem* itemAt( const QPoint& p );
+
+protected:
+ /**
+ * Reimplementation.
+ */
+ virtual void resizeEvent(QResizeEvent* e);
+
+};
+
+}
+
+#endif
diff --git a/src/frontend/searchdialog/btsearchoptionsarea.cpp b/src/frontend/searchdialog/btsearchoptionsarea.cpp
new file mode 100644
index 0000000..a4dbfd4
--- /dev/null
+++ b/src/frontend/searchdialog/btsearchoptionsarea.cpp
@@ -0,0 +1,530 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btsearchoptionsarea.h"
+#include "csearchmodulechooserdialog.h"
+#include "crangechooserdialog.h"
+
+#include "util/directoryutil.h"
+#include "util/cresmgr.h"
+#include "util/ctoolclass.h"
+#include "util/cpointers.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/config/cbtconfig.h"
+#include "frontend/htmldialogs/bttabhtmldialog.h"
+
+#include <QHBoxLayout>
+#include <QGroupBox>
+#include <QGridLayout>
+#include <QLabel>
+#include <QPushButton>
+#include <QRadioButton>
+#include <QDebug>
+#include <QLineEdit>
+#include <QMessageBox>
+#include <QEvent>
+
+
+namespace Search {
+
+BtSearchOptionsArea::BtSearchOptionsArea(QWidget *parent )
+ : QWidget(parent)
+{
+ initView();
+ initConnections();
+ readSettings();
+}
+
+BtSearchOptionsArea::~BtSearchOptionsArea() {
+ saveSettings();
+}
+
+QString BtSearchOptionsArea::searchText() const {
+ return m_searchTextCombo->currentText();
+}
+
+BtSearchOptionsArea::SearchType BtSearchOptionsArea::searchType()
+{
+ if (m_typeAndButton->isChecked()) {
+ return BtSearchOptionsArea::AndType;
+ }
+ if (m_typeOrButton->isChecked()) {
+ return BtSearchOptionsArea::OrType;
+ }
+ return BtSearchOptionsArea::FullType;
+}
+
+QPushButton* BtSearchOptionsArea::searchButton() const {
+ return m_searchButton;
+}
+
+void BtSearchOptionsArea::setSearchText(const QString& text) {
+ bool found = false;
+ int i = 0;
+ for (i = 0; !found && i < m_searchTextCombo->count(); ++i) {
+ if (m_searchTextCombo->itemText(i) == text) {
+ found = true;
+ }
+ }
+ // This is needed because in the for loop i is incremented before the comparison (++i)
+ // As a result the index i is actually one greater than expected.
+ i--;
+ if (!found) {
+ i = 0;
+ m_searchTextCombo->insertItem(0, text );
+ }
+
+ m_searchTextCombo->setCurrentIndex(i);
+ m_searchTextCombo->setFocus();
+}
+
+void BtSearchOptionsArea::initView()
+{
+ QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ this->setSizePolicy(sizePolicy);
+ hboxLayout = new QHBoxLayout(this);
+
+ searchGroupBox = new QGroupBox(this);
+
+ gridLayout = new QGridLayout(searchGroupBox);
+
+ gridLayout->setHorizontalSpacing(3);
+
+ // ******** label for search text editor***********
+ m_searchTextLabel = new QLabel(tr("Search for:"), searchGroupBox);
+ m_searchTextLabel->setWordWrap(false);
+ gridLayout->addWidget(m_searchTextLabel, 0, 0);
+
+ // **********Buttons******************
+
+ m_searchButton = new QPushButton(this);
+ m_searchButton->setText(tr("&Search"));
+ m_searchButton->setIcon( util::filesystem::DirectoryUtil::getIcon(CResMgr::searchdialog::icon));
+ m_searchButton->setToolTip(tr("Start to search the text in the chosen works"));
+ gridLayout->addWidget(m_searchButton, 0, 2);
+
+ m_chooseModulesButton = new QPushButton(tr("Ch&oose..."), searchGroupBox);
+ m_chooseModulesButton->setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::searchdialog::chooseworks_icon));
+ m_chooseModulesButton->setToolTip( tr("Choose works for the search"));
+ gridLayout->addWidget(m_chooseModulesButton, 2, 2);
+
+ m_chooseRangeButton = new QPushButton(tr("S&etup..."), searchGroupBox);
+ m_chooseRangeButton->setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::searchdialog::setupscope_icon));
+ m_chooseRangeButton->setToolTip(tr("Configure predefined scopes for search"));
+ gridLayout->addWidget(m_chooseRangeButton, 3, 2);
+
+ // ************* Search type (AND/OR) selector ***************************************
+ QHBoxLayout* typeSelectorLayout = new QHBoxLayout();
+ int tsLeft, tsTop, tsRight, tsBottom;
+ // Added space looks nicer and enhances readability
+ typeSelectorLayout->getContentsMargins(&tsLeft, &tsTop, &tsRight, &tsBottom);
+ typeSelectorLayout->setContentsMargins(tsLeft, 0, tsRight, tsBottom + CToolClass::mWidth(this,1) );
+ typeSelectorLayout->setSpacing(typeSelectorLayout->spacing()+CToolClass::mWidth(this,1));
+ QHBoxLayout* fullButtonLayout = new QHBoxLayout();
+ fullButtonLayout->setSpacing(CToolClass::mWidth(this,1)/2);
+ m_typeAndButton = new QRadioButton(tr("All words"));
+ m_typeAndButton->setChecked(true);
+ m_typeOrButton = new QRadioButton(tr("Some words"));
+ m_typeFreeButton = new QRadioButton(tr("Free"));
+
+ m_typeAndButton->setToolTip(tr("All of the words (AND is added between the words)"));
+ m_typeOrButton->setToolTip(tr("Some of the words (OR is added between the words)"));
+ m_typeFreeButton->setToolTip(tr("Full lucene syntax"));
+
+ m_helpLabel = new QLabel(tr(" (<a href='syntax_help'>full syntax</a>)"));
+ m_helpLabel->setToolTip(tr("Click the link to get help for search syntax"));
+
+ typeSelectorLayout->addWidget(m_typeAndButton);
+ typeSelectorLayout->addWidget(m_typeOrButton);
+ fullButtonLayout->addWidget(m_typeFreeButton);
+ fullButtonLayout->addWidget(m_helpLabel);
+ typeSelectorLayout->addLayout(fullButtonLayout);
+ gridLayout->addLayout(typeSelectorLayout, 1,1, 1,-1, Qt::AlignLeft|Qt::AlignTop);
+
+ // ************* Label for search range/scope selector *************
+ m_searchScopeLabel = new QLabel(tr("Scope:"), searchGroupBox);
+ m_searchScopeLabel->setWordWrap(false);
+ gridLayout->addWidget(m_searchScopeLabel, 3, 0);
+
+ // ***********Range/scope selector combo box***********
+ m_rangeChooserCombo = new QComboBox(searchGroupBox);
+ QSizePolicy sizePolicy2(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ sizePolicy2.setHorizontalStretch(0);
+ sizePolicy2.setVerticalStretch(0);
+ sizePolicy2.setHeightForWidth(m_rangeChooserCombo->sizePolicy().hasHeightForWidth());
+ m_rangeChooserCombo->setSizePolicy(sizePolicy2);
+ m_rangeChooserCombo->setToolTip(tr("Choose the scope (books/chapters/verses to search in).<br />Applicable for Bibles and commentaries."));
+ gridLayout->addWidget(m_rangeChooserCombo, 3, 1);
+
+ // ************* Search text combo box *******************
+ m_searchTextCombo = new CHistoryComboBox(searchGroupBox);
+ sizePolicy2.setHeightForWidth(m_searchTextCombo->sizePolicy().hasHeightForWidth());
+ m_searchTextCombo->setSizePolicy(sizePolicy2);
+ m_searchTextCombo->setFocusPolicy(Qt::WheelFocus);
+ m_searchTextCombo->setProperty("sizeLimit", QVariant(25));
+ m_searchTextCombo->setProperty("duplicatesEnabled", QVariant(false));
+ m_searchTextCombo->setToolTip(tr("The text you want to search for"));
+ m_searchTextCombo->setInsertPolicy(QComboBox::NoInsert);
+ gridLayout->addWidget(m_searchTextCombo, 0, 1);
+
+ m_modulesLabel = new QLabel(tr("Works:"), searchGroupBox);
+ gridLayout->addWidget(m_modulesLabel, 2, 0);
+
+ m_modulesCombo = new QComboBox(searchGroupBox);
+ m_modulesCombo->setDuplicatesEnabled(false);
+ gridLayout->addWidget(m_modulesCombo, 2, 1);
+
+ hboxLayout->addWidget(searchGroupBox);
+
+ // Set the minimum size before the widgets are populated with data.
+ // Otherwise we will get problems with sizing.
+ setMinimumSize(minimumSizeHint());
+
+ refreshRanges();
+ //set the initial focus
+ m_searchTextCombo->setFocus();
+ // event filter to prevent the Return/Enter presses in the combo box doing something
+ // in the parent widget
+ m_searchTextCombo->installEventFilter(this);
+}
+
+void BtSearchOptionsArea::initConnections()
+{
+ QObject::connect( m_searchTextCombo->lineEdit(), SIGNAL(returnPressed ()),
+ this, SLOT( slotSearchTextEditReturnPressed() )
+ );
+ connect(m_chooseModulesButton, SIGNAL(clicked()), this, SLOT(chooseModules()));
+ connect(m_chooseRangeButton, SIGNAL(clicked()), this, SLOT(setupRanges()));
+ connect(m_modulesCombo, SIGNAL(activated(int)), this, SLOT(moduleListTextSelected(int) ) );
+ connect(m_helpLabel, SIGNAL(linkActivated(QString)), this, SLOT(syntaxHelp()));
+ connect(m_searchTextCombo, SIGNAL(editTextChanged(const QString&)), this, SLOT(slotValidateText(const QString&)));
+}
+
+/** Sets the modules used by the search. */
+void BtSearchOptionsArea::setModules( QList<CSwordModuleInfo*> modules )
+{
+ qDebug("BtSearchOptionsArea::setModules");
+ qDebug() << modules;
+ QString t;
+
+ m_modules.clear(); //remove old modules
+ QList<CSwordModuleInfo*>::iterator end_it = modules.end();
+
+ for (QList<CSwordModuleInfo*>::iterator it(modules.begin()); it != end_it; ++it) {
+ //ToDo: Check for containsRef compat
+ if (*it == 0) { //don't operate on null modules.
+ continue;
+ }
+ qDebug() << "new module:" << (*it)->name();
+ if ( !m_modules.contains(*it) ) {
+ m_modules.append( *it );
+ t.append( (*it)->name() );
+ if (*it != modules.last()) {
+ t += QString::fromLatin1(", "); // so that it will become a readable list (WLC, LXX, GerLut...)
+ }
+ }
+ };
+ //m_modulesLabel->setText(t);
+ int existingIndex = m_modulesCombo->findText(t);
+ qDebug() << "index of the module list string which already exists in combobox:" << existingIndex;
+ if (existingIndex >= 0) {
+ m_modulesCombo->removeItem(existingIndex);
+ }
+ if (m_modulesCombo->count() > 10) {
+ m_modulesCombo->removeItem(m_modulesCombo->count()-1);
+ }
+ m_modulesCombo->insertItem(0, t);
+ m_modulesCombo->setItemData(0, t, Qt::ToolTipRole);
+ m_modulesCombo->setCurrentIndex(0);
+ m_modulesCombo->setToolTip(t);
+ //Save the list in config here, not when deleting, because the history may be used
+ // elsewhere while the dialog is still open
+ QStringList historyList;
+ for (int i = 0; i < m_modulesCombo->count(); ++i) {
+ historyList.append(m_modulesCombo->itemText(i));
+ }
+ CBTConfig::set(CBTConfig::searchModulesHistory, historyList);
+ emit( sigSetSearchButtonStatus( (modules.count() != 0) ) );
+}
+
+// Catch activated signal of module selector combobox
+void BtSearchOptionsArea::moduleListTextSelected(int index)
+{
+ qDebug("BtSearchOptionsArea::moduleListTextSelected");
+ //create the module list
+ QString text = m_modulesCombo->itemText(index);
+ qDebug() << text;
+ QStringList moduleNamesList = text.split(", ");
+ QList<CSwordModuleInfo*> moduleList;
+ foreach(QString name, moduleNamesList) {
+ moduleList.append(CPointers::backend()->findModuleByName(name));
+ }
+ //set the list and the combobox list and text
+ setModules(moduleList);
+}
+
+void BtSearchOptionsArea::chooseModules() {
+ QString title(tr("Works to Search in"));
+ QString label(tr("Select the works which should be searched."));
+ CSearchModuleChooserDialog* dlg = new CSearchModuleChooserDialog(this, title, label, modules());
+ connect(dlg, SIGNAL(modulesChanged(QList<CSwordModuleInfo*>, QTreeWidget*)), this, SLOT(setModules(QList<CSwordModuleInfo*>)));
+ dlg->exec();
+}
+
+QList<CSwordModuleInfo*> BtSearchOptionsArea::modules() const {
+ return m_modules;
+}
+
+void BtSearchOptionsArea::reset() {
+ m_rangeChooserCombo->setCurrentIndex(0);
+ m_searchTextCombo->clearEditText();
+}
+
+void BtSearchOptionsArea::saveSettings() {
+ CBTConfig::set(CBTConfig::searchTexts, m_searchTextCombo->historyItems());
+ SearchType t = FullType;
+ if (m_typeAndButton->isChecked()) {
+ t = AndType;
+ }
+ if (m_typeOrButton->isChecked()) {
+ t = OrType;
+ }
+ CBTConfig::set(CBTConfig::searchType, t);
+}
+
+void BtSearchOptionsArea::readSettings() {
+ QStringList texts = CBTConfig::get(CBTConfig::searchTexts);
+ //for some reason the slot was called when setting the upmost item
+ disconnect(m_searchTextCombo, SIGNAL(editTextChanged(const QString&)), this, SLOT(slotValidateText(const QString&)));
+ for (int i=0; i<texts.size(); i++)
+ {
+ if (texts.at(i).size() > 0)
+ m_searchTextCombo->addItem(texts.at(i));
+ }
+ connect(m_searchTextCombo, SIGNAL(editTextChanged(const QString&)), this, SLOT(slotValidateText(const QString&)));
+
+ m_modulesCombo->insertItems(0, CBTConfig::get(CBTConfig::searchModulesHistory));
+ for (int i = 0; i < m_modulesCombo->count(); ++i) {
+ m_modulesCombo->setItemData(i, m_modulesCombo->itemText(i), Qt::ToolTipRole);
+ }
+
+ int stype = CBTConfig::get(CBTConfig::searchType);
+ switch (stype) {
+ case AndType: m_typeAndButton->setChecked(true);
+ break;
+ case OrType: m_typeOrButton->setChecked(true);
+ break;
+ default: m_typeFreeButton->setChecked(true);
+ }
+}
+
+void BtSearchOptionsArea::aboutToShow() {
+ m_searchTextCombo->setFocus();
+}
+
+void BtSearchOptionsArea::setupRanges() {
+ CRangeChooserDialog* chooser = new CRangeChooserDialog(this);
+ chooser->exec();
+
+ refreshRanges();
+}
+
+void BtSearchOptionsArea::syntaxHelp() {
+
+ QString style = QString(
+ "<style type='text/css'>"
+ "h1 a {font-size: medium}"
+ "table {margin-left: 20px}"
+ "td {"
+ " border-width: 3px 3px 3px 3px;"
+ " border-style: solid solid solid solid;"
+ " border-color: white white white white;"
+ " background-color: #faf0e6;"
+ "}"
+ "p#links {margin-left: 20px}"
+ "</style>");
+
+ //: Don't translate words inside <> tags!
+ //: Translate 'All words' etc. indentically to the Search dialog options.
+ QString intro = tr(
+ "<p>"
+ "This help is mainly for 'Full syntax' option. 'All words' and 'Some words' options " "have more limited syntax; <a href='#wildcards'>wildcards</a> and <a " "href='#fields'>text fields</a> are supported for them. Some other syntax features " "may give strange or wrong results with All words/Some words."
+ "</p>");
+
+ QString links = tr(
+ "<p id='links'>"
+ "<A href='#allsome'>Which words to find</A><br />"
+ "<A href='#grouping'>Grouping and order</A><br />"
+ "<A href='#wildcards'>Wildcards (partial words)</A><br />"
+ "<A href='#fields'>Text fields (different parts of text)</A><br/>"
+ "<A href='#lucene'>Other syntax features</A><br/>"
+ "</p>");
+
+ //: Syntax words (AND, OR...) must not be translated.
+ QString whichwords = tr(
+ "<h1><A name='allsome'>Which words to find</A></h1>"
+ "<p>Search terms are separated by spaces. <strong>AND</strong> (all words), " "<strong>OR</strong> (some words) and <strong>NOT</strong> (not the following word) " "can be added between the words. If none is added explicitly OR is used " "automatically. '<strong>+</strong>word' means the word must be in the results, " "'<strong>-</strong>word' means it must not be in the results.</p>");
+
+ //: In examples words to be searched for may be translated, but syntax words (AND, OR...) must not be translated.
+ QString whichwordstable = tr(
+ "<p><table><tr>"
+ "<td>jesus AND god</td><td>Finds verses with both 'Jesus' and 'God'</td>"
+ "</tr><tr>"
+ "<td>jesus OR god</td><td>Finds verses with 'Jesus' or 'God' or both</td>"
+ "</tr><tr>"
+ "<td>jesus NOT god</td><td>Finds verses with 'Jesus' but with no 'God'</td>"
+ "</tr><tr>"
+ "<td>+jesus -god</td><td>Finds verses with 'Jesus' but with no 'God'</td>"
+ "</tr></table></p>");
+
+ QString grouping = tr(
+ "<h1><A name='grouping'>Grouping and order</A></h1>"
+ "<p>Words can be grouped with <strong>parenthesis</strong>. "
+ "Strict word order can be defined with <strong>quotes</strong>.</p>");
+
+ QString groupingtable = tr(
+ "<p><table><tr>"
+ "<td>(a AND b) OR c</td><td>Finds verses with both 'a' AND 'b', and verses with 'c'</td>"
+ "</tr><tr>"
+ "<td>\"says lord\"</td><td>Finds e.g. '...Isaiah says, \"Lord...' but not '...says the LORD'</td>"
+ "</tr><tr>"
+ "<td>\"says the lord\"</td><td>Finds all verses with 'says the LORD'</td>"
+ "</tr></table></p>");
+
+ QString wildcards = tr(
+ "<h1><A name='wildcards'>Wildcards (partial words)</A></h1>"
+ "<p>'<strong>*</strong>' matches any sequence of 0 or more characters, while '<strong>?</strong>' matches any single character. A wildcard can not be used in the beginning of a word.</p>");
+
+ QString wildcardstable = tr(
+ "<p><table><tr>"
+ "<td>a*</td><td>All words beginning with 'a'</td>"
+ "</tr><tr>"
+ "<td>a*a</td><td>'Assyria', 'aroma', 'abba' etc.</td>"
+ "</tr><tr>"
+ "<td>a?</td><td>'at' and 'an'</td>"
+ "</tr><tr>"
+ "<td>a??a</td><td>'abba', 'area', 'Asia' etc.</td>"
+ "</tr></table></p>");
+
+ QString fields = tr(
+ "<h1><A name='fields'>Text fields (different parts of text)</A></h1>"
+ "<p>Available text fields:<br /><table>"
+ "<tr><td>heading:</td><td>Searches headings</td></tr>"
+ "<tr><td>footnote:</td><td>Searches footnotes</td></tr>"
+ "<tr><td>strong:</td><td>Searches Strong's numbers</td></tr>"
+ "<tr><td>morph:</td><td>Searches morphology codes</td></tr></table></p>");
+
+ QString fieldstable = tr(
+ "<p>Examples:<br /><table>"
+ "<tr><td>heading:Jesus</td><td>Finds headings with 'Jesus'</td></tr>"
+ "<tr><td>footnote:Jesus AND footnote:said</td><td>Finds footnotes with 'Jesus' and 'said'</td></tr>"
+ "<tr><td>strong:G846</td><td>Finds verses with Strong's Greek number 846</td></tr>"
+ "<tr><td>morph:\"N-NSF\"</td><td>Finds verses with morphology code 'N-NSF'</td>"
+ "</tr></table></p>");
+
+ QString lucene = tr(
+ "<h1><A name='lucene'>Other syntax features</A></h1>"
+ "<p>BibleTime uses the CLucene search engine. You can read more on the <a href='http://lucene.apache.org/java/1_4_3/queryparsersyntax.html'>lucene syntax web page</a> (in external browser).</p>");
+
+ QString syntax = style + intro + links + whichwords + whichwordstable +
+ grouping + groupingtable + wildcards + wildcardstable +
+ fields + fieldstable + lucene;
+
+ BtTabHtmlDialog* dlg = new BtTabHtmlDialog(tr("Search Syntax Help"), 0, this);
+ dlg->setHtml(syntax);
+ dlg->show();
+}
+
+void BtSearchOptionsArea::refreshRanges() {
+ //the first option is fixed, the others can be edited using the "Setup ranges" button.
+ m_rangeChooserCombo->clear();
+ m_rangeChooserCombo->insertItem(0, QString("[") + tr("No search scope") + QString("]"));
+ //TODO: what about this?
+ //m_rangeChooserCombo->insertItem(tr("Last search result"));
+
+ //insert the user-defined ranges
+ m_rangeChooserCombo->insertItems(1, CBTConfig::get(CBTConfig::searchScopes).keys());
+
+}
+
+sword::ListKey BtSearchOptionsArea::searchScope() {
+ if (m_rangeChooserCombo->currentIndex() > 0) { //is not "no scope"
+ CBTConfig::StringMap map = CBTConfig::get(CBTConfig::searchScopes);
+ QString scope = map[ m_rangeChooserCombo->currentText() ];
+ if (!scope.isEmpty()) {
+ return sword::VerseKey().ParseVerseList( (const char*)scope.toUtf8(), "Genesis 1:1", true);
+ }
+ }
+ return sword::ListKey();
+}
+
+bool BtSearchOptionsArea::hasSearchScope() {
+ return (searchScope().Count() > 0);
+}
+
+void BtSearchOptionsArea::addToHistory(const QString& text)
+{
+ m_searchTextCombo->addToHistory(text);
+}
+
+void BtSearchOptionsArea::slotSearchTextEditReturnPressed()
+{
+ qDebug("BtSearchOptionsArea::slotSearchTextEditReturnPressed");
+ m_searchTextCombo->addToHistory( m_searchTextCombo->currentText() );
+ emit sigStartSearch();
+}
+
+bool BtSearchOptionsArea::eventFilter(QObject* obj, QEvent* event)
+{
+ if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
+ //qDebug() << "BtSearchOptionsArea::eventFilter" << obj << event;
+ if (obj == m_searchTextCombo->view() || obj == m_searchTextCombo || obj == m_searchTextCombo->lineEdit()) {
+ //qDebug() << "BtSearchOptionsArea::eventFilter" << obj << event;
+ obj->event(event);
+ // don't handle this event in parent
+ event->accept();
+ return true;
+ }
+ }
+ return QWidget::eventFilter(obj, event);
+}
+
+void BtSearchOptionsArea::slotValidateText(const QString& /*newText*/)
+{
+// static const QRegExp re("\\b(AND|OR)\\b");
+// qDebug() << "new text:" << newText;
+// qDebug() << "contains:" << (newText.contains(re));
+// if (newText.isEmpty() || !newText.contains(re) ) {
+// qDebug()<< "no AND/OR";
+// if (!m_typeAndButton->isEnabled()) {
+// m_typeOrButton->setEnabled(true);
+// m_typeAndButton->setEnabled(true);
+// m_typeAndButton->setToolTip(tr("All of the words (AND is added between the words)"));
+// m_typeOrButton->setToolTip(tr("Some of the words"));
+// }
+// }
+// else {
+// qDebug("AND/OR!");
+// if (m_typeAndButton->isEnabled()) {
+// m_typeOrButton->setChecked(true);
+// m_typeOrButton->setEnabled(false);
+// m_typeAndButton->setEnabled(false);
+// m_typeAndButton->setToolTip(tr("Full syntax is used because text includes AND or OR"));
+// m_typeOrButton->setToolTip(tr("Full syntax is used because text includes AND or OR"));
+// }
+// }
+}
+
+//bool BtSearchOptionsArea::isAndSearchType()
+//{
+//
+//}
+
+
+}
diff --git a/src/frontend/searchdialog/btsearchoptionsarea.h b/src/frontend/searchdialog/btsearchoptionsarea.h
new file mode 100644
index 0000000..30f6654
--- /dev/null
+++ b/src/frontend/searchdialog/btsearchoptionsarea.h
@@ -0,0 +1,150 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTSEARCHOPTIONSAREA_H
+#define BTSEARCHOPTIONSAREA_H
+
+#include "chistorycombobox.h"
+
+#include "backend/keys/cswordversekey.h"
+
+#include <QWidget>
+
+class CSwordModuleInfo;
+
+class QGroupBox;
+class QGridLayout;
+class QHBoxLayout;
+class QLabel;
+class QPushButton;
+class QRadioButton;
+class QComboBox;
+class QObject;
+class QEvent;
+
+
+namespace Search {
+
+class BtSearchOptionsArea : public QWidget
+{
+ Q_OBJECT
+public:
+
+ enum SearchType {AndType, OrType, FullType};
+
+ friend class CSearchDialog;
+
+ BtSearchOptionsArea(QWidget *parent=0);
+ ~BtSearchOptionsArea();
+ /*
+ * Add text to search combox box history
+ */
+ void addToHistory(const QString& text);
+ /**
+ * Sets the search text used in the page.
+ */
+ void setSearchText(const QString& text);
+ /**
+ * Returns the search text set in this page.
+ */
+ QString searchText() const;
+
+ SearchType searchType();
+
+ QPushButton* searchButton() const;
+
+ /**
+ * Returns the list of used modules.
+ */
+ QList<CSwordModuleInfo*> modules() const;
+
+ /**
+ * Sets all options back to the default.
+ */
+ void reset();
+ /**
+ * Returns the selected search scope if a search scope was selected.
+ */
+ sword::ListKey searchScope();
+
+ bool hasSearchScope();
+
+
+protected:
+ /**
+ * Initializes this page.
+ */
+ void initView();
+ void initConnections();
+ /**
+ * Reads the settings of the last searchdialog session.
+ */
+ void readSettings();
+ /**
+ * Reads the settings for the searchdialog from disk.
+ */
+ void saveSettings();
+ bool eventFilter(QObject* obj, QEvent* event);
+public slots:
+ /**
+ * Sets the modules used by the search.
+ */
+ void setModules( QList<CSwordModuleInfo*> modules );
+
+ /** Sets the modules when user selects them from the combobox.*/
+ void moduleListTextSelected(int index);
+
+ /**
+ * Reimplementation.
+ */
+ void aboutToShow();
+ /**
+ * Refreshes the list of ranges and the range combobox.
+ */
+ void refreshRanges();
+ /**
+ * Opens the modules chooser dialog.
+ */
+ void chooseModules();
+
+protected slots:
+ void setupRanges();
+ void syntaxHelp();
+ void slotSearchTextEditReturnPressed();
+ void slotValidateText(const QString& newText);
+
+signals:
+ void sigSetSearchButtonStatus(bool);
+ void sigStartSearch();
+
+private:
+ QList<CSwordModuleInfo*> m_modules;
+
+ QHBoxLayout *hboxLayout;
+ QGroupBox *searchGroupBox;
+ QGridLayout *gridLayout;
+ QLabel *m_searchTextLabel;
+ QPushButton* m_searchButton;
+ QLabel* m_helpLabel;
+ QRadioButton* m_typeAndButton;
+ QRadioButton* m_typeOrButton;
+ QRadioButton* m_typeFreeButton;
+ QPushButton *m_chooseModulesButton;
+ QPushButton *m_chooseRangeButton;
+ QLabel *m_searchScopeLabel;
+ QComboBox *m_rangeChooserCombo;
+ CHistoryComboBox *m_searchTextCombo;
+ QLabel *m_modulesLabel;
+ QComboBox* m_modulesCombo;
+
+};
+
+}
+
+#endif
diff --git a/src/frontend/searchdialog/btsearchresultarea.cpp b/src/frontend/searchdialog/btsearchresultarea.cpp
new file mode 100644
index 0000000..585d5d3
--- /dev/null
+++ b/src/frontend/searchdialog/btsearchresultarea.cpp
@@ -0,0 +1,659 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btsearchresultarea.h"
+#include "cmoduleresultview.h"
+#include "csearchresultview.h"
+#include "csearchdialog.h"
+#include "frontend/searchdialog/analysis/csearchanalysisdialog.h"
+
+#include "util/ctoolclass.h"
+#include "frontend/display/cdisplay.h"
+#include "frontend/display/creaddisplay.h"
+#include "backend/rendering/cdisplayrendering.h"
+#include "backend/keys/cswordversekey.h"
+
+#include <QWidget>
+#include <QStringList>
+#include <QVBoxLayout>
+#include <QSize>
+#include <QSplitter>
+#include <QFrame>
+#include <QApplication>
+#include <QProgressDialog>
+#include <QPushButton>
+
+#include <QDebug>
+
+namespace Search {
+
+BtSearchResultArea::BtSearchResultArea(QWidget *parent)
+ : QWidget(parent)
+{
+ qDebug("BtSearchResultArea::BtSearchResultArea");
+ initView();
+ initConnections();
+ qDebug("BtSearchResultArea::BtSearchResultArea end");
+}
+
+BtSearchResultArea::~BtSearchResultArea()
+{
+ saveDialogSettings();
+}
+
+void BtSearchResultArea::initView()
+{
+ QVBoxLayout *mainLayout;
+ QWidget *resultListsWidget;
+ QVBoxLayout *resultListsWidgetLayout;
+
+ //Size is calculated from the font rather than set in pixels,
+ // maybe this is better in different kinds of displays?
+ int mWidth = CToolClass::mWidth(this, 1);
+ this->setMinimumSize(QSize(mWidth*40, mWidth*15));
+ mainLayout = new QVBoxLayout(this);
+ mainSplitter = new QSplitter(this);
+ mainSplitter->setOrientation(Qt::Horizontal);
+
+ resultListsWidget = new QWidget(mainSplitter);
+
+ resultListsWidgetLayout = new QVBoxLayout(resultListsWidget);
+ resultListsWidgetLayout->setContentsMargins(0, 0, 0, 0);
+
+ //Splitter for two result lists
+ resultListSplitter = new QSplitter(resultListsWidget);
+ resultListSplitter->setOrientation(Qt::Vertical);
+ m_moduleListBox = new CModuleResultView(resultListSplitter);
+ resultListSplitter->addWidget(m_moduleListBox);
+ m_resultListBox = new CSearchResultView(resultListSplitter);
+ resultListSplitter->addWidget(m_resultListBox);
+ resultListsWidgetLayout->addWidget(resultListSplitter);
+
+ mainSplitter->addWidget(resultListsWidget);
+
+ //Preview ("info") area
+ m_displayFrame = new QFrame(mainSplitter);
+ m_displayFrame->setFrameShape(QFrame::NoFrame);
+ m_displayFrame->setFrameShadow(QFrame::Plain);
+ mainSplitter->addWidget(m_displayFrame);
+
+ mainLayout->addWidget(mainSplitter);
+
+ QVBoxLayout* frameLayout = new QVBoxLayout(m_displayFrame);
+ frameLayout->setContentsMargins(0,0,0,0);
+ m_previewDisplay = CDisplay::createReadInstance(0, m_displayFrame);
+ m_previewDisplay->view()->setToolTip(tr("Text of the selected search result item"));
+ frameLayout->addWidget(m_previewDisplay->view());
+
+ loadDialogSettings();
+}
+
+void BtSearchResultArea::setSearchResult(QList<CSwordModuleInfo*> modules)
+{
+ const QString searchedText = CSearchDialog::getSearchDialog()->searchText();
+ reset(); //clear current modules
+
+ m_modules = modules;
+ //pre-select the first module in the list
+ //this will pre-select and display the first hit of that module
+ m_moduleListBox->setupTree(modules, searchedText);
+ m_moduleListBox->setCurrentItem(m_moduleListBox->topLevelItem(0), 0);
+
+ qobject_cast<CSearchDialog*>(parent())->m_analyseButton->setEnabled(true);
+}
+
+void BtSearchResultArea::reset()
+{
+ m_moduleListBox->clear();
+ m_resultListBox->clear();
+ m_previewDisplay->setText("<html><head/><body></body></html>");
+ qobject_cast<CSearchDialog*>(parent())->m_analyseButton->setEnabled(false);
+ m_modules.clear();
+}
+
+void BtSearchResultArea::clearPreview(){
+ m_previewDisplay->setText("<html><head/><body></body></html>");
+}
+
+void BtSearchResultArea::updatePreview(const QString& key)
+{
+ using namespace Rendering;
+
+ CSwordModuleInfo* module = m_moduleListBox->activeModule();
+ if ( module ) {
+ const QString searchedText = CSearchDialog::getSearchDialog()->searchText();
+
+ QString text;
+ CDisplayRendering render;
+
+ QList<CSwordModuleInfo*> modules;
+ modules.append(module);
+
+ CTextRendering::KeyTreeItem::Settings settings;
+
+ //for bibles render 5 context verses
+ if (module->type() == CSwordModuleInfo::Bible) {
+ CSwordVerseKey vk(module);
+ vk.Headings(1);
+ vk.key(key);
+
+ ((sword::VerseKey*)(module->module()->getKey()))->Headings(1); //HACK: enable headings for VerseKeys
+
+ //first go back and then go forward the keys to be in context
+ vk.previous(CSwordVerseKey::UseVerse);
+ vk.previous(CSwordVerseKey::UseVerse);
+
+ //include Headings in display, they are indexed and searched too
+ if (vk.Verse() == 1){
+ if (vk.Chapter() == 1){
+ vk.Chapter(0);
+ }
+ vk.Verse(0);
+ }
+
+ const QString startKey = vk.key();
+
+ vk.key(key);
+
+ vk.next(CSwordVerseKey::UseVerse);
+ vk.next(CSwordVerseKey::UseVerse);
+ const QString endKey = vk.key();
+
+ settings.keyRenderingFace = CTextRendering::KeyTreeItem::Settings::CompleteShort;
+ text = render.renderKeyRange(startKey, endKey, modules, key, settings);
+ }
+ //for commentaries only one verse, but with heading
+ else if (module->type() == CSwordModuleInfo::Commentary) {
+ CSwordVerseKey vk(module);
+ vk.Headings(1);
+ vk.key(key);
+
+ ((sword::VerseKey*)(module->module()->getKey()))->Headings(1); //HACK: enable headings for VerseKeys
+
+ //include Headings in display, they are indexed and searched too
+ if (vk.Verse() == 1){
+ if (vk.Chapter() == 1){
+ vk.Chapter(0);
+ }
+ vk.Verse(0);
+ }
+ const QString startKey = vk.key();
+
+ vk.key(key);
+ const QString endKey = vk.key();
+
+ settings.keyRenderingFace = CTextRendering::KeyTreeItem::Settings::NoKey;
+ text = render.renderKeyRange(startKey, endKey, modules, key, settings);
+ }
+ else {
+ text = render.renderSingleKey(key, modules, settings);
+ }
+
+ m_previewDisplay->setText( highlightSearchedText(text, searchedText) );
+ m_previewDisplay->moveToAnchor( CDisplayRendering::keyToHTMLAnchor(key) );
+ }
+}
+
+QStringList BtSearchResultArea::QueryParser(const QString& queryString) {
+ QString token;
+ QStringList tokenList;
+ int cnt, pos;
+
+ token = "";
+ cnt = 0;
+ while(cnt < queryString.length()) {
+ // add to token
+ if ((queryString[cnt]).isLetterOrNumber() || (queryString[cnt] == '*')) {
+ token = token + queryString[cnt];
+ cnt++;
+ }
+ // token break
+ else if (queryString[cnt] == ' ') {
+ token = token.simplified();
+ if ((token != "*") && (token != ""))
+ tokenList.append(token);
+ token = "";
+ cnt++;
+ }
+ // clucene appears to ignore quoted strings in the sence
+ // that it treats all the words within quoted strings as
+ // regular tokens and not as a single token.
+ else if (queryString[cnt] == '"') {
+ cnt++;
+ }
+ // wild card - treat as a special token break
+ //else if (queryString[cnt] == '*') {
+ // token = token + queryString[cnt];
+ // token = token.simplified();
+ // if ((token != "*") && (token != ""))
+ // tokenList.append(token);
+ // // start next token with wildcard (kin*m -> kin* *m)
+ // token = "*";
+ // cnt++;
+ //}
+ // the ! token is also a token break
+ else if (queryString[cnt] == '!') {
+ // store away current token
+ token = token.simplified();
+ if ((token != "*") && (token != ""))
+ tokenList.append(token);
+ // add the ! token
+ tokenList.append("!");
+ token = "";
+ cnt++;
+ }
+ // the - token is also a token break
+ else if (queryString[cnt] == '-') {
+ // store away current token
+ token = token.simplified();
+ if ((token != "*") && (token != ""))
+ tokenList.append(token);
+ // add the ! token
+ tokenList.append("-");
+ token = "";
+ cnt++;
+ }
+ // the + token is also a token break
+ else if (queryString[cnt] == '+') {
+ // store away current token
+ token = token.simplified();
+ if ((token != "*") && (token != ""))
+ tokenList.append(token);
+ // add the + token
+ tokenList.append("+");
+ token = "";
+ cnt++;
+ }
+ // the || token is also a token break
+ else if ((queryString[cnt] == '|') && (queryString[cnt+1] == '|')) {
+ // store away current token
+ token = token.simplified();
+ if ((token != "*") && (token != ""))
+ tokenList.append(token);
+ // add the || token
+ tokenList.append("||");
+ token = "";
+ cnt += 2;
+ }
+ // the && token is also a token break
+ else if ((queryString[cnt] == '&') && (queryString[cnt+1] == '&')) {
+ // store away current token
+ token = token.simplified();
+ if ((token != "*") && (token != ""))
+ tokenList.append(token);
+ // add the || token
+ tokenList.append("&&");
+ token = "";
+ cnt += 2;
+ }
+ else cnt++;
+ }
+ token = token.simplified();
+ if ((token != "*") && (token != ""))
+ tokenList.append(token);
+
+ cnt = 0;
+ QStringList::iterator it;
+ for ( it = tokenList.begin(); it != tokenList.end(); it++ ) {
+ //-----------------------------------------------------------
+ // remove all the NOT(!) tokens - these do not need to be
+ // highlighted in the highlighter
+ //-----------------------------------------------------------
+ if (((*it) == "!") || ((*it) == "NOT") || ((*it) == "-")) {
+ it = tokenList.erase(it);
+ if (it == tokenList.end())
+ break;
+ it = tokenList.erase(it);
+ if (it == tokenList.end())
+ break;
+ it--;
+ }
+ //-----------------------------------------------------------
+ // remove all the operator tokens - these do not need to be
+ // highlighted in the highlighter
+ //-----------------------------------------------------------
+ else if ( ((*it) == "||") || ((*it) == "OR") || ((*it) == "+") ||
+ ((*it) == "AND") || ((*it) == "&&") )
+ {
+ it = tokenList.erase(it);
+ if (it == tokenList.end())
+ break;
+ it--;
+ }
+ // if the token contains a ^ then trim the remainder of the
+ // token from the ^
+ //What??? error: invalid conversion from ‘const void*’ to ‘int’
+ // and how come "contains" returns bool but is used as int?
+ //else if ( (pos = (*it).contains("^")) >= 0 ) {
+ else if ( (pos = (*it).indexOf("^") ) >= 0 ) {
+ (*it) = (*it).left(pos - 1);
+ }
+ // if the token contains a ~ then trim the remainder of the
+ // token from the ~
+ else if ( (pos = (*it).indexOf("~") ) >= 0 ) {
+ (*it) = (*it).left(pos - 2) + "*";
+ }
+ }
+ return(tokenList);
+}
+
+QString BtSearchResultArea::highlightSearchedText(const QString& content, const QString& searchedText) {
+ QString ret = content;
+
+ const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
+
+ // int index = 0;
+ int index = ret.indexOf("<body", 0);
+ int matchLen = 0;
+ int length = searchedText.length();
+
+ // Highlighting constants -
+ // TODO: We need to make the highlight color configurable.
+ const QString rep1("<span style=\"background-color:#FFFF66;\">");
+ const QString rep2("</span>");
+ const unsigned int repLength = rep1.length() + rep1.length();
+ const QString rep3("style=\"background-color:#FFFF66;\" ");
+ const unsigned int rep3Length = rep3.length();
+
+
+ QString newSearchText;
+
+ newSearchText = searchedText;
+
+ // find the strongs search lemma and highlight it
+ // search the searched text for "strong:" until it is not found anymore
+ QStringList list;
+
+ // split the search string - some possibilities are "\\s|\\|", "\\s|\\+", or "\\s|\\|\\+"
+ // TODO: find all possible seperators
+ QString regExp = "\\s";
+ list = searchedText.split(QRegExp(regExp));
+ foreach (QString newSearchText, list) {
+ int sstIndex; // strong search text index for finding "strong:"
+ int idx1, idx2;
+ QString sNumber, lemmaText;
+
+ sstIndex = newSearchText.indexOf("strong:");
+ if (sstIndex == -1)
+ continue;
+
+ // set the start index to the start of <body>
+ int strongIndex = index;
+
+ // Get the strongs number from the search text.
+ // First, find the first space after "strong:"
+ sstIndex = sstIndex + 7;
+ // get the strongs number -> the text following "strong:" to the end of the string.
+ sNumber = newSearchText.mid(sstIndex, -1);
+ // find all the "lemma=" inside the the content
+ while((strongIndex = ret.indexOf("lemma=", strongIndex, cs)) != -1) {
+ // get the strongs number after the lemma and compare it with the
+ // strongs number we are looking for
+ idx1 = ret.indexOf("\"", strongIndex) + 1;
+ idx2 = ret.indexOf("\"", idx1 + 1);
+ lemmaText = ret.mid(idx1, idx2 - idx1);
+
+ // this is interesting because we could have a strongs number like: G3218|G300
+ // To handle this we will use some extra cpu cycles and do a partial match against
+ // the lemmaText
+ if (lemmaText.contains(sNumber)) {
+ // strongs number is found now we need to highlight it
+ // I believe the easiest way is to insert rep3 just before "lemma="
+ ret = ret.insert(strongIndex, rep3);
+ strongIndex += rep3Length;
+ }
+ strongIndex += 6; // 6 is the length of "lemma="
+ }
+ }
+ //---------------------------------------------------------------------
+ // now that the strong: stuff is out of the way continue with
+ // other search options
+ //---------------------------------------------------------------------
+
+ // try to figure out how to use the lucene query parser
+
+ //using namespace lucene::queryParser;
+ //using namespace lucene::search;
+ //using namespace lucene::analysis;
+ //using namespace lucene::util;
+
+ //wchar_t *buf;
+ //char buf8[1000];
+ //standard::WhitespaceAnalyzer analyzer;
+ //lucene_utf8towcs(m_wcharBuffer, searchedText.utf8(), MAX_CONV_SIZE);
+ //boost::scoped_ptr<Query> q( QueryParser::parse(m_wcharBuffer, _T("content"), &analyzer) );
+ //StringReader reader(m_wcharBuffer);
+ //TokenStream* tokenStream = analyzer.tokenStream( _T("field"), &reader);
+ //Token token;
+ //while(tokenStream->next(&token) != 0) {
+ // lucene_wcstoutf8(buf8, token.termText(), 1000);
+ // printf("%s\n", buf8);
+ //}
+
+ //===========================================================
+ // since I could not figure out the lucene query parser, I
+ // made a simple parser.
+ //===========================================================
+ QStringList words = QueryParser(newSearchText);
+ foreach (QString word, words) { //search for every word in the list
+ QRegExp findExp;
+ if (word.contains("*")) {
+ length = word.length() - 1;
+ word.replace('*', "\\S*"); //match within a word
+ findExp = QRegExp(word);
+ findExp.setMinimal(TRUE);
+ }
+ else {
+ length = word.length();
+ findExp = QRegExp("\\b" + word + "\\b");
+ }
+
+ // index = 0; //for every word start at the beginning
+ index = ret.indexOf("<body", 0);
+ findExp.setCaseSensitivity(cs);
+ //while ( (index = ret.find(findExp, index)) != -1 ) { //while we found the word
+ while ( (index = findExp.indexIn(ret, index)) != -1 ) { //while we found the word
+ matchLen = findExp.matchedLength();
+ if (!CToolClass::inHTMLTag(index, ret)) {
+ length = matchLen;
+ ret = ret.insert( index+length, rep2 );
+ ret = ret.insert( index, rep1 );
+ index += repLength;
+ }
+ index += length;
+ }
+ }
+ //qWarning("\n\n\n%s", ret.latin1());
+ return ret;
+}
+
+/** Initializes the signal slot conections of the child widgets, */
+void BtSearchResultArea::initConnections()
+{
+ connect(m_resultListBox, SIGNAL(keySelected(const QString&)), this, SLOT(updatePreview(const QString&)));
+ connect(m_resultListBox, SIGNAL(keyDeselected()), this, SLOT(clearPreview()));
+ connect(m_moduleListBox, SIGNAL(moduleSelected(CSwordModuleInfo*)), m_resultListBox, SLOT(setupTree(CSwordModuleInfo*)));
+ connect(m_moduleListBox, SIGNAL(moduleChanged()), m_previewDisplay->connectionsProxy(), SLOT(clear()));
+
+ // connect the strongs list
+ connect(m_moduleListBox, SIGNAL(strongsSelected(CSwordModuleInfo*, QStringList*)),
+ m_resultListBox, SLOT(setupStrongsTree(CSwordModuleInfo*, QStringList*)));
+}
+
+/** Shows a dialog with the search analysis of the current search. */
+void BtSearchResultArea::showAnalysis() {
+ CSearchAnalysisDialog dlg(m_modules, this);
+ dlg.exec();
+}
+
+/**
+* Load the settings from the resource file
+*/
+void BtSearchResultArea::loadDialogSettings()
+{
+ QList<int> mainSplitterSizes = CBTConfig::get(CBTConfig::searchMainSplitterSizes);
+ if (mainSplitterSizes.count() > 0) {
+ mainSplitter->setSizes(mainSplitterSizes);
+ } else {
+ int w = this->size().width();
+ int w2 = m_moduleListBox->sizeHint().width();
+ mainSplitterSizes << w2 << w - w2;
+ mainSplitter->setSizes(mainSplitterSizes);
+ }
+ QList<int> resultSplitterSizes = CBTConfig::get(CBTConfig::searchResultSplitterSizes);
+ if (resultSplitterSizes.count() > 0) resultListSplitter->setSizes(resultSplitterSizes);
+}
+
+/**
+* Save the settings to the resource file
+*/
+void BtSearchResultArea::saveDialogSettings()
+{
+ CBTConfig::set(CBTConfig::searchMainSplitterSizes, mainSplitter->sizes());
+ CBTConfig::set(CBTConfig::searchResultSplitterSizes, resultListSplitter->sizes());
+}
+
+StrongsResult::StrongsResult()
+{
+}
+
+StrongsResult::StrongsResult(const QString& text, const QString &keyName)
+ : text(text)
+{
+ //keyNameList.clear();
+ keyNameList.append(keyName);
+}
+
+QString StrongsResult::keyText() const {
+ return text;
+}
+
+int StrongsResult::keyCount() const {
+ return keyNameList.count();
+}
+
+void StrongsResult::addKeyName(const QString& keyName) {
+ if (keyNameList.indexOf(keyName) == -1)
+ keyNameList.append(keyName);
+}
+
+QStringList* StrongsResult::getKeyList() {
+ return & keyNameList;
+}
+
+
+
+/********************************************
+************ StrongsResultClass *************
+********************************************/
+void StrongsResultClass::initStrongsResults(void)
+{
+ using namespace Rendering;
+
+ CDisplayRendering render;
+ QList<CSwordModuleInfo*> modules;
+ CTextRendering::KeyTreeItem::Settings settings;
+ QString rText, lText, key;
+ bool found;
+ int sIndex;
+ int count;
+ int index;
+ QString text;
+
+ modules.append(srModule);
+ sword::ListKey& result = srModule->searchResult();
+
+ count = result.Count();
+ if (!count)
+ return;
+ qApp->processEvents( QEventLoop::AllEvents, 1 ); //1 ms only
+ srList.clear();
+ // for whatever reason the text "Parsing...translations." does not appear.
+ // this is not critical but the text is necessary to get the dialog box
+ // to be wide enough.
+ QProgressDialog* progress = new QProgressDialog(QObject::tr("Parsing Strong's Numbers"), 0, 0, count);
+ //0, "progressDialog", tr("Parsing Strong's Numbers"), tr("Parsing Strong's numbers for translations."), true);
+
+ //progress->setAllowCancel(false);
+ //progress->setMinimumDuration(0);
+ progress->show();
+ progress->raise();
+ for (index = 0; index < count; index++){
+ progress->setValue( index );
+ qApp->processEvents(QEventLoop::AllEvents, 1 ); //1 ms only
+
+ key = QString::fromUtf8(result.GetElement(index)->getText());
+ text = render.renderSingleKey(key, modules, settings);
+ sIndex = 0;
+ while ((rText = getStrongsNumberText(text, &sIndex)) != "")
+ {
+ StrongsResultList::iterator it;
+ found = FALSE;
+ for ( it = srList.begin(); it != srList.end(); ++it )
+ {
+ lText = (*it).keyText();
+ if (lText == rText)
+ {
+ found = TRUE;
+ (*it).addKeyName(key);
+ break;
+ }
+ }
+ if (found == FALSE)
+ srList.append( StrongsResult(rText, key) );
+ }
+ }
+ delete progress;
+ progress = 0;
+ //qHeapSort(srList);
+}
+
+QString StrongsResultClass::getStrongsNumberText(const QString& verseContent, int *startIndex) {
+ // get the strongs text
+ int idx1, idx2, index;
+ QString sNumber, strongsText;
+ //const bool cs = CSwordModuleSearch::caseSensitive;
+ const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
+
+ if (*startIndex == 0) {
+ index = verseContent.indexOf("<body");
+ }
+ else {
+ index = *startIndex;
+ }
+
+ // find all the "lemma=" inside the the content
+ while((index = verseContent.indexOf("lemma=", index, cs)) != -1) {
+ // get the strongs number after the lemma and compare it with the
+ // strongs number we are looking for
+ idx1 = verseContent.indexOf("\"", index) + 1;
+ idx2 = verseContent.indexOf("\"", idx1 + 1);
+ sNumber = verseContent.mid(idx1, idx2 - idx1);
+ if (sNumber == lemmaText) {
+ // strongs number is found now we need to get the text of this node
+ // search right until the ">" is found. Get the text from here to
+ // the next "<".
+ index = verseContent.indexOf(">", index, cs) + 1;
+ idx2 = verseContent.indexOf("<", index, cs);
+ strongsText = verseContent.mid(index, idx2 - index);
+ index = idx2;
+ *startIndex = index;
+
+ return(strongsText);
+ }
+ else {
+ index += 6; // 6 is the length of "lemma="
+ }
+ }
+ return QString::null;
+}
+
+
+
+} //namespace Search
diff --git a/src/frontend/searchdialog/btsearchresultarea.h b/src/frontend/searchdialog/btsearchresultarea.h
new file mode 100644
index 0000000..82eb2d4
--- /dev/null
+++ b/src/frontend/searchdialog/btsearchresultarea.h
@@ -0,0 +1,201 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTSEARCHRESULTAREA_H
+#define BTSEARCHRESULTAREA_H
+
+
+#include "backend/managers/cswordbackend.h"
+#include "backend/cswordmodulesearch.h"
+
+#include <QSplitter>
+#include <QList>
+#include <QStringList>
+#include <QWidget>
+
+//forward declarations
+class CReadDisplay;
+class CSwordModuleInfo;
+namespace Search {
+ class CModuleResultView;
+ class CSearchResultView;
+}
+
+class QHBoxLayout;
+class QTreeWidget;
+class QFrame;
+
+namespace Search {
+
+/**
+* This class is used to keep track of the text strongs results.
+* It only keeps track of one instance of a strongs text result.
+*
+* The functions of the class are:
+* - Store an instance of a strongs text result.
+* - Each strongs text result will contain a list of verses (keyNames).
+* - The number of verses (keyNames) is returned by keyCount().
+* - The text for the strongs text result is returned by keyText().
+* - The list of verses (keyNames) is returned by getKeyList() [as QStringList].
+*
+* To add a new verse to a strongs text result use addKeyName.
+*/
+class StrongsResult {
+public:
+ StrongsResult();
+ StrongsResult(const QString& text, const QString &keyName);
+
+ QString keyText() const;
+ int keyCount() const;
+ void addKeyName(const QString& keyName);
+ QStringList* getKeyList();
+
+ /* ????
+ bool operator==(const StrongsResult &l, const StrongsResult &r)
+ { return (l.keyText() == r.keyText()); }
+
+ bool operator<(const StrongsResult &l, const StrongsResult &r)
+ { return (l->keyText() < r->keyText()); }
+
+ bool operator>(const StrongsResult &l, const StrongsResult &r)
+ { return (l->keyText() > r->keyText()); }
+ */
+private:
+ QString text;
+ QStringList keyNameList;
+};
+
+typedef QList<StrongsResult> StrongsResultList;
+
+/**
+* This class is used to keep track of the text strongs results.
+* It keeps track of all instances of all strongs text results.
+* This class makes use of the above class StrongsResult.
+*
+* The functions of the class are:
+* - Store an instance of a strongs text result.
+* - Each strongs text result will contain a list of verses (keyNames).
+* - The number of verses (keyNames) is returned by keyCount().
+* - The text for the strongs text result is returned by keyText().
+* - The list of verses (keyNames) is returned by getKeyList() [as QStringList].
+*
+* To add a new verse to a strongs text result use addKeyName.
+*/
+class StrongsResultClass {
+public:
+ StrongsResultClass(CSwordModuleInfo* module, const QString& strongsNumber)
+ : srModule(module), lemmaText(strongsNumber)
+ {
+ initStrongsResults();
+ }
+
+ QString keyText(int index) const {
+ return srList[index].keyText();
+ }
+ int keyCount(int index) const {
+ return srList[index].keyCount();
+ }
+ QStringList* getKeyList(int index) {
+ return srList[index].getKeyList();
+ }
+ int Count() const {
+ return srList.count();
+ }
+
+private:
+ void initStrongsResults(void);
+ QString getStrongsNumberText(const QString& verseContent, int *startIndex);
+
+ StrongsResultList srList;
+ CSwordModuleInfo* srModule;
+ QString lemmaText;
+};
+
+
+/** The page of the search dialog which contains the search result part.
+ * @author The BibleTime team
+ */
+class BtSearchResultArea : public QWidget
+{
+ Q_OBJECT
+public:
+ BtSearchResultArea(QWidget *parent=0);
+ ~BtSearchResultArea();
+ /**
+ * Sets the modules which contain the result of each.
+ */
+ void setSearchResult(QList<CSwordModuleInfo*> modules);
+
+ QSize sizeHint() const { return baseSize(); }
+ QSize minimumSizeHint() const { return minimumSize(); }
+
+public slots:
+ /**
+ * Resets the current list of modules and the displayed list of found entries.
+ */
+ void reset();
+
+protected:
+ /**
+ * Initializes the view of this widget.
+ */
+ void initView();
+ /**
+ * Initializes the signal slot conections of the child widgets
+ */
+ void initConnections();
+ /**
+ * This function breakes the queryString into clucene tokens
+ */
+ QStringList QueryParser(const QString& queryString);
+ /**
+ * This function highlights the searched text in the content using the search type given by search flags
+ */
+ QString highlightSearchedText(const QString& content, const QString& searchedText);
+
+ /**
+ * Load the settings from the resource file
+ */
+ void loadDialogSettings();
+ /**
+ * Save the settings to the resource file
+ */
+ void saveDialogSettings();
+
+protected slots:
+ /**
+ * Update the preview of the selected key.
+ */
+ void updatePreview(const QString& key);
+ /**
+ * Clear the preview of the selected key.
+ */
+ void clearPreview();
+ /**
+ * Shows a dialog with the search analysis of the current search.
+ */
+ void showAnalysis();
+
+private:
+
+ CModuleResultView* m_moduleListBox;
+ CSearchResultView* m_resultListBox;
+
+ QFrame *m_displayFrame;
+ CReadDisplay* m_previewDisplay;
+
+ QList<CSwordModuleInfo*> m_modules;
+
+ QSplitter *mainSplitter;
+ QSplitter *resultListSplitter;
+};
+
+} //namespace Search
+
+#endif
diff --git a/src/frontend/searchdialog/chistorycombobox.cpp b/src/frontend/searchdialog/chistorycombobox.cpp
new file mode 100644
index 0000000..953d9f3
--- /dev/null
+++ b/src/frontend/searchdialog/chistorycombobox.cpp
@@ -0,0 +1,48 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "chistorycombobox.h"
+#include <QString>
+#include <QCompleter>
+
+namespace Search {
+
+CHistoryComboBox::CHistoryComboBox( QWidget* parent)
+ : QComboBox(parent)
+{
+ setEditable(true);
+ completer()->setCompletionMode(QCompleter::PopupCompletion);
+}
+
+CHistoryComboBox::~CHistoryComboBox()
+{
+}
+
+void CHistoryComboBox::addToHistory(const QString& text)
+{
+ int index = findText(text);
+ if ( index >= 0)
+ removeItem(index);
+ insertItem(1, text);
+ setCurrentIndex(1);
+}
+
+QStringList CHistoryComboBox::historyItems() const
+{
+ QStringList items;
+ for (int i=0; i<count(); i++)
+ {
+ QString text = itemText(i);
+ if (text.size() > 0)
+ items << text;
+ }
+ return items;
+}
+} //end of namespace Search
+
diff --git a/src/frontend/searchdialog/chistorycombobox.h b/src/frontend/searchdialog/chistorycombobox.h
new file mode 100644
index 0000000..967c045
--- /dev/null
+++ b/src/frontend/searchdialog/chistorycombobox.h
@@ -0,0 +1,33 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CHISTORYCOMBOBOX_H
+#define CHISTORYCOMBOBOX_H
+
+#include <QComboBox>
+
+namespace Search {
+
+class CHistoryComboBox : public QComboBox
+{
+ Q_OBJECT
+public:
+ CHistoryComboBox(QWidget* parent = 0);
+ ~CHistoryComboBox();
+ void addToHistory(const QString& item);
+ QStringList historyItems() const;
+
+protected:
+
+private:
+};
+
+} //end of namespace Search
+
+#endif
diff --git a/src/frontend/searchdialog/cmoduleresultview.cpp b/src/frontend/searchdialog/cmoduleresultview.cpp
new file mode 100644
index 0000000..6c3053f
--- /dev/null
+++ b/src/frontend/searchdialog/cmoduleresultview.cpp
@@ -0,0 +1,297 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#include "cmoduleresultview.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+
+#include "frontend/cexportmanager.h"
+
+#include "util/cresmgr.h"
+#include "util/ctoolclass.h"
+#include "util/directoryutil.h"
+
+//Qt includes
+#include <QTreeWidget>
+#include <QAction>
+#include <QStringList>
+#include <QMenu>
+#include <QContextMenuEvent>
+#include <QHeaderView>
+
+namespace Search {
+
+
+/********************************************
+************ ModuleResultList **************
+********************************************/
+
+CModuleResultView::CModuleResultView(QWidget* parent)
+ : QTreeWidget(parent),
+ strongsResults(0)
+{
+ initView();
+ initConnections();
+}
+
+CModuleResultView::~CModuleResultView()
+{}
+
+
+/** Initializes this widget. */
+void CModuleResultView::initView()
+{
+ // see also csearchresultview.cpp
+ setToolTip(tr("Works chosen for the search and the number of the hits in each work"));
+ setHeaderLabels( QStringList(tr("Work")) << tr("Hits") );
+
+ setColumnWidth(0, CToolClass::mWidth(this, 8));
+ setColumnWidth(1, CToolClass::mWidth(this, 4));
+ QSize sz(CToolClass::mWidth(this, 13), CToolClass::mWidth(this, 5));
+ //setMinimumSize(sz);
+ m_size = sz;
+ //TODO: sorting
+ //setSorting(0, true);
+ //setSorting(1, true);
+
+ //setup the popup menu
+ m_popup = new QMenu(this);
+
+ m_actions.copyMenu = new QMenu(tr("Copy..."), m_popup);
+ m_actions.copyMenu->setIcon(util::filesystem::DirectoryUtil::getIcon( CResMgr::searchdialog::result::moduleList::copyMenu::icon) );
+ m_actions.copy.result = new QAction(tr("Reference only"), this);
+ QObject::connect(m_actions.copy.result, SIGNAL(triggered()), this, SLOT(copyResult()) );
+ m_actions.copyMenu->addAction(m_actions.copy.result);
+ m_actions.copy.resultWithText = new QAction(tr("Reference with text"), this);
+ QObject::connect(m_actions.copy.resultWithText, SIGNAL(triggered()), this, SLOT(copyResultWithText()) );
+ m_actions.copyMenu->addAction(m_actions.copy.resultWithText);
+ m_popup->addMenu(m_actions.copyMenu);
+
+ m_actions.saveMenu = new QMenu(tr("Save..."), m_popup);
+ m_actions.saveMenu->setIcon(util::filesystem::DirectoryUtil::getIcon( CResMgr::searchdialog::result::moduleList::saveMenu::icon) );
+ m_actions.save.result = new QAction(tr("Reference only"), this);
+ QObject::connect(m_actions.save.result, SIGNAL(triggered()), this, SLOT(saveResult()) );
+ m_actions.saveMenu->addAction(m_actions.save.result);
+ m_actions.save.resultWithText = new QAction(tr("Reference with text"), this);
+ QObject::connect(m_actions.save.resultWithText, SIGNAL(triggered()), this, SLOT(saveResultWithText()) );
+ m_actions.saveMenu->addAction(m_actions.save.resultWithText);
+ m_popup->addMenu(m_actions.saveMenu);
+
+ m_actions.printMenu = new QMenu(tr("Print..."), m_popup);
+ m_actions.printMenu->setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::searchdialog::result::moduleList::printMenu::icon));
+ m_actions.print.result = new QAction(tr("Reference with text"), this);
+ QObject::connect(m_actions.print.result, SIGNAL(triggered()), this, SLOT(printResult()) );
+ m_actions.printMenu->addAction(m_actions.print.result);
+ m_popup->addMenu(m_actions.printMenu);
+}
+
+/** Initializes the connections of this widget, */
+void CModuleResultView::initConnections()
+{
+ //TODO:
+ connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
+ this, SLOT(executed(QTreeWidgetItem*, QTreeWidgetItem*)));
+}
+
+/** Setups the tree using the given list of modules. */
+void CModuleResultView::setupTree( QList<CSwordModuleInfo*> modules, const QString& searchedText )
+{
+ clear();
+ //TODO: this class is for sorting
+ //util::CSortListViewItem* item = 0;
+ //util::CSortListViewItem* oldItem = 0;
+ QTreeWidgetItem* item = 0;
+ QTreeWidgetItem* oldItem = 0;
+
+ sword::ListKey result;
+
+ if (strongsResults) {
+ delete strongsResults;
+ strongsResults = 0;
+ }
+
+ bool strongsAvailable = false;
+
+ QList<CSwordModuleInfo*>::iterator end_it = modules.end();
+ for (QList<CSwordModuleInfo*>::iterator it(modules.begin()); it != end_it; ++it) {
+ // for (modules.first(); modules.current(); modules.next()) {
+ result = (*it)->searchResult();
+
+ item = new QTreeWidgetItem(this, QStringList((*it)->name()) << QString::number(result.Count()) );
+ //TODO: item->setColumnSorting(1, util::CSortListViewItem::Number);
+
+ item->setIcon(0,CToolClass::getIconForModule(*it) );
+ oldItem = item;
+ //----------------------------------------------------------------------
+ // we need to make a decision here. Either don't show any Strong's
+ // number translations, or show the first one in the search text, or
+ // figure out how to show them all.
+ // I choose option number 2 at this time.
+ //----------------------------------------------------------------------
+ int sstIndex, sTokenIndex; // strong search text index for finding "strong:"
+ if ((sstIndex = searchedText.indexOf("strong:", 0)) != -1) {
+ QString sNumber;
+ //--------------------------------------------------
+ // get the strongs number from the search text
+ //--------------------------------------------------
+ // first find the first space after "strong:"
+ // this should indicate a change in search token
+ sstIndex = sstIndex + 7;
+ sTokenIndex = searchedText.indexOf(" ", sstIndex);
+ sNumber = searchedText.mid(sstIndex, sTokenIndex - sstIndex);
+
+ setupStrongsResults((*it), item, sNumber);
+
+ //TODO: item->setOpen(true);
+ strongsAvailable = true;
+ }
+ };
+
+ //Allow to hide the module strongs if there are any available
+ setRootIsDecorated( strongsAvailable );
+}
+
+void CModuleResultView::setupStrongsResults(CSwordModuleInfo* module, QTreeWidgetItem* parent,
+ const QString& sNumber)
+{
+ QString lText;
+ //TODO:
+ //util::CSortListViewItem* item = 0;
+ QTreeWidgetItem* item = 0;
+
+ strongsResults = new StrongsResultClass(module, sNumber);
+
+ for (int cnt = 0; cnt < strongsResults->Count(); ++cnt) {
+ lText = strongsResults->keyText(cnt);
+
+ item = new QTreeWidgetItem(parent, QStringList(lText) << QString::number(strongsResults->keyCount(cnt)));
+ //TODO:
+ //item->setColumnSorting(1, util::CSortListViewItem::Number);
+ }
+}
+
+//TODO:
+/** Is executed when an item was selected in the list. */
+void CModuleResultView::executed( QTreeWidgetItem* i, QTreeWidgetItem*)
+{
+ QString itemText, lText;
+
+ if (!i){
+ //Clear list
+ emit moduleChanged();
+ return;
+ }
+ if (CSwordModuleInfo* m = CPointers::backend()->findModuleByName(i->text(0))) {
+ emit moduleChanged();
+ emit moduleSelected(m);
+ return;
+ }
+
+ if (!strongsResults) {
+ return;
+ }
+
+ itemText = i->text(0);
+ for (int cnt = 0; cnt < strongsResults->Count(); cnt++) {
+ lText = strongsResults->keyText(cnt);
+ if (lText == itemText) {
+ //clear the verses list
+ emit moduleChanged();
+ emit strongsSelected(activeModule(), strongsResults->getKeyList(cnt));
+ return;
+ }
+ }
+}
+
+/** Returns the currently active module. */
+CSwordModuleInfo* CModuleResultView::activeModule()
+{
+ Q_ASSERT(currentItem());
+
+ QTreeWidgetItem* item = currentItem();
+ if (!item) {
+ return 0;
+ }
+
+ // we need to find the parent most node because that is the node
+ // that is the module name.
+ while (item->parent()) {
+ item = item->parent();
+ }
+
+ if (item) {
+ return CPointers::backend()->findModuleByName(item->text(0));
+ }
+
+ return 0;
+}
+
+/** Reimplementation from QWidget. */
+void CModuleResultView::contextMenuEvent( QContextMenuEvent * event )
+{
+ qDebug("CModuleResultView::showPopup");
+ //make sure that all entries have the correct status
+ m_popup->exec(event->globalPos());
+}
+
+/** Copies the whole search result into the clipboard. */
+void CModuleResultView::copyResult()
+{
+ if (CSwordModuleInfo* m = activeModule()) {
+ sword::ListKey result = m->searchResult();
+ CExportManager mgr(tr("Copy search result..."), true, tr("Copying search result"));
+ mgr.copyKeyList(&result,m,CExportManager::Text,false);
+ };
+}
+
+/** Copies the whole search result with the text into the clipboard. */
+void CModuleResultView::copyResultWithText()
+{
+ if (CSwordModuleInfo* m = activeModule()) {
+ sword::ListKey result = m->searchResult();
+ CExportManager mgr(tr("Copy search result..."), true, tr("Copying search result"));
+ mgr.copyKeyList(&result,m,CExportManager::Text,true);
+ };
+}
+
+/** Saves the search result keys. */
+void CModuleResultView::saveResult()
+{
+ if (CSwordModuleInfo* m = activeModule()) {
+ sword::ListKey result = m->searchResult();
+ CExportManager mgr(tr("Save search result..."), true, tr("Saving search result"));
+ mgr.saveKeyList(&result,m,CExportManager::Text,false);
+ };
+}
+
+/** Saves the search result with it's text. */
+void CModuleResultView::saveResultWithText()
+{
+ if (CSwordModuleInfo* m = activeModule()) {
+ sword::ListKey result = m->searchResult();
+ CExportManager mgr(tr("Save search result..."), true, tr("Saving search result"));
+ mgr.saveKeyList(&result,m,CExportManager::Text,true);
+ };
+}
+
+/** Appends the whole search result to the printer queue. */
+void CModuleResultView::printResult()
+{
+ if (CSwordModuleInfo* m = activeModule()) {
+ sword::ListKey result = m->searchResult();
+ CExportManager mgr(tr("Print search result..."), true, tr("Printing search result"));
+ mgr.printKeyList(&result,m,CBTConfig::getDisplayOptionDefaults(), CBTConfig::getFilterOptionDefaults());
+ };
+}
+
+
+
+} //end of namespace Search
diff --git a/src/frontend/searchdialog/cmoduleresultview.h b/src/frontend/searchdialog/cmoduleresultview.h
new file mode 100644
index 0000000..c23d254
--- /dev/null
+++ b/src/frontend/searchdialog/cmoduleresultview.h
@@ -0,0 +1,136 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CMODULERESULTSVIEW_H
+#define CMODULERESULTSVIEW_H
+
+//BibleTime includes
+#include "btsearchresultarea.h"
+
+//Qt includes
+#include <QLabel>
+#include <QTreeWidget>
+
+
+//forward declarations
+class CSwordModuleInfo;
+
+class QPoint;
+class QMenu;
+class QAction;
+class QStringList;
+class QContextMenuEvent;
+
+class StrongsResultClass;
+
+
+namespace Search {
+
+
+class CModuleResultView : public QTreeWidget {
+ Q_OBJECT
+public:
+ CModuleResultView(QWidget* parent);
+ ~CModuleResultView();
+
+ /**
+ * Setups the tree using the given list of modules.
+ */
+ void setupTree( QList<CSwordModuleInfo*> modules, const QString& searchedText );
+ /**
+ * Returns the currently active module.
+ */
+ CSwordModuleInfo* activeModule();
+
+ virtual QSize sizeHint() {return m_size;}
+
+protected:
+ /**
+ * Initializes this widget.
+ */
+ void initView();
+ /**
+ * Initializes the connections of this widget
+ */
+ void initConnections();
+
+
+ void setupStrongsResults(CSwordModuleInfo* module, QTreeWidgetItem* parent, const QString& searchedText);
+
+protected slots:
+ /**
+ * Is executed when an item was selected in the list.
+ */
+ void executed(QTreeWidgetItem*, QTreeWidgetItem*);
+ /**
+ * Copies the whole search result with the text into the clipboard.
+ */
+ void copyResultWithText();
+ /**
+ * Copies the whole search result into the clipboard.
+ */
+ void copyResult();
+ /**
+ * This event handler (reimplemented from QWidget) opens the popup menu at the given position.
+ */
+ void contextMenuEvent( QContextMenuEvent * event );
+ /**
+ * Appends the whole search result to the printer queue.
+ */
+ void printResult();
+ /**
+ * Saves the search result with it's text.
+ */
+ void saveResultWithText();
+ /**
+ * Saves the search result keys.
+ */
+ void saveResult();
+
+signals:
+ void moduleSelected(CSwordModuleInfo*);
+ void moduleChanged();
+ void strongsSelected(CSwordModuleInfo*, QStringList*);
+
+private:
+ struct {
+ QMenu* saveMenu;
+ struct {
+ QAction* result;
+ QAction* resultWithText;
+ }
+ save;
+
+ QMenu* printMenu;
+ struct {
+ QAction* result;
+ }
+ print;
+
+ QMenu* copyMenu;
+ struct {
+ QAction* result;
+ QAction* resultWithText;
+ }
+ copy;
+
+ } m_actions;
+
+ QMenu* m_popup;
+
+ StrongsResultClass* strongsResults;
+ QSize m_size;
+};
+
+
+} //end of namespace Search
+
+#endif
diff --git a/src/frontend/searchdialog/crangechooserdialog.cpp b/src/frontend/searchdialog/crangechooserdialog.cpp
new file mode 100644
index 0000000..92a8dc0
--- /dev/null
+++ b/src/frontend/searchdialog/crangechooserdialog.cpp
@@ -0,0 +1,330 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#include "crangechooserdialog.h"
+
+#include "backend/config/cbtconfig.h"
+#include "util/dialogutil.h"
+
+//sword
+#include "versekey.h"
+#include "listkey.h"
+
+
+
+
+#include <QListWidget>
+#include <QListWidgetItem>
+#include <QString>
+#include <QLabel>
+#include <QPushButton>
+#include <QTextEdit>
+#include <QLineEdit>
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QFrame>
+#include <QDialogButtonBox>
+
+namespace Search {
+
+
+/********** RangeItem ******************/
+CRangeChooserDialog::RangeItem::RangeItem(QListWidget* view, QListWidgetItem* /*afterThis*/, const QString caption, const QString range)
+ : QListWidgetItem(view)
+{
+ setCaption(caption);
+ setRange(range);
+}
+
+CRangeChooserDialog::RangeItem::~RangeItem() {}
+
+const QString& CRangeChooserDialog::RangeItem::range() const
+{
+ // qWarning("range is %s", (const char*)m_range.utf8());
+ return m_range;
+}
+
+void CRangeChooserDialog::RangeItem::setRange(QString newRange) {
+ m_range = newRange;
+}
+
+QString CRangeChooserDialog::RangeItem::caption() const {
+ return text();
+}
+
+void CRangeChooserDialog::RangeItem::setCaption(const QString newCaption) {
+ setText(newCaption);
+}
+
+
+/*********** Dialog ***************/
+
+CRangeChooserDialog::CRangeChooserDialog( QWidget* parentDialog )
+ : QDialog(parentDialog)
+{
+ //Set the flag to destroy when closed - otherwise eats memory
+ setAttribute(Qt::WA_DeleteOnClose);
+ initView();
+ initConnections();
+
+ //add the existing scopes
+ CBTConfig::StringMap map = CBTConfig::get
+ (CBTConfig::searchScopes);
+ CBTConfig::StringMap::Iterator it;
+ for (it = map.begin(); it != map.end(); ++it) {
+ new RangeItem(m_rangeList, 0, it.key(), it.value());
+ };
+
+ editRange(0);
+ if (RangeItem* i = dynamic_cast<RangeItem*>(m_rangeList->currentItem())
+ ) {
+ nameChanged(i->caption());
+ }
+}
+
+/** Initializes the view of this object. */
+void CRangeChooserDialog::initView()
+{
+ setWindowTitle(tr("Setup Search Scopes"));
+
+ QVBoxLayout* vboxLayout = new QVBoxLayout(this);
+
+ QHBoxLayout* hboxLayout = new QHBoxLayout();
+ QVBoxLayout* vboxLayout1 = new QVBoxLayout();
+ QLabel* rangeListLabel = new QLabel(tr("S&earch range:"), this);
+ vboxLayout1->addWidget(rangeListLabel);
+
+ m_rangeList = new QListWidget(this);
+ m_rangeList->setToolTip(tr("Select a scope from the list to edit the search ranges"));
+ vboxLayout1->addWidget(m_rangeList);
+
+ QHBoxLayout* hboxLayout1 = new QHBoxLayout();
+ m_newRangeButton = new QPushButton(tr("&Add new scope"), this);
+ m_newRangeButton->setToolTip(tr("Add a new search scope. First enter an appropriate name, then edit the search ranges."));
+ hboxLayout1->addWidget(m_newRangeButton);
+ m_deleteRangeButton = new QPushButton(tr("Delete current &scope"), this);
+ m_deleteRangeButton->setToolTip(tr("Delete the selected search scope"));
+ hboxLayout1->addWidget(m_deleteRangeButton);
+
+ vboxLayout1->addLayout(hboxLayout1);
+ hboxLayout->addLayout(vboxLayout1);
+
+ QVBoxLayout* vboxLayout2 = new QVBoxLayout();
+ QHBoxLayout* hboxLayout2 = new QHBoxLayout();
+ QLabel* nameEditLabel = new QLabel(tr("&Name:"), this);
+ hboxLayout2->addWidget(nameEditLabel);
+
+ m_nameEdit = new QLineEdit(this);
+ m_nameEdit->setToolTip(tr("Change the name of the selected search scope"));
+ hboxLayout2->addWidget(m_nameEdit);
+ vboxLayout2->addLayout(hboxLayout2);
+
+ QLabel* rangeEditLabel = new QLabel(tr("Edi&t current range:"), this);
+ vboxLayout2->addWidget(rangeEditLabel);
+
+ m_rangeEdit = new QTextEdit(this);
+ m_rangeEdit->setToolTip(tr("Change the search ranges of the selected search scope item. Have a look at the predefined search scopes to see how search ranges are constructed."));
+
+ vboxLayout2->addWidget(m_rangeEdit);
+
+ QLabel* resultListLabel = new QLabel(tr("Parsed search range:"), this);
+ vboxLayout2->addWidget(resultListLabel);
+
+ m_resultList = new QListWidget(this);
+ m_resultList->setToolTip(tr("The search ranges which will be used for the search, parsed to the canonical form"));
+ vboxLayout2->addWidget(m_resultList);
+
+ hboxLayout->addLayout(vboxLayout2);
+ vboxLayout->addLayout(hboxLayout);
+
+ QFrame* line = new QFrame(this);
+ line->setFrameShape(QFrame::HLine);
+ line->setFrameShadow(QFrame::Sunken);
+ vboxLayout->addWidget(line);
+
+ m_buttonBox = new QDialogButtonBox(this);
+ m_buttonBox->setOrientation(Qt::Horizontal);
+ m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults);
+ util::prepareDialogBox(m_buttonBox);
+ vboxLayout->addWidget(m_buttonBox);
+
+ rangeListLabel->setBuddy(m_rangeList);
+ nameEditLabel->setBuddy(m_nameEdit);
+ rangeEditLabel->setBuddy(m_rangeEdit);
+ resultListLabel->setBuddy(m_resultList);
+}
+
+
+
+void CRangeChooserDialog::initConnections()
+{
+ // Signals from text/list widgets
+ QObject::connect(m_rangeList, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
+ this, SLOT(editRange(QListWidgetItem*)));
+
+ QObject::connect(m_rangeEdit, SIGNAL(textChanged()),
+ this, SLOT(parseRange()));
+ QObject::connect(m_rangeEdit, SIGNAL(textChanged()),
+ this, SLOT(rangeChanged()));
+
+ QObject::connect(m_nameEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(nameChanged(const QString&)));
+
+ // Buttons
+ QObject::connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(slotOk()));
+ QObject::connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(close()));
+ QObject::connect(m_newRangeButton, SIGNAL(clicked()), this, SLOT(addNewRange()));
+ QObject::connect(m_deleteRangeButton, SIGNAL(clicked()), this, SLOT(deleteCurrentRange()));
+ //restore defaults!
+ QPushButton* defaultsButton = m_buttonBox->button(QDialogButtonBox::RestoreDefaults);
+ QObject::connect(defaultsButton, SIGNAL(clicked()), this, SLOT(slotDefault()));
+}
+
+/** Adds a new range to the list. */
+void CRangeChooserDialog::addNewRange()
+{
+ //qDebug("CRangeChooserDialog::addNewRange");
+ //RangeItem* i = new RangeItem(m_rangeList, m_rangeList->lastItem(), tr("New range"));
+ RangeItem* i = new RangeItem(m_rangeList, 0, tr("New range"));
+ //use just setCurrentItem... m_rangeList->setSelected(i, true);
+ m_rangeList->setCurrentItem(i);
+ editRange(i);
+
+ m_nameEdit->setFocus();
+}
+
+/** No descriptions */
+void CRangeChooserDialog::editRange(QListWidgetItem* item)
+{
+ //qDebug("CRangeChooserDialog::editRange");
+ RangeItem* const range = dynamic_cast<RangeItem*>(item);
+
+ m_nameEdit->setEnabled( range ); //only if an item is selected enable the edit part
+ m_rangeEdit->setEnabled( range );
+ m_resultList->setEnabled( range );
+ m_deleteRangeButton->setEnabled( range );
+
+ if (range) {
+ m_nameEdit->setText(range->caption());
+ m_rangeEdit->setText(range->range());
+ }
+}
+
+/** Parses the entered text and prints out the result in the list box below the edit area. */
+void CRangeChooserDialog::parseRange()
+{
+ //qDebug("CRangeChooserDialog::parseRange");
+ m_resultList->clear();
+
+ //TODO: remove this hack:
+ //HACK: repair range to work with Sword 1.5.6
+ QString range( m_rangeEdit->toPlainText() );
+ range.replace(QRegExp("\\s{0,}-\\s{0,}"), "-" );
+
+ sword::VerseKey key;
+ sword::ListKey verses = key.ParseVerseList((const char*)range.toUtf8(), "Genesis 1:1", true);
+ for (int i = 0; i < verses.Count(); ++i) {
+ new QListWidgetItem(QString::fromUtf8(verses.GetElement(i)->getRangeText()), m_resultList );
+ // qWarning("range=%s, text=%s",verses.GetElement(i)->getRangeText(), verses.GetElement(i)->getText() );
+ }
+
+}
+
+/** No descriptions */
+void CRangeChooserDialog::rangeChanged()
+{
+ //qDebug("CRangeChooserDialog::rangeChanged");
+ if (RangeItem* i = dynamic_cast<RangeItem*>(m_rangeList->currentItem())
+ ) {
+ QString range( m_rangeEdit->toPlainText() );
+ //TODO: remove this hack:
+ //HACK: repair range to work with Sword 1.5.6
+ range.replace(QRegExp("\\s{0,}-\\s{0,}"), "-" );
+ i->setRange(range);
+ };
+}
+
+/** No descriptions */
+void CRangeChooserDialog::nameChanged(const QString& newCaption)
+{
+ //qDebug("CRangeChooserDialog::nameChanged");
+ m_rangeEdit->setEnabled(!newCaption.isEmpty());
+ m_resultList->setEnabled(!newCaption.isEmpty());
+ //m_resultList->header()->setEnabled(!newCaption.isEmpty());
+
+ if (RangeItem* i = dynamic_cast<RangeItem*>(m_rangeList->currentItem())
+ ) {
+ if (!newCaption.isEmpty()) {
+ //enable some items (see "else" below)
+ m_newRangeButton->setEnabled(true);
+ m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
+ m_rangeList->setDisabled(false);
+ i->setCaption(newCaption);
+ }
+ else { //invalid name
+ i->setCaption(tr("<invalid name of search range>"));
+ //disable some items to prevent saving invalid range
+ m_newRangeButton->setEnabled(false);
+ m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
+ m_rangeList->setDisabled(true);
+ };
+ };
+}
+
+/** Deletes the selected range. */
+void CRangeChooserDialog::deleteCurrentRange()
+{
+ //qDebug("CRangeChooserDialog::deleteCurrentRange");
+ if (RangeItem* i = dynamic_cast<RangeItem*>(m_rangeList->currentItem()) ) {
+ int row = m_rangeList->row(i);
+ m_rangeList->takeItem(row);
+ delete i;
+ }
+ editRange(m_rangeList->currentItem());
+}
+
+void CRangeChooserDialog::slotOk()
+{
+ m_rangeList->sortItems(); //sorted first because the order will be saved
+ //save the new map of search scopes
+ CBTConfig::StringMap map;
+ for (int i = 0; i < m_rangeList->count(); i++){
+ if ( RangeItem* item = dynamic_cast<RangeItem*>(m_rangeList->item(i)) ) {
+ map[item->caption()] = item->range();
+ };
+ }
+ CBTConfig::set
+ (CBTConfig::searchScopes, map);
+
+ QDialog::accept();
+}
+
+void CRangeChooserDialog::slotDefault()
+{
+ //qDebug("CRangeChooserDialog::slotDefault");
+ m_rangeList->clear();
+ CBTConfig::StringMap map = CBTConfig::getDefault(CBTConfig::searchScopes);
+ CBTConfig::StringMap::Iterator it;
+ for (it = map.begin(); it != map.end(); ++it) {
+ new RangeItem(m_rangeList, 0, it.key(), it.value());
+ };
+ m_rangeList->setCurrentItem(0);
+
+ editRange(0);
+ if (RangeItem* i = dynamic_cast<RangeItem*>(m_rangeList->currentItem())
+ ) {
+ nameChanged(i->caption());
+ }
+
+}
+
+
+} //end of namespace Search
diff --git a/src/frontend/searchdialog/crangechooserdialog.h b/src/frontend/searchdialog/crangechooserdialog.h
new file mode 100644
index 0000000..4859b15
--- /dev/null
+++ b/src/frontend/searchdialog/crangechooserdialog.h
@@ -0,0 +1,89 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CRANGECHOOSERDIALOG_H
+#define CRANGECHOOSERDIALOG_H
+
+#include <QDialog>
+#include <QListWidgetItem>
+
+class QListWidget;
+class QLineEdit;
+class QTextEdit;
+class QPushButton;
+class QDialogButtonBox;
+
+
+namespace Search {
+
+class CRangeChooserDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ CRangeChooserDialog(QWidget* parentDialog);
+ ~CRangeChooserDialog(){};
+
+protected: // Protected methods
+class RangeItem : public QListWidgetItem {
+public:
+ RangeItem(QListWidget*, QListWidgetItem* afterThis = 0, const QString caption = QString::null, const QString range = QString::null);
+ ~RangeItem();
+ const QString& range() const;
+ QString caption() const;
+ void setRange(QString range);
+ void setCaption(const QString);
+private:
+ QString m_range;
+ };
+
+ /**
+ * Initializes the connections of this widget.
+ */
+ void initConnections();
+ /**
+ * Initializes the view of this object.
+ */
+ void initView();
+
+protected slots: // Protected slots
+ /**
+ * Adds a new range to the list.
+ */
+ void addNewRange();
+ void editRange(QListWidgetItem*);
+ /**
+ * Parses the entered text and prints out the result in the list box below the edit area.
+ */
+ void parseRange();
+ void nameChanged(const QString&);
+ void rangeChanged();
+ /**
+ * Deletes the selected range.
+ */
+ void deleteCurrentRange();
+ virtual void slotDefault();
+ virtual void slotOk();
+
+private:
+ QListWidget* m_rangeList;
+ QListWidget* m_resultList;
+ QLineEdit* m_nameEdit;
+ QTextEdit* m_rangeEdit;
+ QPushButton* m_newRangeButton;
+ QPushButton* m_deleteRangeButton;
+ QDialogButtonBox* m_buttonBox;
+};
+
+
+} //end of namespace Search
+
+
+#endif
diff --git a/src/frontend/searchdialog/csearchdialog.cpp b/src/frontend/searchdialog/csearchdialog.cpp
new file mode 100644
index 0000000..947e669
--- /dev/null
+++ b/src/frontend/searchdialog/csearchdialog.cpp
@@ -0,0 +1,304 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+#include "csearchdialog.h"
+#include "btsearchoptionsarea.h"
+#include "btsearchresultarea.h"
+
+#include "backend/cswordmodulesearch.h"
+#include "backend/keys/cswordkey.h"
+#include "backend/keys/cswordversekey.h"
+#include "backend/config/cbtconfig.h"
+
+#include "frontend/cmoduleindexdialog.h"
+
+#include "util/cresmgr.h"
+#include "util/ctoolclass.h"
+#include "util/directoryutil.h"
+
+//Qt includes
+#include <QString>
+#include <QWidget>
+#include <QMessageBox>
+#include <QVBoxLayout>
+#include <QLineEdit>
+#include <QSettings>
+#include <QDialogButtonBox>
+#include <QPushButton>
+#include <QSizePolicy>
+#include <QDebug>
+
+namespace Search {
+
+static CSearchDialog* m_staticDialog = 0;
+
+void CSearchDialog::openDialog(const QList<CSwordModuleInfo*> modules, const QString& searchText, QWidget* parentDialog)
+{
+ if (!m_staticDialog) {
+ m_staticDialog = new CSearchDialog(parentDialog);
+ };
+ m_staticDialog->reset();
+
+ if (modules.count()) {
+ m_staticDialog->setModules(modules);
+ }
+ else {
+ m_staticDialog->showModulesSelector();
+ }
+
+ m_staticDialog->setSearchText(searchText);
+ if (m_staticDialog->isHidden()) {
+ m_staticDialog->show();
+ }
+
+ if (modules.count() && !searchText.isEmpty()) {
+ m_staticDialog->startSearch();
+ }
+ // moved these to after the startSearch() because
+ // the progress dialog caused them to loose focus.
+ m_staticDialog->raise();
+ m_staticDialog->activateWindow();
+}
+
+CSearchDialog* CSearchDialog::getSearchDialog()
+{
+ Q_ASSERT(m_staticDialog);
+ return m_staticDialog;
+}
+
+CSearchDialog::CSearchDialog(QWidget *parent)
+ :QDialog(parent), /*m_searchButton(0),*/ m_closeButton(0),
+ m_searchResultArea(0), m_searchOptionsArea(0)
+{
+ setWindowIcon( util::filesystem::DirectoryUtil::getIcon(CResMgr::searchdialog::icon) );
+ setWindowTitle(tr("Search"));
+ setAttribute(Qt::WA_DeleteOnClose);
+ m_searcher.connectFinished( this, SLOT(searchFinished()));
+ initView();
+ initConnections();
+}
+
+CSearchDialog::~CSearchDialog()
+{
+ saveDialogSettings();
+ m_staticDialog = 0;
+}
+
+/** Starts the search with the set modules and the set search text. */
+void CSearchDialog::startSearch()
+{
+ QString originalSearchText(m_searchOptionsArea->searchText());
+ QString searchText("");
+
+ if (originalSearchText.isEmpty()) {
+ return;
+ }
+
+ searchText = prepareSearchText(originalSearchText);
+
+ // Insert search text into history list of combobox
+ m_searchOptionsArea->addToHistory(originalSearchText);
+
+ // check that we have the indices we need for searching
+ if (!m_searcher.modulesHaveIndices( modules() ) ) {
+ int result = QMessageBox::question(this, tr("Missing indices"),
+ tr("One or more works need indexing before they can be searched.\n"
+ "This could take a long time. Proceed with indexing?"),
+ QMessageBox::Yes | QMessageBox::Default,
+ QMessageBox::No | QMessageBox::Escape);
+ // In SuSE 10.0 the result is the logical or of the button type, just like it is
+ // inputed into the QMessageBox.
+ if ( (result == (QMessageBox::Yes | QMessageBox::Default)) ||
+ (result == QMessageBox::Yes) || (result == QMessageBox::Default) ) {
+ CModuleIndexDialog* dlg = CModuleIndexDialog::getInstance();
+ dlg->indexUnindexedModules( modules() );
+ }
+ else {
+ return;
+ }
+ }
+
+ if (m_searchOptionsArea->hasSearchScope()) {
+ m_searcher.setSearchScope( m_searchOptionsArea->searchScope() );
+ }
+ else {
+ m_searcher.resetSearchScope();
+ }
+
+ m_searcher.setModules( modules() );
+ m_searcher.setSearchedText(searchText);
+
+
+ //Just to be sure that it can't be clicked again, if the search happens to be a bit slow.
+ m_searchOptionsArea->searchButton()->setEnabled(false);
+ m_searchOptionsArea->m_searchTextCombo->setEnabled(false);
+
+ m_searcher.startSearch();
+
+ m_searchOptionsArea->searchButton()->setEnabled(true);
+ m_searchOptionsArea->m_searchTextCombo->setEnabled(true);
+ m_searchOptionsArea->m_searchTextCombo->setFocus();
+}
+
+QString CSearchDialog::prepareSearchText(const QString& orig)
+{
+ qDebug() << "Original search text:" << orig;
+ static const QRegExp syntaxCharacters("[+\\-()!\"~]");
+ static const QRegExp andWords("\\band\\b", Qt::CaseInsensitive);
+ static const QRegExp orWords("\\bor\\b", Qt::CaseInsensitive);
+ QString text("");
+ if (m_searchOptionsArea->searchType() == BtSearchOptionsArea::AndType) {
+ qDebug() << "AND type";
+ text = orig.simplified();
+ text.remove(syntaxCharacters);
+ qDebug() << "After syntax characters removed:" << text;
+ text.replace(andWords, "\"and\"");
+ text.replace(orWords, "\"or\"");
+ qDebug() << "After andor repclaced:" << text;
+ text.replace(" ", " AND ");
+ }
+ if (m_searchOptionsArea->searchType() == BtSearchOptionsArea::OrType) {
+ text = orig.simplified();
+ text.remove(syntaxCharacters);
+ text.replace(andWords, "\"and\"");
+ text.replace(orWords, "\"or\"");
+ }
+ if (m_searchOptionsArea->searchType() == BtSearchOptionsArea::FullType) {
+ text = orig;
+ }
+ qDebug() << "The final search string:" << text;
+ return text;
+}
+
+/** Starts the search with the given module list and given search text. */
+void CSearchDialog::startSearch( const QList<CSwordModuleInfo*> modules, const QString& searchText)
+{
+ m_searchResultArea->reset();
+ m_searchOptionsArea->reset();
+ setModules(modules);
+ setSearchText(searchText);
+
+ startSearch();
+}
+
+/** Returns the list of used modules. */
+QList<CSwordModuleInfo*> CSearchDialog::modules() const
+{
+ return m_searchOptionsArea->modules();
+}
+
+/** Sets the list of modules for the search. */
+void CSearchDialog::setModules( const QList<CSwordModuleInfo*> modules )
+{
+ m_searchOptionsArea->setModules(modules);
+}
+
+/** Returns the search text which is set currently. */
+QString CSearchDialog::searchText() const
+{
+ return m_searchOptionsArea->searchText();
+}
+
+sword::ListKey CSearchDialog::searchScope()
+{
+ return m_searchOptionsArea->searchScope();
+}
+
+/** Sets the search text which is used for the search. */
+void CSearchDialog::setSearchText( const QString searchText )
+{
+ m_searchOptionsArea->setSearchText(searchText);
+}
+
+/** Initializes this object. */
+void CSearchDialog::initView()
+{
+ QVBoxLayout* verticalLayout = new QVBoxLayout(this);
+ setLayout(verticalLayout);
+
+ m_searchOptionsArea = new BtSearchOptionsArea(this);
+ verticalLayout->addWidget(m_searchOptionsArea);
+
+ m_searchResultArea = new BtSearchResultArea(this);
+ verticalLayout->addWidget(m_searchResultArea);
+
+ QHBoxLayout* horizontalLayout = new QHBoxLayout();
+
+ m_analyseButton = new QPushButton(tr("&Analyze results..."), 0);
+ m_analyseButton->setToolTip(tr("Show a graphical analyzis of the search result"));
+ QSpacerItem* spacerItem = new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ horizontalLayout->addWidget(m_analyseButton);
+ horizontalLayout->addItem(spacerItem);
+
+ m_closeButton = new QPushButton(this);
+ m_closeButton->setText(tr("&Close"));
+ m_closeButton->setIcon( util::filesystem::DirectoryUtil::getIcon(CResMgr::searchdialog::close_icon));
+ horizontalLayout->addWidget(m_closeButton);
+
+ verticalLayout->addLayout(horizontalLayout);
+
+ loadDialogSettings();
+}
+
+void CSearchDialog::searchFinished() {
+ if ( m_searcher.foundItems() ) {
+ m_searchResultArea->setSearchResult(modules());
+ }
+ else {
+ m_searchResultArea->reset();
+ }
+ m_staticDialog->raise();
+ m_staticDialog->activateWindow();
+}
+
+void CSearchDialog::showModulesSelector() {
+ m_searchOptionsArea->chooseModules();
+}
+
+/** Initializes the signal slot connections */
+void CSearchDialog::initConnections() {
+ // Search button is clicked
+ bool ok = connect(m_searchOptionsArea->searchButton(), SIGNAL(pressed()),this, SLOT(startSearch()));
+ Q_ASSERT(ok);
+ // Return/Enter is pressed in the search text field
+ ok = connect(m_searchOptionsArea, SIGNAL(sigStartSearch()), this, SLOT(startSearch()) );
+ Q_ASSERT(ok);
+ ok = connect(m_closeButton, SIGNAL(pressed()), this, SLOT(closeButtonPressed()));
+ Q_ASSERT(ok);
+
+ connect(m_analyseButton, SIGNAL(clicked()), m_searchResultArea, SLOT(showAnalysis()));
+
+}
+
+/** Resets the parts to the default. */
+void CSearchDialog::reset() {
+ m_searchOptionsArea->reset();
+ m_searchResultArea->reset();
+}
+
+void CSearchDialog::closeButtonPressed() {
+ // With Qt::WA_DeleteOnClose set, the dialog will be deleted now
+ m_staticDialog->close();
+}
+
+void CSearchDialog::loadDialogSettings()
+{
+ resize(CBTConfig::get(CBTConfig::searchDialogWidth), CBTConfig::get(CBTConfig::searchDialogHeight));
+ move(CBTConfig::get(CBTConfig::searchDialogX), CBTConfig::get(CBTConfig::searchDialogY));
+}
+
+void CSearchDialog::saveDialogSettings()
+{
+ CBTConfig::set(CBTConfig::searchDialogWidth, size().width());
+ CBTConfig::set(CBTConfig::searchDialogHeight, size().height());
+ CBTConfig::set(CBTConfig::searchDialogX, x());
+ CBTConfig::set(CBTConfig::searchDialogY, y());
+}
+
+
+} //end of namespace Search
diff --git a/src/frontend/searchdialog/csearchdialog.h b/src/frontend/searchdialog/csearchdialog.h
new file mode 100644
index 0000000..639ca26
--- /dev/null
+++ b/src/frontend/searchdialog/csearchdialog.h
@@ -0,0 +1,134 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CSEARCHDIALOG_H
+#define CSEARCHDIALOG_H
+
+//BibleTime includes
+#include "backend/managers/cswordbackend.h"
+#include "backend/cswordmodulesearch.h"
+
+#include "util/cpointers.h"
+
+//Qt includes
+#include <QString>
+#include <QDialog>
+
+
+//forward declarations
+namespace Search {
+ class BtSearchResultArea;
+ class BtSearchOptionsArea;
+}
+
+class QWidget;
+class QPushButton;
+
+
+namespace Search {
+
+/**
+ *@author The BibleTime team
+ */
+class CSearchDialog : public QDialog {
+ Q_OBJECT
+
+public:
+ static void openDialog(const QList<CSwordModuleInfo*> modules, const QString& searchText = QString::null, QWidget* parentDialog = 0);
+
+protected:
+ friend class CSearchAnalysisScene;
+ friend class CSearchResultArea;
+ friend class BtSearchResultArea;
+ friend class BibleTime;
+
+ /**
+ * Only interesting for the class members! Useful to get the searched text etc.
+ */
+ static CSearchDialog* getSearchDialog();
+
+ /**
+ * The constructor of the dialog. It's protected because you should use the static public function openDialog.
+ * The dialog destroys itself if it was closed.
+ */
+ CSearchDialog(QWidget *parent);
+ ~CSearchDialog();
+
+ /**
+ * Initializes this object.
+ */
+ void initView();
+ /**
+ * Starts the search with the given module list and given search text.
+ * Doesn't wait for the start button press, starts immediately
+ */
+ void startSearch( const QList<CSwordModuleInfo*> modules, const QString& searchText);
+ /**Prepares the search string given by user for a specific search type */
+ QString prepareSearchText(const QString& orig);
+ /**
+ * Sets the list of modules for the search.
+ */
+ void setModules( const QList<CSwordModuleInfo*> modules );
+ /**
+ * Returns the list of used modules.
+ */
+ QList<CSwordModuleInfo*> modules() const;
+ /**
+ * Sets the search text which is used for the search.
+ */
+ void setSearchText( const QString searchText );
+ /**
+ * Returns the search text which is set currently.
+ */
+ QString searchText() const;
+ /**
+ * Returns the used search scope as a list key
+ */
+ sword::ListKey searchScope();
+
+ /**
+ * Resets the parts to the default.
+ */
+ void reset();
+ /**
+ * Load the settings from the resource file
+ */
+ void loadDialogSettings();
+ /**
+ * Save the settings to the resource file
+ */
+ void saveDialogSettings();
+
+protected slots:
+ /**
+ * Starts the search with the set modules and the set search text.
+ */
+ void startSearch();
+ void searchFinished();
+ void showModulesSelector();
+ /**
+ * Initializes the signal slot connections
+ */
+ void initConnections();
+
+ void closeButtonPressed();
+
+private:
+ QPushButton* m_analyseButton;
+ QPushButton* m_closeButton;
+ BtSearchResultArea* m_searchResultArea;
+ BtSearchOptionsArea* m_searchOptionsArea;
+
+ CSwordModuleSearch m_searcher;
+};
+
+
+} //end of namespace Search
+
+#endif
diff --git a/src/frontend/searchdialog/csearchmodulechooserdialog.cpp b/src/frontend/searchdialog/csearchmodulechooserdialog.cpp
new file mode 100644
index 0000000..cf68f6e
--- /dev/null
+++ b/src/frontend/searchdialog/csearchmodulechooserdialog.cpp
@@ -0,0 +1,61 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2007 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "csearchmodulechooserdialog.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/cswordbackend.h"
+#include "backend/btmoduletreeitem.h"
+
+#include "util/cpointers.h"
+#include "util/cresmgr.h"
+#include "util/ctoolclass.h"
+#include "util/directoryutil.h"
+
+#include <QDialog>
+#include <QButtonGroup>
+#include <QDialogButtonBox>
+#include <QHBoxLayout>
+#include <QSpacerItem>
+#include <QTreeWidget>
+#include <QVBoxLayout>
+#include <QStringList>
+#include <QDebug>
+#include <QHeaderView>
+
+namespace Search {
+
+CSearchModuleChooserDialog::CSearchModuleChooserDialog( QWidget* parent, QString title, QString label,
+ QList<CSwordModuleInfo*> selectedModules)
+ : CModuleChooserDialog(parent, title, label),
+ m_selectedModules(selectedModules)
+{
+ m_hiddenFilter = new BTModuleTreeItem::HiddenOff();
+ QList<BTModuleTreeItem::Filter*> filters;
+ filters.append(m_hiddenFilter);
+ setFilters(filters);
+ init();
+}
+
+CSearchModuleChooserDialog::~CSearchModuleChooserDialog()
+{
+ //see the ctor
+ delete m_hiddenFilter;
+}
+
+void CSearchModuleChooserDialog::initModuleItem(BTModuleTreeItem* btItem, QTreeWidgetItem* widgetItem)
+{
+ widgetItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
+ if (m_selectedModules.contains(btItem->moduleInfo()))
+ widgetItem->setCheckState(0, Qt::Checked);
+ else
+ widgetItem->setCheckState(0, Qt::Unchecked);
+}
+
+} //end of namespace Search
diff --git a/src/frontend/searchdialog/csearchmodulechooserdialog.h b/src/frontend/searchdialog/csearchmodulechooserdialog.h
new file mode 100644
index 0000000..8d5e32c
--- /dev/null
+++ b/src/frontend/searchdialog/csearchmodulechooserdialog.h
@@ -0,0 +1,44 @@
+//
+// C++ Interface: cmodulechooserdialog
+//
+// Description:
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 2007
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#ifndef CSEARCHMODULECHOOSERDIALOG_H
+#define CSEARCHMODULECHOOSERDIALOG_H
+
+class CSwordModuleInfo;
+
+#include "frontend/cmodulechooserdialog.h"
+
+class QTreeWidgetItem;
+
+class BTModuleTreeItem;
+
+
+namespace Search {
+
+class CSearchModuleChooserDialog : public CModuleChooserDialog
+{
+ Q_OBJECT
+public:
+ CSearchModuleChooserDialog(QWidget* parent, QString title, QString label, QList<CSwordModuleInfo*> selectedModules);
+ ~CSearchModuleChooserDialog();
+
+protected: // Protected methods
+ virtual void initModuleItem(BTModuleTreeItem* btItem, QTreeWidgetItem* widgetItem);
+
+private:
+ QList<CSwordModuleInfo*> m_selectedModules;
+ BTModuleTreeItem::HiddenOff* m_hiddenFilter;
+};
+
+} //end of namespace Search
+
+#endif
diff --git a/src/frontend/searchdialog/csearchresultview.cpp b/src/frontend/searchdialog/csearchresultview.cpp
new file mode 100644
index 0000000..74561d6
--- /dev/null
+++ b/src/frontend/searchdialog/csearchresultview.cpp
@@ -0,0 +1,295 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "csearchresultview.h"
+
+#include "backend/keys/cswordversekey.h"
+
+#include "frontend/cdragdrop.h"
+#include "frontend/cexportmanager.h"
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+
+#include <QWidget>
+#include <QMenu>
+#include <QList>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+#include <QContextMenuEvent>
+
+//KDE includes
+
+
+namespace Search {
+
+
+CSearchResultView::CSearchResultView(QWidget* parent)
+ : QTreeWidget(parent),
+ m_module(0)
+{
+ initView();
+ initConnections();
+}
+
+CSearchResultView::~CSearchResultView() {}
+
+/** Initializes the view of this widget. */
+void CSearchResultView::initView()
+{
+ setToolTip(tr("Search result of the selected work"));
+ setHeaderLabel(tr("Results"));
+ setDragEnabled(true);
+ setRootIsDecorated( false );
+ setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+ //setup the popup menu
+ m_popup = new QMenu(this);
+
+ m_actions.copyMenu = new QMenu(tr("Copy..."), m_popup);
+ m_actions.copyMenu->setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::searchdialog::result::foundItems::copyMenu::icon));
+
+ m_actions.copy.result = new QAction(tr("Reference only"), this);
+ QObject::connect(m_actions.copy.result, SIGNAL(triggered()), this, SLOT(copyItems()) );
+ m_actions.copyMenu->addAction(m_actions.copy.result);
+
+ m_actions.copy.resultWithText = new QAction(tr("Reference with text"), this);
+ QObject::connect(m_actions.copy.resultWithText, SIGNAL(triggered()),
+ this, SLOT(copyItemsWithText()));
+ m_actions.copyMenu->addAction(m_actions.copy.resultWithText);
+
+ m_popup->addMenu(m_actions.copyMenu);
+
+ m_actions.saveMenu = new QMenu(tr("Save..."), m_popup);
+ m_actions.saveMenu->setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::searchdialog::result::foundItems::saveMenu::icon));
+
+ m_actions.save.result = new QAction(tr("Reference only"), this);
+ QObject::connect(m_actions.save.result, SIGNAL(triggered()), this, SLOT(saveItems()) );
+ m_actions.saveMenu->addAction(m_actions.save.result);
+
+ m_actions.save.resultWithText = new QAction(tr("Reference with text"), this);
+ m_actions.saveMenu->addAction(m_actions.save.resultWithText);
+ QObject::connect(m_actions.save.resultWithText, SIGNAL(triggered()), this, SLOT(saveItemsWithText()));
+ m_popup->addMenu(m_actions.saveMenu);
+
+ m_actions.printMenu = new QMenu(tr("Print..."), m_popup);
+ m_actions.printMenu->setIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::searchdialog::result::foundItems::printMenu::icon));
+
+ m_actions.print.result = new QAction(tr("Reference with text"), this);
+ QObject::connect(m_actions.print.result, SIGNAL(triggered()), this, SLOT(printItems()) );
+ m_actions.printMenu->addAction(m_actions.print.result);
+ m_popup->addMenu(m_actions.printMenu);
+}
+
+/** No descriptions */
+void CSearchResultView::initConnections() {
+ // connect(this, SIGNAL(executed(QListViewItem*)),
+ // this, SLOT(executed(QListViewItem*)));
+ //TODO: are these right after porting?
+ //items: current, previous
+ connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
+ this, SLOT(executed(QTreeWidgetItem*, QTreeWidgetItem*)));
+}
+
+/** Setups the list with the given module. */
+void CSearchResultView::setupTree(CSwordModuleInfo* m) {
+ clear();
+
+ if (!m) return;
+
+ m_module = m;
+ sword::ListKey& result = m->searchResult();
+ const int count = result.Count();
+ if (!count) return;
+
+ setUpdatesEnabled(false);
+
+ QTreeWidgetItem* oldItem = 0;
+ QTreeWidgetItem* item = 0;
+ for (int index = 0; index < count; index++) {
+ item = new QTreeWidgetItem(this, oldItem);
+ item->setText(0, QString::fromUtf8(result.GetElement(index)->getText()));
+ oldItem = item;
+ }
+
+ setUpdatesEnabled(true);
+ //pre-select the first item
+ this->setCurrentItem(this->topLevelItem(0), 0);
+}
+
+void CSearchResultView::setupStrongsTree(CSwordModuleInfo* m, QStringList* vList)
+{
+ clear();
+ if (!m) {
+ return;
+ }
+
+ m_module = m;
+
+ if (vList->count() <= 0) {
+ return;
+ }
+
+ setUpdatesEnabled(false);
+
+ QTreeWidgetItem* oldItem = 0;
+ QTreeWidgetItem* item = 0;
+
+ foreach (QString s, *vList) {
+ item = new QTreeWidgetItem(this, oldItem);
+ item->setText(0, (s));
+ oldItem = item;
+ }
+
+ setUpdatesEnabled(true);
+
+ //TODO:select the first item
+ //setSelected(firstChild(), true);
+ //executed(currentItem());
+}
+
+//TODO: is this still valid?
+/** Is connected to the signal executed, which is emitted when a mew item was chosen. */
+void CSearchResultView::executed(QTreeWidgetItem* current, QTreeWidgetItem*) {
+ if (current){
+ emit keySelected(current->text(0));
+ }
+ else{
+ emit keyDeselected();
+ }
+}
+
+//TODO: another function?
+/** Reimplementation to show the popup menu. */
+void CSearchResultView::contextMenuEvent(QContextMenuEvent* event)
+{
+ qDebug("CSearchResultView::showPopup");
+ m_popup->exec(event->globalPos());
+}
+
+void CSearchResultView::printItems() {
+ QList<QTreeWidgetItem*> items = selectedItems();
+ CExportManager mgr(tr("Print search result..."), true, tr("Printing search result"));
+
+ QStringList list;
+ foreach (QTreeWidgetItem* k, items) {
+ list.append( k->text(0) );
+ }
+ mgr.printKeyList( list, module(), CBTConfig::getDisplayOptionDefaults(), CBTConfig::getFilterOptionDefaults() );
+}
+
+void CSearchResultView::saveItems() {
+ CExportManager mgr(tr("Save search result..."), true, tr("Saving search result"));
+
+ CSwordModuleInfo* m = module();
+ CSwordKey* k = 0;
+ QList<QTreeWidgetItem*> items = selectedItems();
+ QList<CSwordKey*> keys;
+ foreach (QTreeWidgetItem* i, items) {
+ k = CSwordKey::createInstance( m );
+ k->key(i->text(0));
+ keys.append( k );
+ }
+ mgr.saveKeyList( keys, CExportManager::Text, false);
+
+ qDeleteAll(keys);
+ keys.clear(); //delete all the keys we created
+}
+
+void CSearchResultView::saveItemsWithText() {
+ CExportManager mgr(tr("Save search result..."), true, tr("Saving search result"));
+
+ CSwordModuleInfo* m = module();
+ CSwordKey* k = 0;
+ QList<QTreeWidgetItem*> items = selectedItems();
+ QList<CSwordKey*> keys;
+ foreach (QTreeWidgetItem* i, items) {
+ k = CSwordKey::createInstance( m );
+ k->key(i->text(0));
+ keys.append( k );
+ };
+ mgr.saveKeyList( keys, CExportManager::Text, true);
+
+ qDeleteAll(keys);
+ keys.clear(); //delete all the keys we created
+}
+
+void CSearchResultView::copyItems() {
+ CExportManager mgr(tr("Copy search result..."), true, tr("Copying search result"));
+
+ CSwordModuleInfo* m = module();
+ CSwordKey* k = 0;
+ QList<QTreeWidgetItem*> items = selectedItems();
+ QList<CSwordKey*> keys;
+ foreach (QTreeWidgetItem* i, items) {
+ k = CSwordKey::createInstance( m );
+ k->key(i->text(0));
+ keys.append( k );
+ };
+ mgr.copyKeyList( keys, CExportManager::Text, false);
+
+ qDeleteAll(keys);
+ keys.clear(); //delete all the keys we created
+}
+
+void CSearchResultView::copyItemsWithText() {
+ CExportManager mgr(tr("Copy search result..."), true, tr("Copying search result"));
+
+ CSwordModuleInfo* m = module();
+ CSwordKey* k = 0;
+ QList<QTreeWidgetItem*> items = selectedItems();
+ QList<CSwordKey*> keys;
+ foreach (QTreeWidgetItem* i, items) {
+ k = CSwordKey::createInstance( m );
+ k->key(i->text(0));
+ keys.append( k );
+ };
+ mgr.copyKeyList( keys, CExportManager::Text, true);
+
+ qDeleteAll(keys);
+ keys.clear(); //delete all the keys we created
+}
+
+CSwordModuleInfo* CSearchResultView::module() {
+ return m_module;
+}
+
+//TODO: port this to the new d'n'd
+// Q3DragObject* CSearchResultView::dragObject() {
+// //return a valid DragObject to make DnD possible!
+//
+// /*
+// * First get all selected items and fill with them the dndItems list. The return the QDragObject we got from CDRagDropMgr
+// */
+// CDragDropMgr::ItemList dndItems;
+//
+// Q3PtrList<Q3ListViewItem> items = selectedItems();
+// for (items.first(); items.current(); items.next()) {
+// dndItems.append( CDragDropMgr::Item(m_module->name(), items.current()->text(0), QString::null) ); //no description
+// };
+//
+// return CDragDropMgr::dragObject(dndItems, viewport());
+// }
+
+
+QMimeData * CSearchResultView::mimeData ( const QList<QTreeWidgetItem *> items ) const
+{
+ BTMimeData* mdata = new BTMimeData(m_module->name(), items.first()->text(0), QString::null);
+ foreach (QTreeWidgetItem* i, items) {
+ mdata->appendBookmark(m_module->name(), i->text(0), QString::null);
+ }
+ return mdata;
+}
+
+QStringList CSearchResultView::mimeTypes () const
+{
+ return QStringList("BibleTime/Bookmark");
+}
+
+} //end of namespace
+
diff --git a/src/frontend/searchdialog/csearchresultview.h b/src/frontend/searchdialog/csearchresultview.h
new file mode 100644
index 0000000..4d43bbf
--- /dev/null
+++ b/src/frontend/searchdialog/csearchresultview.h
@@ -0,0 +1,101 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CSEARCHRESULTSVIEW_H
+#define CSEARCHRESULTSVIEW_H
+
+class CSwordModuleInfo;
+
+#include <QTreeWidget>
+
+//forward declarations
+class QMenu;
+class QAction;
+class CReadDisplay;
+
+namespace Search {
+
+class CSearchResultView : public QTreeWidget {
+ Q_OBJECT
+public:
+ CSearchResultView(QWidget* parent);
+ virtual ~CSearchResultView();
+ /** Returns the module which is currently used. */
+ CSwordModuleInfo* module();
+
+protected: // Protected methods
+ /**
+ * Initializes the view of this widget.
+ */
+ void initView();
+ void initConnections();
+
+ //from QTreeWidget
+ virtual QMimeData * mimeData ( const QList<QTreeWidgetItem *> items ) const;
+ virtual QStringList mimeTypes () const;
+
+public slots: // Public slots
+ void saveItems();
+ /**
+ * Setups the list with the given module.
+ */
+ void setupTree(CSwordModuleInfo*);
+ void setupStrongsTree(CSwordModuleInfo*, QStringList*);
+ void copyItemsWithText();
+ void copyItems();
+ void saveItemsWithText();
+ /**
+ * Reimplementation to show the popup menu.
+ */
+ virtual void contextMenuEvent(QContextMenuEvent* event);
+
+protected slots: // Protected slots
+ void printItems();
+
+ /**
+ * Is connected to the signal which is emitted when a new item was chosen.
+ */
+ void executed(QTreeWidgetItem* current, QTreeWidgetItem*);
+
+private:
+ struct {
+ QMenu* saveMenu;
+ struct {
+ QAction* result;
+ QAction* resultWithText;
+ }
+ save;
+
+ QMenu* printMenu;
+ struct {
+ QAction* result;
+ }
+ print;
+
+ QMenu* copyMenu;
+ struct {
+ QAction* result;
+ QAction* resultWithText;
+ }
+ copy;
+ }
+ m_actions;
+
+ QMenu* m_popup;
+ CSwordModuleInfo* m_module;
+
+signals: // Signals
+ void keySelected(const QString&);
+ void keyDeselected();
+};
+
+} //end of namespace Search
+
+#endif
+
diff --git a/src/frontend/settingsdialogs/cacceleratorsettings.cpp.OFF b/src/frontend/settingsdialogs/cacceleratorsettings.cpp.OFF
new file mode 100644
index 0000000..66fa9dc
--- /dev/null
+++ b/src/frontend/settingsdialogs/cacceleratorsettings.cpp.OFF
@@ -0,0 +1,268 @@
+//
+// C++ Implementation: cacceleratorsettings
+//
+// Description:
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 1999-2008
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#include "cacceleratorsettings.h"
+#include "cacceleratorsettings.moc"
+
+#include "backend/config/cbtconfig.h"
+
+#include "frontend/displaywindow/cbiblereadwindow.h"
+#include "frontend/displaywindow/ccommentaryreadwindow.h"
+#include "frontend/displaywindow/clexiconreadwindow.h"
+#include "frontend/displaywindow/cbookreadwindow.h"
+#include "frontend/displaywindow/creadwindow.h"
+
+#include <QWidget>
+#include <QComboBox>
+#include <QStackedWidget>
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QLabel>
+#include <QList>
+
+#include <kactioncollection.h>
+
+
+
+CAcceleratorSettingsPage::CAcceleratorSettingsPage(QWidget *parent)
+ : QWidget(parent)
+{
+ qDebug("CAcceleratorSettingsPage::CAcceleratorSettingsPage");
+ //TODO: widget layout may not work. Maybe it would be easier to use .ui file.
+
+ QVBoxLayout* mainLayout = new QVBoxLayout(this);
+ this->setLayout(mainLayout);
+ //TODO: actionCollection must exist, but is this the right way?
+ m_application.actionCollection = new KActionCollection(this);
+ CBTConfig::setupAccelSettings(
+ CBTConfig::application,
+ m_application.actionCollection
+ );
+ qDebug("create layout for window type chooser");
+ QHBoxLayout* layoutForWindowTypeChooser = new QHBoxLayout(this);
+ mainLayout->addLayout(layoutForWindowTypeChooser);
+ QLabel* label = new QLabel(tr("Choose type:"), this);
+ layoutForWindowTypeChooser->addWidget(label);
+ m_typeChooser = new QComboBox(this);
+ layoutForWindowTypeChooser->addWidget(m_typeChooser);
+
+ connect(
+ m_typeChooser, SIGNAL(activated(const QString&)),
+ SLOT(slotKeyChooserTypeChanged(const QString&))
+ );
+ //too ugly! change!
+ //QLabel* dummy = new QLabel( this); // empty label for stretch
+ //hbox->addWidget(dummy);
+
+ //hbox->setStretchFactor(label, 0);
+ //hbox->setStretchFactor(m_typeChooser, 0);
+ //hbox->setStretchFactor(dummy, 1);
+
+ //mainLayout->setStretchFactor(hbox, 0);
+ qDebug("create stack");
+ m_keyChooserStack = new QStackedWidget(this);
+
+ //mainLayout->setStretchFactor(m_keyChooserStack, 5);
+
+ m_application.title = tr("BibleTime"); //don't set the app action collection to NULL
+ m_general = WindowType(tr("All text windows"));
+ m_bible = WindowType(tr("Bible windows"));
+ m_commentary = WindowType(tr("Commentary windows"));
+ m_lexicon = WindowType(tr("Lexicon windows"));
+ m_book = WindowType(tr("Book windows"));
+
+ m_typeChooser->addItem(m_application.title);
+ m_typeChooser->addItem(m_general.title);
+ m_typeChooser->addItem(m_bible.title);
+ m_typeChooser->addItem(m_commentary.title);
+ m_typeChooser->addItem(m_lexicon.title);
+ m_typeChooser->addItem(m_book.title);
+
+ qDebug("create shortcuteditors");
+ Q_ASSERT(m_application.actionCollection);
+ m_application.keyChooser = new KShortcutsEditor(
+ m_application.actionCollection,
+ m_keyChooserStack
+ );
+ qDebug("add first w");
+ m_keyChooserStack->addWidget(m_application.keyChooser);
+
+ // ----- All display windows ------ //
+ m_general.actionCollection = new KActionCollection(this);
+ CDisplayWindow::insertKeyboardActions( m_general.actionCollection);
+ CBTConfig::setupAccelSettings(
+ CBTConfig::allWindows,
+ m_general.actionCollection
+ );
+ m_general.keyChooser = new KShortcutsEditor(
+ m_general.actionCollection,
+ m_keyChooserStack
+ );
+ qDebug("add second w");
+ m_keyChooserStack->addWidget(m_general.keyChooser);
+
+ // ----- Bible windows ------ //
+ m_bible.actionCollection = new KActionCollection(this);
+ CBibleReadWindow::insertKeyboardActions( m_bible.actionCollection);
+ CBTConfig::setupAccelSettings(
+ CBTConfig::bibleWindow,
+ m_bible.actionCollection
+ );
+ //m_keyChooserStack->addWidget(m_bible.keyChooser);
+
+ // ----- Commentary windows ------ //
+ m_commentary.actionCollection = new KActionCollection(this);
+ CCommentaryReadWindow::insertKeyboardActions( m_commentary.actionCollection);
+ CBTConfig::setupAccelSettings(
+ CBTConfig::commentaryWindow,
+ m_commentary.actionCollection
+ );
+ //m_keyChooserStack->addWidget(m_commentary.keyChooser);
+
+ // ----- Lexicon windows ------ //
+ m_lexicon.actionCollection = new KActionCollection(this);
+ CLexiconReadWindow::insertKeyboardActions( m_lexicon.actionCollection );
+ CBTConfig::setupAccelSettings(
+ CBTConfig::lexiconWindow,
+ m_lexicon.actionCollection
+ );
+ //m_keyChooserStack->addWidget(m_lexicon.keyChooser);
+
+ // ----- Book windows ------ //
+ m_book.actionCollection= new KActionCollection(this);
+ CBookReadWindow::insertKeyboardActions( m_book.actionCollection);
+ CBTConfig::setupAccelSettings(
+ CBTConfig::bookWindow,
+ m_book.actionCollection
+ );
+ //m_keyChooserStack->addWidget(m_book.keyChooser);
+
+ mainLayout->addWidget(m_keyChooserStack);
+ slotKeyChooserTypeChanged(m_application.title);
+
+ qDebug("CAcceleratorSettingsPage::CAcceleratorSettingsPage end");
+}
+
+
+CAcceleratorSettingsPage::~CAcceleratorSettingsPage()
+{
+}
+
+void CAcceleratorSettingsPage::save()
+{
+ /* //TODO: does kde4 work without commitChanges?
+ if (m_general.keyChooser) {
+ m_general.keyChooser->commitChanges();
+ }
+
+ if (m_bible.keyChooser) {
+ m_bible.keyChooser->commitChanges();
+ }
+
+ if (m_commentary.keyChooser) {
+ m_commentary.keyChooser->commitChanges();
+ }
+
+ if (m_lexicon.keyChooser) {
+ m_lexicon.keyChooser->commitChanges();
+ }
+
+ if (m_book.keyChooser) {
+ m_book.keyChooser->commitChanges();
+ }
+ */
+ CBTConfig::saveAccelSettings( //application
+ CBTConfig::application,
+ m_application.actionCollection
+ );
+ CBTConfig::saveAccelSettings( //read display windows
+ CBTConfig::allWindows,
+ m_general.actionCollection
+ );
+ CBTConfig::saveAccelSettings( //bible
+ CBTConfig::bibleWindow,
+ m_bible.actionCollection
+ );
+ CBTConfig::saveAccelSettings( //commentary
+ CBTConfig::commentaryWindow,
+ m_commentary.actionCollection
+ );
+ CBTConfig::saveAccelSettings( //lexicon
+ CBTConfig::lexiconWindow,
+ m_lexicon.actionCollection
+ );
+ CBTConfig::saveAccelSettings( //book
+ CBTConfig::bookWindow,
+ m_book.actionCollection
+ );
+}
+
+
+void CAcceleratorSettingsPage::slotKeyChooserTypeChanged(const QString& title)
+{
+ qDebug("CAcceleratorSettingsPage::slotKeyChooserTypeChanged");
+ //delete all KShortcutsEditors which may not share accels, because this class checks in all instances for key conflicts
+ typedef QList<KShortcutsEditor*> KeyChooserList;
+ KeyChooserList list;
+ list.append(m_bible.keyChooser);
+ list.append(m_commentary.keyChooser);
+ list.append(m_lexicon.keyChooser);
+ list.append(m_book.keyChooser);
+
+ //commit all changes in the keychoosers
+ //for (KeyChooserList::iterator it(list.begin()); it != list.end(); ++it) {
+ // if (*it) { //the list may contain NULL pointers
+ // (*it)->commitChanges();
+ // }
+ //}
+
+ /* Delete all the keychoosers in the list,
+ * the keychoosers are set to NULL, because they are QGuardedPtr
+ */
+ //list.setAutoDelete(true);
+ qDeleteAll(list);
+ list.clear();
+
+ WindowType* t = 0;
+ if (title == m_application.title) { //Application wide
+ t = &m_application;
+ }
+ else if (title == m_general.title) { // All display windows
+ t = &m_general;
+ }
+ else if (title == m_bible.title) { // Bible windows
+ t = &m_bible;
+ }
+ else if (title == m_commentary.title) { // Commentary windows
+ t = &m_commentary;
+ }
+ else if (title == m_lexicon.title) { // Lexicon windows
+ t = &m_lexicon;
+ }
+ else if (title == m_book.title) { // Book windows
+ t = &m_book;
+ }
+
+ Q_ASSERT(t);
+ if (!t->keyChooser) { //was deleted, create a new one
+ t->keyChooser = new KShortcutsEditor(
+ m_keyChooserStack
+ );
+ t->keyChooser->addCollection(
+ t->actionCollection,
+ t->title
+ );
+ }
+
+ m_keyChooserStack->setCurrentWidget(t->keyChooser);
+ qDebug("CAcceleratorSettingsPage::slotKeyChooserTypeChanged end");
+}
diff --git a/src/frontend/settingsdialogs/cacceleratorsettings.h.OFF b/src/frontend/settingsdialogs/cacceleratorsettings.h.OFF
new file mode 100644
index 0000000..adf0b95
--- /dev/null
+++ b/src/frontend/settingsdialogs/cacceleratorsettings.h.OFF
@@ -0,0 +1,72 @@
+//
+// C++ Interface: cacceleratorsettings
+//
+// Description:
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 1999-2008
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CACCELERATORSETTINGS_H
+#define CACCELERATORSETTINGS_H
+
+#include <QWidget>
+#include <QPointer>
+
+#include <kshortcutseditor.h>
+
+class QComboBox;
+class QStackedWidget;
+class KActionCollection;
+
+/**
+ @author The BibleTime team <info@bibletime.info>
+*/
+class CAcceleratorSettingsPage : public QWidget
+{
+ Q_OBJECT
+
+public:
+ CAcceleratorSettingsPage(QWidget *parent);
+
+ ~CAcceleratorSettingsPage();
+
+ void save();
+
+protected slots:
+
+ void slotKeyChooserTypeChanged(const QString& title);
+
+private:
+
+ struct WindowType {
+ QPointer<KShortcutsEditor> keyChooser;
+ KActionCollection* actionCollection;
+ QString title;
+
+ WindowType() {
+ keyChooser = 0;
+ actionCollection = 0;
+ };
+ WindowType(const QString& newTitle) {
+ title = newTitle;
+ keyChooser = 0;
+ actionCollection = 0;
+ }
+ };
+
+ WindowType m_application;
+ WindowType m_general;
+ WindowType m_bible;
+ WindowType m_commentary;
+ WindowType m_lexicon;
+ WindowType m_book;
+
+ QComboBox* m_typeChooser;
+ QStackedWidget* m_keyChooserStack;
+
+};
+
+#endif
diff --git a/src/frontend/settingsdialogs/cconfigurationdialog.cpp b/src/frontend/settingsdialogs/cconfigurationdialog.cpp
new file mode 100644
index 0000000..f3bf536
--- /dev/null
+++ b/src/frontend/settingsdialogs/cconfigurationdialog.cpp
@@ -0,0 +1,93 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cconfigurationdialog.h"
+
+#include "cdisplaysettings.h"
+#include "cswordsettings.h"
+#include "clanguagesettings.h"
+//#include "cacceleratorsettings.h"
+
+#include "util/cpointers.h"
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+#include "util/dialogutil.h"
+
+#include <QWidget>
+#include <QDialogButtonBox>
+#include <QAbstractButton>
+#include <QPushButton>
+#include <QLayout>
+
+CConfigurationDialog::CConfigurationDialog(QWidget * parent, BtActionCollection* actionCollection )
+ : BtConfigDialog(parent),
+ m_actionCollection(actionCollection),
+ m_displayPage(0),
+ m_swordPage(0),
+ m_acceleratorsPage(0),
+ m_languagesPage(0),
+ m_bbox(0)
+{
+ setWindowTitle(tr("Configure BibleTime"));
+ setAttribute(Qt::WA_DeleteOnClose);
+
+ // Add "Display" page
+ m_displayPage = new CDisplaySettingsPage(this);
+ addPage(m_displayPage);
+
+ // Add "Desk" (sword) page
+ m_swordPage = new CSwordSettingsPage(this);
+ addPage(m_swordPage);
+
+ // Add "Languages" (fonts) page
+ m_languagesPage = new CLanguageSettingsPage(this);
+ addPage(m_languagesPage);
+
+// // Add "Keyboard" (accelerators) page
+// m_acceleratorsPage = new CAcceleratorSettingsPage(this);
+// KPageWidgetItem* accelPage = new KPageWidgetItem(m_acceleratorsPage);
+// accelPage->setHeader( tr( "HotKeys" ) );
+// accelPage->setName( tr( "HotKeys" ) );
+// accelPage->setIcon( KIcon(util::filesystem::DirectoryUtil::getIcon(CResMgr::settings::keys::icon)) );
+// addPage(accelPage);
+
+ // Dialog buttons
+ m_bbox = new QDialogButtonBox(this);
+ m_bbox->addButton(QDialogButtonBox::Ok);
+ m_bbox->addButton(QDialogButtonBox::Apply);
+ m_bbox->addButton(QDialogButtonBox::Cancel);
+ util::prepareDialogBox(m_bbox);
+ addButtonBox(m_bbox);
+ bool ok = connect(m_bbox, SIGNAL(clicked(QAbstractButton *)), SLOT(slotButtonClicked(QAbstractButton *)));
+ Q_ASSERT(ok);
+
+ slotChangePage(0);
+}
+
+CConfigurationDialog::~CConfigurationDialog() {}
+
+/** Called if any button was clicked*/
+void CConfigurationDialog::slotButtonClicked(QAbstractButton* button)
+{
+ if (button == static_cast<QAbstractButton*>(m_bbox->button(QDialogButtonBox::Cancel)))
+ {
+ close();
+ return;
+ }
+
+// m_acceleratorsPage->save();
+ m_languagesPage->save();
+ m_swordPage->save();
+ m_displayPage->save();
+ emit signalSettingsChanged( );
+
+ if (button == static_cast<QAbstractButton*>(m_bbox->button(QDialogButtonBox::Ok)))
+ close();
+}
+
diff --git a/src/frontend/settingsdialogs/cconfigurationdialog.h b/src/frontend/settingsdialogs/cconfigurationdialog.h
new file mode 100644
index 0000000..f7a1718
--- /dev/null
+++ b/src/frontend/settingsdialogs/cconfigurationdialog.h
@@ -0,0 +1,49 @@
+//
+// C++ Interface: cconfigurationdialog
+//
+// Description: BibleTime Configuration dialog.
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 1999-2008
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#ifndef CCONFIGURATIONDIALOG_H
+#define CCONFIGURATIONDIALOG_H
+
+#include "frontend/bookshelfmanager/btconfigdialog.h"
+
+class QWidget;
+class QAbstractButton;
+
+class CDisplaySettingsPage;
+class CSwordSettingsPage;
+class CLanguageSettingsPage;
+class CAcceleratorSettingsPage;
+class QDialogButtonBox;
+class BtActionCollection;
+
+class CConfigurationDialog : public BtConfigDialog {
+ Q_OBJECT
+
+public:
+ CConfigurationDialog(QWidget *parent, BtActionCollection* actionCollection);
+ virtual ~CConfigurationDialog();
+protected slots:
+ void slotButtonClicked(QAbstractButton *);
+private:
+ BtActionCollection* m_actionCollection;
+ CDisplaySettingsPage* m_displayPage;
+ CSwordSettingsPage* m_swordPage;
+ CAcceleratorSettingsPage* m_acceleratorsPage;
+ CLanguageSettingsPage* m_languagesPage;
+ QDialogButtonBox* m_bbox;
+
+signals:
+ void signalSettingsChanged();
+};
+
+
+#endif
diff --git a/src/frontend/settingsdialogs/cdisplaysettings.cpp b/src/frontend/settingsdialogs/cdisplaysettings.cpp
new file mode 100644
index 0000000..f04006e
--- /dev/null
+++ b/src/frontend/settingsdialogs/cdisplaysettings.cpp
@@ -0,0 +1,199 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cdisplaysettings.h"
+
+#include "backend/config/cbtconfig.h"
+#include "backend/rendering/cdisplayrendering.h"
+#include "backend/managers/cdisplaytemplatemgr.h"
+
+#include "util/cresmgr.h"
+#include "util/ctoolclass.h"
+#include "util/cpointers.h"
+
+#include <QWebView>
+#include <QCheckBox>
+#include <QComboBox>
+#include <QVBoxLayout>
+#include <QLabel>
+
+// ***********************
+// Container for QWebView to control its size
+class CWebViewerWidget : public QWidget
+{
+ public:
+ CWebViewerWidget(QWidget* parent = 0);
+ ~CWebViewerWidget();
+ virtual QSize sizeHint () const;
+};
+
+CWebViewerWidget::CWebViewerWidget(QWidget* parent)
+ : QWidget(parent)
+{
+}
+
+CWebViewerWidget::~CWebViewerWidget()
+{
+}
+
+QSize CWebViewerWidget::sizeHint () const
+{
+ return QSize(100,100);
+}
+// ************************
+
+/** Initializes the startup section of the OD. */
+CDisplaySettingsPage::CDisplaySettingsPage(QWidget* /*parent*/)
+ : BtConfigPage()
+{
+ QVBoxLayout* layout = new QVBoxLayout(this);
+
+ { //startup logo
+ m_showLogoCheck = new QCheckBox(this);
+ m_showLogoCheck->setText(tr("Show startup logo"));
+ m_showLogoCheck->setToolTip(tr("Show the BibleTime logo on startup"));
+
+ m_showLogoCheck->setChecked(CBTConfig::get(CBTConfig::logo));
+ layout->addWidget(m_showLogoCheck);
+ }
+ layout->addSpacing(20);
+
+ layout->addWidget(
+ CToolClass::explanationLabel(
+ this,
+ tr("Display templates"),
+ tr("Display templates define how text is displayed.")
+ )
+ );
+
+ QHBoxLayout* hboxlayout = new QHBoxLayout();
+
+ m_styleChooserCombo = new QComboBox( this ); //create first to enable buddy for label
+ connect( m_styleChooserCombo, SIGNAL( activated( int ) ),
+ this, SLOT( updateStylePreview() ) );
+
+ QLabel* availableLabel = new QLabel(tr("Available display styles:"), this);
+ availableLabel->setBuddy(m_styleChooserCombo);
+ hboxlayout->addWidget(availableLabel);
+ hboxlayout->addWidget( m_styleChooserCombo );
+ hboxlayout->addStretch();
+ layout->addLayout( hboxlayout );
+
+ QWidget* webViewWidget = new CWebViewerWidget(this);
+ QLayout* webViewLayout = new QVBoxLayout(webViewWidget);
+ m_stylePreviewViewer = new QWebView(webViewWidget);
+ QLabel* previewLabel = new QLabel(tr("Style preview"), webViewWidget);
+ previewLabel->setBuddy(m_stylePreviewViewer);
+ webViewLayout->addWidget(previewLabel);
+ webViewLayout->addWidget(m_stylePreviewViewer);
+ webViewWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
+ layout->addWidget(webViewWidget);
+
+ m_styleChooserCombo->addItems(
+ CPointers::displayTemplateManager()->availableTemplates()
+ );
+
+ for (int i = 0; i < m_styleChooserCombo->count(); ++i)
+ {
+ if ( m_styleChooserCombo->itemText(i) == CBTConfig::get(CBTConfig::displayStyle) )
+ {
+ m_styleChooserCombo->setCurrentIndex( i );
+ break;
+ }
+ }
+
+ updateStylePreview(); //render it
+}
+
+
+void CDisplaySettingsPage::updateStylePreview()
+{
+ //update the style preview widget
+ qDebug("CDisplaySettingsPage::updateStylePreview");
+ using namespace Rendering;
+
+ const QString styleName = m_styleChooserCombo->currentText();
+ qDebug() << "style name: " << styleName;
+ CTextRendering::KeyTree tree;
+
+ CTextRendering::KeyTreeItem::Settings settings;
+ settings.highlight = false;
+
+ tree.append( new CTextRendering::KeyTreeItem(
+ QString("\n<span class=\"entryname\"><a name=\"John316\" href=\"sword://Bible/WEB/John 3:16\">16</a></span>%1")
+ .arg(tr("For God so loved the world, that he gave his one and only Son, that whoever believes in him should not perish, but have eternal life.")),
+ settings));
+
+ settings.highlight = true;
+
+ tree.append( new CTextRendering::KeyTreeItem(
+ QString("\n<span class=\"entryname\"><a name=\"John317\" href=\"sword://Bible/WEB/John 3:17\">17</a></span>%1")
+ .arg(tr("For God didn't send his Son into the world to judge the world, but that the world should be saved through him.")),
+ settings));
+
+ settings.highlight = false;
+
+ tree.append( new CTextRendering::KeyTreeItem(
+ QString("\n<span class=\"entryname\"><a name=\"John318\" href=\"sword://Bible/WEB/John 3:18\">18</a></span>%1")
+ .arg(tr("He who believes in him is not judged. He who doesn't believe has been judged already, because he has not believed in the name of the one and only Son of God.")),
+ settings) );
+
+ tree.append( new CTextRendering::KeyTreeItem(
+ QString("\n<span class=\"entryname\"><a name=\"John319\" href=\"sword://Bible/WEB/John 3:19\">19</a></span>%1")
+ .arg(tr("This is the judgment, that the light has come into the world, and men loved the darkness rather than the light; for their works were evil.")),
+ settings));
+
+ tree.append( new CTextRendering::KeyTreeItem(
+ QString("\n<span class=\"entryname\"><a name=\"John320\" href=\"sword://Bible/WEB/John 3:20\">20</a></span>%1<br/>")
+ .arg(tr("For everyone who does evil hates the light, and doesn't come to the light, lest his works would be exposed.")),
+ settings));
+
+ tree.append( new CTextRendering::KeyTreeItem(
+ QString("\n<span class=\"entryname\"><a name=\"John321\" href=\"sword://Bible/WEB/John 3:21\">21</a></span>%1")
+ .arg(tr("But he who does the truth comes to the light, that his works may be revealed, that they have been done in God.")),
+ settings));
+
+ const QString oldStyleName = CBTConfig::get
+ (CBTConfig::displayStyle);
+ //qDebug() << "old style name: " << oldStyleName;
+ CBTConfig::set
+ (CBTConfig::displayStyle, styleName);
+ //qDebug() << "new style name: " << CBTConfig::get(CBTConfig::displayStyle);
+ CDisplayRendering render;
+ m_stylePreviewViewer->setHtml( render.renderKeyTree(tree));
+
+ CBTConfig::set
+ (CBTConfig::displayStyle, oldStyleName);
+ qDebug("CDisplaySettingsPage::updateStylePreview end");
+}
+
+void CDisplaySettingsPage::save()
+{
+ CBTConfig::set
+ ( CBTConfig::logo, m_showLogoCheck->isChecked() );
+ CBTConfig::set
+ ( CBTConfig::displayStyle, m_styleChooserCombo->currentText() );
+}
+
+// implement the BtConfigPage methods
+
+QString CDisplaySettingsPage::iconName()
+{
+ return CResMgr::settings::startup::icon;
+}
+QString CDisplaySettingsPage::label()
+{
+ //: Empty string, don't translate
+ return tr("");
+}
+QString CDisplaySettingsPage::header()
+{
+ return tr("Display");
+}
+
diff --git a/src/frontend/settingsdialogs/cdisplaysettings.h b/src/frontend/settingsdialogs/cdisplaysettings.h
new file mode 100644
index 0000000..faa929b
--- /dev/null
+++ b/src/frontend/settingsdialogs/cdisplaysettings.h
@@ -0,0 +1,43 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+#ifndef CDISPLAYSETTINGS_H
+#define CDISPLAYSETTINGS_H
+
+#include "frontend/bookshelfmanager/btconfigdialog.h"
+
+#include <QWidget>
+
+class QCheckBox;
+class QComboBox;
+class QWebView;
+
+class CDisplaySettingsPage : public BtConfigPage
+{
+ Q_OBJECT
+
+public:
+ CDisplaySettingsPage(QWidget* parent);
+ void save();
+ QString iconName();
+ QString label();
+ QString header();
+
+protected slots:
+ /** Update the style preview widget. */
+ void updateStylePreview();
+
+private:
+ QCheckBox* m_showLogoCheck;
+ QComboBox* m_styleChooserCombo;
+ QWebView* m_stylePreviewViewer;
+};
+
+#endif
diff --git a/src/frontend/settingsdialogs/cfontchooser.cpp b/src/frontend/settingsdialogs/cfontchooser.cpp
new file mode 100644
index 0000000..f755e57
--- /dev/null
+++ b/src/frontend/settingsdialogs/cfontchooser.cpp
@@ -0,0 +1,359 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cfontchooser.h"
+#include "clistwidget.h"
+#include <QVBoxLayout>
+#include <QLabel>
+#include <QListWidget>
+#include <QFrame>
+#include <QFontDatabase>
+#include <QListWidgetItem>
+#include <QWebSettings>
+#include <QFrame>
+#include <QWebView>
+
+
+// ***********************
+// Container for KHTHMView to control its size
+class WebViewerWidget : public QWidget
+{
+ public:
+ WebViewerWidget(QWidget* parent = 0);
+ ~WebViewerWidget();
+ virtual QSize sizeHint () const;
+};
+
+WebViewerWidget::WebViewerWidget(QWidget* parent)
+ : QWidget(parent)
+{
+}
+
+WebViewerWidget::~WebViewerWidget()
+{
+}
+
+QSize WebViewerWidget::sizeHint () const
+{
+ return QSize(100,85);
+}
+// ************************
+
+
+
+CFontChooser::CFontChooser(QWidget* parent)
+ : QFrame(parent), m_fontWidget(0),
+ m_fontListWidget(0), m_styleListWidget(0), m_sizeListWidget(0)
+{
+ setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ createLayout();
+ connectListWidgets();
+ loadFonts();
+ setFrameStyle(QFrame::Box);
+ setFrameShadow(QFrame::Raised);
+}
+
+
+CFontChooser::~CFontChooser()
+{
+}
+
+
+void CFontChooser::createFontAreaLayout()
+{
+ QHBoxLayout* fontStyleSizeHBoxLayout = new QHBoxLayout();
+
+ // font column
+ QVBoxLayout* fontLayout = new QVBoxLayout();
+ fontStyleSizeHBoxLayout->addLayout(fontLayout);
+
+ QLabel* fontLabel = new QLabel(tr("Font name:"));
+ fontLayout->addWidget(fontLabel);
+
+ m_fontListWidget = new CListWidget();
+ m_fontListWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
+ fontLayout->addWidget(m_fontListWidget);
+
+ // style column
+ QVBoxLayout* styleLayout = new QVBoxLayout();
+ fontStyleSizeHBoxLayout->addLayout(styleLayout);
+
+ QLabel* styleLabel = new QLabel(tr("Font style:"));
+ styleLayout->addWidget(styleLabel);
+
+ m_styleListWidget = new CListWidget();
+ m_styleListWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
+ m_styleListWidget->setCharWidth(12);
+ styleLayout->addWidget(m_styleListWidget);
+
+ // size column
+ QVBoxLayout* sizeLayout = new QVBoxLayout();
+ fontStyleSizeHBoxLayout->addLayout(sizeLayout);
+
+ QLabel* sizeLabel = new QLabel(tr("Size:"));
+ sizeLayout->addWidget(sizeLabel);
+
+ m_sizeListWidget = new CListWidget();
+ m_sizeListWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
+ m_sizeListWidget->setCharWidth(5);
+ sizeLayout->addWidget(m_sizeListWidget);
+
+ m_vBoxLayout->addLayout(fontStyleSizeHBoxLayout);
+}
+
+
+void CFontChooser::createLayout()
+{
+ m_vBoxLayout = new QVBoxLayout(this);
+ createFontAreaLayout();
+ createTextAreaLayout();
+}
+
+
+void CFontChooser::createTextAreaLayout()
+{
+ QWidget* webViewWidget = new WebViewerWidget(this);
+ QLayout* webViewLayout = new QVBoxLayout(webViewWidget);
+
+ m_webView = new QWebView(webViewWidget);
+ webViewLayout->addWidget(m_webView);
+ m_vBoxLayout->addWidget(webViewWidget);
+}
+
+
+void CFontChooser::connectListWidgets()
+{
+
+ bool ok = connect(
+ m_fontListWidget,
+ SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
+ this,
+ SLOT(fontChanged(QListWidgetItem *, QListWidgetItem *)));
+ Q_ASSERT(ok);
+
+ ok = connect(
+ m_styleListWidget,
+ SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
+ this,
+ SLOT(styleChanged(QListWidgetItem *, QListWidgetItem *)));
+ Q_ASSERT(ok);
+
+ ok = connect(
+ m_sizeListWidget,
+ SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
+ this,
+ SLOT(sizeChanged(QListWidgetItem *, QListWidgetItem *)));
+ Q_ASSERT(ok);
+}
+
+
+void CFontChooser::fontChanged(QListWidgetItem* current, QListWidgetItem* /*previous*/)
+{
+ if (current == 0)
+ return;
+ QString fontFamily = current->text();
+ m_font.setFamily(fontFamily);
+ loadStyles(fontFamily);
+ outputHtmlText();
+ emit fontSelected(m_font);
+}
+
+
+QString CFontChooser::formatAsHtml(const QString& text)
+{
+
+ QString htmlText;
+ htmlText.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ htmlText.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
+ htmlText.append("<html xmlns=\"http://www.w3.org/1999/xhtml\">\n");
+ htmlText.append("<head>\n");
+ htmlText.append(" <style type=\"text/css\">\n");
+ htmlText.append(" *[lang=en] { font-family:#FONT-FAMILY#; font-size:#FONT-SIZE#pt; font-weight:#FONT-WEIGHT#; font-style:#FONT-STYLE#; }\n");
+ htmlText.append(" </style>\n");
+ htmlText.append("</head>\n");
+ htmlText.append("<body>\n");
+ htmlText.append(" <div>\n");
+ htmlText.append(" <div style=\"display: inline;\" lang=\"en\">\n");
+ htmlText.append(text);
+ htmlText.append(" </div>\n");
+ htmlText.append("</body>\n");
+ htmlText.append("</html>\n");
+ return htmlText;
+}
+
+
+void CFontChooser::loadFonts()
+{
+ m_fontListWidget->clear();
+ QFontDatabase database;
+ foreach (QString font, database.families()) {
+ m_fontListWidget->addItem(font);
+ }
+ // This triggers loading the styles for the first font
+ m_fontListWidget->setCurrentRow(0);
+}
+
+
+void CFontChooser::loadStyles(const QString& font)
+{
+ m_styleListWidget->clear();
+ QFontDatabase database;
+ foreach (QString style, database.styles(font))
+ {
+ m_styleListWidget->addItem(style);
+ // This triggers loading the sizes for the first style
+ restoreListWidgetValue(m_styleListWidget,m_choosenStyle);
+ }
+}
+
+
+void CFontChooser::loadSizes(const QString& font, const QString& style)
+{
+
+ QString saveText = saveListWidgetValue(m_sizeListWidget);
+
+ // Put new values into listWidget
+ m_sizeListWidget->clear();
+ QFontDatabase database;
+ foreach (int size, database.pointSizes(font, style))
+ {
+ m_sizeListWidget->addItem(QString::number(size));
+ }
+
+ restoreListWidgetValue(m_sizeListWidget, saveText);
+}
+
+
+void CFontChooser::outputHtmlText()
+{
+ QString text = formatAsHtml(m_htmlText);
+ text.replace("#FONT-FAMILY#", m_font.family());
+ text.replace("#FONT-SIZE#", QString::number(m_font.pointSize()));
+ text.replace("#FONT-WEIGHT#", (m_font.bold() ? "bold" : "normal") );
+ text.replace("#FONT-STYLE#", m_font.italic() ? "italic" : "normal");
+ m_webView->setHtml(text);
+}
+
+
+void CFontChooser::restoreListWidgetValue(QListWidget* listWidget, const QString& value)
+{
+ if (value == "") {
+ listWidget->setCurrentRow(0);
+ return;
+ }
+
+ for (int i=0; i< listWidget->count(); i++)
+ {
+ if (listWidget->item(i)->text() == value)
+ {
+ listWidget->setCurrentRow(i);
+ return;
+ }
+ }
+ listWidget->setCurrentRow(0);
+}
+
+
+QString CFontChooser::saveListWidgetValue(QListWidget* listWidget)
+{
+ QString saveText;
+ int row = listWidget->currentRow();
+ if (row >= 0) {
+ saveText = listWidget->item(row)->text();
+ }
+ return saveText;
+}
+
+
+void CFontChooser::setFont(const QFont& font)
+{
+ disconnect(m_fontListWidget, 0, 0, 0);
+ disconnect(m_styleListWidget, 0, 0, 0);
+ disconnect(m_sizeListWidget, 0, 0, 0);
+
+ // set the font
+ m_font = font;
+ restoreListWidgetValue(m_fontListWidget, m_font.family());
+
+ // set the style
+ loadStyles( m_font.family());
+ QFontDatabase database;
+ QString styleString = database.styleString(m_font);
+ m_choosenStyle = styleString;
+ restoreListWidgetValue(m_styleListWidget, styleString);
+
+ // set the size
+ loadSizes(m_font.family(), styleString);
+ restoreListWidgetValue(m_sizeListWidget, QString::number(m_font.pointSize()) );
+
+ outputHtmlText();
+ connectListWidgets();
+}
+
+
+void CFontChooser::setFontStyle(const QString& styleString, QFont* font)
+{
+ if (styleString.contains("bold",Qt::CaseInsensitive))
+ font->setBold(true);
+ else
+ font->setBold(false);
+
+ if (styleString.contains("italic",Qt::CaseInsensitive) || styleString.contains("oblique",Qt::CaseInsensitive) )
+ font->setItalic(true);
+ else
+ font->setItalic(false);
+}
+
+
+void CFontChooser::setSampleText(const QString& htmlText)
+{
+ m_htmlText = htmlText;
+ outputHtmlText();
+}
+
+
+void CFontChooser::sizeChanged(QListWidgetItem* current, QListWidgetItem* /*previous*/)
+{
+ if (current == 0)
+ return;
+
+ QString size = m_sizeListWidget->currentItem()->text();
+ m_font.setPointSize(size.toInt());
+
+ outputHtmlText();
+ emit fontSelected(m_font);
+}
+
+
+QSize CFontChooser::sizeHint() const
+{
+ return QSize(170,170);
+}
+
+void CFontChooser::styleChanged(QListWidgetItem* current, QListWidgetItem* /*previous*/)
+{
+ if (current == 0)
+ return;
+
+ QString styleString = current->text();
+ setFontStyle(styleString, &m_font);
+
+ // Save style if the user choose it
+ bool focus = m_styleListWidget->hasFocus();
+ if (focus)
+ m_choosenStyle = styleString;
+
+ QString font = m_fontListWidget->currentItem()->text();
+ loadSizes(font, styleString);
+
+ outputHtmlText();
+ emit fontSelected(m_font);
+}
+
+
diff --git a/src/frontend/settingsdialogs/cfontchooser.h b/src/frontend/settingsdialogs/cfontchooser.h
new file mode 100644
index 0000000..028fda9
--- /dev/null
+++ b/src/frontend/settingsdialogs/cfontchooser.h
@@ -0,0 +1,74 @@
+//
+// C++ Interface: CFontChooser
+//
+// Description: BibleTime font chooser
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 1999-2008
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#ifndef CFONTCHOOSER_H
+#define CFONTCHOOSER_H
+
+// These following two defines allow chosing between using KDE and
+// Qt only for rendering the preview text
+
+
+#include <QWidget>
+#include <QFrame>
+
+class QString;
+class QFrame;
+class QListWidget;
+class QListWidgetItem;
+class QVBoxLayout;
+class QWebView;
+class CListWidget;
+
+class CFontChooser : public QFrame {
+ Q_OBJECT
+
+public:
+ CFontChooser(QWidget* parent = 0);
+ ~CFontChooser();
+ void setFont(const QFont& font);
+ void setSampleText(const QString& text);
+ QSize sizeHint() const;
+
+private:
+ void createFontAreaLayout();
+ void createLayout();
+ void createTextAreaLayout();
+ void connectListWidgets();
+ QString formatAsHtml(const QString& text);
+ void loadFonts();
+ void loadSizes(const QString& font, const QString& style);
+ void loadStyles(const QString& font);
+ void outputHtmlText();
+ void restoreListWidgetValue(QListWidget* listWidget, const QString& value);
+ QString saveListWidgetValue(QListWidget* listWidget);
+
+ QFrame* m_fontWidget;
+ QWebView* m_webView;
+ CListWidget* m_fontListWidget;
+ CListWidget* m_styleListWidget;
+ CListWidget* m_sizeListWidget;
+ QString m_htmlText;
+ QFont m_font;
+ QVBoxLayout* m_vBoxLayout;
+ QString m_choosenStyle;
+
+private slots:
+ void fontChanged(QListWidgetItem* current, QListWidgetItem* previous);
+ void setFontStyle(const QString& styleString, QFont* font);
+ void sizeChanged(QListWidgetItem* current, QListWidgetItem* previous);
+ void styleChanged(QListWidgetItem* current, QListWidgetItem* previous);
+
+signals:
+ void fontSelected(const QFont&);
+};
+
+#endif
diff --git a/src/frontend/settingsdialogs/clanguagesettings.cpp b/src/frontend/settingsdialogs/clanguagesettings.cpp
new file mode 100644
index 0000000..30d6e6b
--- /dev/null
+++ b/src/frontend/settingsdialogs/clanguagesettings.cpp
@@ -0,0 +1,302 @@
+//
+// C++ Implementation: clanguagesettings
+//
+// Description:
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 1999-2008
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#include "clanguagesettings.h"
+
+#include "util/cpointers.h"
+#include "util/ctoolclass.h"
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+
+#include <QWidget>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QComboBox>
+#include <QCheckBox>
+#include <QLabel>
+
+
+#include "cfontchooser.h"
+
+
+//Sword includes
+#include <localemgr.h>
+#include <swlocale.h>
+
+CLanguageSettingsPage::CLanguageSettingsPage(QWidget* /*parent*/)
+ : BtConfigPage()
+{
+
+ QVBoxLayout* layout = new QVBoxLayout(this);
+
+ //Sword locales
+ layout->addWidget(
+ CToolClass::explanationLabel(
+ this,
+ tr(""),
+ tr("Select the language in which the Biblical book names are displayed.")
+ ));
+
+ m_swordLocaleCombo = new QComboBox(this);
+ QLabel* label = new QLabel( tr("Language for names of Bible books:"), this);
+ label->setBuddy(m_swordLocaleCombo);
+ m_swordLocaleCombo->setToolTip(tr("The languages which can be used for the biblical booknames"));
+
+
+ QHBoxLayout* hBoxLayout = new QHBoxLayout();
+ hBoxLayout->addWidget(label);
+ hBoxLayout->addWidget(m_swordLocaleCombo);
+ hBoxLayout->addStretch();
+ layout->addLayout(hBoxLayout);
+
+ QStringList languageNames;
+ languageNames.append( languageMgr()->languageForAbbrev("en_US")->translatedName() );
+
+ std::list<sword::SWBuf> locales = sword::LocaleMgr::getSystemLocaleMgr()->getAvailableLocales();
+ for (std::list<sword::SWBuf>::const_iterator it = locales.begin(); it != locales.end(); it++)
+ {
+ // qWarning("working on %s", (*it).c_str());
+ const CLanguageMgr::Language* const l =
+ CPointers::languageMgr()->languageForAbbrev( sword::LocaleMgr::getSystemLocaleMgr()->getLocale((*it).c_str())->getName() );
+
+ if (l->isValid())
+ {
+ languageNames.append( l->translatedName() );
+ }
+ else
+ {
+ languageNames.append(
+ sword::LocaleMgr::getSystemLocaleMgr()->getLocale((*it).c_str())->getDescription()
+ );
+ }
+ } //for
+
+ languageNames.sort();
+ m_swordLocaleCombo->addItems( languageNames );
+
+ const CLanguageMgr::Language* const l =
+ CPointers::languageMgr()->languageForAbbrev( CBTConfig::get(CBTConfig::language) );
+
+ QString currentLanguageName;
+ if ( l->isValid() && languageNames.contains(l->translatedName()) )
+ { //tranlated language name is in the box
+ currentLanguageName = l->translatedName();
+ }
+ else
+ { //a language like "German Abbrevs" might be the language to set
+ sword::SWLocale* locale =
+ sword::LocaleMgr::getSystemLocaleMgr()->getLocale( CBTConfig::get(CBTConfig::language).toLocal8Bit() );
+ if (locale)
+ {
+ currentLanguageName = QString::fromLatin1(locale->getDescription());
+ }
+ }
+
+ if (currentLanguageName.isEmpty())
+ { // set english as default if nothing was chosen
+ Q_ASSERT(languageMgr()->languageForAbbrev("en_US"));
+ currentLanguageName = languageMgr()->languageForAbbrev("en_US")->translatedName();
+ }
+
+ //now set the item with the right name as current item
+ for (int i = 0; i < m_swordLocaleCombo->count(); ++i)
+ {
+ if (currentLanguageName == m_swordLocaleCombo->itemText(i))
+ {
+ m_swordLocaleCombo->setCurrentIndex(i);
+ break; //item found, finish the loop
+ }
+ }
+
+ layout->addSpacing(20);
+
+ //Font settings
+
+ layout->addWidget(
+ CToolClass::explanationLabel(
+ this,
+ tr("Fonts"),
+ tr("You can specify a custom font for each language.")
+ )
+ );
+ QHBoxLayout* hLayout = new QHBoxLayout();
+
+ m_usageCombo = new QComboBox(this);
+ m_usageCombo->setToolTip(tr("The font selection below will apply to all texts in this language"));
+
+ hLayout->addWidget(m_usageCombo);
+
+ CLanguageMgr::LangMap langMap = languageMgr()->availableLanguages();
+
+ for (CLanguageMgr::LangMapIterator it = langMap.constBegin() ; it != langMap.constEnd(); ++it )
+ {
+ const QString name =
+ (*it)->translatedName().isEmpty()
+ ? (*it)->abbrev()
+ : (*it)->translatedName();
+
+ m_fontMap.insert(name, CBTConfig::get(*it) );
+ }
+
+ for( QMap<QString, CBTConfig::FontSettingsPair>::Iterator it = m_fontMap.begin(); it != m_fontMap.end(); ++it )
+ {
+ if ( m_fontMap[it.key()].first )
+ { //show font icon
+ m_usageCombo->addItem(util::filesystem::DirectoryUtil::getIcon("fonts.svg"), it.key() );
+ }
+ else
+ { //don't show icon for font
+ m_usageCombo->addItem(it.key());
+ }
+ }
+
+ m_useOwnFontCheck = new QCheckBox(tr("Use custom font"), this);
+ m_useOwnFontCheck->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ connect(m_useOwnFontCheck, SIGNAL(toggled(bool)), SLOT(useOwnFontClicked(bool)) );
+ hLayout->addWidget(m_useOwnFontCheck);
+
+ layout->addLayout(hLayout);
+ hLayout->setContentsMargins(0,0,0,0);
+ //#warning TODO: remember the last selected font and jump there.
+
+ m_fontChooser = new CFontChooser(this);
+
+ //TODO: Eeli's wishlist: why not show something relevant here, like a Bible verse in chosen (not tr()'ed!) language?
+ QString sampleText;
+ sampleText.append("1 In the beginning God created the heaven and the earth. ");
+ sampleText.append("2 And the earth was without form, and void; and darkness was on the face of the deep.");
+ sampleText.append(" And the Spirit of God moved on the face of the waters.");
+
+ m_fontChooser->setSampleText(sampleText);
+ layout->addWidget(m_fontChooser);
+
+ connect(m_fontChooser, SIGNAL(fontSelected(const QFont&)), SLOT(newDisplayWindowFontSelected(const QFont&)));
+ connect(m_usageCombo, SIGNAL(activated(const QString&)), SLOT(newDisplayWindowFontAreaSelected(const QString&)));
+
+ m_fontChooser->setFont( m_fontMap[m_usageCombo->currentText()].second );
+ useOwnFontClicked( m_fontMap[m_usageCombo->currentText()].first );
+ m_useOwnFontCheck->setChecked( m_fontMap[m_usageCombo->currentText()].first );
+ m_fontChooser->setMinimumSize(m_fontChooser->sizeHint());
+}
+
+
+CLanguageSettingsPage::~CLanguageSettingsPage()
+{
+}
+
+void CLanguageSettingsPage::save()
+{
+ for(QMap<QString, CBTConfig::FontSettingsPair>::Iterator it = m_fontMap.begin(); it != m_fontMap.end(); ++it )
+ {
+ const CLanguageMgr::Language* const lang = languageMgr()->languageForTranslatedName(it.key());
+ if (!lang->isValid())
+ { //we possibly use a language, for which we have only the abbrev
+ if (!lang->abbrev().isEmpty()) {
+ CLanguageMgr::Language l(it.key(), it.key(), it.key()); //create a temp language
+ CBTConfig::set(&l, it.value());
+ }
+ }
+ else
+ {
+ CBTConfig::set(lang, it.value());
+ }
+ }
+
+
+ QString languageAbbrev;
+
+ const QString currentLanguageName = m_swordLocaleCombo->currentText();
+ const CLanguageMgr::Language* const l = CPointers::languageMgr()->languageForTranslatedName( currentLanguageName );
+
+ if (l && l->isValid())
+ {
+ languageAbbrev = l->abbrev();
+ }
+ else
+ { //it can be the lang abbrev like de_abbrev or the Sword description
+ std::list <sword::SWBuf> locales = sword::LocaleMgr::getSystemLocaleMgr()->getAvailableLocales();
+
+ for (std::list <sword::SWBuf>::iterator it = locales.begin(); it != locales.end(); it++)
+ {
+ sword::SWLocale* locale = sword::LocaleMgr::getSystemLocaleMgr()->getLocale((*it).c_str());
+ Q_ASSERT(locale);
+
+ if ( locale && (QString::fromLatin1(locale->getDescription()) == currentLanguageName) )
+ {
+ languageAbbrev = QString::fromLatin1(locale->getName()); //we found the abbrevation for the current language
+ break;
+ }
+ }
+
+ if (languageAbbrev.isEmpty())
+ {
+ languageAbbrev = currentLanguageName; //probably a non-standard locale name like de_abbrev
+ }
+ }
+
+ if (!languageAbbrev.isEmpty())
+ {
+ CBTConfig::set(CBTConfig::language, languageAbbrev);
+ }
+}
+
+/** */
+void CLanguageSettingsPage::newDisplayWindowFontSelected(const QFont &newFont)
+{
+ //belongs to the languages/fonts page
+ CBTConfig::FontSettingsPair oldSettings = m_fontMap[ m_usageCombo->currentText() ];
+ m_fontMap.insert( m_usageCombo->currentText(), CBTConfig::FontSettingsPair(oldSettings.first, newFont) );
+}
+
+/** Called when the combobox contents is changed */
+void CLanguageSettingsPage::newDisplayWindowFontAreaSelected(const QString& usage)
+{
+ //belongs to fonts/languages
+ useOwnFontClicked( m_fontMap[usage].first );
+ m_useOwnFontCheck->setChecked( m_fontMap[usage].first );
+
+ m_fontChooser->setFont( m_fontMap[usage].second );
+}
+
+
+/** This slot is called when the "Use own font for language" bo was clicked. */
+void CLanguageSettingsPage::useOwnFontClicked( bool isOn )
+{
+ //belongs to fonts/languages
+
+ m_fontChooser->setEnabled(isOn);
+ m_fontMap[ m_usageCombo->currentText() ].first = isOn;
+
+ if (isOn)
+ { //show font icon
+ m_usageCombo->setItemIcon(m_usageCombo->currentIndex(), util::filesystem::DirectoryUtil::getIcon("fonts.svg") );
+ }
+ else
+ { //don't show
+ m_usageCombo->setItemText(m_usageCombo->currentIndex(), m_usageCombo->currentText() ); //TODO: should this change icon to empty?
+ }
+}
+
+
+QString CLanguageSettingsPage::iconName()
+{
+ return CResMgr::settings::fonts::icon;
+}
+QString CLanguageSettingsPage::label()
+{
+ //: Empty string, don't translate
+ return tr("");
+}
+QString CLanguageSettingsPage::header()
+{
+ return tr("Languages");
+}
diff --git a/src/frontend/settingsdialogs/clanguagesettings.h b/src/frontend/settingsdialogs/clanguagesettings.h
new file mode 100644
index 0000000..cf635d3
--- /dev/null
+++ b/src/frontend/settingsdialogs/clanguagesettings.h
@@ -0,0 +1,65 @@
+//
+// C++ Interface: clanguagesettings
+//
+// Description:
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 1999-2008
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CLANGUAGESETTINGS_H
+#define CLANGUAGESETTINGS_H
+
+
+#include "util/cpointers.h"
+#include "backend/config/cbtconfig.h"
+#include "frontend/bookshelfmanager/btconfigdialog.h"
+
+#include <QWidget>
+#include <QMap>
+
+class QComboBox;
+class QCheckBox;
+class CFontChooser;
+
+
+/**
+ @author The BibleTime team <info@bibletime.info>
+*/
+class CLanguageSettingsPage : public BtConfigPage, CPointers
+{
+Q_OBJECT
+public:
+ CLanguageSettingsPage(QWidget *parent);
+ ~CLanguageSettingsPage();
+ void save();
+ QString iconName();
+ QString label();
+ QString header();
+
+protected slots:
+ /**
+ * This slot is called when the "Use own font for language" button was clicked.
+ */
+ void useOwnFontClicked(bool);
+ /**
+ * Called when a new font in the fonts page was selected.
+ */
+ void newDisplayWindowFontSelected(const QFont &);
+ /**
+ * Called when the combobox contents is changed
+ */
+ void newDisplayWindowFontAreaSelected(const QString&);
+
+private:
+ QComboBox* m_swordLocaleCombo;
+ QComboBox* m_usageCombo;
+ QCheckBox* m_useOwnFontCheck;
+ CFontChooser* m_fontChooser;
+
+ QMap<QString,CBTConfig::FontSettingsPair> m_fontMap;
+};
+
+#endif
diff --git a/src/frontend/settingsdialogs/clistwidget.cpp b/src/frontend/settingsdialogs/clistwidget.cpp
new file mode 100644
index 0000000..8fdc130
--- /dev/null
+++ b/src/frontend/settingsdialogs/clistwidget.cpp
@@ -0,0 +1,30 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "util/ctoolclass.h"
+#include "clistwidget.h"
+
+CListWidget::CListWidget(QWidget* parent)
+ : QListWidget(parent)
+{
+}
+
+CListWidget::~CListWidget()
+{
+}
+
+QSize CListWidget::sizeHint () const
+{
+ return QSize(100,120);
+}
+
+void CListWidget::setCharWidth(int width)
+{
+ setMaximumWidth(CToolClass::mWidth(this, width));
+}
diff --git a/src/frontend/settingsdialogs/clistwidget.h b/src/frontend/settingsdialogs/clistwidget.h
new file mode 100644
index 0000000..6afd232
--- /dev/null
+++ b/src/frontend/settingsdialogs/clistwidget.h
@@ -0,0 +1,28 @@
+//
+// C++ Interface: CListWidget
+//
+// Description: BibleTime font chooser
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 1999-2008
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#ifndef CLISTWIDGET_H
+#define CLISTWIDGET_H
+
+#include <QListWidget>
+
+class CListWidget : public QListWidget {
+ Q_OBJECT
+
+public:
+ CListWidget(QWidget* parent = 0);
+ ~CListWidget();
+ virtual QSize sizeHint () const;
+ void setCharWidth(int width);
+};
+
+#endif
diff --git a/src/frontend/settingsdialogs/cswordsettings.cpp b/src/frontend/settingsdialogs/cswordsettings.cpp
new file mode 100644
index 0000000..29afd17
--- /dev/null
+++ b/src/frontend/settingsdialogs/cswordsettings.cpp
@@ -0,0 +1,423 @@
+//
+// C++ Implementation: cswordsettings
+//
+// Description:
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 1999-2008
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#include "cswordsettings.h"
+
+#include "backend/config/cbtconfig.h"
+
+#include "util/cresmgr.h"
+#include "util/ctoolclass.h"
+#include "util/cpointers.h"
+
+#include <QWidget>
+#include <QTabWidget>
+#include <QComboBox>
+#include <QCheckBox>
+#include <QString>
+#include <QGridLayout>
+#include <QVBoxLayout>
+#include <QList>
+#include <QStringList>
+#include <QLabel>
+
+
+
+CSwordSettingsPage::CSwordSettingsPage(QWidget* /*parent*/)
+ : BtConfigPage()
+{
+ QVBoxLayout* vbox = new QVBoxLayout(this);
+ QTabWidget* tabWidget = new QTabWidget();
+ vbox->addWidget(tabWidget);
+ setLayout(vbox);
+
+ m_worksTab = new StandardWorksTab();
+ m_filtersTab = new TextFiltersTab();
+ tabWidget->addTab(m_worksTab, tr("Standard works"));
+ tabWidget->addTab(m_filtersTab, tr("Text filters"));
+}
+
+//Standard works tab
+
+StandardWorksTab::StandardWorksTab()
+ : QWidget(0)
+{
+
+ // move: tabCtl->addTab(currentTab, tr("Standard works"));
+ QGridLayout* gridLayout = new QGridLayout(this); //the last row is for stretching available space
+ gridLayout->setSizeConstraint(QLayout::SetMinimumSize);
+
+ gridLayout->addWidget(
+ CToolClass::explanationLabel(
+ this,
+ tr(""),
+ tr("Standard works are used when no particular work is specified, \
+ for example when a hyperlink into a Bible or lexicon was clicked .")),
+ 0,0,1,2 /*fill the horizontal space*/
+ );
+
+ //Create selection boxes
+
+ m_standardBibleCombo = new QComboBox(this);
+ QLabel* label = new QLabel( tr("Bible:"), this);
+ label->setAlignment(Qt::AlignRight);
+ label->setBuddy(m_standardBibleCombo);
+ ////label->setAutoResize(true); //? not found in docs
+ m_standardBibleCombo->setToolTip(tr("The standard Bible is used when a hyperlink into a Bible is clicked"));
+
+ gridLayout->addWidget(label,1,0);
+ gridLayout->addWidget(m_standardBibleCombo, 1, 1);
+
+ m_standardCommentaryCombo = new QComboBox(this);
+ label = new QLabel( tr("Commentary:"), this);
+ label->setAlignment(Qt::AlignRight);
+ label->setBuddy(m_standardCommentaryCombo);
+ //label->setAutoResize(true);
+ m_standardCommentaryCombo->setToolTip(tr("The standard commentary is used when a hyperlink into a commentary is clicked"));
+
+ gridLayout->addWidget(label, 2, 0);
+ gridLayout->addWidget(m_standardCommentaryCombo, 2, 1);
+
+ m_standardLexiconCombo = new QComboBox(this);
+ label = new QLabel(tr("Lexicon:"), this);
+ label->setAlignment(Qt::AlignRight);
+ label->setBuddy(m_standardLexiconCombo);
+ //label->setAutoResize(true);
+ m_standardLexiconCombo->setToolTip(tr("The standard lexicon is used when a hyperlink into a lexicon is clicked"));
+
+ gridLayout->addWidget(label,3,0);
+ gridLayout->addWidget(m_standardLexiconCombo, 3, 1);
+
+ m_standardDailyDevotionalCombo = new QComboBox(this);
+ label = new QLabel(tr("Daily devotional:"), this);
+ label->setAlignment(Qt::AlignRight);
+ label->setBuddy(m_standardDailyDevotionalCombo);
+ //label->setAutoResize(true);
+ m_standardDailyDevotionalCombo->setToolTip(tr("The standard devotional will be used to display a short start up devotional"));
+
+ gridLayout->addWidget(label,4,0);
+ gridLayout->addWidget(m_standardDailyDevotionalCombo, 4, 1);
+
+ m_standardHebrewStrongCombo = new QComboBox(this);
+ label = new QLabel(tr("Hebrew Strong's lexicon:"), this);
+ label->setAlignment(Qt::AlignRight);
+ label->setBuddy(m_standardHebrewStrongCombo);
+ //label->setAutoResize(true);
+ m_standardHebrewStrongCombo->setToolTip(tr("The standard Hebrew lexicon is used when a hyperlink into a Hebrew lexicon is clicked"));
+
+ gridLayout->addWidget(label, 5, 0);
+ gridLayout->addWidget(m_standardHebrewStrongCombo, 5, 1);
+
+ m_standardGreekStrongCombo = new QComboBox(this);
+ label = new QLabel(tr("Greek Strong's lexicon:"), this);
+ label->setAlignment(Qt::AlignRight);
+ label->setBuddy(m_standardGreekStrongCombo);
+ //label->setAutoResize(true);
+ m_standardGreekStrongCombo->setToolTip(tr("The standard Greek lexicon is used when a hyperlink into a Greek lexicon is clicked"));
+
+ gridLayout->addWidget(label, 6, 0);
+ gridLayout->addWidget(m_standardGreekStrongCombo, 6, 1);
+
+ m_standardHebrewMorphCombo = new QComboBox(this);
+ label = new QLabel( tr("Hebrew morphological lexicon:"), this);
+ label->setAlignment(Qt::AlignRight);
+ label->setBuddy(m_standardHebrewMorphCombo);
+ //label->setAutoResize(true);
+ m_standardHebrewMorphCombo->setToolTip(tr("The standard morphological lexicon for Hebrew texts is used when a hyperlink of a morphological tag in a Hebrew text is clicked"));
+
+ gridLayout->addWidget(label, 7, 0);
+ gridLayout->addWidget(m_standardHebrewMorphCombo, 7, 1);
+
+ m_standardGreekMorphCombo = new QComboBox(this);
+ label = new QLabel(tr("Greek morphological lexicon:"), this);
+ label->setAlignment(Qt::AlignRight);
+ label->setBuddy(m_standardGreekMorphCombo);
+ //label->setAutoResize(true);
+ m_standardGreekMorphCombo->setToolTip(tr("The standard morphological lexicon for Greek texts is used when a hyperlink of a morphological tag in a Greek text is clicked"));
+
+ gridLayout->addWidget(label, 8, 0);
+ gridLayout->addWidget(m_standardGreekMorphCombo, 8, 1);
+
+ gridLayout->setRowStretch(9,5);
+
+ //fill the comboboxes with the right modules
+
+ QList<CSwordModuleInfo*>& modules = backend()->moduleList();
+ QString modDescript;
+ QList<CSwordModuleInfo*>::iterator end_it = modules.end();
+ for (QList<CSwordModuleInfo*>::iterator it(modules.begin()); it != end_it; ++it)
+ {
+ modDescript = (*it)->config(CSwordModuleInfo::Description);
+
+ switch ((*it)->type())
+ {
+ case CSwordModuleInfo::Bible:
+ m_standardBibleCombo->addItem(modDescript);
+ break;
+ case CSwordModuleInfo::Commentary:
+ m_standardCommentaryCombo->addItem(modDescript);
+ break;
+ case CSwordModuleInfo::Lexicon:
+ {
+ bool inserted = false;
+ if ((*it)->has(CSwordModuleInfo::HebrewDef))
+ {
+ m_standardHebrewStrongCombo->addItem(modDescript);
+ inserted = true;
+ }
+ if ((*it)->has(CSwordModuleInfo::GreekDef))
+ {
+ m_standardGreekStrongCombo->addItem(modDescript);
+ inserted = true;
+ }
+ if ((*it)->has(CSwordModuleInfo::HebrewParse))
+ {
+ m_standardHebrewMorphCombo->addItem(modDescript);
+ inserted = true;
+ }
+ if ((*it)->has(CSwordModuleInfo::GreekParse))
+ {
+ m_standardGreekMorphCombo->addItem(modDescript);
+ inserted = true;
+ }
+ if ((*it)->category() == CSwordModuleInfo::DailyDevotional)
+ {
+ m_standardDailyDevotionalCombo->addItem(modDescript);
+ inserted = true;
+ }
+
+ if (!inserted)
+ { //daily dvotionals, striong lexicons etc. are not very useful for word lookups
+ m_standardLexiconCombo->addItem(modDescript);
+ }
+ break;
+ }
+ default://unknown type
+ break;
+ } //switch
+ } //for
+
+ //using two lists and one loop is better than six loops with almost the same code :)
+ QList<QComboBox*> comboList;
+ QStringList moduleList;
+
+ for (int i = 0; i <= (int)CBTConfig::lastModuleType; ++i)
+ {
+ //fill the combobox list in the right order (i.e. same order as the CBTConfig::module enum list)
+ CBTConfig::modules moduleType = (CBTConfig::modules)(i);
+ switch (moduleType)
+ {
+ case CBTConfig::standardBible:
+ comboList.append(m_standardBibleCombo);
+ break;
+ case CBTConfig::standardCommentary:
+ comboList.append(m_standardCommentaryCombo);
+ break;
+ case CBTConfig::standardLexicon:
+ comboList.append(m_standardLexiconCombo);
+ break;
+ case CBTConfig::standardDailyDevotional:
+ comboList.append(m_standardDailyDevotionalCombo);
+ break;
+ case CBTConfig::standardHebrewStrongsLexicon:
+ comboList.append(m_standardHebrewStrongCombo);
+ break;
+ case CBTConfig::standardGreekStrongsLexicon:
+ comboList.append(m_standardGreekStrongCombo);
+ break;
+ case CBTConfig::standardHebrewMorphLexicon:
+ comboList.append(m_standardHebrewMorphCombo);
+ break;
+ case CBTConfig::standardGreekMorphLexicon:
+ comboList.append(m_standardGreekMorphCombo);
+ break;
+ }; //switch
+
+ //fill the module list
+ CSwordModuleInfo* const m = CBTConfig::get( (CBTConfig::modules)(i) );
+ if (m)
+ {
+ moduleList << m->config(CSwordModuleInfo::Description);
+ }
+ else
+ {
+ moduleList << QString::null;
+ }
+ } //for
+
+ QString module = QString::null;
+ int item = 0;
+ int count = 0;
+ QListIterator<QComboBox*> it(comboList);
+ while (it.hasNext())
+ {
+ //for (QComboBox* combo = comboList.first(); combo; combo = comboList.next() )
+ QComboBox* combo = it.next();
+ module = moduleList[comboList.indexOf(combo)];
+ count = combo->count();
+ combo->setMaximumWidth(300);
+
+ for (item = 0; item < count; item++)
+ {
+ if (combo->itemText(item) == module )
+ {
+ combo->setCurrentIndex(item);
+ break;
+ }
+ }
+ }
+}
+
+
+TextFiltersTab::TextFiltersTab()
+{
+ QVBoxLayout* layout = new QVBoxLayout(this);
+ layout->setMargin(5);
+ QWidget* eLabel = CToolClass::explanationLabel(
+ this,
+ tr(""),
+ tr("Filters control the appearance of text. \
+Here you can specify default settings for all filters. \
+You can override these settings in each display window.")
+ );
+ eLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
+ eLabel->setMaximumHeight(50);
+ eLabel->setMinimumWidth(300);
+ layout->setSpacing(2);
+ layout->addWidget(eLabel);
+
+ m_lineBreaksCheck = new QCheckBox(this);
+ m_lineBreaksCheck->setText(tr("Insert line break after each verse"));
+ m_lineBreaksCheck->setChecked(CBTConfig::get(CBTConfig::lineBreaks));
+ layout->addWidget(m_lineBreaksCheck);
+
+ m_verseNumbersCheck = new QCheckBox(this);
+ m_verseNumbersCheck->setText(tr("Show verse numbers"));
+ m_verseNumbersCheck->setChecked(CBTConfig::get(CBTConfig::verseNumbers));
+ layout->addWidget(m_verseNumbersCheck);
+
+ m_headingsCheck = new QCheckBox(this);
+ m_headingsCheck->setText(tr("Show section headings"));
+ m_headingsCheck->setChecked(CBTConfig::get(CBTConfig::headings));
+ layout->addWidget(m_headingsCheck);
+
+
+ m_scriptureReferencesCheck = new QCheckBox(this);
+ m_scriptureReferencesCheck->setText(tr("Show scripture cross-references"));
+ m_scriptureReferencesCheck->setChecked(CBTConfig::get(CBTConfig::scriptureReferences));
+ layout->addWidget(m_scriptureReferencesCheck);
+
+ m_greekAccentsCheck = new QCheckBox(this);
+ m_greekAccentsCheck->setText(tr("Show Greek accents"));
+ m_greekAccentsCheck->setChecked(CBTConfig::get(CBTConfig::greekAccents));
+ layout->addWidget(m_greekAccentsCheck);
+
+ m_hebrewPointsCheck = new QCheckBox(this);
+ m_hebrewPointsCheck->setText(tr("Show Hebrew vowel points"));
+ m_hebrewPointsCheck->setChecked(CBTConfig::get(CBTConfig::hebrewPoints));
+ layout->addWidget(m_hebrewPointsCheck);
+
+ m_hebrewCantillationCheck = new QCheckBox(this);
+ m_hebrewCantillationCheck->setText(tr("Show Hebrew cantillation marks"));
+ m_hebrewCantillationCheck->setChecked(CBTConfig::get(CBTConfig::hebrewCantillation));
+ layout->addWidget(m_hebrewCantillationCheck);
+
+ m_morphSegmentationCheck = new QCheckBox(this);
+ m_morphSegmentationCheck->setText(tr("Show morph segmentation"));
+ m_morphSegmentationCheck->setChecked(CBTConfig::get(CBTConfig::morphSegmentation));
+ layout->addWidget(m_morphSegmentationCheck);
+
+ m_textualVariantsCheck = new QCheckBox(this);
+ m_textualVariantsCheck->setText(tr("Use textual variants"));
+ m_textualVariantsCheck->setChecked(CBTConfig::get(CBTConfig::textualVariants));
+ layout->addWidget(m_textualVariantsCheck);
+
+ layout->addStretch(4);
+}
+
+void CSwordSettingsPage::save()
+{
+ m_worksTab->save();
+ m_filtersTab->save();
+}
+
+QString CSwordSettingsPage::iconName()
+{
+ return CResMgr::settings::sword::icon;
+}
+QString CSwordSettingsPage::label()
+{
+ //: Empty string, don't translate
+ return tr("");
+}
+QString CSwordSettingsPage::header()
+{
+ return tr("Desk");
+}
+
+void StandardWorksTab::save()
+{
+ for (int i = 0; i <= (int)CBTConfig::lastModuleType; ++i)
+ {
+ QString moduleDescription = QString::null;
+
+ CBTConfig::modules moduleType = (CBTConfig::modules)(i);
+ switch (moduleType)
+ {
+ case CBTConfig::standardBible:
+ moduleDescription = m_standardBibleCombo->currentText();
+ break;
+ case CBTConfig::standardCommentary:
+ moduleDescription = m_standardCommentaryCombo->currentText();
+ break;
+ case CBTConfig::standardLexicon:
+ moduleDescription = m_standardLexiconCombo->currentText();
+ break;
+ case CBTConfig::standardDailyDevotional:
+ moduleDescription = m_standardDailyDevotionalCombo->currentText();
+ break;
+ case CBTConfig::standardHebrewStrongsLexicon:
+ moduleDescription = m_standardHebrewStrongCombo->currentText();
+ break;
+ case CBTConfig::standardGreekStrongsLexicon:
+ moduleDescription = m_standardGreekStrongCombo->currentText();
+ break;
+ case CBTConfig::standardHebrewMorphLexicon:
+ moduleDescription = m_standardHebrewMorphCombo->currentText();
+ break;
+ case CBTConfig::standardGreekMorphLexicon:
+ moduleDescription = m_standardGreekMorphCombo->currentText();
+ break;
+ default:
+ qWarning("Unhandled module type.");
+ };
+
+ CSwordModuleInfo* const module = backend()->findModuleByDescription(moduleDescription);
+ CBTConfig::set
+ (moduleType, module);
+ }
+}
+
+
+void TextFiltersTab::save()
+{
+ CBTConfig::set(CBTConfig::lineBreaks, m_lineBreaksCheck->isChecked());
+ CBTConfig::set(CBTConfig::verseNumbers, m_verseNumbersCheck->isChecked());
+ CBTConfig::set(CBTConfig::headings, m_headingsCheck->isChecked());
+ CBTConfig::set(CBTConfig::scriptureReferences, m_scriptureReferencesCheck->isChecked());
+ CBTConfig::set(CBTConfig::hebrewPoints, m_hebrewPointsCheck->isChecked());
+ CBTConfig::set(CBTConfig::hebrewCantillation, m_hebrewCantillationCheck->isChecked());
+ CBTConfig::set(CBTConfig::morphSegmentation, m_morphSegmentationCheck->isChecked());
+ CBTConfig::set(CBTConfig::greekAccents, m_greekAccentsCheck->isChecked());
+ CBTConfig::set(CBTConfig::textualVariants, m_textualVariantsCheck->isChecked());
+}
+
+
diff --git a/src/frontend/settingsdialogs/cswordsettings.h b/src/frontend/settingsdialogs/cswordsettings.h
new file mode 100644
index 0000000..19db47b
--- /dev/null
+++ b/src/frontend/settingsdialogs/cswordsettings.h
@@ -0,0 +1,86 @@
+//
+// C++ Interface: cswordsettings
+//
+// Description: Widgets for "Sword" ("Desk") settings of configuration dialog.
+//
+//
+// Author: The BibleTime team <info@bibletime.info>, (C) 1999-2008
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#ifndef CSWORDSETTINGS_H
+#define CSWORDSETTINGS_H
+
+#include "frontend/bookshelfmanager/btconfigdialog.h"
+
+#include "util/cpointers.h"
+
+#include <QTabWidget>
+
+
+class QComboBox;
+class QCheckBox;
+
+class StandardWorksTab;
+class TextFiltersTab;
+
+class CSwordSettingsPage : public BtConfigPage
+{
+ Q_OBJECT
+
+public:
+ CSwordSettingsPage(QWidget* parent);
+ void save();
+ QString iconName();
+ QString label();
+ QString header();
+
+private:
+ StandardWorksTab* m_worksTab;
+ TextFiltersTab* m_filtersTab;
+};
+
+//Tab pages. To be used only in Sword settings page.
+
+class StandardWorksTab : public QWidget, CPointers
+{
+ Q_OBJECT
+
+public:
+ StandardWorksTab();
+ void save();
+
+private:
+ QComboBox* m_standardBibleCombo;
+ QComboBox* m_standardCommentaryCombo;
+ QComboBox* m_standardLexiconCombo;
+ QComboBox* m_standardDailyDevotionalCombo;
+ QComboBox* m_standardHebrewStrongCombo;
+ QComboBox* m_standardGreekStrongCombo;
+ QComboBox* m_standardHebrewMorphCombo;
+ QComboBox* m_standardGreekMorphCombo;
+};
+
+class TextFiltersTab : public QWidget
+{
+ Q_OBJECT
+
+public:
+ TextFiltersTab();
+ void save();
+
+private:
+ QCheckBox* m_lineBreaksCheck;
+ QCheckBox* m_verseNumbersCheck;
+ QCheckBox* m_headingsCheck;
+ QCheckBox* m_hebrewPointsCheck;
+ QCheckBox* m_hebrewCantillationCheck;
+ QCheckBox* m_morphSegmentationCheck;
+ QCheckBox* m_greekAccentsCheck;
+ QCheckBox* m_textualVariantsCheck;
+ QCheckBox* m_scriptureReferencesCheck;
+};
+
+#endif