summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRoberto C. Sanchez <roberto@connexer.com>2014-10-21 22:48:19 -0400
committerRoberto C. Sanchez <roberto@connexer.com>2014-10-21 22:48:19 -0400
commit1af3b165c9377702ca62a64112bc089a6f575c30 (patch)
tree4df9cca5543b2cab5ca56dbb1214d7d3b1f291e3 /src
parent5b5fd0dce407556f98ed8edee89dc830bf1437b1 (diff)
Imported Upstream version 2.0~beta2
Diffstat (limited to 'src')
-rw-r--r--src/backend/btmoduletreeitem.cpp272
-rw-r--r--src/backend/btmoduletreeitem.h166
-rw-r--r--src/backend/config/cbtconfig.cpp720
-rw-r--r--src/backend/config/cbtconfig.h197
-rw-r--r--src/backend/cswordmodulesearch.cpp123
-rw-r--r--src/backend/cswordmodulesearch.h98
-rw-r--r--src/backend/drivers/cswordbiblemoduleinfo.cpp261
-rw-r--r--src/backend/drivers/cswordbiblemoduleinfo.h126
-rw-r--r--src/backend/drivers/cswordbookmoduleinfo.cpp68
-rw-r--r--src/backend/drivers/cswordbookmoduleinfo.h64
-rw-r--r--src/backend/drivers/cswordcommentarymoduleinfo.cpp32
-rw-r--r--src/backend/drivers/cswordcommentarymoduleinfo.h43
-rw-r--r--src/backend/drivers/cswordlexiconmoduleinfo.cpp170
-rw-r--r--src/backend/drivers/cswordlexiconmoduleinfo.h71
-rw-r--r--src/backend/drivers/cswordmoduleinfo.cpp955
-rw-r--r--src/backend/drivers/cswordmoduleinfo.h384
-rw-r--r--src/backend/filters/bt_gbfhtml.cpp296
-rw-r--r--src/backend/filters/bt_gbfhtml.h55
-rw-r--r--src/backend/filters/bt_osishtml.cpp619
-rw-r--r--src/backend/filters/bt_osishtml.h67
-rw-r--r--src/backend/filters/bt_plainhtml.cpp72
-rw-r--r--src/backend/filters/bt_plainhtml.h33
-rw-r--r--src/backend/filters/bt_thmlhtml.cpp385
-rw-r--r--src/backend/filters/bt_thmlhtml.h53
-rw-r--r--src/backend/filters/bt_thmlplain.cpp221
-rw-r--r--src/backend/filters/bt_thmlplain.h28
-rw-r--r--src/backend/filters/osismorphsegmentation.cpp83
-rw-r--r--src/backend/filters/osismorphsegmentation.h36
-rw-r--r--src/backend/keys/cswordkey.cpp185
-rw-r--r--src/backend/keys/cswordkey.h111
-rw-r--r--src/backend/keys/cswordldkey.cpp118
-rw-r--r--src/backend/keys/cswordldkey.h110
-rw-r--r--src/backend/keys/cswordtreekey.cpp93
-rw-r--r--src/backend/keys/cswordtreekey.h79
-rw-r--r--src/backend/keys/cswordversekey.cpp303
-rw-r--r--src/backend/keys/cswordversekey.h122
-rw-r--r--src/backend/managers/btstringmgr.cpp139
-rw-r--r--src/backend/managers/btstringmgr.h53
-rw-r--r--src/backend/managers/cdisplaytemplatemgr.cpp170
-rw-r--r--src/backend/managers/cdisplaytemplatemgr.h91
-rw-r--r--src/backend/managers/clanguagemgr.cpp546
-rw-r--r--src/backend/managers/clanguagemgr.h151
-rw-r--r--src/backend/managers/creferencemanager.cpp422
-rw-r--r--src/backend/managers/creferencemanager.h110
-rw-r--r--src/backend/managers/cswordbackend.cpp555
-rw-r--r--src/backend/managers/cswordbackend.h273
-rw-r--r--src/backend/rendering/cbookdisplay.cpp136
-rw-r--r--src/backend/rendering/cbookdisplay.h45
-rw-r--r--src/backend/rendering/cchapterdisplay.cpp59
-rw-r--r--src/backend/rendering/cchapterdisplay.h37
-rw-r--r--src/backend/rendering/cdisplayrendering.cpp158
-rw-r--r--src/backend/rendering/cdisplayrendering.h38
-rw-r--r--src/backend/rendering/centrydisplay.cpp63
-rw-r--r--src/backend/rendering/centrydisplay.h51
-rw-r--r--src/backend/rendering/chtmlexportrendering.cpp234
-rw-r--r--src/backend/rendering/chtmlexportrendering.h58
-rw-r--r--src/backend/rendering/cplaintextexportrendering.cpp53
-rw-r--r--src/backend/rendering/cplaintextexportrendering.h40
-rw-r--r--src/backend/rendering/ctextrendering.cpp263
-rw-r--r--src/backend/rendering/ctextrendering.h128
-rw-r--r--src/bibletime.cpp314
-rw-r--r--src/bibletime.h380
-rw-r--r--src/bibletime_dbus.cpp208
-rw-r--r--src/bibletime_dbus_adaptor.cpp71
-rw-r--r--src/bibletime_dbus_adaptor.h110
-rw-r--r--src/bibletime_init.cpp481
-rw-r--r--src/bibletime_slots.cpp510
-rw-r--r--src/bibletimeapp.cpp43
-rw-r--r--src/bibletimeapp.h30
-rw-r--r--src/display-templates/Blue.tmpl338
-rw-r--r--src/display-templates/Crazy.tmpl311
-rw-r--r--src/display-templates/Green.tmpl320
-rw-r--r--src/display-templates/HighContrast.tmpl332
-rw-r--r--src/display-templates/Simple.tmpl134
-rw-r--r--src/display-templates/basic_template.txt205
-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
-rw-r--r--src/main.cpp213
-rw-r--r--src/tests/backend/config/cbtconfig_test.cpp36
-rw-r--r--src/tests/bibletime_test.cpp20
-rw-r--r--src/tests/bibletime_test.h28
-rw-r--r--src/util/cpointers.cpp55
-rw-r--r--src/util/cpointers.h116
-rw-r--r--src/util/cresmgr.cpp496
-rw-r--r--src/util/cresmgr.h509
-rw-r--r--src/util/ctoolclass.cpp279
-rw-r--r--src/util/ctoolclass.h94
-rw-r--r--src/util/dialogutil.cpp61
-rw-r--r--src/util/dialogutil.h23
-rw-r--r--src/util/directoryutil.cpp368
-rw-r--r--src/util/directoryutil.h112
-rw-r--r--src/util/exceptions.h16
-rw-r--r--src/util/migrationutil.cpp92
-rw-r--r--src/util/migrationutil.h39
291 files changed, 45270 insertions, 0 deletions
diff --git a/src/backend/btmoduletreeitem.cpp b/src/backend/btmoduletreeitem.cpp
new file mode 100644
index 0000000..275c841
--- /dev/null
+++ b/src/backend/btmoduletreeitem.cpp
@@ -0,0 +1,272 @@
+/*********
+*
+* 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 "btmoduletreeitem.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "util/cpointers.h"
+#include "backend/managers/cswordbackend.h"
+#include "util/cresmgr.h"
+#include "util/ctoolclass.h"
+
+#include <QString>
+#include <QList>
+
+#include <QDebug>
+
+
+
+//This ctor creates the root item and the tree.
+BTModuleTreeItem::BTModuleTreeItem(QList<BTModuleTreeItem::Filter*>& filters, BTModuleTreeItem::Grouping grouping, QList<CSwordModuleInfo*>* modules)
+ : m_moduleInfo(0),
+ m_firstChild(0),
+ m_next(0),
+ m_type(BTModuleTreeItem::Root),
+ m_category(CSwordModuleInfo::UnknownCategory)
+{
+ if (modules) {
+ m_originalModuleList = *modules;
+ } else {
+ m_originalModuleList = CPointers::backend()->moduleList();
+ }
+ //populate the tree with groups/modules
+ create_tree(filters, grouping);
+}
+
+/**
+* Private constructor which sets the members of the non-root item. This will be the first child of the
+* parent, the previous firstChild will be the next sibling of this.
+*/
+BTModuleTreeItem::BTModuleTreeItem(BTModuleTreeItem* parentItem, const QString& text, BTModuleTreeItem::Type type, CSwordModuleInfo* info, CSwordModuleInfo::Category category)
+ : m_moduleInfo(info),
+ m_text(text),
+ m_firstChild(0),
+ m_next(0),
+ m_type(type),
+ m_category(category)
+{
+ if (info) {
+ m_text = info->name();
+ m_type = BTModuleTreeItem::Module;
+ }
+ BTModuleTreeItem* tmp = parentItem->m_firstChild;
+ parentItem->m_firstChild = this;
+ if (tmp) this->m_next = tmp;
+}
+
+
+BTModuleTreeItem::~BTModuleTreeItem()
+{
+ // this works recursively
+ foreach(BTModuleTreeItem* i, children()) {
+ delete i;
+ }
+}
+
+QList<BTModuleTreeItem*> BTModuleTreeItem::children() const
+{
+ //qDebug("BTModuleTreeItem::children");
+ QList<BTModuleTreeItem*> childList;
+ if (m_firstChild) {
+ BTModuleTreeItem* child = m_firstChild;
+ while (child) {
+ //qDebug() << "child:" << child->text();
+ childList.append(child);
+ child = child->m_next;
+ }
+ }
+ return childList;
+}
+
+//TODO
+QString BTModuleTreeItem::iconName() const
+{
+ if (m_type == Category) {
+ switch ( m_category) {
+ case CSwordModuleInfo::Bibles:
+ return CResMgr::categories::bibles::icon;
+ break;
+ case CSwordModuleInfo::Commentaries:
+ return CResMgr::categories::commentaries::icon;
+ break;
+ case CSwordModuleInfo::Books:
+ return CResMgr::categories::books::icon;
+ break;
+ case CSwordModuleInfo::Cult:
+ return CResMgr::categories::cults::icon;
+ break;
+ case CSwordModuleInfo::Images:
+ return CResMgr::categories::images::icon;
+ break;
+ case CSwordModuleInfo::DailyDevotional:
+ return CResMgr::categories::dailydevotional::icon;
+ break;
+ case CSwordModuleInfo::Lexicons:
+ return CResMgr::categories::lexicons::icon;
+ break;
+ case CSwordModuleInfo::Glossary:
+ return CResMgr::categories::glossary::icon;
+ break;
+ default: break;
+ }
+ }
+ else if (m_type == Module) {
+ return CToolClass::getIconNameForModule(m_moduleInfo);
+ }
+ else if (m_type == Language) {
+ //TODO: don't hardcode here
+ return "flag.svg";
+ }
+
+ return QString::null;
+}
+
+
+void BTModuleTreeItem::create_tree(QList<BTModuleTreeItem::Filter*>& filters, BTModuleTreeItem::Grouping grouping)
+{
+ qDebug("BTModuleTreeItem::create_tree");
+ static bool map_initialized = false;
+ static QMap<CSwordModuleInfo::Category, QString> CategoryNamesMap;
+ if (!map_initialized) {
+ CategoryNamesMap.insert(CSwordModuleInfo::Commentaries, QObject::tr("Commentaries"));
+ CategoryNamesMap.insert(CSwordModuleInfo::Cult, QObject::tr("Cults/Unorthodox"));
+ CategoryNamesMap.insert(CSwordModuleInfo::Images, QObject::tr("Maps and Images"));
+ CategoryNamesMap.insert(CSwordModuleInfo::DailyDevotional, QObject::tr("Daily Devotionals"));
+ CategoryNamesMap.insert(CSwordModuleInfo::Lexicons, QObject::tr("Lexicons and Dictionaries"));
+ CategoryNamesMap.insert(CSwordModuleInfo::Bibles, QObject::tr("Bibles"));
+ CategoryNamesMap.insert(CSwordModuleInfo::Glossary, QObject::tr("Glossaries"));
+ CategoryNamesMap.insert(CSwordModuleInfo::Books, QObject::tr("Books"));
+
+ map_initialized = true;
+ }
+
+ //QList<CSwordModuleInfo*> originalInfoList = CPointers::backend()->moduleList();
+
+ foreach (CSwordModuleInfo* info, m_originalModuleList) {
+ bool included;
+ included = true;
+ foreach (BTModuleTreeItem::Filter* f, filters) {
+ if (!f->filter(info)) {
+ included = false;
+ break;
+ }
+ }
+ if (included) {
+ //qDebug() << "a module will be included: " << info->name();
+
+ BTModuleTreeItem* parentGroupForModule = this;
+ BTModuleTreeItem* parentGroupForLanguage = this;
+ BTModuleTreeItem* parentGroupForCategory = this;
+
+ //the order of if(grouping...) clauses is important
+ if (grouping == BTModuleTreeItem::LangMod || grouping == BTModuleTreeItem::LangCatMod) {
+ BTModuleTreeItem* langItem = create_parent_item(parentGroupForLanguage, info->language()->translatedName(), BTModuleTreeItem::Language);
+
+ if (grouping == BTModuleTreeItem::LangMod)
+ parentGroupForModule = langItem;
+ else
+ parentGroupForCategory = langItem;
+ }
+
+ if (grouping == BTModuleTreeItem::CatMod || grouping == BTModuleTreeItem::CatLangMod) {
+ BTModuleTreeItem* catItem = create_parent_item(parentGroupForCategory, CategoryNamesMap.value(info->category()), BTModuleTreeItem::Category, info->category());
+
+ if (grouping == BTModuleTreeItem::CatMod)
+ parentGroupForModule = catItem;
+ else
+ parentGroupForLanguage = catItem;
+ }
+
+ if (grouping == BTModuleTreeItem::CatLangMod) {
+ // category is there already, create language and make it the parent for the module
+ parentGroupForModule = create_parent_item(parentGroupForLanguage, info->language()->translatedName(), BTModuleTreeItem::Language);
+ }
+
+ if (grouping == BTModuleTreeItem::LangCatMod) {
+ //language is there already, create category and make it the parent for the module
+ parentGroupForModule = create_parent_item(parentGroupForCategory, CategoryNamesMap.value(info->category()), BTModuleTreeItem::Category, info->category());
+ }
+
+ // the parent group for module has been set above, now just add the module to it
+ new BTModuleTreeItem(parentGroupForModule, QString::null, BTModuleTreeItem::Module, info);
+
+ } // end: if (included)
+ }
+
+ // Finally sort the items
+ sort_children(this);
+}
+
+BTModuleTreeItem* BTModuleTreeItem::create_parent_item(
+ BTModuleTreeItem* parentGroup,
+ const QString& itemText,
+ BTModuleTreeItem::Type type,
+ CSwordModuleInfo::Category category)
+{
+ BTModuleTreeItem* item = 0;
+ foreach(BTModuleTreeItem* it, parentGroup->children()) {
+ if (it->text() == itemText) {
+ item = it;
+ break;
+ }
+ }
+ if (!item)
+ item = new BTModuleTreeItem(parentGroup, itemText, type, 0, category);
+
+ return item;
+}
+
+void BTModuleTreeItem::sort_children(BTModuleTreeItem* parent)
+{
+ //qDebug("BTModuleTreeItem::sort_children");
+
+ // sort each child recursively depth-first
+ foreach(BTModuleTreeItem* item, parent->children()) {
+ sort_children(item);
+ }
+
+ QList<BTModuleTreeItem*> items = parent->children();
+ if (items.size() > 0) {
+ // Sort the list of the children according to each item's text
+ qSort(items.begin(), items.end(), BTModuleTreeItem::localeAwareLessThan);
+ //put the children back to tree in sorted order
+ BTModuleTreeItem* first = items.at(0);
+ BTModuleTreeItem* prev = first;
+ foreach (BTModuleTreeItem* item2, items) {
+ prev->m_next = item2;
+ prev = item2;
+ }
+ prev->m_next = 0;
+ parent->m_firstChild = first; // attach the partial tree to the parent
+ }
+}
+
+bool BTModuleTreeItem::localeAwareLessThan(BTModuleTreeItem* first, BTModuleTreeItem* second)
+{
+ static bool map_initialized = false;
+ static QMap<QString, int> CategoryNameValueMap;
+ if (!map_initialized) {
+ //this is the sorting order for categories
+ CategoryNameValueMap.insert(QObject::tr("Bibles"), 1);
+ CategoryNameValueMap.insert(QObject::tr("Commentaries"), 2);
+ CategoryNameValueMap.insert(QObject::tr("Books"), 3);
+ CategoryNameValueMap.insert(QObject::tr("Lexicons and Dictionaries"), 4);
+ CategoryNameValueMap.insert(QObject::tr("Glossaries"), 5);
+ CategoryNameValueMap.insert(QObject::tr("Daily Devotionals"), 6);
+ CategoryNameValueMap.insert(QObject::tr("Maps and Images"), 7);
+ CategoryNameValueMap.insert(QObject::tr("Cults/Unorthodox"), 8);
+ map_initialized = true;
+ }
+
+ //Categories are always in the same order, not alphabetically
+ if (first->type() == BTModuleTreeItem::Category) {
+ return (CategoryNameValueMap.value(first->text()) < CategoryNameValueMap.value(second->text()));
+ }
+ return (QString::localeAwareCompare(first->text(), second->text()) < 0 );
+}
diff --git a/src/backend/btmoduletreeitem.h b/src/backend/btmoduletreeitem.h
new file mode 100644
index 0000000..abdfdb7
--- /dev/null
+++ b/src/backend/btmoduletreeitem.h
@@ -0,0 +1,166 @@
+/*********
+*
+* 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 BTMODULETREEITEM_H
+#define BTMODULETREEITEM_H
+
+#include "backend/drivers/cswordmoduleinfo.h"
+
+#include <QString>
+
+
+/**
+Item of a tree which represents Sword modules categorized and filtered.
+Can be used when building trees for different views.
+
+The tree will be created with the public constructor. It creates the root item and
+populates it with the rest of the tree. The root item is the handle to the tree.
+Users can get the list of the children and operate on it recursively.
+
+The tree is meant to be created, read and then deleted. If you need to apply for example
+different set of filters you have to create a new tree - it's not possible to modify the tree.
+
+Example:
+
+ ...
+ QList<BTModuleTreeItem::Filter*> noFilters
+ BTModuleTreeItem root(noFilters, BTModuleTreeItem::CatLangMod);
+ add_to_view(&root, qtreewidget->invisibleRootItem());
+ ...
+ void add_to_view(BTModuleTreeItem* item, QTreeWidgetItem* widgetItem) {
+ foreach (BTModuleTreeItem* i, item->children()) {
+ add_to_view(i, new QTreeWidgetItem(widgetItem));
+ }
+ if (item->type() == BTModuleTreeItem::Category) prepare_category_item(widgetItem, item);
+ ...
+ }
+
+
+ @author The BibleTime team <info@bibletime.info>
+*/
+class BTModuleTreeItem
+{
+public:
+
+ /**
+ * A filter which is given to the root constructor. It filters some modules
+ * out from the tree. If it returns true when the filter() is called the module will be added,
+ * if it returns false the module will be left out.
+ *
+ * If you want for example to get only unindexed modules in the list you should
+ * write a class (possibly a small inner class inside the calling class) which
+ * inherits Filter and write the operator() function which returns true if the
+ * module is unindexed and false if it's indexed.
+ *
+ * It's also possible to do arbitrary tasks to modules by using more complex subclasses.
+ *
+ * The filters will be applied in the order in which they are in the list.
+ * A module will be filtered out if even one filter rejects it and testing
+ * will stop with the first negative.
+ *
+ * Example:
+ * QList<BTModuleTreeItem::Filter*> filters;
+ * MyFilter filter; BTModuleTreeItem::HiddenOff hideFilter;
+ * filters.append(&hideFilter); filters.append(&filter);
+ * BTModuleTreeItem root(filters, BTModuleTreeItem::CatLangMod);
+ */
+ struct Filter {
+ virtual bool filter(CSwordModuleInfo*) = 0;
+ inline virtual ~Filter() {};
+ };
+
+ /**
+ * One example of a filter which can be used with any view. If the module has been
+ * set "hidden" it will be filtered out.
+ */
+ struct HiddenOff : public Filter {
+ inline bool filter(CSwordModuleInfo* mi) { return !mi->isHidden(); }
+ inline virtual ~HiddenOff() {};
+ };
+
+ /**
+ * Type of the item: root item, category (Bibles, Commentaries etc.), language or module.
+ */
+ enum Type {Root, Category, Language, Module};
+
+ /**
+ * Tells how to group the modules. For example:
+ * CatLangMod: first category, second language, third module. Mod: don't use
+ * Category or Language at all, Module is toplevel and tree is flat.
+ */
+ enum Grouping {CatLangMod, CatMod, LangCatMod, LangMod, Mod};
+
+
+ /**
+ * This constructor creates a root item. Create it for example with scoped_ptr or in stack.
+ * The root item is populated with the item tree.
+ * The constructor takes a list of filters (see Filter), grouping indicator (see Grouping)
+ * and optionally the module list from which the tree is constructed
+ * (by default CPointers::backend()->moduleList() is used).
+ */
+ BTModuleTreeItem(QList<BTModuleTreeItem::Filter*>& filters,
+ BTModuleTreeItem::Grouping grouping, QList<CSwordModuleInfo*>* modules = 0);
+
+ /** When the root item is deleted the whole tree is deleted. */
+ ~BTModuleTreeItem();
+
+ /**
+ * Returns the item type.
+ */
+ inline BTModuleTreeItem::Type type() const {return m_type;}
+ /**
+ * Returns the item text (category name, language name or module name).
+ */
+ inline QString text() const {return m_text;}
+ /**
+ * Returns the path to the icon which is appropriate for this type of item, or QString::null.
+ */
+ QString iconName() const;
+ /**
+ * If the type is Module returns a pointer to the corresponding CSwordModuleInfo object,
+ * otherwise returns 0.
+ */
+ inline CSwordModuleInfo* moduleInfo() const {return m_moduleInfo;}
+ /**
+ * Returns a list of the direct children of this item.
+ */
+ QList<BTModuleTreeItem*> children() const;
+
+ /**
+ * For alphabetical sorting which uses text(). See QString::localeAwareCompare().
+ * Categories will always be in the same order regardless of the i18n.
+ */
+ static bool localeAwareLessThan(BTModuleTreeItem* first, BTModuleTreeItem* second);
+
+
+private:
+ /**
+ * Private constructor which sets the members.
+ */
+ BTModuleTreeItem(BTModuleTreeItem* parentItem, const QString& text, Type type, CSwordModuleInfo* info=0, CSwordModuleInfo::Category category=CSwordModuleInfo::UnknownCategory);
+ /** Default ctor is private because it is not to be called.*/
+ BTModuleTreeItem();
+
+ /** Creates the tree under this root item (called only from root ctor). */
+ void create_tree(QList<BTModuleTreeItem::Filter*>& filters, BTModuleTreeItem::Grouping grouping);
+ /** Sorts recursively the children of of the given item. */
+ void sort_children(BTModuleTreeItem* parent);
+ /** Helper function for creating a group item while creating the tree. */
+ BTModuleTreeItem* create_parent_item(BTModuleTreeItem* parent, const QString& text, BTModuleTreeItem::Type type, CSwordModuleInfo::Category category=CSwordModuleInfo::UnknownCategory);
+
+ CSwordModuleInfo* m_moduleInfo;
+ QString m_text;
+ BTModuleTreeItem* m_firstChild;
+ BTModuleTreeItem* m_next;
+ Type m_type;
+ CSwordModuleInfo::Category m_category;
+ QList<CSwordModuleInfo*> m_originalModuleList;
+};
+
+#endif
diff --git a/src/backend/config/cbtconfig.cpp b/src/backend/config/cbtconfig.cpp
new file mode 100644
index 0000000..a0fb4f2
--- /dev/null
+++ b/src/backend/config/cbtconfig.cpp
@@ -0,0 +1,720 @@
+/*********
+*
+* 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 "cbtconfig.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/clanguagemgr.h"
+#include "backend/managers/cdisplaytemplatemgr.h"
+#include "backend/btmoduletreeitem.h"
+#include "util/cpointers.h"
+#include "util/directoryutil.h"
+#include "frontend/searchdialog/btsearchoptionsarea.h"
+
+//Qt includes
+#include <QApplication>
+#include <QString>
+#include <QStringList>
+#include <QMap>
+#include <QList>
+#include <QDebug>
+#include <QSettings>
+#include <QLocale>
+#include <QWebSettings>
+
+//Sword includes
+#include <versekey.h> //for range configuration
+
+//init statics
+QFont* CBTConfig::m_defaultFont = 0;
+CBTConfig::FontCache CBTConfig::fontConfigMap;
+
+/* No constructor and destructor, because this class only contains static methods.
+ It won't be instantiated. */
+
+QString CBTConfig::getKey( const CBTConfig::strings ID) {
+ switch ( ID ) {
+ case bibletimeVersion: return "bibletimeVersion";
+ case language: return "language";
+ case displayStyle: return "displayStyle";
+ case bookshelfCurrentItem: return "bookshelfCurrentItem";
+ }
+ Q_ASSERT(false);
+ return QString::null;
+}
+
+QString CBTConfig::getDefault( const CBTConfig::strings ID) {
+ switch ( ID ) {
+ case bibletimeVersion: return "0.0"; // main() will realize this and set the value to VERSION
+ case language: return QLocale::system().name();
+ case displayStyle: return CDisplayTemplateMgr::defaultTemplate();
+ case bookshelfCurrentItem: return QString();
+ }
+ return QString::null;
+}
+
+QString CBTConfig::getKey( const CBTConfig::modules ID) {
+ switch ( ID ) {
+ case standardBible: return "standardBible";
+ case standardCommentary: return "standardCommentary";
+ case standardLexicon: return "standardLexicon";
+ case standardDailyDevotional: return "standardDailyDevotional";
+ case standardHebrewStrongsLexicon: return "standardHebrewLexicon";
+ case standardGreekStrongsLexicon: return "standardGreekLexicon";
+ case standardHebrewMorphLexicon: return "standardHebrewMorphLexicon";
+ case standardGreekMorphLexicon: return "standardGreekMorphLexicon";
+ }
+ Q_ASSERT(false);
+ return QString::null;
+}
+
+QString CBTConfig::getDefault( const CBTConfig::modules ID) {
+ // CSwordBackend* b = CPointers::backend();
+ switch ( ID ) {
+ case standardBible: return "KJV";
+ case standardCommentary: return "MHC";
+ case standardLexicon: return "ISBE";
+ case standardDailyDevotional: return ""; //no default
+
+ case standardHebrewStrongsLexicon: return "StrongsHebrew";
+ case standardGreekStrongsLexicon: return "StrongsGreek";
+ case standardHebrewMorphLexicon: return "StrongsHebrew";
+ case standardGreekMorphLexicon: return "StrongsGreek";
+ }
+
+ return QString::null;
+}
+
+QString CBTConfig::getKey( const CBTConfig::bools ID) {
+ switch ( ID ) {
+ case firstSearchDialog: return "firstSearchDialog";
+ case readOldBookmarks: return "readOldBookmarks";
+
+ case toolbar: return "toolbar";
+ case mainIndex: return "mainIndex";
+ case infoDisplay: return "infoDisplay";
+
+ case autoTileVertical: return "autoTileVertical";
+ case autoTileHorizontal: return "autoTileHorizontal";
+ case autoCascade: return "autoCascade";
+
+ case lineBreaks: return "lineBreaks";
+ case verseNumbers: return "verseNumbers";
+
+ case logo: return "logo";
+ case autoDeleteOrphanedIndices: return "autoDeleteOrphanedIndices";
+ case crashedLastTime: return "crashedLastTime";
+ case crashedTwoTimes: return "crashedTwoTimes";
+
+ case bookshelfShowHidden: return "bookshelfShowHidden";
+ case allowNetworkConnection: return "allowNetworkConnection";
+ }
+ Q_ASSERT(false);
+ return false;
+}
+
+QString CBTConfig::getKey( const CBTConfig::ints ID) {
+ switch ( ID ) {
+ case footnotes: return "footnotes";
+ case strongNumbers: return "strongNumbers";
+ case headings: return "headings";
+ case morphTags: return "morphTags";
+ case lemmas: return "lemmas";
+ case hebrewPoints: return "hebrewPoints";
+ case hebrewCantillation: return "hebrewCantillation";
+ case greekAccents: return "greekAccents";
+ case textualVariants: return "textualVariants";
+ case scriptureReferences: return "scriptureReferences";
+ case morphSegmentation: return "morphSegmentation";
+ case bookshelfContentsX: return "bookshelfContentsX";
+ case bookshelfContentsY: return "bookshelfContentsY";
+ case magDelay: return "magDelay";
+ case bookshelfGrouping: return "bookshelfGrouping";
+ case mainindexActiveTab: return "mainindexActiveTab";
+ case searchDialogWidth: return "searchDialogWidth";
+ case searchDialogHeight: return "searchDialogHeight";
+ case searchDialogX: return "searchDialogX";
+ case searchDialogY: return "searchDialogY";
+ case searchType: return "searchType";
+ case installPathIndex: return "installPathIndex";
+ }
+ Q_ASSERT(false);
+ return QString::null;
+}
+
+bool CBTConfig::getDefault( const CBTConfig::bools ID) {
+ switch ( ID ) {
+ case firstSearchDialog: return true;
+ case readOldBookmarks: return false;
+
+ case toolbar: return true;
+ case mainIndex: return true;
+ case infoDisplay: return true;
+
+ case autoTileVertical: return true;
+ case autoTileHorizontal: return false;
+ case autoCascade: return false;
+
+ case lineBreaks: return false;
+ case verseNumbers: return true;
+
+ case logo: return true;
+ case autoDeleteOrphanedIndices: return true;
+ case crashedLastTime: return false;
+ case crashedTwoTimes: return false;
+ case bookshelfShowHidden: return false;
+ case allowNetworkConnection: return false;
+ }
+ return false;
+}
+
+int CBTConfig::getDefault( const CBTConfig::ints ID) {
+ switch ( ID ) {
+ case footnotes: return int(true);
+ case strongNumbers: return int(true);
+ case headings: return int(true);
+ case morphTags: return int(true);
+ case lemmas: return int(true);
+ case hebrewPoints: return int(true);
+ case hebrewCantillation: return int(true);
+ case greekAccents: return int(true);
+ case textualVariants: return int(false);
+ case scriptureReferences: return int(true);
+ case morphSegmentation: return int(true);
+ case bookshelfContentsX: return 0;
+ case bookshelfContentsY: return 0;
+ case magDelay: return 400;
+ case bookshelfGrouping: return BTModuleTreeItem::CatLangMod;
+ case searchDialogWidth: return 200;
+ case searchDialogHeight: return 400;
+ case searchDialogX: return 200;
+ case searchDialogY: return 200;
+ case searchType: return Search::BtSearchOptionsArea::AndType;
+ case mainindexActiveTab: return 0;
+ case installPathIndex: return 0;
+ }
+ return 0;
+}
+
+QString CBTConfig::getKey( const CBTConfig::intLists ID) {
+ switch ( ID ) {
+ case leftPaneSplitterSizes: return "leftPaneSplitterSizes";
+ case mainSplitterSizes: return "mainSplitterSizes";
+ case searchMainSplitterSizes: return "searchMainSplitterSizes";
+ case searchResultSplitterSizes: return "searchResultSplitterSizes";
+ }
+ Q_ASSERT(false);
+ return QString::null;
+}
+
+QList<int> CBTConfig::getDefault( const CBTConfig::intLists /*ID*/) {
+ QList<int> result;
+ /*switch ( ID ) {
+ case leftPaneSplitterSizes: break;
+ case mainSplitterSizes: break;
+ case searchMainSplitterSizes: break;
+ case searchResultSplitterSizes: break;*/
+ return result;
+}
+
+QString CBTConfig::getKey( const CBTConfig::stringLists ID) {
+ switch ( ID ) {
+ case searchCompletionTexts: return QString("searchCompletionTexts");
+ case searchTexts: return QString("searchTexts");
+ case searchModulesHistory: return QString("searchModulesHistory");
+ case bookshelfOpenGroups: return QString("bookshelfOpenGroups");
+ case hiddenModules: return QString("hiddenModules");
+ }
+ Q_ASSERT(false);
+ return QString::null;
+}
+
+QStringList CBTConfig::getDefault( const CBTConfig::stringLists ID) {
+ switch ( ID ) {
+ case searchTexts: {
+ QStringList list;
+ list.append(QString::null);
+ return list;
+ }
+ case searchCompletionTexts: return QStringList();
+ case bookshelfOpenGroups: return QStringList();
+ case hiddenModules: return QStringList();
+ case searchModulesHistory: return QStringList();
+ }
+ return QStringList();
+}
+
+QString CBTConfig::getKey( const CBTConfig::stringMaps ID) {
+ switch (ID) {
+ case searchScopes:
+ return QString("SearchScopes");
+ };
+ Q_ASSERT(false);
+ return QString::null;
+}
+
+CBTConfig::StringMap CBTConfig::getDefault( const CBTConfig::stringMaps ID) {
+ switch ( ID ) {
+ case searchScopes: {
+ CBTConfig::StringMap map;
+ map.insert(QObject::tr("Old testament"), QString("Gen - Mal"));
+ map.insert(QObject::tr("Moses/Pentateuch/Torah"),QString("Gen - Deut"));
+ map.insert(QObject::tr("History"), QString("Jos - Est"));
+ map.insert(QObject::tr("Prophets"), QString("Isa - Mal"));
+ map.insert(QObject::tr("New testament"), QString("Mat - Rev"));
+ map.insert(QObject::tr("Gospels"), QString("Mat - Joh"));
+ map.insert(QObject::tr("Letters/Epistles"), QString("Rom - Jude"));
+ map.insert(QObject::tr("Paul's Epistles"), QString("Rom - Phile"));
+
+ //make the list to the current bookname language!
+ CBTConfig::StringMap::Iterator it;
+ sword::VerseKey vk;
+ vk.setLocale("en_US");
+
+ for (it = map.begin(); it != map.end(); ++it) {
+ sword::ListKey list = vk.ParseVerseList(it.value().toLocal8Bit(), "Genesis 1:1", true);
+ QString data;
+ for (int i = 0; i < list.Count(); ++i) {
+ data += QString::fromUtf8(list.GetElement(i)->getRangeText()) + "; ";
+ }
+ map[it.key()] = data; //set the new data
+ };
+
+ return map;
+ };
+ default:
+ return CBTConfig::StringMap();
+ }
+
+ return CBTConfig::StringMap();
+}
+
+
+QString CBTConfig::getKey( const CLanguageMgr::Language* const language ) {
+ Q_ASSERT(!language->name().isEmpty());
+ return language->name();
+}
+
+QFont& CBTConfig::getDefault( const CLanguageMgr::Language* const)
+{
+ //language specific lookup of the font name
+ if (m_defaultFont)
+ {
+ return *m_defaultFont;
+ }
+
+// TODO - make the font name and size a configuration option
+ //int fontSize = QWebSettings::globalSettings()->fontSize(QWebSettings::DefaultFontSize);
+ int fontSize = 12;
+ QString fontName = QWebSettings::globalSettings()->fontFamily(QWebSettings::StandardFont);
+
+ m_defaultFont = new QFont(fontName, fontSize); //TODO: there may be a mem leak here!
+ return *m_defaultFont;
+}
+
+QString CBTConfig::get( const CBTConfig::strings ID)
+{
+ QString result;
+ getConfig()->beginGroup("strings");
+ result = getConfig()->value(getKey(ID), getDefault(ID)).toString();
+ getConfig()->endGroup();
+ return result;
+
+}
+
+CSwordModuleInfo* CBTConfig::get( const CBTConfig::modules ID)
+{
+ CSwordModuleInfo* result;
+ getConfig()->beginGroup("modules");
+ result = CPointers::backend()->findModuleByName( getConfig()->value(getKey(ID), getDefault(ID)).toString() );
+ getConfig()->endGroup();
+ return result;
+}
+
+bool CBTConfig::get( const CBTConfig::bools ID)
+{
+ bool result;
+ getConfig()->beginGroup("bools");
+ result = getConfig()->value(getKey(ID), getDefault(ID)).toBool();
+ getConfig()->endGroup();
+ return result;
+}
+
+int CBTConfig::get( const CBTConfig::ints ID)
+{
+ int result;
+ getConfig()->beginGroup("ints");
+ result = getConfig()->value(getKey(ID), getDefault(ID)).toInt();
+ getConfig()->endGroup();
+ return result;
+}
+
+QList<int> CBTConfig::get( const CBTConfig::intLists ID )
+{
+ QList<int> result;
+ getConfig()->beginGroup("intlists");
+ result = StringToIntList( getConfig()->value(getKey(ID), IntListToString( getDefault(ID) )).toString() );
+ getConfig()->endGroup();
+ return result;
+}
+
+QStringList CBTConfig::get( const CBTConfig::stringLists ID )
+{
+ QStringList result;
+ getConfig()->beginGroup("stringlists");
+ result = getConfig()->value(getKey(ID), getDefault(ID)).toStringList();
+ getConfig()->endGroup();
+ return result;
+}
+
+CBTConfig::StringMap CBTConfig::get( const CBTConfig::stringMaps ID )
+{
+ getConfig()->beginGroup(getKey(ID));
+ CBTConfig::StringMap map;
+
+ QStringList keys(getConfig()->childKeys());
+ if (!keys.isEmpty()) {
+ switch (ID) {
+ case searchScopes: { //make sure we return the scopes in the chosen language. saved keys are in english
+ sword::VerseKey vk;
+ foreach (QString key, keys) {
+ Q_ASSERT(!key.isEmpty());
+ sword::ListKey list = vk.ParseVerseList(getConfig()->value(key).toString().toUtf8(), "Genesis 1:1", true);
+ QString data;
+ for (int i = 0; i < list.Count(); ++i) {
+ data += QString::fromUtf8(list.GetElement(i)->getRangeText()) + "; ";
+ }
+ map[key] = data; //set the new data
+ }
+ }
+ default: break;
+ }
+ }
+ else
+ {
+ map = getDefault(ID);
+ }
+ getConfig()->endGroup();
+ return map;
+}
+
+CBTConfig::FontSettingsPair CBTConfig::get( const CLanguageMgr::Language* const language )
+{
+ if (fontConfigMap.contains(language)) {
+ return fontConfigMap.find(language).value();
+ }
+
+ FontSettingsPair settings;
+
+ getConfig()->beginGroup("font standard settings");
+ settings.first = getConfig()->value(getKey(language), QVariant(false)).toBool();
+ getConfig()->endGroup();
+ getConfig()->beginGroup("fonts");
+
+ QFont font;
+ if (settings.first)
+ font.fromString(getConfig()->value(getKey(language), getDefault(language)).toString());
+ else
+ font = getDefault(language);
+
+ settings.second = font;
+ getConfig()->endGroup();
+
+ fontConfigMap.insert(language, settings); //cache the value
+ return settings;
+}
+
+void CBTConfig::set( const CBTConfig::strings ID, const QString value )
+{
+// KConfigGroup cg = CBTConfig::getConfig()->group("strings");
+// cg.writeEntry(getKey(ID), value);
+ getConfig()->beginGroup("strings");
+ getConfig()->setValue(getKey(ID), value);
+ getConfig()->endGroup();
+}
+
+void CBTConfig::set( const CBTConfig::modules ID, CSwordModuleInfo* const value )
+{
+// KConfigGroup cg = CBTConfig::getConfig()->group("modules");
+// cg.writeEntry(getKey(ID), value ? value->name() : QString::null);
+ getConfig()->beginGroup("modules");
+ getConfig()->setValue(getKey(ID), value ? value->name() : QString::null);
+ getConfig()->endGroup();
+}
+
+void CBTConfig::set( const CBTConfig::modules ID, const QString& value )
+{
+ CSwordModuleInfo* module = CPointers::backend()->findModuleByName(value);
+ if (module) {
+ CBTConfig::set(ID, module);
+ }
+}
+
+void CBTConfig::set(const CBTConfig::bools ID,const bool value )
+{
+ getConfig()->beginGroup("bools");
+ getConfig()->setValue(getKey(ID), value);
+ getConfig()->endGroup();
+}
+
+void CBTConfig::set(const CBTConfig::ints ID, const int value )
+{
+ getConfig()->beginGroup("ints");
+ getConfig()->setValue(getKey(ID), value);
+ getConfig()->endGroup();
+}
+
+void CBTConfig::set( const CBTConfig::intLists ID, const QList<int> value )
+{
+ getConfig()->beginGroup("intlists");
+ getConfig()->setValue(getKey(ID), IntListToString(value));
+ getConfig()->endGroup();
+}
+
+void CBTConfig::set( const CBTConfig::stringLists ID, const QStringList value )
+{
+ getConfig()->beginGroup("stringlists");
+ getConfig()->setValue(getKey(ID), value);
+ getConfig()->endGroup();
+}
+
+void CBTConfig::set( const CBTConfig::stringMaps ID, const CBTConfig::StringMap value )
+{
+ getConfig()->beginGroup(getKey(ID));
+ getConfig()->remove(""); //clear all entries of this group to make sure old stuff gets removed
+
+ switch (ID) {
+ case searchScopes: {
+ /**
+ * We want to make sure that the search scopes are saved with english key names so loading them
+ * will always work with each locale set.
+ */
+ CBTConfig::StringMap::ConstIterator it;
+ QString data;// = QString::null;
+
+ sword::VerseKey vk;
+ for (it = value.begin(); it != value.end(); ++it) {
+ sword::ListKey list = vk.ParseVerseList(it.value().toUtf8(), "Genesis 1:1", true);
+ data = QString::null;
+ for (int i = 0; i < list.Count(); ++i) {
+ if ( sword::VerseKey* range = dynamic_cast<sword::VerseKey*>(list.GetElement(i)) ) {
+ range->setLocale("en");
+ data += QString::fromUtf8( range->getRangeText() ) + ";";
+ }
+ }
+ getConfig()->setValue(it.key(), data);
+ }
+ break;
+ }
+ default: {
+ for (CBTConfig::StringMap::ConstIterator it = value.begin(); it != value.end(); ++it) {
+ getConfig()->setValue(it.key(), it.value());
+ }
+ break;
+ }
+ }
+ getConfig()->endGroup();
+}
+
+
+void CBTConfig::set( const CLanguageMgr::Language* const language, const FontSettingsPair& value )
+{
+ getConfig()->beginGroup("fonts");
+ getConfig()->setValue(getKey(language), value.second.toString());
+ getConfig()->endGroup();
+ getConfig()->beginGroup("font standard settings");
+ getConfig()->setValue(getKey(language), value.first);
+ getConfig()->endGroup();
+
+ if (fontConfigMap.contains(language)) {
+ fontConfigMap.remove
+ (language); //remove it from the cache
+ }
+}
+
+CSwordBackend::DisplayOptions CBTConfig::getDisplayOptionDefaults()
+{
+ CSwordBackend::DisplayOptions options;
+ options.lineBreaks = get(CBTConfig::lineBreaks);
+ options.verseNumbers = get(CBTConfig::verseNumbers);
+
+ return options;
+}
+
+CSwordBackend::FilterOptions CBTConfig::getFilterOptionDefaults()
+{
+ CSwordBackend::FilterOptions options;
+
+ options.footnotes = true; //required for the info display
+ options.strongNumbers = true; //get(CBTConfig::strongNumbers);
+ options.headings = get(CBTConfig::headings);
+ options.morphTags = true;//required for the info display
+ options.lemmas = true;//required for the info display
+ options.redLetterWords = true;
+ options.hebrewPoints = get(CBTConfig::hebrewPoints);
+ options.hebrewCantillation = get(CBTConfig::hebrewCantillation);
+ options.greekAccents = get(CBTConfig::greekAccents);
+ options.textualVariants = get(CBTConfig::textualVariants);
+ options.scriptureReferences = get(CBTConfig::scriptureReferences);
+ options.morphSegmentation = get(CBTConfig::morphSegmentation);
+
+ return options;
+}
+
+//void CBTConfig::setupAccelSettings(const CBTConfig::keys /*type*/, KActionCollection* const /*actionCollection*/)
+//{
+// qDebug("CBTConfig::setupAccelSettings");
+// QString groupName;
+// switch (type) {
+// case allWindows : {
+// groupName = "Displaywindow shortcuts";
+// break;
+// };
+// case writeWindow : {
+// groupName = "Writewindow shortcuts";
+// break;
+// };
+// case readWindow : {
+// groupName = "Readwindow shortcuts";
+// break;
+// };
+// case bookWindow : {
+// groupName = "Book shortcuts";
+// break;
+// };
+// case bibleWindow : {
+// groupName = "Bible shortcuts";
+// break;
+// };
+// case commentaryWindow : {
+// groupName = "Commentary shortcuts";
+// break;
+// };
+// case lexiconWindow : {
+// groupName = "Lexicon shortcuts";
+// break;
+// };
+// case application : {
+// groupName = "Application shortcuts";
+// break;
+// };
+// };
+// qDebug() << groupName;
+// Q_ASSERT(CBTConfig::getConfig());
+// //buggy???
+// KConfigGroup* cg = &(CBTConfig::getConfig()->group(groupName));
+// //KConfigGroup* cg;
+//
+// Q_ASSERT(cg);
+// Q_ASSERT(actionCollection);
+// //actionCollection->readSettings(cg);
+// actionCollection->setConfigGroup(groupName);
+//
+// actionCollection->readSettings();
+// qDebug("CBTConfig::setupAccelSettings end");
+//}
+
+//void CBTConfig::saveAccelSettings(const CBTConfig::keys /*type*/, KActionCollection* const /*actionCollection*/)
+//{
+// qDebug("CBTConfig::saveAccelSettings");
+// QString groupName;
+// switch (type) {
+// case allWindows : {
+// groupName = "Displaywindow shortcuts";
+// break;
+// };
+// case writeWindow : {
+// groupName = "Writewindow shortcuts";
+// break;
+// };
+// case readWindow : {
+// groupName = "Readwindow shortcuts";
+// break;
+// };
+// case bookWindow : {
+// groupName = "Book shortcuts";
+// break;
+// };
+// case bibleWindow : {
+// groupName = "Bible shortcuts";
+// break;
+// };
+// case commentaryWindow : {
+// groupName = "Commentary shortcuts";
+// break;
+// };
+// case lexiconWindow : {
+// groupName = "Lexicon shortcuts";
+// break;
+// };
+// case application : {
+// groupName = "Application shortcuts";
+// break;
+// };
+// };
+//
+// // KConfigGroup* cg = &(CBTConfig::getConfig()->group(groupName));
+//
+// qDebug("NOT saving accelerators!");
+// //actionCollection->writeSettings(cg);
+// qDebug("CBTConfig::saveAccelSettings end");
+//}
+
+
+QString CBTConfig::getModuleEncryptionKey( const QString& module )
+{
+ Q_ASSERT(!module.isEmpty());
+ QString result;
+ getConfig()->beginGroup("Module keys");
+ result = getConfig()->value(module, QVariant(QString::null)).toString();
+ getConfig()->endGroup();
+ return result;
+}
+
+void CBTConfig::setModuleEncryptionKey( const QString& module, const QString& key )
+{
+ getConfig()->beginGroup("Module keys");
+ getConfig()->setValue(module, key);
+ getConfig()->endGroup();
+}
+
+QSettings* CBTConfig::getConfig()
+{
+ static QSettings config(util::filesystem::DirectoryUtil::getUserBaseDir().absolutePath() + "/bibletimerc", QSettings::IniFormat);
+ return &config;
+}
+
+void CBTConfig::syncConfig()
+{
+ CBTConfig::getConfig()->sync();
+}
+
+QString CBTConfig::IntListToString( const QList<int> intList )
+{
+ QStringList intStrings;
+ foreach(int i, intList)
+ {
+ intStrings << QString::number(i);
+ }
+ return intStrings.join(",");
+}
+
+QList<int> CBTConfig::StringToIntList( const QString intListString )
+{
+ QList<int> intList;
+ if (!intListString.isEmpty() && intListString.contains(','))
+ {
+ foreach(QString intString, intListString.split(","))
+ {
+ intList << intString.trimmed().toInt();
+ }
+ }
+ return intList;
+}
diff --git a/src/backend/config/cbtconfig.h b/src/backend/config/cbtconfig.h
new file mode 100644
index 0000000..0ded865
--- /dev/null
+++ b/src/backend/config/cbtconfig.h
@@ -0,0 +1,197 @@
+/*********
+*
+* 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 CBTCONFIG_H
+#define CBTCONFIG_H
+
+#include "backend/managers/cswordbackend.h"
+
+//Qt includes
+#include <QString>
+#include <QFont>
+#include <QList>
+#include <QMap>
+
+//Forward declarations
+class QSettings;
+//class CLanguageMgr::Language;
+
+/**
+ * This class is the interface to the config object of BibleTime
+ * @author The BibleTime team
+ */
+class CBTConfig {
+public:
+ typedef QMap<QString, QString> StringMap;
+
+ enum strings {
+ bibletimeVersion,
+ language,
+ displayStyle,
+ bookshelfCurrentItem
+ };
+ enum modules {
+ standardBible = 0, //just to make sure, default is IMHO 0, so that's redundant here
+ standardCommentary,
+ standardLexicon,
+ standardDailyDevotional,
+ standardHebrewStrongsLexicon,
+ standardGreekStrongsLexicon,
+ standardHebrewMorphLexicon,
+ standardGreekMorphLexicon,
+ lastModuleType = standardGreekMorphLexicon
+ };
+ enum bools {
+ firstSearchDialog,
+ readOldBookmarks,
+
+ toolbar,
+ mainIndex,
+ infoDisplay,
+
+ autoTileVertical,
+ autoTileHorizontal,
+ autoCascade,
+
+ lineBreaks,
+ verseNumbers,
+
+ logo,
+ autoDeleteOrphanedIndices,
+ crashedLastTime,
+ crashedTwoTimes,
+
+ bookshelfShowHidden,
+
+ allowNetworkConnection
+ };
+ enum ints {
+ footnotes,
+ strongNumbers,
+ headings,
+ morphTags,
+ lemmas,
+ hebrewPoints,
+ hebrewCantillation,
+ greekAccents,
+ textualVariants,
+ scriptureReferences,
+ morphSegmentation,
+
+ bookshelfContentsX,
+ bookshelfContentsY,
+ magDelay, /* The delay until a mouse move makes the content appear in the mag */
+ bookshelfGrouping,
+ mainindexActiveTab,
+
+ searchDialogWidth,
+ searchDialogHeight,
+ searchDialogX,
+ searchDialogY,
+ searchType,
+
+ installPathIndex
+ };
+ enum intLists {
+ leftPaneSplitterSizes,
+ mainSplitterSizes,
+ searchMainSplitterSizes,
+ searchResultSplitterSizes
+ };
+ enum stringLists {
+ searchCompletionTexts,
+ searchTexts,
+ searchModulesHistory,
+ bookshelfOpenGroups,
+ hiddenModules
+ };
+ enum keys {
+ allWindows,
+ readWindow,
+ writeWindow,
+ bookWindow,
+ bibleWindow,
+ commentaryWindow,
+ lexiconWindow,
+ application
+ };
+ enum stringMaps {
+ searchScopes
+ };
+ typedef std::pair<bool, QFont> FontSettingsPair;
+
+ static QString get( const CBTConfig::strings );
+ static CSwordModuleInfo* get( const CBTConfig::modules );
+ static bool get( const CBTConfig::bools );
+ static int get( const CBTConfig::ints );
+ static QList<int> get( const CBTConfig::intLists );
+ static QStringList get( const CBTConfig::stringLists );
+ static CBTConfig::StringMap get( const CBTConfig::stringMaps );
+
+ static FontSettingsPair get( const CLanguageMgr::Language* const );
+
+ static QString getDefault( const CBTConfig::strings );
+ static QString getDefault( const CBTConfig::modules );
+ static bool getDefault( const CBTConfig::bools );
+ static int getDefault( const CBTConfig::ints );
+ static QList<int> getDefault( const CBTConfig::intLists );
+ static QStringList getDefault( const CBTConfig::stringLists );
+ static CBTConfig::StringMap getDefault( const CBTConfig::stringMaps );
+ static QFont& getDefault( const CLanguageMgr::Language* const );
+
+ static void set( const CBTConfig::strings, const QString value );
+ static void set( const CBTConfig::modules, CSwordModuleInfo* const module );
+ static void set( const CBTConfig::modules, const QString& moduleName );
+ static void set( const CBTConfig::bools, const bool value );
+ static void set( const CBTConfig::ints, const int value );
+ static void set( const CBTConfig::intLists, const QList<int> value );
+ static void set( const CBTConfig::stringLists, const QStringList value);
+ static void set( const CBTConfig::stringMaps, const CBTConfig::StringMap value);
+ static void set( const CLanguageMgr::Language* const language, const FontSettingsPair& fontSettings );
+
+ static CSwordBackend::FilterOptions getFilterOptionDefaults();
+ static CSwordBackend::DisplayOptions getDisplayOptionDefaults();
+
+// static void setupAccelSettings(const CBTConfig::keys type, KActionCollection* const actionCollection);
+// static void saveAccelSettings(const CBTConfig::keys type, KActionCollection* const actionCollection);
+
+ static QString getModuleEncryptionKey( const QString& name );
+ static void setModuleEncryptionKey( const QString& name, const QString& key );
+
+ /** Re-reads the config from disk */
+ static void syncConfig();
+
+private:
+ friend class BibleTimeTest;
+ /** The config object.
+ * @return A config object which is used currently, may be the global config or the session config
+ */
+ static QSettings* getConfig();
+
+ static QString getKey( const CBTConfig::strings );
+ static QString getKey( const CBTConfig::modules );
+ static QString getKey( const CBTConfig::bools );
+ static QString getKey( const CBTConfig::ints );
+ static QString getKey( const CBTConfig::intLists );
+ static QString getKey( const CBTConfig::stringLists );
+ static QString getKey( const CBTConfig::stringMaps );
+ static QString getKey( const CLanguageMgr::Language* const );
+
+ static QString IntListToString( const QList<int> );
+ static QList<int> StringToIntList( const QString );
+
+ //static caches
+ static QFont* m_defaultFont;
+
+ typedef QMap<const CLanguageMgr::Language*, CBTConfig::FontSettingsPair> FontCache;
+ static QMap<const CLanguageMgr::Language*, CBTConfig::FontSettingsPair> fontConfigMap;
+};
+
+
+#endif
diff --git a/src/backend/cswordmodulesearch.cpp b/src/backend/cswordmodulesearch.cpp
new file mode 100644
index 0000000..f57a87a
--- /dev/null
+++ b/src/backend/cswordmodulesearch.cpp
@@ -0,0 +1,123 @@
+/*********
+*
+* 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 "cswordmodulesearch.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/cswordbackend.h"
+#include "backend/config/cbtconfig.h"
+
+//Sword includes
+#include <swmodule.h>
+#include <swkey.h>
+#include <listkey.h>
+
+
+CSwordModuleSearch* CSwordModuleSearch::searcher = 0;
+
+CSwordModuleSearch::CSwordModuleSearch()
+ : m_searchedText(QString::null),
+ m_searchOptions(0),
+ m_foundItems(false)
+{
+ searcher = this;
+}
+
+CSwordModuleSearch::~CSwordModuleSearch() {
+ searcher = 0;
+}
+
+/** This function sets the modules which should be searched. */
+void CSwordModuleSearch::setModules( const QList<CSwordModuleInfo*>& list ) {
+ m_moduleList = list;
+}
+
+/** Starts the search for the search text. */
+bool CSwordModuleSearch::startSearch() {
+ backend()->setFilterOptions ( CBTConfig::getFilterOptionDefaults() );
+ m_foundItems = false;
+
+ bool foundItems = false;
+
+ // for (m_moduleList.first(); m_moduleList.current() && !m_terminateSearch; m_moduleList.next()) {
+ QList<CSwordModuleInfo*>::iterator end_it = m_moduleList.end();
+
+ for (QList<CSwordModuleInfo*>::iterator it = m_moduleList.begin(); it != end_it; ++it) {
+ if ( (*it)->searchIndexed(m_searchedText/*, m_searchOptions*/, m_searchScope) ) {
+ foundItems = true;
+ }
+ }
+
+ m_foundItems = foundItems;
+
+ //m_finishedSig.activate();
+ emit finished();
+ return true;
+}
+
+/** Sets the text which should be search in the modules. */
+void CSwordModuleSearch::setSearchedText( const QString& text ) {
+ m_searchedText = text;
+}
+
+/** Sets the search scope. */
+void CSwordModuleSearch::setSearchScope( const sword::ListKey& scope ) {
+ m_searchScope.copyFrom( scope );
+
+ if (!strlen(scope.getRangeText())) { //we can't search with an empty search scope, would crash
+ //reset the scope
+ resetSearchScope();
+
+ //disable searching with a scope!
+ // if (m_searchOptions | useScope) {
+ // qWarning("using the scope!");
+ //set back the scope flag
+ // }
+ }
+}
+
+/** Sets the search scope back. */
+void CSwordModuleSearch::resetSearchScope() {
+ m_searchScope.ClearList();
+}
+
+/** Returns true if in the last search the searcher found items, if no items were found return false. */
+bool CSwordModuleSearch::foundItems() const {
+ return m_foundItems;
+}
+
+/** Returns a copy of the used search scope. */
+const sword::ListKey& CSwordModuleSearch::searchScope() const {
+ return m_searchScope;
+}
+
+void CSwordModuleSearch::connectFinished( QObject *receiver, const char *member ) {
+ //m_finishedSig.connect(receiver, member);
+ QObject::connect(this, SIGNAL(finished()), receiver, member);
+}
+
+/** Should be called when the search finished. */
+void CSwordModuleSearch::searchFinished() {
+ //m_finishedSig.activate();
+ emit finished();
+}
+
+bool CSwordModuleSearch::modulesHaveIndices( const QList<CSwordModuleInfo*>& modules )
+{
+ bool hasIndices = true;
+ QList<CSwordModuleInfo*>::const_iterator end_it = modules.end();
+ for( QList<CSwordModuleInfo*>::const_iterator it = modules.begin(); it != end_it; ++it) {
+ if (!(*it)->hasIndex()) {
+ hasIndices = false;
+ break;
+ }
+ }
+ return hasIndices;
+}
diff --git a/src/backend/cswordmodulesearch.h b/src/backend/cswordmodulesearch.h
new file mode 100644
index 0000000..7ba6a6f
--- /dev/null
+++ b/src/backend/cswordmodulesearch.h
@@ -0,0 +1,98 @@
+/*********
+*
+* 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 CSWORDMODULESEARCH_H
+#define CSWORDMODULESEARCH_H
+
+//BibleTime - backend
+class CSwordModuleInfo;
+
+//BibleTime - utils
+#include "util/cpointers.h"
+
+//Qt includes
+#include <QObject>
+#include <QString>
+
+//Sword includes
+#include <listkey.h>
+
+/**
+ * CSwordModuleSearch manages the search on Sword modules. It manages the thread(s)
+ * and manages the different modules.
+ *
+ * @author The BibleTime team
+ * @version $Id: cswordmodulesearch.h,v 1.34 2006/08/08 19:32:48 joachim Exp $
+ */
+
+class CSwordModuleSearch: public QObject, CPointers {
+ Q_OBJECT
+
+public:
+ CSwordModuleSearch();
+ /**
+ * The destructor of this class. It cleans uop memory before it's deleted.
+ */
+ virtual ~CSwordModuleSearch();
+ /**
+ * Sets the text which should be search in the modules.
+ */
+ void setSearchedText( const QString& );
+ /**
+ * Starts the search for the search text.
+ */
+ bool startSearch();
+ /**
+ * This function sets the modules which should be searched.
+ */
+ void setModules( const QList<CSwordModuleInfo*>& );
+ /**
+ * Sets the search scope.
+ */
+ void setSearchScope( const sword::ListKey& scope );
+ /**
+ * Sets the seaech scope back.
+ */
+ void resetSearchScope();
+ /**
+ * @return "true" if in the last search the searcher found items, if no items were found return "false"
+ */
+ bool foundItems() const;
+ /**
+ * Returns a copy of the used search scope.
+ */
+ const sword::ListKey& searchScope() const;
+
+ void connectFinished( QObject * receiver, const char * member );
+ void searchFinished();
+
+ /**
+ * Returns true if all of the specified modules have indices already built.
+ */
+ bool modulesHaveIndices( const QList<CSwordModuleInfo*>& );
+
+protected:
+ QString m_searchedText;
+ sword::ListKey m_searchScope;
+ QList<CSwordModuleInfo*> m_moduleList;
+
+ int m_searchOptions;
+
+ bool m_foundItems;
+
+signals:
+ void finished();
+
+private:
+ static CSwordModuleSearch* searcher;
+};
+
+#endif
diff --git a/src/backend/drivers/cswordbiblemoduleinfo.cpp b/src/backend/drivers/cswordbiblemoduleinfo.cpp
new file mode 100644
index 0000000..921157b
--- /dev/null
+++ b/src/backend/drivers/cswordbiblemoduleinfo.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.
+*
+**********/
+
+//BibleTime includes
+#include "cswordbiblemoduleinfo.h"
+#include "backend/managers/cswordbackend.h"
+#include "backend/keys/cswordversekey.h"
+
+//Qt
+#include <QFile>
+
+//Sword
+#include <versekey.h>
+
+#include <boost/scoped_ptr.hpp>
+
+
+CSwordBibleModuleInfo::CSwordBibleModuleInfo( sword::SWModule* module, CSwordBackend* const usedBackend )
+: CSwordModuleInfo(module, usedBackend),
+m_lowerBound(0),
+m_upperBound(0),
+m_bookList(0),
+m_cachedLocale("unknown"),
+m_hasOT(-1),
+m_hasNT(-1) {}
+
+CSwordBibleModuleInfo::CSwordBibleModuleInfo( const CSwordBibleModuleInfo& m ) :
+CSwordModuleInfo(m),
+m_lowerBound(0),
+m_upperBound(0),
+m_bookList(0) {
+ if (m.m_bookList) {
+ m_bookList = new QStringList();
+ *m_bookList = *m.m_bookList;
+ }
+
+ m_hasOT = m.m_hasOT;
+ m_hasNT = m.m_hasNT;
+ m_cachedLocale = m.m_cachedLocale;
+}
+
+CSwordModuleInfo* CSwordBibleModuleInfo::clone() {
+ return new CSwordBibleModuleInfo(*this);
+}
+
+CSwordBibleModuleInfo::~CSwordBibleModuleInfo() {
+ delete m_bookList;
+}
+
+void CSwordBibleModuleInfo::initBounds() {
+ if (m_hasOT == -1) {
+ m_hasOT = hasTestament(OldTestament);
+ }
+
+ if (m_hasNT == -1) {
+ m_hasNT = hasTestament(NewTestament);
+ }
+
+ if (m_hasOT) {
+ m_lowerBound.key("Genesis 1:1");
+ }
+ else {
+ m_lowerBound.key("Matthew 1:1");
+ }
+
+ if (!m_hasNT) {
+ m_upperBound.key("Malachi 4:6");
+ }
+ else {
+ m_upperBound.key("Revelation of John 22:21");
+ }
+}
+
+
+/** Returns the books available in this module */
+QStringList* CSwordBibleModuleInfo::books() {
+ if (m_cachedLocale != backend()->booknameLanguage()) { //if the locale has changed
+ delete m_bookList;
+ m_bookList = 0;
+ }
+
+ if (!m_bookList) {
+ m_bookList = new QStringList();
+
+ initBounds();
+ int min = 0;
+ int max = 1;
+
+ //find out if we have ot and nt, only ot or only nt
+
+ if (m_hasOT>0 && m_hasNT>0) { //both
+ min = 0;
+ max = 1;
+ }
+ else if (m_hasOT>0 && !m_hasNT) { //only OT
+ min = 0;
+ max = 0;
+ }
+ else if (!m_hasOT && m_hasNT>0) { //only NT
+ min = 1;
+ max = 1;
+ }
+ else if (!m_hasOT && !m_hasNT) { //somethings wrong here! - no OT and no NT
+ qWarning("CSwordBibleModuleInfo (%s) no OT and not NT! Check your config!", module()->Name());
+ min = 0;
+ max = -1;
+ }
+
+ boost::scoped_ptr<sword::VerseKey> key((sword::VerseKey *)module()->CreateKey());
+ (*key) = sword::TOP;
+
+ for (key->Testament(min+1); !key->Error() && (key->Testament()-1) <= max; key->Book(key->Book()+1)) {
+ m_bookList->append( QString::fromUtf8(key->getBookName()) );
+ }
+
+ m_cachedLocale = backend()->booknameLanguage();
+ }
+
+ return m_bookList;
+}
+
+/** Returns the number of chapters for the given book. */
+unsigned int CSwordBibleModuleInfo::chapterCount(const unsigned int book) {
+ int result = 0;
+
+ boost::scoped_ptr<sword::VerseKey> key((sword::VerseKey *)module()->CreateKey());
+ (*key) = sword::TOP;
+
+ // works for old and new versions
+ key->Book(book);
+ (*key) = sword::MAXCHAPTER;
+ result = key->Chapter();
+
+ return result;
+}
+
+unsigned int CSwordBibleModuleInfo::chapterCount(const QString& book) {
+ return chapterCount( bookNumber(book) );
+}
+
+/** Returns the number of verses for the given chapter. */
+
+unsigned int CSwordBibleModuleInfo::verseCount( const unsigned int book, const unsigned int chapter ) {
+ unsigned int result = 0;
+
+ boost::scoped_ptr<sword::VerseKey> key((sword::VerseKey *)module()->CreateKey());
+ (*key) = sword::TOP;
+
+ // works for old and new versions
+ key->Book(book);
+ key->Chapter(chapter);
+ (*key) = sword::MAXVERSE;
+ result = key->Verse();
+
+ return result;
+}
+
+unsigned int CSwordBibleModuleInfo::verseCount( const QString& book, const unsigned int chapter ) {
+ return verseCount( bookNumber(book), chapter );
+}
+
+unsigned int CSwordBibleModuleInfo::bookNumber(const QString &book) {
+ unsigned int bookNumber = 0;
+ bool found = false;
+ int min = 0;
+ int max = 1;
+
+ //find out if we have ot and nt, only ot or only nt
+ initBounds();
+
+ boost::scoped_ptr<sword::VerseKey> key((sword::VerseKey *)module()->CreateKey());
+ (*key) = sword::TOP;
+
+#ifdef SWORD_MULTIVERSE
+ key->setBookName(book.toUtf8().constData());
+
+ bookNumber = ((key->Testament() > 1) ? key->BMAX[0] : 0) + key->Book();
+#else
+
+ if ((m_hasOT>0 && m_hasNT>0) || (m_hasOT == -1 && m_hasNT == -1)) {
+ min = 0;
+ max = 1;
+ bookNumber = 0;
+ }
+ else if (m_hasOT>0 && !m_hasNT) {
+ min = 0;
+ max = 0;
+ bookNumber = 0;
+ }
+ else if (!m_hasOT && m_hasNT>0) {
+ min = 1;
+ max = 1;
+ bookNumber = key->BMAX[0];
+ }
+ else if (!m_hasOT && !m_hasNT) {
+ min = 0;
+ max = -1; //no loop
+ bookNumber = 0;
+ }
+
+ for (int i = min; i <= max && !found; ++i) {
+ for ( int j = 0; j < key->BMAX[i] && !found; ++j) {
+ ++bookNumber;
+
+ if (book == QString::fromUtf8( key->books[i][j].name) )
+ found = true;
+ }
+ }
+#endif
+
+ return bookNumber;
+}
+
+/** Returns true if his module has the text of desired type of testament */
+bool CSwordBibleModuleInfo::hasTestament( CSwordBibleModuleInfo::Testament type ) {
+ if (m_hasOT == -1 || m_hasNT == -1) {
+ const bool oldStatus = module()->getSkipConsecutiveLinks();
+ module()->setSkipConsecutiveLinks(true);
+
+ *module() = sword::TOP; //position to first entry
+ sword::VerseKey key( module()->KeyText() );
+
+ if (key.Testament() == 1) { // OT && NT
+ m_hasOT = 1;
+ }
+ else if (key.Testament() == 2) { //no OT
+ m_hasOT = 0;
+ }
+
+ *module() = sword::BOTTOM;
+ key = module()->KeyText();
+
+ if (key.Testament() == 1) { // only OT, no NT
+ m_hasNT = 0;
+ }
+ else if (key.Testament() == 2) { //has NT
+ m_hasNT = 1;
+ }
+
+ module()->setSkipConsecutiveLinks(oldStatus);
+ }
+
+ switch (type) {
+
+ case OldTestament:
+ return m_hasOT>0;
+
+ case NewTestament:
+ return m_hasNT>0;
+
+ default:
+ return false;
+ }
+}
+
diff --git a/src/backend/drivers/cswordbiblemoduleinfo.h b/src/backend/drivers/cswordbiblemoduleinfo.h
new file mode 100644
index 0000000..c25eb37
--- /dev/null
+++ b/src/backend/drivers/cswordbiblemoduleinfo.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 CSWORDBIBLEMODULEINFO_H
+#define CSWORDBIBLEMODULEINFO_H
+
+#include "cswordmoduleinfo.h"
+#include "backend/keys/cswordversekey.h"
+
+//Qt
+#include <QStringList>
+
+/**
+ * This is the CModuleInfo imlementation for Bible modules managed by Sword.
+ *
+ * @short Implementation for Sword Bibles
+ * @author The BibleTime team
+ * @version $Id: cswordbiblemoduleinfo.h,v 1.18 2006/02/25 11:38:15 joachim Exp $
+ */
+
+class CSwordBibleModuleInfo : public CSwordModuleInfo {
+
+public:
+ enum Testament {
+ OldTestament = 1,
+ NewTestament = 2
+ };
+
+ /**
+ * The constructor of this class
+ */
+ CSwordBibleModuleInfo( sword::SWModule* module, CSwordBackend* const );
+ /** The copy constructor for this Bible module.
+ */
+ CSwordBibleModuleInfo( const CSwordBibleModuleInfo& m );
+ /**
+ * The destructor of this class
+ */
+ ~CSwordBibleModuleInfo();
+ /**
+ * Returns the number of avalable verses for the given chapter and book.
+ *
+ * @param book The number book we should use
+ * @param chapter The chapter we should use
+ * @return The number of verses for the given book and chapter
+ */
+ virtual unsigned int verseCount( const unsigned int book, const unsigned int chapter );
+ /**
+ * Returns the number of avalable verses for the given chapter and book.
+ *
+ * @param book The name of the book we use
+ * @param chapter The number of the chapter we use
+ * @return The number of verses for the given book and chapter
+ */
+ virtual unsigned int verseCount( const QString& book, const unsigned int chapter );
+ /** Information about the chapters in a book.
+ * @return The number of available chapters of the given book.
+ * @return The number of chapters for the given book
+ */
+ virtual unsigned int chapterCount( const unsigned int book );
+ /** Information about the chapters in a book.
+ * @return The number of available chapters of the given book.
+ */
+ virtual unsigned int chapterCount( const QString& book );
+ /** Return all book of this module.
+ * @return A QStringList containing the books which are available in this module.
+ */
+ virtual QStringList* books();
+ /**
+ * Reimplementation, Returns the type
+ */
+ virtual CSwordModuleInfo::ModuleType type() const;
+ /**
+ * @return the book number, values starting with 1; 0 if not found
+ */
+ unsigned int bookNumber(const QString &book);
+ /**
+ * Returns true if his module has the text of desired type of testament
+ */
+ bool hasTestament( CSwordBibleModuleInfo::Testament );
+ /** Reimplementation to clone this object. */
+ virtual CSwordModuleInfo* clone();
+ /**
+ * Returns the key which represents the lower bound of this module.
+ */
+ inline const CSwordVerseKey& lowerBound();
+ /**
+ * Returns the key which represents the upper bound of this module.
+ */
+ inline const CSwordVerseKey& upperBound();
+
+private:
+ void initBounds();
+
+ CSwordVerseKey m_lowerBound;
+ CSwordVerseKey m_upperBound;
+
+ QStringList* m_bookList; //This booklist is cached
+ QString m_cachedLocale;
+ short int m_hasOT;
+ short int m_hasNT;
+};
+
+inline CSwordModuleInfo::ModuleType CSwordBibleModuleInfo::type() const {
+ return CSwordModuleInfo::Bible;
+}
+
+/** Returns the key which represents the lower bound of this module. */
+inline const CSwordVerseKey& CSwordBibleModuleInfo::lowerBound() {
+ initBounds();
+ return m_lowerBound;
+}
+
+/** Returns the key which represents the lower bound of this module. */
+inline const CSwordVerseKey& CSwordBibleModuleInfo::upperBound() {
+ initBounds();
+ return m_upperBound;
+}
+
+#endif
diff --git a/src/backend/drivers/cswordbookmoduleinfo.cpp b/src/backend/drivers/cswordbookmoduleinfo.cpp
new file mode 100644
index 0000000..0a8c1e6
--- /dev/null
+++ b/src/backend/drivers/cswordbookmoduleinfo.cpp
@@ -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.
+*
+**********/
+
+//BibleTime includes
+#include "cswordbookmoduleinfo.h"
+#include "backend/keys/cswordtreekey.h"
+
+//Sword includes
+#include <treekeyidx.h>
+#include <treekey.h>
+
+CSwordBookModuleInfo::CSwordBookModuleInfo( sword::SWModule* module, CSwordBackend* const usedBackend )
+: CSwordModuleInfo(module, usedBackend),
+m_depth(-1) {}
+
+CSwordBookModuleInfo::CSwordBookModuleInfo( const CSwordBookModuleInfo& module )
+: CSwordModuleInfo(module) {
+ m_depth = module.m_depth;
+}
+
+CSwordBookModuleInfo::~CSwordBookModuleInfo() {}
+
+int CSwordBookModuleInfo::depth() {
+ if (m_depth == -1) {
+ sword::TreeKeyIdx* key = tree();
+
+ if (key) {
+ key->root();
+ computeDepth(key, 0);
+ }
+ }
+
+ return m_depth;
+}
+
+void CSwordBookModuleInfo::computeDepth(sword::TreeKeyIdx* key, int level ) {
+ std::string savedKey;
+ // savedKey = key->getFullName(); //sword 1.5.8
+ savedKey = key->getText();
+
+ if (level > m_depth) {
+ m_depth = level;
+ }
+
+ if (key->hasChildren()) {
+ key->firstChild();
+ computeDepth(key, level+1);
+
+ key->setText( savedKey.c_str() );//return to the initial value
+ }
+
+ if (key->nextSibling()) {
+ computeDepth(key, level);
+ }
+}
+
+/** Returns a treekey filled with the structure of this module */
+sword::TreeKeyIdx* CSwordBookModuleInfo::tree() const {
+ sword::TreeKeyIdx* treeKey = dynamic_cast<sword::TreeKeyIdx*>((sword::SWKey*)*(module()));
+ Q_ASSERT(treeKey);
+ return treeKey;
+}
diff --git a/src/backend/drivers/cswordbookmoduleinfo.h b/src/backend/drivers/cswordbookmoduleinfo.h
new file mode 100644
index 0000000..f471d61
--- /dev/null
+++ b/src/backend/drivers/cswordbookmoduleinfo.h
@@ -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.
+*
+**********/
+
+#ifndef CSWORDGENBOOKMODULEINFO_H
+#define CSWORDGENBOOKMODULEINFO_H
+
+#include "cswordmoduleinfo.h"
+
+//Sword
+#include <treekeyidx.h>
+
+/** Class for generic book support
+ * @author The BibleTime team
+ */
+
+class CSwordBookModuleInfo : public CSwordModuleInfo {
+
+public:
+ /** Constructor.
+ * @param module The module which belongs to this object
+ * @param backend The parent backend for this book module.
+ */
+ CSwordBookModuleInfo( sword::SWModule* module, CSwordBackend* const backend );
+ /** Copy constructor.
+ * Copy constructor to copy the passed parameter.
+ * @param module The module which should be copied.
+ */
+ CSwordBookModuleInfo( const CSwordBookModuleInfo& module );
+ /** Destructor.
+ */
+ ~CSwordBookModuleInfo();
+ /**
+ * Returns the type of the module.
+ */
+ virtual CSwordModuleInfo::ModuleType type() const;
+ /**
+ * Returns the maximal depth of sections and subsections.
+ */
+ int depth();
+ /**
+ * @return A treekey filled with the structure of this module. Don't delete the returned key because it's casted from the module object.
+ */
+ sword::TreeKeyIdx* tree() const;
+
+private:
+ /**
+ * A recursive helper function to help computng the module depth!
+ */
+ void computeDepth(sword::TreeKeyIdx* key, int level = 0 );
+ int m_depth;
+};
+
+inline CSwordBookModuleInfo::ModuleType CSwordBookModuleInfo::type() const {
+ return CSwordModuleInfo::GenericBook;
+}
+
+
+#endif
diff --git a/src/backend/drivers/cswordcommentarymoduleinfo.cpp b/src/backend/drivers/cswordcommentarymoduleinfo.cpp
new file mode 100644
index 0000000..b09e2f3
--- /dev/null
+++ b/src/backend/drivers/cswordcommentarymoduleinfo.cpp
@@ -0,0 +1,32 @@
+/*********
+*
+* 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 "cswordcommentarymoduleinfo.h"
+
+CSwordCommentaryModuleInfo::CSwordCommentaryModuleInfo( sword::SWModule* module, CSwordBackend* const usedBackend)
+: CSwordBibleModuleInfo(module, usedBackend) {}
+
+CSwordCommentaryModuleInfo::~CSwordCommentaryModuleInfo() {}
+
+/** No descriptions */
+CSwordModuleInfo* CSwordCommentaryModuleInfo::clone() {
+ return new CSwordCommentaryModuleInfo(*this);
+}
+
+/** Returns true if this module may be written by the write display windows. */
+bool CSwordCommentaryModuleInfo::isWritable() const {
+ // qWarning(module()->getConfigEntry("ModDrv"));
+ //a module is only writable if it's a RawFiles module with writable returning true
+
+ if ( (std::string(module()->getConfigEntry("ModDrv")) == std::string("RawFiles")) && module()->isWritable()) {
+ return true;
+ };
+
+ return false;
+}
diff --git a/src/backend/drivers/cswordcommentarymoduleinfo.h b/src/backend/drivers/cswordcommentarymoduleinfo.h
new file mode 100644
index 0000000..7ebf23f
--- /dev/null
+++ b/src/backend/drivers/cswordcommentarymoduleinfo.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 CSWORDCOMMENTARYMODULEINFO_H
+#define CSWORDCOMMENTARYMODULEINFO_H
+
+//own includes
+#include "cswordbiblemoduleinfo.h"
+
+/** Commentary module implementation.
+ * This CSwordModule implementation provides access to Sword's commentary modules.
+ * @author The BibleTime team
+ * @version $Id: cswordcommentarymoduleinfo.h,v 1.13 2006/02/25 11:38:15 joachim Exp $
+ */
+
+class CSwordCommentaryModuleInfo : public CSwordBibleModuleInfo {
+
+public:
+ CSwordCommentaryModuleInfo( sword::SWModule* module, CSwordBackend* const );
+ ~CSwordCommentaryModuleInfo();
+ /** Reimplementation to return the commentary type.
+ */
+ virtual CSwordModuleInfo::ModuleType type() const;
+ /** Reimplementation to clone the current object.
+ */
+ virtual CSwordModuleInfo* clone();
+ /**
+ * Returns true if this module may be written by the write display windows.
+ */
+ virtual bool isWritable() const;
+};
+
+inline CSwordModuleInfo::ModuleType CSwordCommentaryModuleInfo::type() const {
+ return CSwordModuleInfo::Commentary;
+}
+
+#endif
diff --git a/src/backend/drivers/cswordlexiconmoduleinfo.cpp b/src/backend/drivers/cswordlexiconmoduleinfo.cpp
new file mode 100644
index 0000000..a8b81e4
--- /dev/null
+++ b/src/backend/drivers/cswordlexiconmoduleinfo.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 "cswordlexiconmoduleinfo.h"
+#include "util/directoryutil.h"
+
+//Qt
+#include <QFile>
+#include <QDataStream>
+#include <QTextCodec>
+
+//Sword
+#include <swmodule.h>
+
+//STL includes
+#include <algorithm>
+
+//Change it once the format changed to make all systems rebuild their caches
+#define CACHE_FORMAT "2"
+
+CSwordLexiconModuleInfo::CSwordLexiconModuleInfo( sword::SWModule* module, CSwordBackend* const backend ) : CSwordModuleInfo(module, backend) {
+ m_entryList = 0;
+}
+
+CSwordLexiconModuleInfo::CSwordLexiconModuleInfo( const CSwordLexiconModuleInfo& m ) : CSwordModuleInfo(m) {
+ delete m_entryList;
+ m_entryList = 0;
+
+ if (m.m_entryList) {
+ m_entryList = new QStringList();
+ *m_entryList = *m.m_entryList;//copy list items
+ }
+}
+
+CSwordLexiconModuleInfo::~CSwordLexiconModuleInfo() {
+ delete m_entryList;
+ m_entryList = 0;
+}
+
+/** Returns the entries of the module. */
+QStringList* CSwordLexiconModuleInfo::entries() {
+ if (!module()) {
+ return 0;
+ }
+
+ sword::SWModule* my_module = module();
+ bool is_unicode = isUnicode();
+
+ if (!m_entryList) {
+ m_entryList = new QStringList();
+ bool read = false;
+
+ //Check for buggy modules! They will not be loaded any more.
+
+ if ( name() == QString("ZhEnglish")) {
+ qWarning("Module ZhEnglish is buggy and will not be loaded.");
+ return m_entryList;
+ }
+
+ QString dir(util::filesystem::DirectoryUtil::getUserCacheDir().absolutePath());
+ QFile f1(
+ QString(dir)
+ .append("/")
+ .append(name())
+ );
+
+ if ( f1.open( QIODevice::ReadOnly ) ) {
+ QDataStream s( &f1 );
+ QString mod_ver, prog_ver;
+ s >> mod_ver;
+ s >> prog_ver;
+
+ if ((mod_ver == config(ModuleVersion)) && (prog_ver == CACHE_FORMAT)) {
+ s >> *m_entryList;
+ read = true;
+ }
+
+ f1.close();
+ // qWarning("read entries %d",m_entryList->count());
+ }
+
+ // Q_ASSERT(read);
+ // Q_ASSERT(m_entryList->count());
+ if (!read || !m_entryList->count()) {
+ my_module->setSkipConsecutiveLinks(true);
+ (*my_module) = sword::TOP;
+ snap(); //snap to top entry
+
+ // qWarning("Reading in module" );
+ int i = 0;
+
+ do {
+ if ( is_unicode ) {
+ m_entryList->append(QString::fromUtf8(my_module->KeyText()));
+ // qWarning("Entry: %s", my_module->KeyText() );
+ }
+ else { //for latin1 modules use fromLatin1 because of speed
+ // m_entryList->append(QString::fromLatin1(my_module->KeyText()));
+ QTextCodec* codec = QTextCodec::codecForName("Windows-1252");
+ m_entryList->append(codec->toUnicode(my_module->KeyText()));
+ }
+
+ (*my_module)++;
+ i++;
+ }
+ while ( !my_module->Error() );
+
+ // qWarning("Reading finished. Module has %d entries.", i );
+
+ (*my_module) = sword::TOP; //back to the first entry
+
+ my_module->setSkipConsecutiveLinks(false);
+
+ if (m_entryList->count()) {
+ m_entryList->first().simplified();
+
+ if (m_entryList->first().trimmed().isEmpty()) {
+ m_entryList->erase( m_entryList->begin() );
+ }
+
+ //now sort the list, this is necesssary because Sword doesn't do Unicode ordering
+ // qWarning("sorting");
+ // QStringList::iterator start(m_entryList->begin());
+ // QStringList::iterator end(m_entryList->end());
+ // std::sort( start, end, myLocaleAwareCompare() ); //stl sort
+ // m_entryList->sort(); //make sure the module is sorted by utf-8
+ }
+
+ qWarning("Writing cache file.");
+
+ if (m_entryList->count()) {
+ //create cache
+ QString dir = util::filesystem::DirectoryUtil::getUserCacheDir().absolutePath();
+ //QFile f2( QString::fromLatin1("%1/%2").arg(dir).arg( name() ) );
+ QFile f2( QString(dir).append("/").append(name()) );
+
+
+ if (f2.open( QIODevice::WriteOnly )) {
+ QDataStream s( &f2 );
+ s << config(CSwordModuleInfo::ModuleVersion); //store module version
+ s << QString(CACHE_FORMAT); //store BT version -- format may change
+ s << *m_entryList;
+ f2.close();
+ }
+ }
+ }
+ }
+
+ return m_entryList;
+}
+
+/** Jumps to the closest entry in the module. */
+bool CSwordLexiconModuleInfo::snap() {
+ if(module()->getRawEntry()) { // Snap to the current entry
+ return true;
+ }
+
+ return false;
+}
+
+/** No descriptions */
+CSwordModuleInfo* CSwordLexiconModuleInfo::clone() {
+ return new CSwordLexiconModuleInfo(*this);
+}
diff --git a/src/backend/drivers/cswordlexiconmoduleinfo.h b/src/backend/drivers/cswordlexiconmoduleinfo.h
new file mode 100644
index 0000000..13f72e4
--- /dev/null
+++ b/src/backend/drivers/cswordlexiconmoduleinfo.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 CSWORDLEXICONMODULEINFO_H
+#define CSWORDLEXICONMODULEINFO_H
+
+//own includes
+#include "cswordmoduleinfo.h"
+
+//Qt includes
+#include <QStringList>
+
+/**
+ * The implementation of CModuleInfo for the Sword lexiccons and citionaries.
+ * @author The BibleTime team
+ * @version $Id: cswordlexiconmoduleinfo.h,v 1.12 2006/02/25 11:38:15 joachim Exp $
+ */
+
+class CSwordLexiconModuleInfo : public CSwordModuleInfo {
+
+public:
+ /**
+ * The standard constructor fot this object.
+ * A default constructor doesn't exist. Use this one.
+ */
+ CSwordLexiconModuleInfo( sword::SWModule* module, CSwordBackend* const );
+ /**
+ * The copy constructor
+ */
+ CSwordLexiconModuleInfo( const CSwordLexiconModuleInfo& m );
+ /** Reimplementation to return a valid clone.
+ */
+ virtual CSwordModuleInfo* clone();
+ /** Destructor.
+ */
+ virtual ~CSwordLexiconModuleInfo();
+ /**
+ * Returns the entries of the module.
+ * This function returns the entries of the modules represented by this object.
+ * If this function is called for the first time the list is load from disk and stored in a list which cahes it.
+ * If the function is called again, the cached list is returned so we have a major speed improvement.
+ * @return The list of lexicon entries
+ */
+ QStringList* entries();
+ /**
+ * Reimplementation, to return the right type for this lexicon.
+ */
+ virtual CSwordModuleInfo::ModuleType type() const;
+ /**
+ * Jumps to the closest entry in the module.
+ */
+ bool snap();
+
+private:
+ /**
+ * This is the list which caches the entres of the module.
+ */
+ QStringList* m_entryList;
+};
+
+inline CSwordModuleInfo::ModuleType CSwordLexiconModuleInfo::type() const {
+ return CSwordModuleInfo::Lexicon;
+}
+
+#endif
diff --git a/src/backend/drivers/cswordmoduleinfo.cpp b/src/backend/drivers/cswordmoduleinfo.cpp
new file mode 100644
index 0000000..c76f5ef
--- /dev/null
+++ b/src/backend/drivers/cswordmoduleinfo.cpp
@@ -0,0 +1,955 @@
+/*********
+*
+* 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 "cswordmoduleinfo.h"
+#include "cswordlexiconmoduleinfo.h"
+
+#include "backend/managers/cswordbackend.h"
+#include "backend/cswordmodulesearch.h"
+#include "backend/keys/cswordkey.h"
+#include "backend/rendering/centrydisplay.h"
+#include "backend/managers/clanguagemgr.h"
+
+#include "util/directoryutil.h"
+#include "util/cpointers.h"
+#include "util/exceptions.h"
+#include "backend/config/cbtconfig.h"
+
+
+#include <boost/scoped_ptr.hpp>
+
+//Qt includes
+#include <QRegExp>
+#include <QDir>
+#include <QFileInfo>
+#include <QList>
+#include <QByteArray>
+#include <QDebug>
+#include <QSettings>
+#include <QMessageBox>
+#include <QCoreApplication>
+
+//Sword includes
+#include <swbuf.h>
+#include <swkey.h>
+#include <listkey.h>
+#include <versekey.h>
+#include <swconfig.h>
+#include <rtfhtml.h>
+
+//Lucence includes
+#include <CLucene.h>
+#include <CLucene/util/Reader.h>
+#include <CLucene/util/Misc.h>
+#include <CLucene/util/dirent.h>
+
+
+//Increment this, if the index format changes
+//Then indices on the user's systems will be rebuilt
+const unsigned int INDEX_VERSION = 6;
+
+//Maximum index entry size, 1MiB for now
+//Lucene default is too small
+const unsigned long BT_MAX_LUCENE_FIELD_LENGTH = 1024*1024;
+
+CSwordModuleInfo::CSwordModuleInfo(sword::SWModule * module, CSwordBackend * const usedBackend) {
+ m_module = module;
+ Q_ASSERT(module);
+
+ m_hidden = false;
+ m_cancelIndexing = false;
+ m_searchResult.ClearList();
+ m_backend = usedBackend ? usedBackend : CPointers::backend();
+ m_dataCache.name = module ? QString(module->Name()) : QString::null;
+ m_dataCache.isUnicode = module ? module->isUnicode() : false;
+ m_dataCache.category = UnknownCategory;
+ m_dataCache.language = 0;
+ m_dataCache.hasVersion = !QString((*m_backend->getConfig())[module->Name()]["Version"]).isEmpty();
+
+ if (backend()) {
+ if (hasVersion() && (minimumSwordVersion() > sword::SWVersion::currentVersion)) {
+ qWarning("The module \"%s\" requires a newer Sword library. Please update to \"Sword %s\".",
+ name().toUtf8().constData(), (const char *)minimumSwordVersion());
+ }
+ }
+}
+
+CSwordModuleInfo::CSwordModuleInfo(const CSwordModuleInfo & m) : QObject(){
+ m_module = m.m_module;
+ m_backend = m.m_backend;
+ m_dataCache = m.m_dataCache;
+ m_searchResult = m.m_searchResult;
+ m_hidden = m.m_hidden;
+ m_cancelIndexing = m.m_cancelIndexing;
+}
+
+/** No descriptions */
+CSwordModuleInfo *CSwordModuleInfo::clone() {
+ return new CSwordModuleInfo(*this);
+}
+
+CSwordModuleInfo::~CSwordModuleInfo() {
+ m_searchResult.ClearList();
+ m_module = 0; //the Sword module object is deleted by the backend
+}
+
+/** Sets the unlock key of the modules and writes the key into the cofig file.*/
+bool CSwordModuleInfo::unlock(const QString & unlockKey) {
+ if (!isEncrypted()) {
+ return false;
+ }
+
+ CBTConfig::setModuleEncryptionKey(name(), unlockKey);
+ backend()->setCipherKey(m_module->Name(), unlockKey.toUtf8().constData());
+ //TODO: write to Sword config as well
+
+ return true;
+}
+
+/** This function returns true if this module is locked, otherwise return false. */
+bool CSwordModuleInfo::isLocked() {
+ //still works, but the cipherkey is stored in CBTConfig.
+ //Works because it is set in sword on program startup.
+
+ if (isEncrypted()) {
+ if (unlockKeyIsValid()) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+/** This functions returns true if this module is encrypted (locked or unlocked). */
+bool CSwordModuleInfo::isEncrypted() const {
+ /**
+ * If we have the CipherKey entry the module
+ * is encrypted but not necessarily locked
+ */
+
+ //This code is still right, though we do no longer write to the module config files any more
+ sword::ConfigEntMap config = backend()->getConfig()->Sections.find(name().toUtf8().constData())->second;
+ sword::ConfigEntMap::iterator it = config.find("CipherKey");
+
+ if (it != config.end()) {
+ return true;
+ }
+
+ return false;
+}
+
+/** This function makes an estimate if a module was properly unlocked.
+* It returns true if the first entry of the module is not empty and
+* contains only printable characters (for the first 100 chars or so).
+* If that is the case, we can safely assume that a) the module was properly
+* unlocked and b) no buffer overflows will occur, which can happen when
+* Sword filters process garbage text which was not properly decrypted.
+*/
+bool CSwordModuleInfo::unlockKeyIsValid() {
+
+ (*m_module) = sword::TOP;
+
+ // This needs to use ::fromLatin1 because if the text is still locked,
+ // a lot of garbage will show up. It will also work with properly decrypted
+ // Unicode text, because all non-ASCII Unicode chars consist of bytes >127
+ // and therefore contain no control (nonprintable) characters, which are all <127.
+ QString test = isUnicode()
+ ? QString::fromUtf8(m_module->getRawEntryBuf().c_str())
+ : QString::fromLatin1( m_module->getRawEntryBuf().c_str() );
+
+ if (test.isEmpty()) {
+ qWarning() << "Unlock key of module" << name() << "is NOT valid!";
+ return false;
+ }
+
+ for (int i = 0; i <= test.length() && i < 100; i++) {
+ if ( !test[i].isPrint() && !test[i].isNull() ) {
+ qWarning() << "Unlock key of module" << name() << "is NOT valid!";
+ return false;
+ }
+ }
+
+ qDebug() << "Unlock key of module" << name() << "is valid";
+ return true;
+}
+
+QString CSwordModuleInfo::getGlobalBaseIndexLocation() {
+ return util::filesystem::DirectoryUtil::getUserIndexDir().absolutePath();
+}
+
+QString CSwordModuleInfo::getModuleBaseIndexLocation() const {
+ return getGlobalBaseIndexLocation() + QString("/") + name().toLocal8Bit();
+}
+
+QString CSwordModuleInfo::getModuleStandardIndexLocation() const { //this for now returns the location of the main index
+ return getModuleBaseIndexLocation() + QString("/standard");
+}
+
+bool CSwordModuleInfo::hasIndex() {
+ //this will return true only
+ //if the index exists and has correct version information for both index and module
+ QDir d;
+ if (!d.exists( getModuleStandardIndexLocation() )) {
+ return false;
+ }
+
+ //first check if the index version and module version are ok
+ QSettings module_config(getModuleBaseIndexLocation() + QString("/bibletime-index.conf"), QSettings::IniFormat);
+
+ if (hasVersion()) {
+ if (module_config.value("module-version") != QString(config(CSwordModuleInfo::ModuleVersion)) ) {
+ return false;
+ }
+ }
+ if (module_config.value("index-version") != QString::number( INDEX_VERSION )) {
+ qDebug("%s: INDEX_VERSION is not compatible with this version of BibleTime.", name().toUtf8().constData());
+ return false;
+ }
+
+ //then check if the index is there
+ return lucene::index::IndexReader::indexExists(getModuleStandardIndexLocation().toAscii().constData());
+}
+
+
+void CSwordModuleInfo::buildIndex() {
+
+ m_cancelIndexing = false;
+
+ try
+ {
+ //Without this we don't get strongs, lemmas, etc
+ backend()->setFilterOptions ( CBTConfig::getFilterOptionDefaults() );
+ //make sure we reset all important filter options which influcence the plain filters.
+ backend()->setOption( CSwordModuleInfo::strongNumbers, false );
+ backend()->setOption( CSwordModuleInfo::morphTags, false );
+ backend()->setOption( CSwordModuleInfo::morphSegmentation, false );
+ backend()->setOption( CSwordModuleInfo::footnotes, false );
+ backend()->setOption( CSwordModuleInfo::headings, false );
+ backend()->setOption( CSwordModuleInfo::scriptureReferences, false );
+ backend()->setOption( CSwordModuleInfo::redLetterWords, false );
+
+ // do not use any stop words
+ const TCHAR* stop_words[] = { NULL };
+ lucene::analysis::standard::StandardAnalyzer an( (const TCHAR**)stop_words );
+ QString index = getModuleStandardIndexLocation();
+
+ QDir dir("/");
+ dir.mkpath( getGlobalBaseIndexLocation() );
+ dir.mkpath( getModuleBaseIndexLocation() );
+ dir.mkpath( getModuleStandardIndexLocation() );
+
+ if (lucene::index::IndexReader::indexExists(index.toAscii().constData())) {
+ if (lucene::index::IndexReader::isLocked(index.toAscii().constData()) ) {
+ lucene::index::IndexReader::unlock(index.toAscii().constData());
+ }
+ }
+
+ boost::scoped_ptr<lucene::index::IndexWriter> writer( new lucene::index::IndexWriter(index.toAscii().constData(), &an, true) ); //always create a new index
+ writer->setMaxFieldLength(BT_MAX_LUCENE_FIELD_LENGTH);
+ writer->setUseCompoundFile(true); //merge segments into a single file
+ writer->setMinMergeDocs(1000);
+
+ *m_module = sword::TOP;
+ unsigned long verseLowIndex = m_module->Index();
+ *m_module = sword::BOTTOM;
+ unsigned long verseHighIndex = m_module->Index();
+
+ //verseLowIndex is not 0 in all cases (i.e. NT-only modules)
+ unsigned long verseIndex = verseLowIndex + 1;
+ unsigned long verseSpan = verseHighIndex - verseLowIndex;
+
+ //Index() is not implemented properly for lexicons, so we use a
+ //workaround.
+ if (type() == CSwordModuleInfo::Lexicon){
+ verseIndex = 0;
+ verseLowIndex = 0;
+ verseSpan = ((CSwordLexiconModuleInfo*)this)->entries()->size();
+ }
+
+ emit indexingProgress(0);
+
+ sword::SWKey* key = m_module->getKey();
+ //VerseKey for bibles
+ sword::VerseKey* vk = dynamic_cast<sword::VerseKey*>(key);
+
+ if (vk) {
+ // we have to be sure to insert the english key into the index, otherwise we'd be in trouble if the language changes
+ vk->setLocale("en_US");
+ //If we have a verse based module, we want to include the pre-chapter etc. headings in the search
+ vk->Headings(1);
+ }
+
+ //holds UTF-8 data and is faster than QString.
+ QByteArray textBuffer;
+
+ // we start with the first module entry, key is automatically updated
+ // because key is a pointer to the modules key
+ m_module->setSkipConsecutiveLinks(true);
+
+ wchar_t wcharBuffer[BT_MAX_LUCENE_FIELD_LENGTH + 1];
+
+ for (*m_module = sword::TOP; !(m_module->Error()) && !m_cancelIndexing; (*m_module)++) {
+
+ //If it is a sword-heading, store in buffer and index later in Verse X:1
+ if (vk) {
+ if (vk->Verse() == 0) {
+ textBuffer.append( m_module->StripText() );
+ continue;
+ }
+ }
+
+ boost::scoped_ptr<lucene::document::Document> doc(new lucene::document::Document());
+
+ //index the key
+ lucene_utf8towcs(wcharBuffer, key->getText(), BT_MAX_LUCENE_FIELD_LENGTH);
+ //doc->add(*lucene::document::Field::UnIndexed((const TCHAR*)_T("key"), (const TCHAR*)wcharBuffer));
+ doc->add(*(new lucene::document::Field((const TCHAR*)_T("key"), (const TCHAR*)wcharBuffer, lucene::document::Field::STORE_YES | lucene::document::Field::INDEX_NO)));
+ // index the main text
+ //at this point we have to make sure we disabled the strongs and the other options
+ //so the plain filters won't include the numbers somehow.
+ lucene_utf8towcs(wcharBuffer, (const char*) textBuffer.append(m_module->StripText()), BT_MAX_LUCENE_FIELD_LENGTH);
+ //doc->add(*lucene::document::Field::UnStored((const TCHAR*)_T("content"), (const TCHAR*)wcharBuffer));
+ doc->add(*(new lucene::document::Field((const TCHAR*)_T("content"), (const TCHAR*)wcharBuffer, lucene::document::Field::STORE_NO | lucene::document::Field::INDEX_TOKENIZED)));
+ textBuffer.resize(0); //clean up
+
+ // index attributes
+ sword::AttributeList::iterator attListI;
+ sword::AttributeValue::iterator attValueI;
+ // Footnotes
+ for (attListI = m_module->getEntryAttributes()["Footnote"].begin();
+ attListI != m_module->getEntryAttributes()["Footnote"].end();
+ attListI++) {
+ lucene_utf8towcs(wcharBuffer, attListI->second["body"], BT_MAX_LUCENE_FIELD_LENGTH);
+ //doc->add(*lucene::document::Field::UnStored((const TCHAR*)_T("footnote"), wcharBuffer));
+ doc->add(*(new lucene::document::Field((const TCHAR*)_T("footnote"), (const TCHAR*)wcharBuffer, lucene::document::Field::STORE_NO | lucene::document::Field::INDEX_TOKENIZED)));
+ } // for attListI
+
+ // Headings
+ for (attValueI = m_module->getEntryAttributes()["Heading"]["Preverse"].begin();
+ attValueI != m_module->getEntryAttributes()["Heading"]["Preverse"].end();
+ attValueI++) {
+ lucene_utf8towcs(wcharBuffer, attValueI->second, BT_MAX_LUCENE_FIELD_LENGTH);
+ //doc->add(*lucene::document::Field::UnStored((const TCHAR*)_T("heading"), wcharBuffer));
+ doc->add(*(new lucene::document::Field((const TCHAR*)_T("heading"), (const TCHAR*)wcharBuffer, lucene::document::Field::STORE_NO | lucene::document::Field::INDEX_TOKENIZED)));
+ } // for attValueI
+
+ // Strongs/Morphs
+ for (attListI = m_module->getEntryAttributes()["Word"].begin();
+ attListI != m_module->getEntryAttributes()["Word"].end();
+ attListI++) {
+ // for each attribute
+ if (attListI->second["LemmaClass"] == "strong") {
+ lucene_utf8towcs(wcharBuffer, attListI->second["Lemma"], BT_MAX_LUCENE_FIELD_LENGTH);
+ //doc->add(*lucene::document::Field::UnStored((const TCHAR*)_T("strong"), wcharBuffer));
+ doc->add(*(new lucene::document::Field((const TCHAR*)_T("strong"), (const TCHAR*)wcharBuffer, lucene::document::Field::STORE_NO | lucene::document::Field::INDEX_TOKENIZED)));
+ //qWarning("Adding strong %s", attListI->second["Lemma"].c_str());
+ }
+ if (attListI->second.find("Morph") != attListI->second.end()) {
+ lucene_utf8towcs(wcharBuffer, attListI->second["Morph"], BT_MAX_LUCENE_FIELD_LENGTH);
+ //doc->add(*lucene::document::Field::UnStored((const TCHAR*)_T("morph"), wcharBuffer));
+ doc->add(*(new lucene::document::Field((const TCHAR*)_T("morph"), (const TCHAR*)wcharBuffer, lucene::document::Field::STORE_NO | lucene::document::Field::INDEX_TOKENIZED)));
+ }
+ } // for attListI
+
+ writer->addDocument(doc.get());
+ //Index() is not implemented properly for lexicons, so we use a
+ //workaround.
+ if (type() == CSwordModuleInfo::Lexicon){
+ verseIndex++;
+ }
+ else{
+ verseIndex = m_module->Index();
+ }
+
+ if (verseIndex % 200 == 0) {
+ int indexingProgressValue;
+ if (verseSpan == 0) { //prevent division by zero
+ //m_indexingProgress.setValue( QVariant(0) );
+ indexingProgressValue = 0;
+ } else {
+ //m_indexingProgress.setValue( QVariant((int)((100*(verseIndex-verseLowIndex))/(verseHighIndex-verseLowIndex))) );
+ indexingProgressValue = (int)((100*(verseIndex-verseLowIndex)) / (verseSpan));
+ }
+ //m_indexingProgress.activate();
+ emit indexingProgress(indexingProgressValue);
+ }
+ }
+
+ if (!m_cancelIndexing)
+ {
+ writer->optimize();
+ }
+ writer->close();
+
+ if (m_cancelIndexing){
+ deleteIndexForModule(name());
+ m_cancelIndexing = false;
+ }
+ else
+ {
+ QSettings module_config(getModuleBaseIndexLocation() + QString("/bibletime-index.conf"), QSettings::IniFormat);
+ if (hasVersion()) module_config.setValue("module-version", config(CSwordModuleInfo::ModuleVersion) );
+ module_config.setValue("index-version", INDEX_VERSION );
+ }
+ }
+ catch(...)
+ {
+ qWarning("CLucene exception occurred while indexing");
+ QMessageBox::warning(0, QCoreApplication::tr("Indexing aborted"), QCoreApplication::tr("An internal error occurred while building the index."));
+ deleteIndexForModule(name());
+ m_cancelIndexing = false;
+ }
+}
+
+void CSwordModuleInfo::deleteIndexForModule( QString name ) {
+ util::filesystem::DirectoryUtil::removeRecursive( getGlobalBaseIndexLocation() + "/" + name );
+}
+
+unsigned long CSwordModuleInfo::indexSize() const {
+ return util::filesystem::DirectoryUtil::getDirSizeRecursive( getModuleBaseIndexLocation() );
+}
+
+
+bool CSwordModuleInfo::searchIndexed(const QString& searchedText, sword::ListKey& scope) {
+ char utfBuffer[BT_MAX_LUCENE_FIELD_LENGTH + 1];
+ wchar_t wcharBuffer[BT_MAX_LUCENE_FIELD_LENGTH + 1];
+
+ // work around Swords thread insafety for Bibles and Commentaries
+ boost::scoped_ptr < CSwordKey > key(CSwordKey::createInstance(this));
+ sword::SWKey* s = dynamic_cast < sword::SWKey * >(key.get());
+ QList<sword::VerseKey*> list;
+
+ if (s) {
+ m_module->SetKey(*s);
+ }
+
+ m_searchResult.ClearList();
+
+ try {
+ // do not use any stop words
+ const TCHAR* stop_words[] = { NULL };
+ lucene::analysis::standard::StandardAnalyzer analyzer( stop_words );
+ lucene::search::IndexSearcher searcher(getModuleStandardIndexLocation().toAscii().constData());
+ lucene_utf8towcs(wcharBuffer, searchedText.toUtf8().constData(), BT_MAX_LUCENE_FIELD_LENGTH);
+ boost::scoped_ptr<lucene::search::Query> q( lucene::queryParser::QueryParser::parse((const TCHAR*)wcharBuffer, (const TCHAR*)_T("content"), &analyzer) );
+
+ boost::scoped_ptr<lucene::search::Hits> h( searcher.search(q.get(), lucene::search::Sort::INDEXORDER) );
+
+ const bool useScope = (scope.Count() > 0);
+// const bool isVerseModule = (type() == CSwordModuleInfo::Bible) || (type() == CSwordModuleInfo::Commentary);
+
+ lucene::document::Document* doc = 0;
+ boost::scoped_ptr<sword::SWKey> swKey( module()->CreateKey() );
+
+
+ for (int i = 0; i < h->length(); ++i) {
+ doc = &h->doc(i);
+ lucene_wcstoutf8(utfBuffer, (const wchar_t*)doc->get((const TCHAR*)_T("key")), BT_MAX_LUCENE_FIELD_LENGTH);
+
+ swKey->setText(utfBuffer);
+
+ // limit results based on scope
+ //if (searchOptions & CSwordModuleSearch::useScope && scope.Count() > 0){
+ if (useScope) {
+ for (int j = 0; j < scope.Count(); j++) {
+ sword::VerseKey* vkey = dynamic_cast<sword::VerseKey*>(scope.getElement(j));
+ if (vkey->LowerBound().compare(*swKey) <= 0 && vkey->UpperBound().compare(*swKey) >= 0) {
+ m_searchResult.add(*swKey);
+ }
+ }
+ } else { // no scope, give me all buffers
+ m_searchResult.add(*swKey);
+ }
+ }
+ }
+ catch (...) {
+ qWarning("CLucene exception occurred");
+ QMessageBox::warning(0, QCoreApplication::tr("Search aborted"), QCoreApplication::tr("An internal error occurred while executing your search."));
+ return false;
+ }
+
+ qDeleteAll(list);
+ list.clear();
+
+ return (m_searchResult.Count() > 0);
+}
+
+/** Returns the last search result for this module. */
+sword::ListKey & CSwordModuleInfo::searchResult(const sword::ListKey * newResult) {
+ if (newResult) {
+ m_searchResult.copyFrom(*newResult);
+ }
+
+ return m_searchResult;
+}
+
+/** Clears the last search result. */
+void CSwordModuleInfo::clearSearchResult() {
+ m_searchResult.ClearList();
+}
+
+/** Returns the required Sword version for this module. Returns -1 if no special Sword version is required. */
+sword::SWVersion CSwordModuleInfo::minimumSwordVersion() {
+ return sword::SWVersion(config(CSwordModuleInfo::MinimumSwordVersion).toUtf8().constData());
+}
+
+QString CSwordModuleInfo::config(const CSwordModuleInfo::ConfigEntry entry) const {
+ switch (entry) {
+
+ case AboutInformation:
+ return getFormattedConfigEntry("About");
+
+ case CipherKey: {
+ if (CBTConfig::getModuleEncryptionKey(name()).isNull()) { //fall back!
+ return QString(m_module->getConfigEntry("CipherKey"));
+ }
+ else {
+ return CBTConfig::getModuleEncryptionKey(name());
+ }
+ }
+
+ case AbsoluteDataPath: {
+ QString path( getSimpleConfigEntry("AbsoluteDataPath") );
+ path.replace(QRegExp("/./"), "/"); // make /abs/path/./modules/ looking better
+ //make sure we have a trailing slash!
+
+ if (path.right(1) != "/") {
+ path.append('/');
+ }
+
+ return path;
+ }
+
+ case DataPath: { //make sure we remove the dataFile part if it's a Lexicon
+ QString path(getSimpleConfigEntry("DataPath"));
+
+ if ((type() == CSwordModuleInfo::GenericBook) || (type() == CSwordModuleInfo::Lexicon)) {
+ int pos = path.lastIndexOf("/"); //last slash in the string
+
+ if (pos != -1) {
+ path = path.left(pos + 1); //include the slash
+ }
+ }
+
+ return path;
+ }
+
+ case Description:
+ return getFormattedConfigEntry("Description");
+
+ case ModuleVersion: {
+ QString version(getSimpleConfigEntry("Version"));
+
+ if (version.isEmpty()) {
+ version = "1.0";
+ }
+
+ return version;
+ }
+
+ case MinimumSwordVersion: {
+ const QString minimumVersion(getSimpleConfigEntry("MinimumVersion"));
+ return !minimumVersion.isEmpty()? minimumVersion : QString("0.0");
+ }
+
+ case TextDir: {
+ const QString dir(getSimpleConfigEntry("Direction"));
+ return !dir.isEmpty()? dir : QString("LtoR");
+ }
+
+ case DisplayLevel: {
+ const QString level(getSimpleConfigEntry("DisplayLevel"));
+ return !level.isEmpty()? level : QString("1");
+ }
+
+ case GlossaryFrom: {
+ if (!category() == Glossary) {
+ return QString::null;
+ };
+
+ const QString lang(getSimpleConfigEntry("GlossaryFrom"));
+
+ return !lang.isEmpty()? lang : QString::null;
+ }
+
+ case GlossaryTo: {
+ if (!category() == Glossary) {
+ return QString::null;
+ };
+
+ const QString lang(getSimpleConfigEntry("GlossaryTo"));
+
+ return !lang.isEmpty()? lang : QString::null;
+ }
+
+ case Markup: {
+ const QString markup(getSimpleConfigEntry("SourceType"));
+ return !markup.isEmpty()? markup : QString("Unknown");
+ }
+
+ case DistributionLicense:
+ return getSimpleConfigEntry("DistributionLicense");
+
+ case DistributionSource:
+ return getSimpleConfigEntry("DistributionSource");
+
+ case DistributionNotes:
+ return getSimpleConfigEntry("DistributionNotes");
+
+ case TextSource:
+ return getSimpleConfigEntry("TextSource");
+
+ case CopyrightNotes:
+ return getSimpleConfigEntry("CopyrightNotes");
+
+ case CopyrightHolder:
+ return getSimpleConfigEntry("CopyrightHolder");
+
+ case CopyrightDate:
+ return getSimpleConfigEntry("CopyrightDate");
+
+ case CopyrightContactName:
+ return getSimpleConfigEntry("CopyrightContactName");
+
+ case CopyrightContactAddress:
+ return getSimpleConfigEntry("CopyrightContactAddress");
+
+ case CopyrightContactEmail:
+ return getSimpleConfigEntry("CopyrightContactEmail");
+
+ default:
+ return QString::null;
+ }
+}
+
+/** Returns true if the module supports the feature given as parameter. */
+bool CSwordModuleInfo::has(const CSwordModuleInfo::Feature feature) const {
+ switch (feature) {
+
+ // case StrongsNumbers:
+ // return m_module->getConfig().has("Feature", "StrongsNumber");
+
+ case GreekDef:
+ return m_module->getConfig().has("Feature", "GreekDef");
+
+ case HebrewDef:
+ return m_module->getConfig().has("Feature", "HebrewDef");
+
+ case GreekParse:
+ return m_module->getConfig().has("Feature", "GreekParse");
+
+ case HebrewParse:
+ return m_module->getConfig().has("Feature", "HebrewParse");
+ }
+
+ return false;
+}
+
+bool CSwordModuleInfo::has(const CSwordModuleInfo::FilterTypes option) const {
+ //BAD workaround to see if the filter is GBF, OSIS or ThML!
+ const QString name = backend()->configOptionName(option);
+
+ if (m_module->getConfig().has("GlobalOptionFilter", QString("OSIS").append(name).toUtf8().constData())) {
+ return true;
+ }
+
+ if (m_module->getConfig().has("GlobalOptionFilter", QString("GBF").append(name).toUtf8().constData())) {
+ return true;
+ }
+
+ if (m_module->getConfig().has("GlobalOptionFilter", QString("ThML").append(name).toUtf8().constData())) {
+ return true;
+ }
+
+ if (m_module->getConfig().has("GlobalOptionFilter", QString("UTF8").append(name).toUtf8().constData())) {
+ return true;
+ }
+
+ if (m_module->getConfig().has("GlobalOptionFilter", name.toUtf8().constData())) {
+ return true;
+ }
+
+ return false;
+}
+
+/** Returns the text direction of the module's text., */
+CSwordModuleInfo::TextDirection CSwordModuleInfo::textDirection() {
+ if (config(TextDir) == "RtoL") {
+ return CSwordModuleInfo::RightToLeft;
+ }
+ else {
+ return CSwordModuleInfo::LeftToRight;
+ }
+}
+
+/** Writes the new text at the given position into the module. This does only work for writable modules. */
+void CSwordModuleInfo::write(CSwordKey * key, const QString & newText) {
+ module()->KeyText(key->key().toUtf8().constData());
+
+ //don't store a pointer to the const char* value somewhere because QCString doesn't keep the value of it
+ module()->setEntry(isUnicode()? newText.toUtf8().constData() : newText.toLocal8Bit().constData());
+}
+
+/** Deletes the current entry and removes it from the module. */
+bool CSwordModuleInfo::deleteEntry(CSwordKey * const key) {
+ module()->KeyText(isUnicode()? key->key().toUtf8().constData() : key->key().toLocal8Bit().constData());
+
+ if (module()) {
+ module()->deleteEntry();
+ return true;
+ }
+
+ return false;
+}
+
+/** Returns the category of this module. See CSwordModuleInfo::Category for possible values. */
+CSwordModuleInfo::Category CSwordModuleInfo::category() const {
+ //qDebug("CSwordModuleInfo::category");
+ if (m_dataCache.category == CSwordModuleInfo::UnknownCategory) {
+ const QString cat(m_module->getConfigEntry("Category"));
+ //qDebug() << "the category was unknown, add a category "<< cat << "for module" << m_module->Name();
+
+ if (cat == "Cults / Unorthodox / Questionable Material") {
+ m_dataCache.category = Cult;
+ }
+ else if (cat == "Daily Devotional" || m_module->getConfig().has("Feature", "DailyDevotion")) {
+ m_dataCache.category = DailyDevotional;
+ }
+ else if (cat == "Glossaries" || m_module->getConfig().has("Feature", "Glossary")) { //allow both
+ m_dataCache.category = Glossary;
+ }
+ else if (cat == "Images" || cat == "Maps") {
+ m_dataCache.category = Images;
+ }
+ else if (type() == Commentary) {
+ m_dataCache.category = Commentaries;
+ }
+ else if (type() == Bible) {
+ m_dataCache.category = Bibles;
+ }
+ else if (type() == Lexicon) {
+ m_dataCache.category = Lexicons;
+ }
+ else if (type() == GenericBook) {
+ m_dataCache.category = Books;
+ }
+ }
+ //qDebug() << "assigned category: " << m_dataCache.category;
+ return m_dataCache.category;
+}
+
+/** Returns the display object for this module. */
+Rendering::CEntryDisplay * CSwordModuleInfo::getDisplay() const {
+ return dynamic_cast < Rendering::CEntryDisplay * >(m_module->Disp());
+}
+
+QString CSwordModuleInfo::aboutText() const {
+ QString text;
+ text += "<table>";
+
+ text += QString("<tr><td><b>%1</b></td><td>%2</td><tr>")
+ .arg(tr("Version"))
+ .arg(hasVersion()? config(CSwordModuleInfo::ModuleVersion) : tr("unknown"));
+
+ text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>")
+ .arg(tr("Markup"))
+ .arg(!QString(m_module->getConfigEntry("SourceType")).isEmpty()? QString(m_module->
+ getConfigEntry("SourceType")) : tr("unknown"));
+
+ text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>")
+ .arg(tr("Location"))
+ .arg(config(CSwordModuleInfo::AbsoluteDataPath));
+
+ text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>")
+ .arg(tr("Language"))
+ .arg(language()->translatedName());
+
+ if (m_module->getConfigEntry("Category"))
+ text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>")
+ .arg(tr("Category"))
+ .arg(m_module->getConfigEntry("Category"));
+
+ if (m_module->getConfigEntry("LCSH"))
+ text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>")
+ .arg(tr("LCSH"))
+ .arg(m_module->getConfigEntry("LCSH"));
+
+ text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>")
+ .arg(tr("Writable"))
+ .arg(isWritable()? tr("yes") : tr("no"));
+
+ if (isEncrypted())
+ text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>")
+ .arg(tr("Unlock key"))
+ .arg(config(CSwordModuleInfo::CipherKey));
+
+ QString options;
+
+ unsigned int opts;
+
+ for (opts = CSwordModuleInfo::filterTypesMIN; opts <= CSwordModuleInfo::filterTypesMAX; ++opts) {
+ if (has(static_cast < CSwordModuleInfo::FilterTypes > (opts))) {
+ if (!options.isEmpty()) {
+ options += QString::fromLatin1(", ");
+ }
+
+ options += CSwordBackend::translatedOptionName(static_cast < CSwordModuleInfo::FilterTypes > (opts));
+ }
+ }
+
+ if (!options.isEmpty()) {
+ text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>")
+ .arg(tr("Features"))
+ .arg(options);
+ }
+
+ text += "</table><hr>";
+
+ if (category() == Cult) //clearly say the module contains cult/questionable materials
+ text += QString("<br/><b>%1</b><br/><br/>")
+ .arg(tr("Take care, this work contains cult / questionable material!"));
+
+ text += QString("<b>%1:</b><br>%2</font>")
+ .arg(tr("About"))
+ .arg(config(AboutInformation));
+
+ typedef QList<CSwordModuleInfo::ConfigEntry> ListConfigEntry;
+
+ ListConfigEntry entries;
+
+ entries.append(DistributionLicense);
+
+ entries.append(DistributionSource);
+
+ entries.append(DistributionNotes);
+
+ entries.append(TextSource);
+
+ entries.append(CopyrightNotes);
+
+ entries.append(CopyrightHolder);
+
+ entries.append(CopyrightDate);
+
+ entries.append(CopyrightContactName);
+
+ entries.append(CopyrightContactAddress);
+
+ entries.append(CopyrightContactEmail);
+
+ typedef QMap<CSwordModuleInfo::ConfigEntry, QString> MapConfigEntry;
+
+ MapConfigEntry entryMap;
+
+ entryMap[DistributionLicense] = tr("Distribution license");
+
+ entryMap[DistributionSource] = tr("Distribution source");
+
+ entryMap[DistributionNotes] = tr("Distribution notes");
+
+ entryMap[TextSource] = tr("Text source");
+
+ entryMap[CopyrightNotes] = tr("Copyright notes");
+
+ entryMap[CopyrightHolder] = tr("Copyright holder");
+
+ entryMap[CopyrightDate] = tr("Copyright date");
+
+ entryMap[CopyrightContactName] = tr("Copyright contact name");
+
+ entryMap[CopyrightContactAddress] = tr("Copyright contact address");
+
+ entryMap[CopyrightContactEmail] = tr("Copyright contact email");
+
+ text += ("<hr><table>");
+
+ for (ListConfigEntry::iterator it(entries.begin()); it != entries.end(); ++it) {
+ QString t( config(*it) );
+
+ if (!t.isEmpty()) {
+ text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>")
+ .arg(entryMap[*it])
+ .arg(config(*it));
+ }
+
+ }
+
+
+ text += "</table></font>";
+
+ return text;
+}
+
+/** Returns the language of the module. */
+const CLanguageMgr::Language* CSwordModuleInfo::language() const {
+ if (!m_dataCache.language) {
+ if (module()) {
+ if (category() == Glossary) {
+ //special handling for glossaries, we use the "from language" as language for the module
+ m_dataCache.language = (CPointers::languageMgr())->languageForAbbrev(config(GlossaryFrom));
+ }
+ else {
+ m_dataCache.language = (CPointers::languageMgr())->languageForAbbrev(module()->Lang());
+ }
+ }
+ else {
+ m_dataCache.language = (CPointers::languageMgr())->defaultLanguage(); //default language
+ }
+ }
+
+ return m_dataCache.language;
+}
+
+
+/*!
+ \fn CSwordModuleInfo::getSimpleConfigEntry(char* name)
+*/
+QString CSwordModuleInfo::getSimpleConfigEntry(const QString& name) const {
+ QString ret = isUnicode()
+ ? QString::fromUtf8(m_module->getConfigEntry(name.toUtf8().constData()))
+ : QString::fromLatin1(m_module->getConfigEntry(name.toUtf8().constData()));
+
+ return ret.isEmpty() ? QString::null : ret;
+}
+
+QString CSwordModuleInfo::getFormattedConfigEntry(const QString& name) const {
+ sword::SWBuf RTF_Buffer(m_module->getConfigEntry(name.toUtf8().constData()));
+ sword::RTFHTML RTF_Filter;
+ RTF_Filter.processText(RTF_Buffer, 0, 0);
+ QString ret = isUnicode()
+ ? QString::fromUtf8(RTF_Buffer.c_str())
+ : QString::fromLatin1(RTF_Buffer.c_str());
+
+ return ret.isEmpty() ? QString::null : ret;
+}
+
+void CSwordModuleInfo::setHidden(bool hidden)
+{
+ //qDebug("CSwordModuleInfo::setHidden");
+ QStringList hiddenModules = CBTConfig::get(CBTConfig::hiddenModules);
+ if (hidden && !hiddenModules.contains(this->name())) {
+ hiddenModules.append(this->name());
+ CBTConfig::set(CBTConfig::hiddenModules, hiddenModules);
+ }
+ if (!hidden && hiddenModules.contains(this->name()) ) {
+ hiddenModules.removeAll(this->name());
+ CBTConfig::set(CBTConfig::hiddenModules, hiddenModules);
+ }
+}
+
+bool CSwordModuleInfo::isHidden() const
+{
+ //qDebug("CSwordModuleInfo::isHidden");
+ QStringList hiddenModules = CBTConfig::get(CBTConfig::hiddenModules);
+ if (hiddenModules.contains(this->name())) {
+ return true;
+ }
+ return false;
+}
diff --git a/src/backend/drivers/cswordmoduleinfo.h b/src/backend/drivers/cswordmoduleinfo.h
new file mode 100644
index 0000000..0f612f9
--- /dev/null
+++ b/src/backend/drivers/cswordmoduleinfo.h
@@ -0,0 +1,384 @@
+/*********
+*
+* 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 CSWORDMODULEINFO_H
+#define CSWORDMODULEINFO_H
+
+#include "backend/managers/clanguagemgr.h"
+
+//Qt
+#include <QString>
+#include <QList>
+
+//Sword
+#include <listkey.h>
+#include <swsearchable.h>
+#include <swmodule.h>
+#include <swversion.h>
+#include <swdisp.h>
+
+class CSwordBackend;
+class CSwordKey;
+
+namespace Rendering {
+
+ class CEntryDisplay;
+}
+
+/**
+ * Base class for Sword modules.
+ * This is the base class for all Sword modules. Every class handling a special Sword module type
+ * does inherit from this class.
+ *
+ * @author The BibleTime team
+ * @version $Id: cswordmoduleinfo.h,v 1.83 2007/02/04 23:12:32 joachim Exp $
+ */
+
+class CSwordModuleInfo: public QObject
+{
+ Q_OBJECT
+
+public:
+ /**
+ * These are the options which could be supported by modules and by this backend.
+ * It's used in @ref CSwordBackend::setOption.
+ */
+ enum FilterTypes {
+ footnotes, /**< Footnotes embedded in the module's text */
+ strongNumbers, /**< strong numbers, usually in the text for the info display */
+ headings, /**< additional section headings */
+ morphTags, /**< morphology */
+ lemmas, /**< lemma tags */
+ hebrewPoints,/**< Hebrew vowel points */
+ hebrewCantillation, /**<Hewbrew caantillation points */
+ greekAccents, /**< Greek accents may be switched on and off */
+ scriptureReferences, /**< scripture references may be switched on and off, just makes sense in Bibles */
+ redLetterWords, /**< Jesus words in red, color is template specific */
+ textualVariants, /**< variants */
+ morphSegmentation, /**< morph word segmentation, supported by OSIS */
+ filterTypesMIN = footnotes, /**< first entry of this enum */
+ filterTypesMAX = morphSegmentation /**< last item in this enum */
+ // transliteration /* The following are handled in a special way */
+ };
+ /** The text direction of a module */
+ enum TextDirection { /* The text direction of the modules's text */
+ LeftToRight, /**< Left to right text direction, the default setting */
+ RightToLeft /**< Right to left text directin, e.g. for hebrew */
+ };
+ /** The module type.
+ */
+ enum ModuleType {
+ Bible, /**< Bible module */
+ Commentary, /**< Commentary module */
+ Lexicon, /**< Lexicon module */
+ GenericBook, /**< Generic book module */
+ Unknown /**< Fall back type for unknown modules */
+ };
+ /**
+ * This enum is used to give
+ * back an error code after unlocking the module
+ * BibleTime stores the unlock key not in the module's config file but in BibleTime's
+ * configuration file.
+ */
+ enum UnlockErrorCode {
+ noError, /**< No error occured, everything worked ok. The key was written to the BibleTime config */
+ wrongUnlockKey, /**< The wrong key was used. Module is not unlocked */
+ notLocked, /**< The module was not locked so it can't be unlocked */
+ noPermission /**< The key was not written to config because we have no permissions */
+ };
+ enum ConfigEntry {
+ AboutInformation, /**< The about information of a module which is stored in the config file*/
+ AbsoluteDataPath, /**< The absolute data path stored in the config object */
+ CipherKey, /**< The cipher key which was used to unlock the module. Not necessarily set.*/
+ DataPath, /**< The relative path. See AbsoluteDataPath*/
+ Description, /**< The module description stored in the config file */
+ ModuleVersion, /**< The module's version.*/
+ MinimumSwordVersion, /**< The required Sword Version of this module. Otherwise some things may not work (compression etc.).*/
+ TextDir, /**< The text direction */
+ DisplayLevel, /**< Mostly used for books. Gives the level which should contain the connected entries.*/
+ GlossaryFrom, /**< lamguage from which the Glosaary tramslates */
+ GlossaryTo, /**< lamguages to which the glossary maps to */
+ DistributionLicense,
+ DistributionSource,
+ DistributionNotes,
+ TextSource,
+ CopyrightNotes,
+ CopyrightHolder,
+ CopyrightDate,
+ CopyrightContactName,
+ CopyrightContactAddress,
+ CopyrightContactEmail,
+ Markup /**< The markup of this module */
+ };
+ enum Feature {
+ //StrongsNumbers, /**< Use for Bibles which have embedded strong numbers */ BT does not use this as a user option
+ GreekDef,
+ HebrewDef,
+ GreekParse,
+ HebrewParse,
+ featureMin = GreekDef,
+ featureMax = HebrewParse
+ };
+ enum Category {
+ UnknownCategory = 0, /**< The category wasn't set or has an unknwon value */
+ Bibles,
+ Commentaries,
+ Books,
+ Lexicons,
+ Glossary,
+ DailyDevotional,
+ Images,
+ Cult /**< The module is a cult / sect / questionable module */
+ };
+
+ /**
+ * Returns the base directory for search indices
+ */
+ static QString getGlobalBaseIndexLocation();
+ /**
+ * Removes search index for this module, even if the module is not there any more
+ */
+ static void deleteIndexForModule( QString name );
+
+
+ /**
+ * Returns the config entry which is pecified by the parameter.
+ */
+ QString config( const CSwordModuleInfo::ConfigEntry entry ) const;
+
+ CSwordModuleInfo( sword::SWModule* module, CSwordBackend* const = 0 );
+ /** Copy constructor to copy the passed parameter.
+ * @param m The module to be copied
+ */
+ CSwordModuleInfo( const CSwordModuleInfo& m );
+ /** Reimplementation to return a valid clone.
+ */
+ virtual CSwordModuleInfo* clone();
+ /** Destructor.
+ */
+ virtual ~CSwordModuleInfo();
+
+ /**
+ * Returns the module object so all objects can access the original Sword module.
+ */
+ sword::SWModule* module() const;
+ /**
+ * Sets the unlock key of the modules and writes the key into the cofig file.
+ * @return True if the unlock process was succesful, if the key was wrong, or if the config file was write protected return false.
+ */
+ bool unlock( const QString& unlockKey );
+ /**
+ * Returns the display object for this module. Normally every module should have a Display object.
+ * Please don't use module()->Display() because this function does return the Sword display and does
+ * render the text, too.
+ * This function performs some casts to return the correct display. If it returns 0 there's no valid
+ * display object.
+ */
+ Rendering::CEntryDisplay* getDisplay() const;
+ /**
+ * This function does return true if the data files of the module are encrypted by the module author
+ * (the on who made the module) no matter if it's locked or not.
+ * @return True if this module is encryped
+ */
+ bool isEncrypted() const;
+ /**
+ * This function returns true if this module is locked (encrypted + correct cipher key),
+ * otherwise return false.
+ * @return True if this module is locked, i.e. encrypted but without a key set
+ */
+ bool isLocked();
+
+ bool unlockKeyIsValid();
+
+ /** The module version.
+ * @return true if this module has a version number and false if it doesn't have one.
+ */
+ inline bool hasVersion() const;
+
+ /**
+ * Returns true if the module's index has been built.
+ */
+ virtual bool hasIndex();
+ /**
+ * Returns the path to this module's index base dir
+ */
+ virtual QString getModuleBaseIndexLocation() const;
+ /**
+ * Returns the path to this module's standard index
+ */
+ virtual QString getModuleStandardIndexLocation() const;
+ /**
+ * Builds a search index for this module
+ */
+ virtual void buildIndex();
+ /**
+ * Returns index size
+ */
+ virtual unsigned long indexSize() const;
+ /**
+ * Returns true if something was found, otherwise return false.
+ * This function uses CLucene to perform and index based search. It also
+ * overwrites the variable containing the last search result.
+ */
+ virtual bool searchIndexed(const QString& searchedText, sword::ListKey& scope);
+ /**
+ * Returns the last search result for this module.
+ * The last result is cleared by @ref search
+ */
+ virtual sword::ListKey& searchResult( const sword::ListKey* newResult = 0 );
+ /**
+ * Clears the last search result.
+ * This does immediately clean the last search result,
+ * no matter if search is in progress or not.
+ */
+ void clearSearchResult();
+ /**
+ * Returns the type of the module.
+ */
+ virtual CSwordModuleInfo::ModuleType type() const;
+ /**
+ * Returns the required Sword version for this module.
+ * Returns -1 if no special Sword version is required.
+ */
+ sword::SWVersion minimumSwordVersion();
+ /**
+ * Returns the name of the module.
+ * @return The name of this module.
+ */
+ QString name() const;
+ /**
+ * Snaps to the closest entry in the module if the current key is
+ * not present in the data files.
+ */
+ virtual bool snap() {
+ return false;
+ };
+
+ bool has( const CSwordModuleInfo::Feature ) const;
+ bool has( const CSwordModuleInfo::FilterTypes ) const;
+ /**
+ * Returns the text direction of the module's text.,
+ */
+ virtual CSwordModuleInfo::TextDirection textDirection();
+ /**
+ * Writes the new text at the given position into the module. This does only work for writabe modules.
+ */
+ virtual void write( CSwordKey* key, const QString& newText );
+ /**
+ * Deletes the current entry and removes it from the module.
+ */
+ bool deleteEntry( CSwordKey* const key );
+ /**
+ * Returns the language of the module.
+ */
+ const CLanguageMgr::Language* language() const;
+ /**
+ * Returns true if this module may be written by the write display windows.
+ */
+ inline virtual bool isWritable() const;
+ /**
+ * Returns true if this module is hidden (not to be shown with other modules in certain views).
+ */
+ bool isHidden() const;
+
+ void setHidden(bool hidden);
+
+ /**
+ * Returns the category of this module. See CSwordModuleInfo::Category for possible values.
+ */
+ CSwordModuleInfo::Category category() const;
+ /**
+ * The about text which belongs to this module.
+ */
+ QString aboutText() const;
+ /**
+ * Returns true if this module is Unicode encoded. False if the charset is iso8859-1.
+ * Protected because it should not be used outside of the CSword*ModuleInfo classes.
+ */
+ inline bool isUnicode() const {
+ return m_dataCache.isUnicode;
+ }
+
+public slots:
+ inline void cancelIndexing() { m_cancelIndexing = true; };
+
+protected:
+ friend class CSwordBackend;
+
+ inline CSwordBackend* backend() const {
+ return m_backend;
+ }
+
+ inline void backend( CSwordBackend* newBackend ) {
+ if (newBackend) {
+ m_backend = newBackend;
+ }
+ }
+
+ QString getSimpleConfigEntry(const QString& name) const;
+ QString getFormattedConfigEntry(const QString& name) const;
+
+signals:
+ void indexingFinished();
+ void indexingProgress(int);
+
+private:
+ sword::SWModule* m_module;
+ sword::ListKey m_searchResult;
+
+ mutable struct DataCache {
+ DataCache() {
+ language = 0;
+ }
+
+ QString name;
+ bool isUnicode;
+ CSwordModuleInfo::Category category;
+ const CLanguageMgr::Language* language;
+ bool hasVersion;
+ }
+
+ m_dataCache;
+
+ CSwordBackend* m_backend;
+
+ bool m_hidden;
+
+ bool m_cancelIndexing;
+};
+
+inline CSwordModuleInfo::ModuleType CSwordModuleInfo::type() const {
+ return CSwordModuleInfo::Unknown;
+}
+
+inline sword::SWModule* CSwordModuleInfo::module() const {
+ return m_module;
+}
+
+inline bool CSwordModuleInfo::hasVersion() const {
+ return m_dataCache.hasVersion;
+}
+
+
+/**
+* Returns the name of the module.
+* The Sword library takes care of the duplicate names: _n is added after each duplicate.
+*/
+inline QString CSwordModuleInfo::name() const {
+ return m_dataCache.name;
+}
+
+/** Returns true if this module may be written by the write display windows. */
+inline bool CSwordModuleInfo::isWritable() const {
+ return false;
+}
+
+//#include "util/cpointers.h"
+
+#endif
diff --git a/src/backend/filters/bt_gbfhtml.cpp b/src/backend/filters/bt_gbfhtml.cpp
new file mode 100644
index 0000000..0627cee
--- /dev/null
+++ b/src/backend/filters/bt_gbfhtml.cpp
@@ -0,0 +1,296 @@
+/*********
+*
+* 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 "bt_gbfhtml.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/cswordbackend.h"
+#include "util/cpointers.h"
+
+//Sword includes
+#include <utilxml.h>
+
+//Qt includes
+#include <QRegExp>
+#include <QString>
+
+Filters::BT_GBFHTML::BT_GBFHTML() : sword::GBFHTML() {
+
+ setEscapeStringCaseSensitive(true);
+ setPassThruUnknownEscapeString(true); //the HTML widget will render the HTML escape codes
+
+ removeTokenSubstitute("Rf");
+ // addTokenSubstitute("RB", "<span>"); //start of a footnote with embedded text
+
+ addTokenSubstitute("FI", "<span class=\"italic\">"); // italics begin
+ addTokenSubstitute("Fi", "</span>");
+
+ addTokenSubstitute("FB", "<span class=\"bold\">"); // bold begin
+ addTokenSubstitute("Fb", "</span>");
+
+ addTokenSubstitute("FR", "<span class=\"jesuswords\">");
+ addTokenSubstitute("Fr", "</span>");
+
+ addTokenSubstitute("FU", "<u>"); // underline begin
+ addTokenSubstitute("Fu", "</u>");
+
+ addTokenSubstitute("FO", "<span class=\"quotation\">"); // Old Testament quote begin
+ addTokenSubstitute("Fo", "</span>");
+
+
+ addTokenSubstitute("FS", "<span class=\"sup\">"); // Superscript begin// Subscript begin
+ addTokenSubstitute("Fs", "</span>");
+
+ addTokenSubstitute("FV", "<span class=\"sub\">"); // Subscript begin
+ addTokenSubstitute("Fv", "</span>");
+
+ addTokenSubstitute("TT", "<div class=\"booktitle\">");
+ addTokenSubstitute("Tt", "</div>");
+
+ addTokenSubstitute("TS", "<div class=\"sectiontitle\">");
+ addTokenSubstitute("Ts", "</div>");
+
+ //addTokenSubstitute("PP", "<span class=\"poetry\">"); // poetry begin
+ //addTokenSubstitute("Pp", "</span>");
+
+
+ addTokenSubstitute("Fn", "</font>"); // font end
+ addTokenSubstitute("CL", "<br/>"); // new line
+ addTokenSubstitute("CM", "<br/>"); // paragraph <!P> is a non showing comment that can be changed in the front end to <P> if desired
+
+ addTokenSubstitute("CG", "&gt;"); // literal greater-than sign
+ addTokenSubstitute("CT", "&lt;"); // literal less-than sign
+
+ addTokenSubstitute("JR", "<span class=\"right\">"); // right align begin
+ addTokenSubstitute("JC", "<span class=\"center\">"); // center align begin
+ addTokenSubstitute("JL", "</span>"); // align end
+}
+
+/** No descriptions */
+char Filters::BT_GBFHTML::processText(sword::SWBuf& buf, const sword::SWKey * key, const sword::SWModule * module) {
+ GBFHTML::processText(buf, key, module);
+
+ if (!module->isProcessEntryAttributes()) {
+ return 1; //no processing should be done, may happen in a search
+ }
+
+ CSwordModuleInfo* m = CPointers::backend()->findModuleByName( module->Name() );
+
+ if (m && !(m->has(CSwordModuleInfo::lemmas) || m->has(CSwordModuleInfo::morphTags) || m->has(CSwordModuleInfo::strongNumbers))) { //only parse if the module has strongs or lemmas
+ return 1; //WARNING: Return alread here
+ }
+
+ //Am Anfang<WH07225> schuf<WH01254><WTH8804> Gott<WH0430> Himmel<WH08064> und<WT> Erde<WH0776>.
+ //A simple word<WT> means: No entry for this word "word"
+ QString result;
+
+ QString t = QString::fromUtf8(buf.c_str());
+
+ QRegExp tag("([.,;:]?<W[HGT][^>]*>\\s*)+");
+
+ QStringList list;
+
+ int lastMatchEnd = 0;
+
+ int pos = tag.indexIn(t,0);
+
+ if (pos == -1) { //no strong or morph code found in this text
+ return 1; //WARNING: Return already here
+ }
+
+ //split the text into parts which end with the GBF tag marker for strongs/lemmas
+ while (pos != -1) {
+ list.append(t.mid(lastMatchEnd, pos+tag.matchedLength()-lastMatchEnd));
+
+ lastMatchEnd = pos + tag.matchedLength();
+ pos = tag.indexIn(t, pos + tag.matchedLength());
+ }
+
+ //append the trailing text to the list.
+ if (!t.right(t.length() - lastMatchEnd).isEmpty()) {
+ list.append(t.right(t.length() - lastMatchEnd));
+ }
+
+ //list is now a list of words with 1-n Strongs at the end, which belong to this word.
+
+ //now create the necessary HTML in list entries and concat them to the result
+ tag = QRegExp("<W([HGT])([^>]*)>");
+ tag.setMinimal(true);
+
+ for (QStringList::iterator it = list.begin(); it != list.end(); ++it) {
+ QString e = (*it); //current entry to process
+ //qWarning(e.latin1());
+
+ //check if there is a word to which the strongs info belongs to.
+ //If yes, wrap that word with the strongs info
+ //If not, leave out the strongs info, because it can't be tight to a text
+ //Comparing the first char with < is not enough, because the tokenReplace is done already
+ //so there might be html tags already.
+ const bool textPresent = (e.trimmed().remove(QRegExp("[.,;:]")).left(2) != "<W");
+
+ if (!textPresent) {
+ result += (*it);
+ continue;
+ }
+
+ int pos = tag.indexIn(e, 0); //try to find a strong number marker
+ bool insertedTag = false;
+ bool hasLemmaAttr = false;
+ bool hasMorphAttr = false;
+
+ QString value = QString::null;
+ int tagAttributeStart = -1;
+
+ while (pos != -1) { //work on all strong/lemma tags in this section, should be between 1-3 loops
+ const bool isMorph = (tag.cap(1) == "T");
+ value = isMorph ? tag.cap(2) : tag.cap(2).prepend( tag.cap(1) );
+
+ if (value.isEmpty()) {
+ break;
+ }
+
+ //insert the span
+ if (!insertedTag) { //we have to insert a new tag end and beginning, i.e. our first loop
+ e.replace(pos, tag.matchedLength(), "</span>");
+ pos += 7;
+
+ //skip blanks, commas, dots and stuff at the beginning, it doesn't belong to the morph code
+ QString rep("<span ");
+ rep.append(isMorph ? "morph" : "lemma").append("=\"").append(value).append("\">");
+
+ hasMorphAttr = isMorph;
+ hasLemmaAttr = !isMorph;
+
+ int startPos = 0;
+ QChar c = e[startPos];
+
+ while ((startPos < pos) && (c.isSpace() || c.isPunct())) {
+ ++startPos;
+
+ c = e[startPos];
+ }
+
+ e.insert( startPos, rep );
+ tagAttributeStart = startPos + 6; //to point to the start of the attributes
+ pos += rep.length();
+ }
+ else { //add the attribute to the existing tag
+ e.remove(pos, tag.matchedLength());
+
+ if (tagAttributeStart == -1) {
+ continue; //nothing valid found
+ }
+
+ if ((!isMorph && hasLemmaAttr) || (isMorph && hasMorphAttr)) { //we append another attribute value, e.g. 3000 gets 3000|5000
+ //search the existing attribute start
+ QRegExp attrRegExp( isMorph ? "morph=\".+(?=\")" : "lemma=\".+(?=\")" );
+ attrRegExp.setMinimal(true);
+ const int foundPos = e.indexOf(attrRegExp, tagAttributeStart);
+
+ if (foundPos != -1) {
+ e.insert(foundPos + attrRegExp.matchedLength(), QString("|").append(value));
+ pos += value.length() + 1;
+
+ hasLemmaAttr = !isMorph;
+ hasMorphAttr = isMorph;
+ }
+ }
+ else { //attribute was not yet inserted
+ QString attr = QString(isMorph ? "morph" : "lemma").append("=\"").append(value).append("\" ");
+
+ e.insert(tagAttributeStart, attr);
+ pos += attr.length();
+
+ hasMorphAttr = isMorph;
+ hasLemmaAttr = !isMorph;
+ }
+
+ //tagAttributeStart remains the same
+ }
+
+ insertedTag = true;
+ pos = tag.indexIn(e, pos);
+ }
+
+ result += e;
+ }
+
+ if (list.count()) {
+ buf = (const char*)result.toUtf8().constData();
+ }
+
+ return 1;
+}
+
+bool Filters::BT_GBFHTML::handleToken(sword::SWBuf &buf, const char *token, sword::BasicFilterUserData *userData) {
+ if (!substituteToken(buf, token)) { //more than a simple replace
+ const unsigned int tokenLength = strlen(token);
+ unsigned long i;
+ sword::SWBuf value;
+
+ BT_UserData* myUserData = dynamic_cast<BT_UserData*>(userData);
+ sword::SWModule* myModule = const_cast<sword::SWModule*>(myUserData->module); //hack to be able to call stuff like Lang()
+
+ if ( !strncmp(token, "WG", 2)
+ || !strncmp(token, "WH", 2)
+ || !strncmp(token, "WT", 2) ) {
+ buf.append('<');
+ buf.append(token);
+ buf.append('>');
+ }
+ else if (!strncmp(token, "RB", 2)) {
+ myUserData->hasFootnotePreTag = true;
+ buf.append("<span class=\"footnotepre\">");
+ }
+ else if (!strncmp(token, "RF", 2)) {
+ //we use several append calls because appendFormatted slows down filtering, which should be fast
+
+ if (myUserData->hasFootnotePreTag) {
+ // qWarning("inserted footnotepre end");
+ buf.append("</span>");
+ myUserData->hasFootnotePreTag = false;
+ }
+
+ buf.append(" <span class=\"footnote\" note=\"");
+ buf.append(myModule->Name());
+ buf.append('/');
+ buf.append(myUserData->key->getShortText());
+ buf.append('/');
+ buf.append( QString::number(myUserData->swordFootnote++).toUtf8().constData() );
+ buf.append("\">*</span> ");
+
+ userData->suspendTextPassThru = true;
+ }
+ else if (!strncmp(token, "Rf", 2)) { //end of footnote
+ userData->suspendTextPassThru = false;
+ }
+ else if (!strncmp(token, "FN", 2)) { //the end </font> tag is inserted in addTokenSubsitute
+ buf.append("<font face=\"");
+
+ for (i = 2; i < tokenLength; i++) {
+ if(token[i] != '\"') {
+ buf.append( token[i] );
+ }
+ }
+
+ buf.append("\">");
+ }
+ else if (!strncmp(token, "CA", 2)) { // ASCII value
+ buf.append( (char)atoi(&token[2]) );
+ }
+ else {
+ return GBFHTML::handleToken(buf, token, userData);
+ }
+ }
+
+ return true;
+}
diff --git a/src/backend/filters/bt_gbfhtml.h b/src/backend/filters/bt_gbfhtml.h
new file mode 100644
index 0000000..b9118aa
--- /dev/null
+++ b/src/backend/filters/bt_gbfhtml.h
@@ -0,0 +1,55 @@
+/*********
+*
+* 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.
+*
+**********/
+
+
+
+/* $Header: /cvsroot/bibletime/bibletime/bibletime/backend/filters/bt_gbfhtml.h,v 1.24 2006/02/25 11:38:15 joachim Exp $ */
+/* $Revision: 1.24 $ */
+
+#ifndef BT_GBFHTML_H
+#define BT_GBFHTML_H
+
+//Sword includes
+#include <gbfhtml.h>
+
+namespace Filters {
+
+ /** GBF to HTML filter,
+ * This filter converts GBF Text into HTML
+ */
+
+class BT_GBFHTML : public sword::GBFHTML/*, protected CFilterTool */
+ {
+
+protected:
+
+class BT_UserData : public sword::GBFHTML::MyUserData {
+
+public:
+BT_UserData(const sword::SWModule *module, const sword::SWKey *key) : sword::GBFHTML::MyUserData(module, key) {
+ swordFootnote = 1;
+ hasFootnotePreTag = false;
+ }
+
+ short unsigned int swordFootnote;
+ };
+
+ virtual sword::BasicFilterUserData *createUserData(const sword::SWModule* module, const sword::SWKey* key) {
+ return new BT_UserData(module, key);
+ }
+
+public:
+ BT_GBFHTML();
+ virtual bool handleToken(sword::SWBuf &buf, const char *token, sword::BasicFilterUserData *userData);
+ virtual char processText(sword::SWBuf& buf, const sword::SWKey*, const sword::SWModule * = 0);
+ };
+
+}
+
+#endif
diff --git a/src/backend/filters/bt_osishtml.cpp b/src/backend/filters/bt_osishtml.cpp
new file mode 100644
index 0000000..b9c9746
--- /dev/null
+++ b/src/backend/filters/bt_osishtml.cpp
@@ -0,0 +1,619 @@
+/*********
+*
+* 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 "bt_osishtml.h"
+#include "backend/managers/clanguagemgr.h"
+#include "backend/managers/creferencemanager.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+
+#include "backend/config/cbtconfig.h"
+#include "util/cpointers.h"
+
+//Sword
+#include <swmodule.h>
+#include <swbuf.h>
+#include <utilxml.h>
+
+//Qt
+#include <QString>
+
+//KDE
+
+
+Filters::BT_OSISHTML::BT_OSISHTML() : sword::OSISHTMLHREF() {
+ setPassThruUnknownEscapeString(true); //the HTML widget will render the HTML escape codes
+
+ addTokenSubstitute("inscription", "<span class=\"inscription\">");
+ addTokenSubstitute("/inscription","</span>");
+
+ addTokenSubstitute("mentioned", "<span class=\"mentioned\">");
+ addTokenSubstitute("/mentioned", "</span>");
+
+// addTokenSubstitute("divineName", "<span class=\"name\"><span class=\"divine\">");
+// addTokenSubstitute("/divineName", "</span></span>");
+
+ //TODO Move that down to the real tag handling, segs without the type morph would generate incorrect markup, as the end span is always inserted
+// addTokenSubstitute("seg type=\"morph\"", "<span class=\"morphSegmentation\">");
+// addTokenSubstitute("/seg", "</span>");
+
+ // OSIS tables
+ addTokenSubstitute("table", "<table>");
+ addTokenSubstitute("/table", "</table>");
+ addTokenSubstitute("row", "<tr>");
+ addTokenSubstitute("/row", "</tr>");
+ addTokenSubstitute("cell", "<td>");
+ addTokenSubstitute("/cell", "</td>");
+
+}
+
+bool Filters::BT_OSISHTML::handleToken(sword::SWBuf &buf, const char *token, sword::BasicFilterUserData *userData) {
+ // manually process if it wasn't a simple substitution
+
+ if (!substituteToken(buf, token)) {
+ BT_UserData* myUserData = dynamic_cast<BT_UserData*>(userData);
+ sword::SWModule* myModule = const_cast<sword::SWModule*>(myUserData->module); //hack
+
+ sword::XMLTag tag(token);
+ // qWarning("found %s", token);
+ const bool osisQToTick = ((!userData->module->getConfigEntry("OSISqToTick")) || (strcmp(userData->module->getConfigEntry("OSISqToTick"), "false")));
+
+ if (!tag.getName()) {
+ return false;
+ }
+
+ // <div> tag
+ if (!strcmp(tag.getName(), "div")) {
+ //handle intro
+
+ if ((!tag.isEmpty()) && (!tag.isEndTag())) { //start tag
+ sword::SWBuf type( tag.getAttribute("type") );
+
+ if (type == "introduction") {
+ buf.append("<div class=\"introduction\">");
+ }
+ else if (type == "chapter") {
+ buf.append("<div class=\"chapter\" />"); //don't open a div here, that would lead to a broken XML structure
+ }
+ else {
+ buf.append("<div>");
+ }
+ }
+ else if (tag.isEndTag()) { //end tag
+ buf.append("</div>");
+ }
+ }
+ else if (!strcmp(tag.getName(), "w")) {
+ if ((!tag.isEmpty()) && (!tag.isEndTag())) { //start tag
+ const char *attrib;
+ const char *val;
+
+ sword::XMLTag outTag("span");
+ sword::SWBuf attrValue;
+
+ if ((attrib = tag.getAttribute("xlit"))) {
+ val = strchr(attrib, ':');
+ val = (val) ? (val + 1) : attrib;
+ outTag.setAttribute("xlit", val);
+ }
+
+ if ((attrib = tag.getAttribute("gloss"))) {
+ val = strchr(attrib, ':');
+ val = (val) ? (val + 1) : attrib;
+ outTag.setAttribute("gloss", val);
+ }
+
+ if ((attrib = tag.getAttribute("lemma"))) {
+ char splitChar = '|';
+ const int countSplit1 = tag.getAttributePartCount("lemma", '|');
+ const int countSplit2 = tag.getAttributePartCount("lemma", ' '); //TODO: not allowed, remove soon
+ int count = 0;
+
+ if (countSplit1 > countSplit2) { //| split char
+ splitChar = '|'; //TODO: not allowed, remove soon
+ count = countSplit1;
+ }
+ else {
+ splitChar = ' ';
+ count = countSplit2;
+ }
+
+ int i = (count > 1) ? 0 : -1; // -1 for whole value cuz it's faster, but does the same thing as 0
+ attrValue = "";
+
+ do {
+ if (attrValue.length()) {
+ attrValue.append( '|' );
+ }
+
+ attrib = tag.getAttribute("lemma", i, splitChar);
+
+ if (i < 0) { // to handle our -1 condition
+ i = 0;
+ }
+
+ val = strchr(attrib, ':');
+ val = (val) ? (val + 1) : attrib;
+
+ attrValue.append(val);
+ }
+ while (++i < count);
+
+ if (attrValue.length()) {
+ outTag.setAttribute("lemma", attrValue.c_str());
+ }
+ }
+
+ if ((attrib = tag.getAttribute("morph"))) {
+ char splitChar = '|';
+ const int countSplit1 = tag.getAttributePartCount("morph", '|');
+ const int countSplit2 = tag.getAttributePartCount("morph", ' '); //TODO: not allowed, remove soon
+ int count = 0;
+
+ if (countSplit1 > countSplit2) { //| split char
+ splitChar = '|';
+ count = countSplit1;
+ }
+ else {
+ splitChar = ' ';
+ count = countSplit2;
+ }
+
+ int i = (count > 1) ? 0 : -1; // -1 for whole value cuz it's faster, but does the same thing as 0
+
+ attrValue = "";
+
+ do {
+ if (attrValue.length()) {
+ attrValue.append('|');
+ }
+
+ attrib = tag.getAttribute("morph", i, splitChar);
+
+ if (i < 0) {
+ i = 0; // to handle our -1 condition
+ }
+
+ val = strchr(attrib, ':');
+
+ if (val) { //the prefix gives the modulename
+ //check the prefix
+ if (!strncmp("robinson:", attrib, 9)) { //robinson
+ attrValue.append( "Robinson:" ); //work is not the same as Sword's module name
+ attrValue.append( val+1 );
+ }
+ //strongs is handled by BibleTime
+ /*else if (!strncmp("strongs", attrib, val-atrrib)) {
+ attrValue.append( !strncmp(attrib, "x-", 2) ? attrib+2 : attrib );
+ }*/
+ else {
+ attrValue.append( !strncmp(attrib, "x-", 2) ? attrib+2 : attrib );
+ }
+ }
+ else { //no prefix given
+ val = attrib;
+ const bool skipFirst = ((val[0] == 'T') && ((val[1] == 'H') || (val[1] == 'H')));
+ attrValue.append( skipFirst ? val+1 : val );
+ }
+ }
+ while (++i < count);
+
+ if (attrValue.length()) {
+ outTag.setAttribute("morph", attrValue.c_str());
+ }
+ }
+
+ if ((attrib = tag.getAttribute("POS"))) {
+ val = strchr(attrib, ':');
+ val = (val) ? (val + 1) : attrib;
+ outTag.setAttribute("pos", val);
+ }
+
+ buf.append( outTag.toString() );
+ }
+ else if (tag.isEndTag()) { // end or empty <w> tag
+ buf.append("</span>");
+ }
+ }
+
+ // <note> tag
+ else if (!strcmp(tag.getName(), "note")) {
+ if (!tag.isEndTag()) { //start tag
+ const sword::SWBuf type( tag.getAttribute("type") );
+
+ if (type == "crossReference") { //note containing cross references
+ myUserData->inCrossrefNote = true;
+ myUserData->noteType = BT_UserData::CrossReference;
+ myUserData->swordFootnote++; // cross refs count as notes, too
+
+ /* //get the refList value of the right entry attribute
+ AttributeList notes = myModule->getEntryAttributes()["Footnote"];
+ bool foundNote = false;
+
+ SWBuf id( tag.getAttribute("osisID") );
+ SWBuf refList;
+
+ for (AttributeList::iterator list_it = notes.begin(); (list_it != notes.end()) && !foundNote; ++list_it ) {
+ for (AttributeValue::iterator val_it = list_it->second.begin(); (val_it != list_it->second.end()) && !foundNote; ++val_it ) {
+ if ((val_it->first == "osisID") && (val_it->second == id)) {
+ foundNote = true; //this break the loop
+ refList = list_it->second["refList"];
+ }
+ }
+ }
+
+ if (refList.length()) {
+ buf.append(" <span class=\"crossreference\" crossrefs=\"");
+ buf.append(refList.c_str());
+ buf.append("\"> ");
+
+ myUserData->noteType = BT_UserData::CrossReference;
+ }
+ else {
+ myUserData->noteType = BT_UserData::Unknown;
+ }*/
+
+ buf.append("<span class=\"crossreference\">");
+#ifdef SWORD_SIMPLERENDER
+ sword::SWBuf footnoteNumber = tag.getAttribute("swordFootnote");
+ sword::SWBuf footnoteBody = myModule->getEntryAttributes()["Footnote"][footnoteNumber]["body"];
+ buf += myModule->RenderText(footnoteBody);
+#endif
+ }
+
+ /* else if (type == "explanation") {
+ }
+ */
+ else if ((type == "strongsMarkup") || (type == "x-strongsMarkup")) {
+ /**
+ * leave strong's markup notes out, in the future we'll probably have
+ * different option filters to turn different note types on or off
+ */
+
+ myUserData->suspendTextPassThru = true;
+ myUserData->noteType = BT_UserData::StrongsMarkup;
+ }
+
+ else {
+ // qWarning("found note in %s", myUserData->key->getShortText());
+ buf.append(" <span class=\"footnote\" note=\"");
+ buf.append(myModule->Name());
+ buf.append('/');
+ buf.append(myUserData->key->getShortText());
+ buf.append('/');
+ buf.append( QString::number(myUserData->swordFootnote++).toUtf8().constData() ); //inefficient
+
+ const sword::SWBuf n = tag.getAttribute("n");
+
+ buf.append("\">");
+ buf.append( (n.length() > 0) ? n.c_str() : "*" );
+ buf.append("</span> ");
+
+ myUserData->noteType = BT_UserData::Footnote;
+ myUserData->suspendTextPassThru = true;
+ }
+ }
+ else { //if (tag.isEndTag()) {
+ Q_ASSERT(myUserData->noteType != BT_UserData::Unknown);
+
+ if (myUserData->noteType == BT_UserData::CrossReference) {
+ buf.append("</span> ");
+// myUserData->suspendTextPassThru = false;
+ myUserData->inCrossrefNote = false;
+ }
+
+ myUserData->noteType = BT_UserData::Unknown;
+ myUserData->suspendTextPassThru = false;
+ }
+ }
+ // The <p> paragraph tag is handled by OSISHTMLHref
+ else if (!strcmp(tag.getName(), "reference")) { // <reference> tag
+ if (!tag.isEndTag() && !tag.isEmpty()) {
+
+ renderReference(tag.getAttribute("osisRef"), buf, myModule, myUserData);
+
+ }
+ else if (tag.isEndTag()) {
+ buf.append("</a>");
+ }
+ else { // empty reference marker
+ // -- what should we do? nothing for now.
+ }
+ }
+
+ // <l> is handled by OSISHTMLHref
+ // <title>
+ else if (!strcmp(tag.getName(), "title")) {
+ if (!tag.isEndTag() && !tag.isEmpty()) {
+ buf.append("<div class=\"sectiontitle\">");
+ }
+ else if (tag.isEndTag()) {
+ buf.append("</div>");
+ }
+ else { // empty title marker
+ // what to do? is this even valid?
+ buf.append("<br/>");
+ }
+ }
+
+ // <hi> highlighted text
+ else if (!strcmp(tag.getName(), "hi")) {
+ const sword::SWBuf type = tag.getAttribute("type");
+
+ if ((!tag.isEndTag()) && (!tag.isEmpty())) {
+ if (type == "bold") {
+ buf.append("<span class=\"bold\">");
+ }
+ else if (type == "illuminated") {
+ buf.append("<span class=\"illuminated\">");
+ }
+ else if (type == "italic") {
+ buf.append("<span class=\"italic\">");
+ }
+ else if (type == "line-through") {
+ buf.append("<span class=\"line-through\">");
+ }
+ else if (type == "normal") {
+ buf.append("<span class=\"normal\">");
+ }
+ else if (type == "small-caps") {
+ buf.append("<span class=\"small-caps\">");
+ }
+ else if (type == "underline") {
+ buf.append("<span class=\"underline\">");
+ }
+ else {
+ buf.append("<span>"); //don't break markup, </span> is inserted later
+ }
+ }
+ else if (tag.isEndTag()) { //all hi replacements are html spans
+ buf.append("</span>");
+ }
+ }
+
+ //name
+ else if (!strcmp(tag.getName(), "name")) {
+ const sword::SWBuf type = tag.getAttribute("type");
+
+ if ((!tag.isEndTag()) && (!tag.isEmpty())) {
+ if (type == "geographic") {
+ buf.append("<span class=\"name\"><span class=\"geographic\">");
+ }
+ else if (type == "holiday") {
+ buf.append("<span class=\"name\"><span class=\"holiday\">");
+ }
+ else if (type == "nonhuman") {
+ buf.append("<span class=\"name\"><span class=\"nonhuman\">");
+ }
+ else if (type == "person") {
+ buf.append("<span class=\"name\"><span class=\"person\">");
+ }
+ else if (type == "ritual") {
+ buf.append("<span class=\"name\"><span class=\"ritual\">");
+ }
+ else {
+ buf.append("<span class=\"name\"><span>");
+ }
+ }
+ else if (tag.isEndTag()) { //all hi replacements are html spans
+ buf.append("</span></span> ");
+ }
+ }
+ else if (!strcmp(tag.getName(), "transChange")) {
+ sword::SWBuf type( tag.getAttribute("type") );
+
+ if ( !type.length() ) {
+ type = tag.getAttribute("changeType");
+ }
+
+ if ((!tag.isEndTag()) && (!tag.isEmpty())) {
+ if (type == "added") {
+ buf.append("<span class=\"transchange\" title=\"");
+ buf.append(QObject::tr("Added text").toUtf8().constData());
+ buf.append("\"><span class=\"added\">");
+ }
+ else if (type == "amplified") {
+ buf.append("<span class=\"transchange\"><span class=\"amplified\">");
+ }
+ else if (type == "changed") {
+ buf.append("<span class=\"transchange\"><span class=\"changed\">");
+ }
+ else if (type == "deleted") {
+ buf.append("<span class=\"transchange\"><span class=\"deleted\">");
+ }
+ else if (type == "moved") {
+ buf.append("<span class=\"transchange\"><span class=\"moved\">");
+ }
+ else if (type == "tenseChange") {
+ buf.append("<span class=\"transchange\" title=\"");
+ buf.append(QObject::tr("Verb tense changed").toUtf8().constData());
+ buf.append("\"><span class=\"tenseChange\">");
+ }
+ else {
+ buf.append("<span class=\"transchange\"><span>");
+ }
+ }
+ else if (tag.isEndTag()) { //all hi replacements are html spans
+ buf.append("</span></span>");
+ }
+ }
+ else if (!strcmp(tag.getName(), "p")) {
+ if (tag.isEmpty()) {
+ buf.append("<p/>");
+ }
+ }
+
+ // <q> quote
+ else if (!strcmp(tag.getName(), "q")) {
+ sword::SWBuf type = tag.getAttribute("type");
+ sword::SWBuf who = tag.getAttribute("who");
+ const char *lev = tag.getAttribute("level");
+ int level = (lev) ? atoi(lev) : 1;
+ const char* quoteMarker = tag.getAttribute("marker");
+
+ if ((!tag.isEndTag())) {
+ myUserData->quote.who = who;
+ if (quoteMarker) {
+ buf.append(quoteMarker);
+ }
+ else if(osisQToTick) //alternate " and '
+ buf.append((level % 2) ? '\"' : '\'');
+
+ if (who == "Jesus") {
+ buf.append("<span class=\"jesuswords\">");
+ }
+ }
+ else if (tag.isEndTag()) {
+ if (myUserData->quote.who == "Jesus") {
+ buf.append("</span>");
+ }
+ if (quoteMarker) {
+ buf.append(quoteMarker);
+ }
+ else if (osisQToTick) { //alternate " and '
+ buf.append((level % 2) ? '\"' : '\'');
+ }
+
+ myUserData->quote.who = "";
+ }
+ }
+
+ // abbr tag
+ else if (!strcmp(tag.getName(), "abbr")) {
+ if (!tag.isEndTag() && !tag.isEmpty()) {
+ const sword::SWBuf expansion = tag.getAttribute("expansion");
+
+ buf.append("<span class=\"abbreviation\" expansion=\"");
+ buf.append(expansion);
+ buf.append("\">");
+ }
+ else if (tag.isEndTag()) {
+ buf.append("</span>");
+ }
+ }
+
+ // <milestone> tag
+ else if (!strcmp(tag.getName(), "milestone")) {
+ const sword::SWBuf type = tag.getAttribute("type");
+
+ if ((type == "screen") || (type == "line")) {//line break
+ buf.append("<br/>");
+ userData->supressAdjacentWhitespace = true;
+ }
+ else if (type == "x-p") { //e.g. occurs in the KJV2006 module
+ //buf.append("<br/>");
+ const sword::SWBuf marker = tag.getAttribute("marker");
+ if (marker.length() > 0) {
+ buf.append(marker);
+ }
+ }
+ }
+ //seg tag
+ else if (!strcmp(tag.getName(), "seg")) {
+ if (!tag.isEndTag() && !tag.isEmpty()) {
+
+ const sword::SWBuf type = tag.getAttribute("type");
+
+ if (type == "morph") {//line break
+ //This code is for WLC and MORPH (WHI)
+ sword::XMLTag outTag("span");
+ outTag.setAttribute("class", "morphSegmentation");
+ const char* attrValue;
+ //Transfer the values to the span
+ //Problem: the data is in hebrew/aramaic, how to encode in HTML/BibleTime?
+ if ((attrValue = tag.getAttribute("lemma"))) outTag.setAttribute("lemma", attrValue);
+ if ((attrValue = tag.getAttribute("morph"))) outTag.setAttribute("morph", attrValue);
+ if ((attrValue = tag.getAttribute("homonym"))) outTag.setAttribute("homonym", attrValue);
+
+ buf.append(outTag.toString());
+ //buf.append("<span class=\"morphSegmentation\">");
+ }
+ else{
+ buf.append("<span>");
+ }
+ }
+ else { // seg end tag
+ buf.append("</span>");
+ }
+ //qWarning(QString("handled <seg> token. result: %1").arg(buf.c_str()).latin1());
+ }
+
+ //divine name, don't use simple tag replacing because it may have attributes
+ else if (!strcmp(tag.getName(), "divineName")) {
+ if (!tag.isEndTag()) {
+ buf.append("<span class=\"name\"><span class=\"divine\">");
+ }
+ else { //all hi replacements are html spans
+ buf.append("</span></span>");
+ }
+ }
+
+ else { //all tokens handled by OSISHTMLHref will run through the filter now
+ return sword::OSISHTMLHREF::handleToken(buf, token, userData);
+ }
+ }
+
+ return false;
+}
+
+void Filters::BT_OSISHTML::renderReference(const char *osisRef, sword::SWBuf &buf, sword::SWModule *myModule, BT_UserData *myUserData) {
+ QString ref( osisRef );
+ QString hrefRef( ref );
+ //Q_ASSERT(!ref.isEmpty()); checked later
+
+ if (!ref.isEmpty()) {
+ //find out the mod, using the current module makes sense if it's a bible or commentary because the refs link into a bible by default.
+ //If the osisRef is something like "ModuleID:key comes here" then the
+ // modulename is given, so we'll use that one
+
+ CSwordModuleInfo* mod = CPointers::backend()->findSwordModuleByPointer(myModule);
+ //Q_ASSERT(mod); checked later
+ if (!mod || (mod->type() != CSwordModuleInfo::Bible
+ && mod->type() != CSwordModuleInfo::Commentary)) {
+
+ mod = CBTConfig::get( CBTConfig::standardBible );
+ }
+
+ // Q_ASSERT(mod); There's no necessarily a module or standard Bible
+
+ //if the osisRef like "GerLut:key" contains a module, use that
+ int pos = ref.indexOf(":");
+
+ if ((pos >= 0) && ref.at(pos-1).isLetter() && ref.at(pos+1).isLetter()) {
+ QString newModuleName = ref.left(pos);
+ hrefRef = ref.mid(pos+1);
+
+ if (CPointers::backend()->findModuleByName(newModuleName)) {
+ mod = CPointers::backend()->findModuleByName(newModuleName);
+ }
+ }
+
+ if (mod) {
+ CReferenceManager::ParseOptions options;
+ options.refBase = QString::fromUtf8(myUserData->key->getText());
+ options.refDestinationModule = QString(mod->name());
+ options.sourceLanguage = QString(myModule->Lang());
+ options.destinationLanguage = QString("en");
+
+ buf.append("<a href=\"");
+ buf.append( //create the hyperlink with key and mod
+ CReferenceManager::encodeHyperlink(
+ mod->name(),
+ CReferenceManager::parseVerseReference(hrefRef, options),
+ CReferenceManager::typeFromModule(mod->type())
+ ).toUtf8().constData()
+ );
+ buf.append("\" crossrefs=\"");
+ buf.append((const char*)CReferenceManager::parseVerseReference(ref, options).toUtf8().constData()); //ref must contain the osisRef module marker if there was any
+ buf.append("\">");
+ }
+ // should we add something if there were no referenced module available?
+ }
+}
+
diff --git a/src/backend/filters/bt_osishtml.h b/src/backend/filters/bt_osishtml.h
new file mode 100644
index 0000000..7ae5e6d
--- /dev/null
+++ b/src/backend/filters/bt_osishtml.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 BT_OSISHTML_H
+#define BT_OSISHTML_H
+
+//Sword includes
+#include <swbuf.h>
+#include <osishtmlhref.h>
+
+namespace Filters {
+
+ /** BibleTime's OSIS to HTMl filter.
+ * This filter works on OSIS tags and outputs HTML in the structure supported by BibleTime.
+ */
+
+class BT_OSISHTML : public sword::OSISHTMLHREF {
+
+protected:
+
+class BT_UserData : public sword::OSISHTMLHREF::MyUserData {
+
+public:
+BT_UserData(const sword::SWModule *module, const sword::SWKey *key) : sword::OSISHTMLHREF::MyUserData(module, key) {
+ noteType = Unknown;
+ swordFootnote = 1;
+ inCrossrefNote = false;
+ }
+
+ unsigned short int swordFootnote;
+ bool inCrossrefNote;
+
+ enum NoteType {
+ Unknown,
+ Alternative,
+ CrossReference,
+ Footnote,
+ StrongsMarkup
+ } noteType;
+
+ struct {
+ sword::SWBuf who;
+ }
+
+ quote;
+ };
+
+ virtual sword::BasicFilterUserData *createUserData(const sword::SWModule* module, const sword::SWKey* key) {
+ return new BT_UserData(module, key);
+ }
+
+public:
+ BT_OSISHTML();
+ virtual bool handleToken(sword::SWBuf &buf, const char *token, sword::BasicFilterUserData *userData);
+private:
+ void renderReference(const char *osisRef, sword::SWBuf &buf, sword::SWModule *myModule, BT_UserData *myUserData);
+ };
+
+} //end of Filters namespace
+
+#endif
diff --git a/src/backend/filters/bt_plainhtml.cpp b/src/backend/filters/bt_plainhtml.cpp
new file mode 100644
index 0000000..67557cc
--- /dev/null
+++ b/src/backend/filters/bt_plainhtml.cpp
@@ -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.
+*
+**********/
+
+#include "bt_plainhtml.h"
+
+Filters::BT_PLAINHTML::BT_PLAINHTML() : sword::SWFilter() {
+}
+
+/** No descriptions */
+char Filters::BT_PLAINHTML::processText(sword::SWBuf& text, const sword::SWKey* /*key*/, const sword::SWModule* /*module*/) {
+ int count = 0;
+
+ sword::SWBuf orig = text;
+ const char *from = orig.c_str();
+ for (text = ""; *from; from++)
+ {
+ if ((*from == '\n') && (from[1] == '\n')) // two newlinea are a paragraph
+ {
+ text += "<P>";
+ from++;
+ continue;
+ }
+ //This is a special case: Newlines in the plaintext editor are stored as <br />, not as \n
+ //we need to let them through
+ else if ((*from == '<') && (from[1] == 'b') && (from[2] == 'r') && (from[3] == ' ') && (from[4] == '/') && (from[5] == '>')){
+ text += "<br />";
+ from += 5;
+ continue;
+ }
+ else if ((*from == '\n')){ // only one new line
+ text += "<BR>";
+ continue;
+ }
+ else if (*from == '<') {
+ text += "&lt;";
+ continue;
+ }
+ else if (*from == '>') {
+ text += "&gt;";
+ continue;
+ }
+ else if (*from == '&'){
+ text += "&amp;";
+ continue;
+ }
+ else if (*from == '{') { //footnote start
+ text += "<FONT COLOR=\"#80000\"><SMALL> (";
+ continue;
+ }
+ else if (*from == '}') //footnote end
+ {
+ text += ") </SMALL></FONT>";
+ continue;
+ }
+ else if ((*from == ' ') && (count > 5000))
+ {
+ text += "<WBR>";
+ count = 0;
+ continue;
+ }
+
+ text += *from;
+ count++;
+ }
+ return 0;
+}
diff --git a/src/backend/filters/bt_plainhtml.h b/src/backend/filters/bt_plainhtml.h
new file mode 100644
index 0000000..ce1ef36
--- /dev/null
+++ b/src/backend/filters/bt_plainhtml.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 BT_PLAINHTML_H
+#define BT_PLAINHTML_H
+
+//Sword includes
+#include <swfilter.h>
+#include <swbuf.h>
+
+class SWKey;
+class SWModule;
+
+namespace Filters {
+
+ /** Plain to HTML filter,
+ * This filter converts Plain Text into HTML
+ */
+class BT_PLAINHTML : public sword::SWFilter{
+protected:
+ virtual char processText(sword::SWBuf& buf, const sword::SWKey*, const sword::SWModule * = 0);
+public:
+ BT_PLAINHTML();
+ };
+}
+
+#endif
diff --git a/src/backend/filters/bt_thmlhtml.cpp b/src/backend/filters/bt_thmlhtml.cpp
new file mode 100644
index 0000000..a5f17d2
--- /dev/null
+++ b/src/backend/filters/bt_thmlhtml.cpp
@@ -0,0 +1,385 @@
+/*********
+*
+* 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 "bt_thmlhtml.h"
+#include "backend/managers/clanguagemgr.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/creferencemanager.h"
+
+#include "backend/config/cbtconfig.h"
+#include "util/cpointers.h"
+#include <boost/scoped_ptr.hpp>
+
+//Sword includes
+#include <swmodule.h>
+#include <utilxml.h>
+#include <versekey.h>
+#include <utilstr.h>
+
+//Qt includes
+#include <QString>
+#include <QRegExp>
+
+Filters::BT_ThMLHTML::BT_ThMLHTML() {
+ setEscapeStringCaseSensitive(true);
+ setPassThruUnknownEscapeString(true); //the HTML widget will render the HTML escape codes
+
+ setTokenStart("<");
+ setTokenEnd(">");
+ setTokenCaseSensitive(true);
+
+ addTokenSubstitute("/foreign", "</span>");
+
+ removeTokenSubstitute("note");
+ removeTokenSubstitute("/note");
+}
+
+char Filters::BT_ThMLHTML::processText(sword::SWBuf& buf, const sword::SWKey* key, const sword::SWModule* module) {
+ sword::ThMLHTML::processText(buf, key, module);
+
+ CSwordModuleInfo* m = CPointers::backend()->findModuleByName( module->Name() );
+
+ if (m && !(m->has(CSwordModuleInfo::lemmas) || m->has(CSwordModuleInfo::strongNumbers))) { //only parse if the module has strongs or lemmas
+ return 1;
+ }
+
+ QString result;
+
+ QString t = QString::fromUtf8(buf.c_str());
+ QRegExp tag("([.,;]?<sync[^>]+(type|value)=\"([^\"]+)\"[^>]+(type|value)=\"([^\"]+)\"([^<]*)>)+");
+
+ QStringList list;
+ int lastMatchEnd = 0;
+ int pos = tag.indexIn(t,0);
+
+ if (pos == -1) { //no strong or morph code found in this text
+ return 1; //WARNING: Return alread here
+ }
+
+ while (pos != -1) {
+ list.append(t.mid(lastMatchEnd, pos+tag.matchedLength()-lastMatchEnd));
+
+ lastMatchEnd = pos+tag.matchedLength();
+ pos = tag.indexIn(t,pos+tag.matchedLength());
+ }
+
+ if (!t.right(t.length() - lastMatchEnd).isEmpty()) {
+ list.append(t.right(t.length() - lastMatchEnd));
+ }
+
+ tag = QRegExp("<sync[^>]+(type|value|class)=\"([^\"]+)\"[^>]+(type|value|class)=\"([^\"]+)\"[^>]+((type|value|class)=\"([^\"]+)\")*([^<]*)>");
+
+ for (QStringList::iterator it = list.begin(); it != list.end(); ++it) {
+ QString e( *it );
+
+ const bool textPresent = (e.trimmed().remove(QRegExp("[.,;:]")).left(1) != "<");
+
+ if (!textPresent) {
+ continue;
+ }
+
+
+ bool hasLemmaAttr = false;
+ bool hasMorphAttr = false;
+
+ int pos = tag.indexIn(e, 0);
+ bool insertedTag = false;
+ QString value;
+ QString valueClass;
+
+ while (pos != -1) {
+ bool isMorph = false;
+ bool isStrongs = false;
+ value = QString::null;
+ valueClass = QString::null;
+
+ // check 3 attribute/value pairs
+
+ for (int i = 1; i < 6; i += 2) {
+ if (i > 4)
+ i++;
+
+ if (tag.cap(i) == "type") {
+ isMorph = (tag.cap(i+1) == "morph");
+ isStrongs = (tag.cap(i+1) == "Strongs");
+ }
+ else if (tag.cap(i) == "value") {
+ value = tag.cap(i+1);
+ }
+ else if (tag.cap(i) == "class") {
+ valueClass = tag.cap(i+1);
+ }
+ }
+
+ // prepend the class qualifier to the value
+ if (!valueClass.isEmpty()) {
+ value = valueClass + ":" + value;
+ // value.append(":").append(value);
+ }
+
+ if (value.isEmpty()) {
+ break;
+ }
+
+ //insert the span
+ if (!insertedTag) {
+ e.replace(pos, tag.matchedLength(), "</span>");
+ pos += 7;
+
+ QString rep = QString("<span lemma=\"").append(value).append("\">");
+ int startPos = 0;
+ QChar c = e[startPos];
+
+ while ((startPos < pos) && (c.isSpace() || c.isPunct())) {
+ ++startPos;
+ c = e[startPos];
+ }
+
+ hasLemmaAttr = isStrongs;
+ hasMorphAttr = isMorph;
+
+ e.insert( startPos, rep );
+ pos += rep.length();
+ }
+ else { //add the attribute to the existing tag
+ e.remove(pos, tag.matchedLength());
+
+ if ((!isMorph && hasLemmaAttr) || (isMorph && hasMorphAttr)) { //we append another attribute value, e.g. 3000 gets 3000|5000
+ //search the existing attribute start
+ QRegExp attrRegExp( isMorph ? "morph=\".+(?=\")" : "lemma=\".+(?=\")" );
+ attrRegExp.setMinimal(true);
+ const int foundAttrPos = e.indexOf(attrRegExp, pos);
+
+ if (foundAttrPos != -1) {
+ e.insert(foundAttrPos + attrRegExp.matchedLength(), QString("|").append(value));
+ pos += value.length() + 1;
+
+ hasLemmaAttr = !isMorph;
+ hasMorphAttr = isMorph;
+ }
+ }
+ else { //attribute was not yet inserted
+ const int attrPos = e.indexOf(QRegExp("morph=|lemma="), 0);
+
+ if (attrPos >= 0) {
+ QString attr;
+ attr.append(isMorph ? "morph" : "lemma").append("=\"").append(value).append("\" ");
+ e.insert(attrPos, attr);
+
+ hasMorphAttr = isMorph;
+ hasLemmaAttr = !isMorph;
+
+ pos += attr.length();
+ }
+ }
+ }
+
+ insertedTag = true;
+ pos = tag.indexIn(e, pos);
+ }
+
+ result.append( e );
+ }
+
+ if (list.count()) {
+ buf = (const char*)result.toUtf8();
+ }
+
+ return 1;
+}
+
+
+bool Filters::BT_ThMLHTML::handleToken(sword::SWBuf &buf, const char *token, sword::BasicFilterUserData *userData) {
+ if (!substituteToken(buf, token) && !substituteEscapeString(buf, token)) {
+ sword::XMLTag tag(token);
+ BT_UserData* myUserData = dynamic_cast<BT_UserData*>(userData);
+ sword::SWModule* myModule = const_cast<sword::SWModule*>(myUserData->module); //hack to be able to call stuff like Lang()
+
+ if ( tag.getName() && !sword::stricmp(tag.getName(), "foreign") ) { // a text part in another language, we have to set the right font
+
+ if (tag.getAttribute("lang")) {
+ const char* abbrev = tag.getAttribute("lang");
+ //const CLanguageMgr::Language* const language = CPointers::languageMgr()->languageForAbbrev( QString::fromLatin1(abbrev) );
+
+ buf.append("<span class=\"foreign\" lang=\"");
+ buf.append(abbrev);
+ buf.append("\">");
+ }
+ }
+ else if (tag.getName() && !sword::stricmp(tag.getName(), "sync")) { //lemmas, morph codes or strongs
+
+ if (tag.getAttribute("type") && (!sword::stricmp(tag.getAttribute("type"), "morph") || !sword::stricmp(tag.getAttribute("type"), "Strongs") || !sword::stricmp(tag.getAttribute("type"), "lemma"))) { // Morph or Strong
+ buf.append('<');
+ buf.append(token);
+ buf.append('>');
+ }
+ }
+ else if (tag.getName() && !sword::stricmp(tag.getName(), "note")) { // <note> tag
+
+ if (!tag.isEndTag() && !tag.isEmpty()) {
+ //appending is faster than appendFormatted
+ buf.append(" <span class=\"footnote\" note=\"");
+ buf.append(myModule->Name());
+ buf.append('/');
+ buf.append(myUserData->key->getShortText());
+ buf.append('/');
+ buf.append( QString::number(myUserData->swordFootnote++).toUtf8().constData() );
+ buf.append("\">*</span> ");
+
+ myUserData->suspendTextPassThru = true;
+ myUserData->inFootnoteTag = true;
+ }
+ else if (tag.isEndTag() && !tag.isEmpty()) { //end tag
+ //buf += ")</span>";
+ myUserData->suspendTextPassThru = false;
+ myUserData->inFootnoteTag = false;
+ }
+ }
+ else if (tag.getName() && !sword::stricmp(tag.getName(), "scripRef")) { // a scripRef
+ //scrip refs which are embeded in footnotes may not be displayed!
+
+ if (!myUserData->inFootnoteTag) {
+ if (tag.isEndTag()) {
+ if (myUserData->inscriptRef) { // like "<scripRef passage="John 3:16">See John 3:16</scripRef>"
+ buf.append("</a></span>");
+
+ myUserData->inscriptRef = false;
+ myUserData->suspendTextPassThru = false;
+ }
+ else { // like "<scripRef>John 3:16</scripRef>"
+
+ CSwordModuleInfo* mod = CBTConfig::get(CBTConfig::standardBible);
+ //Q_ASSERT(mod); tested later
+ if (mod) {
+ CReferenceManager::ParseOptions options;
+ options.refBase = QString::fromUtf8(myUserData->key->getText()); //current module key
+ options.refDestinationModule = QString(mod->name());
+ options.sourceLanguage = QString(myModule->Lang());
+ options.destinationLanguage = QString("en");
+
+ //it's ok to split the reference, because to descriptive text is given
+ bool insertSemicolon = false;
+ buf.append("<span class=\"crossreference\">");
+ QStringList refs = QString::fromUtf8(myUserData->lastTextNode.c_str()).split(";");
+ QString oldRef; //the previous reference to use as a base for the next refs
+ for (QStringList::iterator it(refs.begin()); it != refs.end(); ++it) {
+
+ if (! oldRef.isEmpty() ){
+ options.refBase = oldRef; //use the last ref as a base, e.g. Rom 1,2-3, when the next ref is only 3:3-10
+ }
+ const QString completeRef( CReferenceManager::parseVerseReference((*it), options) );
+
+ oldRef = completeRef; //use the parsed result as the base for the next ref.
+
+ if (insertSemicolon) { //prepend a ref divider if we're after the first one
+ buf.append("; ");
+ }
+
+ buf.append("<a href=\"");
+ buf.append(
+ CReferenceManager::encodeHyperlink(
+ mod->name(),
+ completeRef,
+ CReferenceManager::typeFromModule(mod->type())
+ ).toUtf8().constData()
+ );
+
+ buf.append("\" crossrefs=\"");
+ buf.append((const char*)completeRef.toUtf8());
+ buf.append("\">");
+
+ buf.append((const char*)(*it).toUtf8());
+
+ buf.append("</a>");
+
+ insertSemicolon = true;
+ }
+ buf.append("</span>"); //crossref end
+ }
+
+ myUserData->suspendTextPassThru = false;
+ }
+ }
+ else if (tag.getAttribute("passage") ) { //the passage was given as a parameter value
+ myUserData->inscriptRef = true;
+ myUserData->suspendTextPassThru = false;
+
+ const char* ref = tag.getAttribute("passage");
+ Q_ASSERT(ref);
+
+ CSwordModuleInfo* mod = CBTConfig::get(CBTConfig::standardBible);
+ //Q_ASSERT(mod); tested later
+
+ CReferenceManager::ParseOptions options;
+ options.refBase = QString::fromUtf8(myUserData->key->getText());
+
+ options.sourceLanguage = myModule->Lang();
+ options.destinationLanguage = QString("en");
+
+ const QString completeRef = CReferenceManager::parseVerseReference(QString::fromUtf8(ref), options);
+
+ if (mod) {
+ options.refDestinationModule = QString(mod->name());
+ buf.append("<span class=\"crossreference\">");
+ buf.append("<a href=\"");
+ buf.append(
+ CReferenceManager::encodeHyperlink(
+ mod->name(),
+ completeRef,
+ CReferenceManager::typeFromModule(mod->type())
+ ).toUtf8().constData()
+ );
+ buf.append("\" crossrefs=\"");
+ buf.append((const char*)completeRef.toUtf8());
+ buf.append("\">");
+ }
+ else {
+ buf.append("<span><a>");
+ }
+ }
+ else if ( !tag.getAttribute("passage") ) { // we're starting a scripRef like "<scripRef>John 3:16</scripRef>"
+ myUserData->inscriptRef = false;
+
+ // let's stop text from going to output, the text get's added in the -tag handler
+ myUserData->suspendTextPassThru = true;
+ }
+ }
+ }
+ else if (tag.getName() && !sword::stricmp(tag.getName(), "div")) {
+ if (tag.isEndTag()) {
+ buf.append("</div>");
+ }
+ else if ( tag.getAttribute("class") && !sword::stricmp(tag.getAttribute("class"),"sechead") ) {
+ buf.append("<div class=\"sectiontitle\">");
+ }
+ else if (tag.getAttribute("class") && !sword::stricmp(tag.getAttribute("class"), "title")) {
+ buf.append("<div class=\"booktitle\">");
+ }
+ }
+ else if (tag.getName() && !sword::stricmp(tag.getName(), "img") && tag.getAttribute("src")) {
+ const char* value = tag.getAttribute("src");
+
+ if (value[0] == '/') {
+ value++; //strip the first /
+ }
+
+ buf.append("<img src=\"file:");
+ buf.append(myUserData->module->getConfigEntry("AbsoluteDataPath"));
+ buf.append('/');
+ buf.append(value);
+ buf.append("\" />");
+ }
+ else { // let unknown token pass thru
+ return sword::ThMLHTML::handleToken(buf, token, userData);
+ }
+ }
+
+ return true;
+}
diff --git a/src/backend/filters/bt_thmlhtml.h b/src/backend/filters/bt_thmlhtml.h
new file mode 100644
index 0000000..df20472
--- /dev/null
+++ b/src/backend/filters/bt_thmlhtml.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 BT_THMLHTML_H
+#define BT_THMLHTML_H
+
+//Sword
+#include <swbuf.h>
+#include <thmlhtml.h>
+
+namespace Filters {
+
+ /** ThML to HTML filter.
+ * This filter converts ThML text to HTML text
+ */
+
+class BT_ThMLHTML : public sword::ThMLHTML {
+
+protected:
+
+class BT_UserData : public sword::ThMLHTML::MyUserData {
+
+public:
+BT_UserData(const sword::SWModule *module, const sword::SWKey *key) : sword::ThMLHTML::MyUserData(module, key) {
+ inscriptRef = false;
+ swordFootnote = 1;
+ inFootnoteTag = false;
+ }
+
+ bool inscriptRef;
+ bool inFootnoteTag;
+ unsigned short int swordFootnote;
+ };
+
+ virtual sword::BasicFilterUserData *createUserData(const sword::SWModule* module, const sword::SWKey* key) {
+ return new BT_UserData(module, key);
+ }
+
+public:
+ BT_ThMLHTML ();
+ virtual bool handleToken(sword::SWBuf& buf, const char *token, sword::BasicFilterUserData *userData);
+ virtual char processText(sword::SWBuf& buf, const sword::SWKey*, const sword::SWModule* = 0);
+ };
+
+}
+
+#endif
diff --git a/src/backend/filters/bt_thmlplain.cpp b/src/backend/filters/bt_thmlplain.cpp
new file mode 100644
index 0000000..e08afb7
--- /dev/null
+++ b/src/backend/filters/bt_thmlplain.cpp
@@ -0,0 +1,221 @@
+/*********
+*
+* 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.
+*
+**********/
+
+/******************************************************************************
+ *
+ * thmlplain - SWFilter descendant to strip out all ThML tags or convert to
+ * ASCII rendered symbols.
+ */
+
+#include "bt_thmlplain.h"
+
+Filters::BT_ThMLPlain::BT_ThMLPlain() {
+}
+
+char Filters::BT_ThMLPlain::processText(sword::SWBuf &text, const sword::SWKey* /*key*/, const sword::SWModule* /*module*/)
+{
+ char token[2048];
+ int tokpos = 0;
+ bool intoken = false;
+ bool ampersand = false;
+
+ const char *from;
+ sword::SWBuf orig = text;
+ from = orig.c_str();
+ for (text = ""; *from; from++)
+ {
+ if (*from == 10 || *from == 13)
+ from++;
+ if (*from == '<') {
+ intoken = true;
+ tokpos = 0;
+ token[0] = 0;
+ token[1] = 0;
+ token[2] = 0;
+ ampersand = false;
+ continue;
+ }
+ else if (*from == '&') {
+ intoken = true;
+ tokpos = 0;
+ token[0] = 0;
+ token[1] = 0;
+ token[2] = 0;
+ ampersand = true;
+ continue;
+ }
+ if (*from == ';' && ampersand) {
+ intoken = false;
+ ampersand = false;
+
+ if (!strncmp("nbsp", token, 4)) text += " ";
+ else if (!strncmp("quot", token, 4)) text += "\"";
+ else if (!strncmp("amp", token, 3)) text += "&";
+ else if (!strncmp("lt", token, 2)) text += "<";
+ else if (!strncmp("gt", token, 2)) text += ">";
+ else if (!strncmp("brvbar", token, 6)) text += "¦";
+ else if (!strncmp("sect", token, 4)) text += "§";
+ else if (!strncmp("copy", token, 4)) text += "©";
+ else if (!strncmp("laquo", token, 5)) text += "«";
+ else if (!strncmp("reg", token, 3)) text += "®";
+ else if (!strncmp("acute", token, 5)) text += "´";
+ else if (!strncmp("para", token, 4)) text += "¶";
+ else if (!strncmp("raquo", token, 5)) text += "»";
+
+ else if (!strncmp("Aacute", token, 6)) text += "Á";
+ else if (!strncmp("Agrave", token, 6)) text += "À";
+ else if (!strncmp("Acirc", token, 5)) text += "Â";
+ else if (!strncmp("Auml", token, 4)) text += "Ä";
+ else if (!strncmp("Atilde", token, 6)) text += "Ã";
+ else if (!strncmp("Aring", token, 5)) text += "Å";
+ else if (!strncmp("aacute", token, 6)) text += "á";
+ else if (!strncmp("agrave", token, 6)) text += "à";
+ else if (!strncmp("acirc", token, 5)) text += "â";
+ else if (!strncmp("auml", token, 4)) text += "ä";
+ else if (!strncmp("atilde", token, 6)) text += "ã";
+ else if (!strncmp("aring", token, 5)) text += "å";
+ else if (!strncmp("Eacute", token, 6)) text += "É";
+ else if (!strncmp("Egrave", token, 6)) text += "È";
+ else if (!strncmp("Ecirc", token, 5)) text += "Ê";
+ else if (!strncmp("Euml", token, 4)) text += "Ë";
+ else if (!strncmp("eacute", token, 6)) text += "é";
+ else if (!strncmp("egrave", token, 6)) text += "è";
+ else if (!strncmp("ecirc", token, 5)) text += "ê";
+ else if (!strncmp("euml", token, 4)) text += "ë";
+ else if (!strncmp("Iacute", token, 6)) text += "Í";
+ else if (!strncmp("Igrave", token, 6)) text += "Ì";
+ else if (!strncmp("Icirc", token, 5)) text += "Î";
+ else if (!strncmp("Iuml", token, 4)) text += "Ï";
+ else if (!strncmp("iacute", token, 6)) text += "í";
+ else if (!strncmp("igrave", token, 6)) text += "ì";
+ else if (!strncmp("icirc", token, 5)) text += "î";
+ else if (!strncmp("iuml", token, 4)) text += "ï";
+ else if (!strncmp("Oacute", token, 6)) text += "Ó";
+ else if (!strncmp("Ograve", token, 6)) text += "Ò";
+ else if (!strncmp("Ocirc", token, 5)) text += "Ô";
+ else if (!strncmp("Ouml", token, 4)) text += "Ö";
+ else if (!strncmp("Otilde", token, 6)) text += "Õ";
+ else if (!strncmp("oacute", token, 6)) text += "ó";
+ else if (!strncmp("ograve", token, 6)) text += "ò";
+ else if (!strncmp("ocirc", token, 5)) text += "ô";
+ else if (!strncmp("ouml", token, 4)) text += "ö";
+ else if (!strncmp("otilde", token, 6)) text += "õ";
+ else if (!strncmp("Uacute", token, 6)) text += "Ú";
+ else if (!strncmp("Ugrave", token, 6)) text += "Ù";
+ else if (!strncmp("Ucirc", token, 5)) text += "Û";
+ else if (!strncmp("Uuml", token, 4)) text += "Ü";
+ else if (!strncmp("uacute", token, 6)) text += "ú";
+ else if (!strncmp("ugrave", token, 6)) text += "ù";
+ else if (!strncmp("ucirc", token, 5)) text += "û";
+ else if (!strncmp("uuml", token, 4)) text += "ü";
+ else if (!strncmp("Yacute", token, 6)) text += "Ý";
+ else if (!strncmp("yacute", token, 6)) text += "ý";
+ else if (!strncmp("yuml", token, 4)) text += "ÿ";
+
+ else if (!strncmp("deg", token, 3)) text += "°";
+ else if (!strncmp("plusmn", token, 6)) text += "±";
+ else if (!strncmp("sup2", token, 4)) text += "²";
+ else if (!strncmp("sup3", token, 4)) text += "³";
+ else if (!strncmp("sup1", token, 4)) text += "¹";
+ else if (!strncmp("nbsp", token, 4)) text += "º";
+ else if (!strncmp("pound", token, 5)) text += "£";
+ else if (!strncmp("cent", token, 4)) text += "¢";
+ else if (!strncmp("frac14", token, 6)) text += "¼";
+ else if (!strncmp("frac12", token, 6)) text += "½";
+ else if (!strncmp("frac34", token, 6)) text += "¾";
+ else if (!strncmp("iquest", token, 6)) text += "¿";
+ else if (!strncmp("iexcl", token, 5)) text += "¡";
+ else if (!strncmp("ETH", token, 3)) text += "Ð";
+ else if (!strncmp("eth", token, 3)) text += "ð";
+ else if (!strncmp("THORN", token, 5)) text += "Þ";
+ else if (!strncmp("thorn", token, 5)) text += "þ";
+ else if (!strncmp("AElig", token, 5)) text += "Æ";
+ else if (!strncmp("aelig", token, 5)) text += "æ";
+ else if (!strncmp("Oslash", token, 6)) text += "Ø";
+ else if (!strncmp("curren", token, 6)) text += "¤";
+ else if (!strncmp("Ccedil", token, 6)) text += "Ç";
+ else if (!strncmp("ccedil", token, 6)) text += "ç";
+ else if (!strncmp("szlig", token, 5)) text += "ß";
+ else if (!strncmp("Ntilde", token, 6)) text += "Ñ";
+ else if (!strncmp("ntilde", token, 6)) text += "ñ";
+ else if (!strncmp("yen", token, 3)) text += "¥";
+ else if (!strncmp("not", token, 3)) text += "¬";
+ else if (!strncmp("ordf", token, 4)) text += "ª";
+ else if (!strncmp("uml", token, 3)) text += "¨";
+ else if (!strncmp("shy", token, 3)) text += "­";
+ else if (!strncmp("macr", token, 4)) text += "¯";
+ else if (!strncmp("micro", token, 5)) text += "µ";
+ else if (!strncmp("middot", token, 6)) text +="·";
+ else if (!strncmp("cedil", token, 5)) text += "¸";
+ else if (!strncmp("ordm", token, 4)) text += "º";
+ else if (!strncmp("times", token, 5)) text += "×";
+ else if (!strncmp("divide", token, 6)) text +="÷";
+ else if (!strncmp("oslash", token, 6)) text +="ø";
+ continue;
+
+ }
+ else if (*from == '>' && !ampersand) {
+ intoken = false;
+ // process desired tokens
+ if (!strncmp(token, "sync type=\"Strongs\" value=\"", 27)) {
+ text += ' ';
+ text += '<';
+ for (unsigned int i = 27; token[i] != '\"'; i++)
+ text += token[i];
+ text += '>';
+ continue;
+ }
+ if (!strncmp(token, "sync type=\"morph\" value=\"", 25)) {
+ text += ' ';
+ text += '(';
+ for (unsigned int i = 25; token[i] != '\"'; i++)
+ text += token[i];
+ text += ')';
+ continue;
+ }
+ if (!strncmp("note", token, 4)) {
+ text += ' ';
+ text += '(';
+ }
+ else if (!strncmp("br", token, 2))
+ text += '\n';
+ else if (!strncmp("/p", token, 2))
+ text += '\n';
+ else if (!strncmp("/note", token, 5)) {
+ text += ')';
+ text += ' ';
+ }
+ continue;
+ }
+ if (intoken) {
+ if (tokpos < 2045)
+ token[tokpos++] = *from;
+ token[tokpos+2] = 0;
+ }
+ else text += *from;
+ }
+
+ orig = text;
+ from = orig.c_str();
+ for (text = ""; *from; from++) { //loop to remove extra spaces
+ if ((strchr(" \t\n\r", *from))) {
+ while (*(from+1) && (strchr(" \t\n\r", *(from+1)))) {
+ from++;
+ }
+ text += " ";
+ }
+ else {
+ text += *from;
+ }
+ }
+ text += (char)0;
+
+ return 0;
+}
+
diff --git a/src/backend/filters/bt_thmlplain.h b/src/backend/filters/bt_thmlplain.h
new file mode 100644
index 0000000..9d0a0c5
--- /dev/null
+++ b/src/backend/filters/bt_thmlplain.h
@@ -0,0 +1,28 @@
+/*********
+*
+* 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 BT_THMLPLAIN_H
+#define BT_THMLPLAIN_H
+
+#include <swbuf.h>
+#include <swfilter.h>
+
+namespace Filters {
+
+ /** This filter converts ThML text to plain text
+ */
+class BT_ThMLPlain : public sword::SWFilter {
+protected:
+ virtual char processText(sword::SWBuf &text, const sword::SWKey *key = 0, const sword::SWModule *module = 0);
+public:
+ BT_ThMLPlain();
+};
+
+}
+#endif
diff --git a/src/backend/filters/osismorphsegmentation.cpp b/src/backend/filters/osismorphsegmentation.cpp
new file mode 100644
index 0000000..9ec00f7
--- /dev/null
+++ b/src/backend/filters/osismorphsegmentation.cpp
@@ -0,0 +1,83 @@
+/*********
+*
+* 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 "osismorphsegmentation.h"
+
+//Sword
+#include <utilxml.h>
+
+const char Filters::OSISMorphSegmentation::oName[] = "Morph segmentation";
+const char Filters::OSISMorphSegmentation::oTip[] = "Toggles morph segmentation On and Off if they exist";
+
+const sword::SWBuf Filters::OSISMorphSegmentation::choices[3] = {"Off", "On", ""};
+
+const sword::StringList Filters::OSISMorphSegmentation::oValues(&choices[0], &choices[2]);
+
+Filters::OSISMorphSegmentation::OSISMorphSegmentation() : sword::SWOptionFilter(oName, oTip, &oValues) {
+ setOptionValue("Off");
+ }
+
+Filters::OSISMorphSegmentation::~OSISMorphSegmentation() {}
+
+char Filters::OSISMorphSegmentation::processText(sword::SWBuf &text, const sword::SWKey */*key*/, const sword::SWModule */*module*/) {
+ sword::SWBuf token;
+ bool intoken = false;
+ bool hide = false;
+
+ sword::SWBuf orig( text );
+ const char *from = orig.c_str();
+
+ sword::XMLTag tag;
+
+ for (text = ""; *from; ++from) {
+ if (*from == '<') {
+ intoken = true;
+ token = "";
+ continue;
+ }
+
+ if (*from == '>') { // process tokens
+ intoken = false;
+
+ if (!strncmp(token.c_str(), "seg ", 4) || !strncmp(token.c_str(), "/seg", 4)) {
+ tag = token;
+
+ if (!tag.isEndTag() && tag.getAttribute("type") && !strcmp("morph", tag.getAttribute("type"))) { //<seg type="morph"> start tag
+ hide = (option == 0); //only hide if option is Off
+ }
+
+ if (hide) { //hides start and end tags as long as hide is set
+
+ if (tag.isEndTag()) { //</seg>
+ hide = false;
+ }
+
+ continue; //leave out the current token
+ }
+ } //end of seg tag handling
+
+ text.append('<');
+ text.append(token);
+ text.append('>');
+
+ // hide = false; //not right, because there may be child tags in seg. Only /seg may disable the seg hiding.
+
+ continue;
+ } //end of intoken part
+
+ if (intoken) { //copy token
+ token.append(*from);
+ }
+ else { //copy text which is not inside of a tag
+ text.append(*from);
+ }
+ }
+
+ return 0;
+}
+
diff --git a/src/backend/filters/osismorphsegmentation.h b/src/backend/filters/osismorphsegmentation.h
new file mode 100644
index 0000000..e419fe2
--- /dev/null
+++ b/src/backend/filters/osismorphsegmentation.h
@@ -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.
+*
+**********/
+
+#ifndef OSISMORPHSEGMENTATION_H
+#define OSISMORPHSEGMENTATION_H
+
+#include <swbuf.h>
+#include <swoptfilter.h>
+
+namespace Filters {
+
+/** This Filter shows/hides headings in a OSIS text.
+ * @author Martin Gruner
+ */
+class OSISMorphSegmentation : public sword::SWOptionFilter {
+ static const char oName[];
+ static const char oTip[];
+ static const sword::SWBuf choices[3];
+ static const sword::StringList oValues;
+
+public:
+ OSISMorphSegmentation();
+ virtual ~OSISMorphSegmentation();
+
+ virtual char processText(sword::SWBuf &text, const sword::SWKey *key = 0, const sword::SWModule *module = 0);
+};
+
+}
+
+#endif
diff --git a/src/backend/keys/cswordkey.cpp b/src/backend/keys/cswordkey.cpp
new file mode 100644
index 0000000..acb6da9
--- /dev/null
+++ b/src/backend/keys/cswordkey.cpp
@@ -0,0 +1,185 @@
+/*********
+*
+* 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 "cswordkey.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "cswordversekey.h"
+#include "cswordldkey.h"
+#include "cswordtreekey.h"
+
+#include "util/ctoolclass.h"
+
+//Sword
+#include <swmodule.h>
+#include <swkey.h>
+#include <versekey.h>
+#include <treekey.h>
+#include <treekeyidx.h>
+#include <utilstr.h>
+
+//Qt
+#include <QRegExp>
+#include <QString>
+#include <QTextCodec>
+
+CSwordKey::CSwordKey(CSwordModuleInfo* const module) : m_module(module) {}
+
+CSwordKey::CSwordKey(const CSwordKey& k) {
+ m_module = k.m_module;
+}
+
+QString CSwordKey::rawText() {
+ if (!m_module) return QString::null;
+
+ if (dynamic_cast<sword::SWKey*>(this)) {
+ char * buffer = new char[strlen(rawKey()) + 1];
+ strcpy(buffer, rawKey());
+ m_module->module()->getKey()->setText( buffer );
+ delete [] buffer;
+ }
+
+ if (key().isNull()) return QString::null;
+
+ return QString::fromUtf8( m_module->module()->getRawEntry() );
+}
+
+QString CSwordKey::renderedText( const CSwordKey::TextRenderType mode ) {
+ Q_ASSERT(m_module);
+ if (!m_module) {
+ return QString::null;
+ }
+
+ sword::SWKey* const k = dynamic_cast<sword::SWKey*>(this);
+
+ if (k) {
+ char * keyBuffer = new char[strlen(rawKey()) + 1];
+ strcpy(keyBuffer, rawKey());
+ sword::VerseKey* vk_mod = dynamic_cast<sword::VerseKey*>(m_module->module()->getKey());
+
+ if (vk_mod) {
+ vk_mod->Headings(1);
+ }
+
+ m_module->module()->getKey()->setText( keyBuffer );
+
+ if (m_module->type() == CSwordModuleInfo::Lexicon) {
+ m_module->snap();
+ /* In lexicons make sure that our key (e.g. 123) was successfully set to the module,
+ i.e. the module key contains this key (e.g. 0123 contains 123) */
+
+ if ( sword::stricmp(m_module->module()->getKey()->getText(), keyBuffer)
+ && !strstr(m_module->module()->getKey()->getText(), keyBuffer)
+ ) {
+ qDebug("return an empty key for %s", m_module->module()->getKey()->getText());
+ return QString::null;
+ }
+ }
+ delete [] keyBuffer;
+ }
+
+ //Q_ASSERT(!key().isNull());
+ if (!key().isNull()) { //we have valid text
+ QString text = QString::fromUtf8( m_module->module()->RenderText() );
+
+ // This is yucky, but if we want strong lexicon refs we have to do it here.
+ if (m_module->type() == CSwordModuleInfo::Lexicon) {
+ QString t(text);
+ QRegExp rx("(GREEK|HEBREW) for 0*([1-9]\\d*)"); // ignore 0's before number
+ int pos = 0;
+ while( (pos = rx.indexIn(t, pos)) != -1 ) {
+ QString language = rx.cap(1);
+ QString langcode = QString(language.at(0)); // "G" or "H"
+ QString number = rx.cap(2);
+ QString paddednumber = number.rightJustified(5, '0'); // Form 00123
+
+ text.replace(
+ QRegExp( QString(
+ "(>[^<>]+)" // Avoid replacing inside tags
+ "\\b(0*%1)\\b").arg(number) ), // And span around 0's
+ QString("\\1<span lemma=\"%1%2\"><a href=\"strongs://%3/%4\">\\2</a></span>")
+ .arg(langcode, paddednumber, language, paddednumber)
+ );
+ pos += rx.matchedLength();
+ }
+ }
+
+ if (mode == HTMLEscaped) {
+ //we have to encode all UTF-8 in HTML escapes
+ // go though every character and write down the escaped HTML unicode entity
+ // form is &#<decimal unicode value here>;
+ QString ret;
+ QChar c;
+ const unsigned int length = text.length();
+
+ for (unsigned int i = 0; i < length; ++i) {
+ c = text.at(i);
+
+ if (c.toLatin1()) { //normal latin1 character
+ ret.append(c);
+ }
+ else {//unicode character, needs to be escaped
+ ret.append("&#")
+ .append(c.unicode())
+ .append(";");
+ }
+ }
+
+ return ret;
+ }
+ else {
+ return text;
+ }
+ }
+
+ return QString::null;
+}
+
+QString CSwordKey::strippedText() {
+ if (!m_module) return QString::null;
+
+ if (dynamic_cast<sword::SWKey*>(this)) {
+ char * buffer = new char[strlen(rawKey()) + 1];
+ strcpy(buffer, rawKey());
+ m_module->module()->getKey()->setText( buffer );
+ delete [] buffer;
+ }
+
+ return QString::fromUtf8( m_module->module()->StripText() );
+}
+
+const QTextCodec* CSwordKey::cp1252Codec() {
+ static QTextCodec * codec = QTextCodec::codecForName("Windows-1252");
+ return codec;
+}
+
+
+/** This will create a proper key object from a given module */
+CSwordKey* CSwordKey::createInstance( CSwordModuleInfo* const module ) {
+ if (!module) {
+ return 0;
+ }
+
+ switch( module->type() ) {
+
+ case CSwordModuleInfo::Bible://fall through
+
+ case CSwordModuleInfo::Commentary:
+ return new CSwordVerseKey( (sword::VerseKey *) ( (sword::SWKey *)(*module->module()) ), module );
+
+ case CSwordModuleInfo::Lexicon:
+ return new CSwordLDKey( (sword::SWKey *)(*module->module()), module);
+
+ case CSwordModuleInfo::GenericBook:
+ return new CSwordTreeKey( (sword::TreeKeyIdx*)((sword::SWKey *)(*module->module())), module );
+
+ default:
+ return 0;
+ }
+}
diff --git a/src/backend/keys/cswordkey.h b/src/backend/keys/cswordkey.h
new file mode 100644
index 0000000..e0e6300
--- /dev/null
+++ b/src/backend/keys/cswordkey.h
@@ -0,0 +1,111 @@
+/*********
+*
+* 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 CSWORDKEY_H
+#define CSWORDKEY_H
+
+//Qt
+#include <QString>
+
+class CSwordModuleInfo;
+class QTextCodec;
+
+/** Base class for all keys.
+ * The base class for all Sword based keys.
+ * @author The BibleTime team
+ * @version $Id: cswordkey.h,v 1.27 2006/10/30 19:53:32 mgruner Exp $
+ */
+
+class CSwordKey {
+
+protected:
+ /** Constructor. May only be called from sublasses because this class contains pure virtual methods.
+ * @param module The module which belongs to this key, may be NULL
+ */
+ CSwordKey(CSwordModuleInfo* const module = 0); //protected constructor, because CSwordKey shouldn't be used (it's an abstract base class).
+ /** Copy constructor.
+ */
+ CSwordKey(const CSwordKey&); //copy constructor
+
+public:
+ enum TextRenderType {
+ Normal = 0,
+ HTMLEscaped
+ };
+ /** Destructor.
+ * Public, not protected like the constructor, because CSwordKey pointers may be deleted by all others.
+ */
+ virtual ~CSwordKey() {};
+
+ //pure virtual functions
+ /** Returns the current key.
+ * @return The current key which belongs to the current object.
+ */
+ virtual QString key() const = 0;
+ /** Sets the current key. Sets the key using a utf8 enabled QString.
+ * @param key The key which should be used to set the current one
+ */
+ virtual bool key(const QString& key) = 0;
+ /** Set the key using a utf8-decoded c-string
+ * @param key The key which should be used to set the current one
+ */
+ virtual bool key(const char* key) = 0;
+ /** Clone this object. Clone this current object and return it.
+ * @return A clone of the current object.
+ */
+ virtual CSwordKey* copy() const = 0;
+
+ //implemented functions
+ /** Set/get the module. Set and get the module which belongs to this key.
+ * @return The module which belongs to this key.
+ */
+ inline virtual CSwordModuleInfo* module(CSwordModuleInfo* const newModule = 0);
+ /** Returns the raw, unchanged text. Returns the text without any filter modifications,
+ * just in the way it comes out of the module.
+ */
+ virtual QString rawText();
+ /** Returns the rendered text. Returns the text of the current key after passign it through the
+ * modules filters.
+ */
+ virtual QString renderedText( const CSwordKey::TextRenderType mode = CSwordKey::Normal );
+ /** Stripped down text. Returns the text after removing all markup tags from it.
+ */
+ virtual QString strippedText();
+ /**
+ * This returns a new object of the right CSwordKey* implementation
+ * (e.g. CSwordVerseKey or CSwordLDKey)
+ * The type is determined by the type of the module.
+ * @see CSwordModuleInfo, CSwordBibleModuleInfo, CSwordCommentaryModuleInfo, CSwordLexiconModukleInfo
+ */
+ static CSwordKey* createInstance(CSwordModuleInfo * const module);
+
+protected:
+ /**
+ * Returns the encoded key appropriate for use directly with Sword.
+ */
+ virtual const char * rawKey() const = 0;
+ static const QTextCodec* cp1252Codec();
+ CSwordModuleInfo* m_module; //module pointer used by all keys
+
+private:
+ /**
+ * Disable the assignment operator
+ */
+ CSwordKey& operator= ( const CSwordKey & );
+
+};
+
+inline CSwordModuleInfo* CSwordKey::module(CSwordModuleInfo* const newModule) {
+ if (newModule) {
+ m_module = newModule;
+ }
+ return m_module;
+}
+
+#endif
diff --git a/src/backend/keys/cswordldkey.cpp b/src/backend/keys/cswordldkey.cpp
new file mode 100644
index 0000000..3205827
--- /dev/null
+++ b/src/backend/keys/cswordldkey.cpp
@@ -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.
+*
+**********/
+
+#include "cswordldkey.h"
+#include "backend/drivers/cswordlexiconmoduleinfo.h"
+
+//Sword includes
+#include <swmodule.h>
+#include <swld.h>
+#include <utilstr.h>
+
+//Qt includes
+#include <QTextCodec>
+
+CSwordLDKey::CSwordLDKey( CSwordModuleInfo* module ) {
+ if ((m_module = dynamic_cast<CSwordLexiconModuleInfo*>(module))) {
+ // *(m_module->module()) = TOP;
+ }
+
+ SWKey::operator= (" ");
+}
+
+/** No descriptions */
+CSwordLDKey::CSwordLDKey( const CSwordLDKey &k ) : CSwordKey(k), SWKey((const char*)k) {}
+
+/** No descriptions */
+CSwordLDKey::CSwordLDKey( const SWKey *k, CSwordModuleInfo* module) : CSwordKey(module), SWKey(*k) {}
+
+/** Clones this object by copying the members. */
+CSwordLDKey* CSwordLDKey::copy() const {
+ return new CSwordLDKey(*this);
+}
+
+/** Sets the module of this key. */
+CSwordModuleInfo* CSwordLDKey::module(CSwordModuleInfo* const newModule) {
+ if (newModule && newModule->type() == CSwordModuleInfo::Lexicon) {
+ const QString oldKey = key();
+ m_module = newModule;
+ key(oldKey);
+ }
+
+ return m_module;
+}
+
+QString CSwordLDKey::key() const {
+ //return QString::fromUtf8((const char*)*this);
+ Q_ASSERT(m_module);
+
+ if (m_module->isUnicode()) {
+ return QString::fromUtf8((const char*)*this);
+ } else {
+ return cp1252Codec()->toUnicode((const char*)*this);
+ }
+}
+
+const char * CSwordLDKey::rawKey() const {
+ return (const char*)*this;
+}
+
+bool CSwordLDKey::key( const QString& newKey ) {
+ Q_ASSERT(m_module);
+
+ if (m_module->isUnicode()) {
+ return key(newKey.toUtf8().constData());
+ } else {
+ return key((const char*)cp1252Codec()->fromUnicode(newKey));
+ }
+}
+
+
+/** Sets the key of this instance */
+bool CSwordLDKey::key( const char* newKey ) {
+ Q_ASSERT(newKey);
+
+ if (newKey) {
+ SWKey::operator = (newKey); //set the key
+ m_module->module()->SetKey(this);
+ m_module->snap();
+ }
+
+ return !Error();
+}
+
+/** Uses the parameter to returns the next entry afer this key. */
+CSwordLDKey* CSwordLDKey::NextEntry() {
+ m_module->module()->SetKey(this); //use this key as base for the next one!
+ // m_module->module()->getKey()->setText( (const char*)key().utf8() );
+
+ m_module->module()->setSkipConsecutiveLinks(true);
+ ( *( m_module->module() ) )++;
+ m_module->module()->setSkipConsecutiveLinks(false);
+
+ key(m_module->module()->KeyText());
+ SWKey::operator = (m_module->module()->KeyText());
+
+ return this;
+}
+
+/** Uses the parameter to returns the next entry afer this key. */
+CSwordLDKey* CSwordLDKey::PreviousEntry() {
+ m_module->module()->SetKey(this); //use this key as base for the next one!
+ // m_module->module()->getKey()->setText( (const char*)key().utf8() );
+
+ m_module->module()->setSkipConsecutiveLinks(true);
+ ( *( m_module->module() ) )--;
+ m_module->module()->setSkipConsecutiveLinks(false);
+
+ SWKey::operator = (m_module->module()->KeyText());
+
+ return this;
+}
+
diff --git a/src/backend/keys/cswordldkey.h b/src/backend/keys/cswordldkey.h
new file mode 100644
index 0000000..0349597
--- /dev/null
+++ b/src/backend/keys/cswordldkey.h
@@ -0,0 +1,110 @@
+/*********
+*
+* 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 CSWORDLDKEY_H
+#define CSWORDLDKEY_H
+
+#include "cswordkey.h"
+class CSwordModuleInfo;
+
+//Qt
+#include <QString>
+
+//Sword includes
+#include <swkey.h>
+
+/**
+ * This class is the implementation of CSwordKey used for dictionaries and lexicons.
+ *
+ * CSwordLDKey is the implementation of CKey for Lexicons and dictionaries.
+ * It provides a simple interface to set the current key,
+ * to get the text for the key and functions to get the next and previous items
+ * of the used module in comparision to the current key.<BR>
+ * Here's an example how to use this class:<BR>
+ * @code
+ * CSwordLexiconModuleInfo* m_module = backend()->findModuleByName("ISBE");
+ * CSwordLDKey ldKey(m_module);
+ * ldKey.key("Adam");
+ * ldKey.nextEntry();
+ * qDebug( QString("The current key is: %1").arg(ldKey.key()));
+ * @endcode
+ *
+ * Please not, that the result will be invalid if use the operator const char*
+ * on the adress of the object, use something like this
+ *
+ * @code
+ * CSwordLDKey* key = new CSwordLDKey( lexicon_module );
+ * const QString keyname = key->getKey();
+ * @endcode
+ *
+ * @author The BibleTime team
+ * @version $Id: cswordldkey.h,v 1.24 2006/02/25 11:38:15 joachim Exp $
+ */
+
+class CSwordLDKey : public CSwordKey, public sword::SWKey {
+
+public:
+ /**
+ * Constructor of CSwordLDKey
+ */
+ CSwordLDKey( CSwordModuleInfo* module );
+ /**
+ * Copy constructor for this key class.
+ */
+ CSwordLDKey( const CSwordLDKey &k );
+ /**
+ * Copy constructor for this key class.
+ */
+ CSwordLDKey( const sword::SWKey *k, CSwordModuleInfo* module);
+ /**
+ * Clones this object by copying the members.
+ */
+ virtual CSwordLDKey* copy() const;
+ /**
+ * Uses the parameter to returns the next entry afer this key.
+ */
+ CSwordLDKey* NextEntry( void );
+ /**
+ * Uses the parameter to returns the previous entry afer this key.
+ */
+ CSwordLDKey* PreviousEntry( void );
+ /**
+ * Sets the module of this key.
+ */
+ virtual CSwordModuleInfo* module( CSwordModuleInfo* const module = 0 );
+ /**
+ * Returns the current key as a QString
+ */
+ virtual QString key() const;
+ /**
+ * Set the current key using unicode decoded QString.
+ */
+ virtual bool key( const QString& newKey );
+ /**
+ * Set the current key from char*. To avoid encoding problems use key(QString) instead.
+ */
+ virtual bool key( const char* );
+
+protected:
+ /**
+ * Returns the raw key appropriate for use directly with Sword.
+ */
+ virtual const char* rawKey() const;
+
+private:
+ /**
+ * Disable assignment operator
+ */
+ CSwordLDKey& operator= (const CSwordLDKey& );
+
+};
+
+
+#endif
+
diff --git a/src/backend/keys/cswordtreekey.cpp b/src/backend/keys/cswordtreekey.cpp
new file mode 100644
index 0000000..6e02806
--- /dev/null
+++ b/src/backend/keys/cswordtreekey.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 "cswordtreekey.h"
+#include "backend/drivers/cswordbookmoduleinfo.h"
+
+#include <QTextCodec>
+
+#include <QDebug>
+
+CSwordTreeKey::CSwordTreeKey( const CSwordTreeKey& k ) : CSwordKey(k), TreeKeyIdx(k) {}
+
+CSwordTreeKey::CSwordTreeKey( const TreeKeyIdx *k, CSwordModuleInfo* module ) : CSwordKey(module), TreeKeyIdx(*k) {}
+
+CSwordTreeKey* CSwordTreeKey::copy() const {
+ return new CSwordTreeKey(*this);
+}
+
+/** Sets the key of this instance */
+QString CSwordTreeKey::key() const {
+ //return getTextUnicode();
+ Q_ASSERT(m_module);
+ if (m_module->isUnicode()) {
+ return QString::fromUtf8(getText());
+ } else {
+ return cp1252Codec()->toUnicode(getText());
+ }
+}
+
+const char * CSwordTreeKey::rawKey() const {
+ return getText();
+}
+
+bool CSwordTreeKey::key( const QString& newKey ) {
+ //return key( newKey.toLocal8Bit().constData() );
+ //return key(m_module->getTextCodec()->fromUnicode(newKey).constData());
+ Q_ASSERT(m_module);
+ if (m_module->isUnicode()) {
+ return key(newKey.toUtf8().constData());
+ } else {
+ return key((const char*)cp1252Codec()->fromUnicode(newKey));
+ }
+}
+
+bool CSwordTreeKey::key( const char* newKey ) {
+ Q_ASSERT(newKey);
+
+ if (newKey) {
+ TreeKeyIdx::operator = (newKey);
+ }
+ else {
+ root();
+ }
+
+ return !Error();
+}
+
+QString CSwordTreeKey::getLocalNameUnicode()
+{
+ //return m_module->getTextCodec()->toUnicode(getLocalName());
+ //Only UTF-8 and latin1 are legal Sword module encodings
+ Q_ASSERT(m_module);
+ if (m_module->isUnicode()) {
+ return QString::fromUtf8(getLocalName());
+ } else {
+ return cp1252Codec()->toUnicode(getLocalName());
+ }
+}
+
+CSwordModuleInfo* CSwordTreeKey::module( CSwordModuleInfo* const newModule ) {
+ if (newModule && (newModule != m_module) && (newModule->type() == CSwordModuleInfo::GenericBook) ) {
+ m_module = newModule;
+
+ const QString oldKey = key();
+
+ CSwordBookModuleInfo* newBook = dynamic_cast<CSwordBookModuleInfo*>(newModule);
+ copyFrom( *(newBook->tree()) );
+
+ key(oldKey); //try to restore our old key
+
+ //set the key to the root node
+ root();
+ firstChild();
+ }
+
+ return m_module;
+}
diff --git a/src/backend/keys/cswordtreekey.h b/src/backend/keys/cswordtreekey.h
new file mode 100644
index 0000000..4114652
--- /dev/null
+++ b/src/backend/keys/cswordtreekey.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 CSWORDTREEKEYIDX_H
+#define CSWORDTREEKEYIDX_H
+
+//BibleTime
+#include "cswordkey.h"
+
+//Sword
+#include <treekeyidx.h>
+
+class CSwordModuleInfo;
+
+/** BibleTime's implementation of Sword's TreeKeyIdx class.
+ * @short CSwordKey implementation for Sword's TreeKey
+ * @author The BibleTime team
+ */
+
+class CSwordTreeKey : public CSwordKey, public sword::TreeKeyIdx {
+
+public:
+ /** Constructor of this CSwordKey implementation.
+ * @param k The Sword tree key which belongs to this key
+ * @param module The module which belongs to this key
+ */
+ CSwordTreeKey( const sword::TreeKeyIdx *k, CSwordModuleInfo* module );
+ /** Copy constructor.
+ */
+ CSwordTreeKey( const CSwordTreeKey& k );
+ /** The module which belongs to this key.
+ * @return The module.
+ */
+ virtual CSwordModuleInfo* module( CSwordModuleInfo* const newModule );
+ /** Copy method.
+ * @return A new copy of this object.
+ */
+ virtual CSwordTreeKey* copy() const;
+
+ /**
+ * Returns the TreeKeyIdx::getLocalKey value in unicode.
+ * Local key is the last part of the tree key, for example "Subsection1" from "/Section1/Subsection1".
+ * Use this instead of getLocalKey() to avoid encoding problems.
+ */
+ QString getLocalNameUnicode();
+ /**
+ * Returns the current key as unicode decoded QString.
+ */
+ virtual QString key() const;
+ /**
+ * Set the key. If the parameter is empty or null, the key will be set to "/"
+ */
+ virtual bool key( const QString& key );
+ /**
+ * Set the key from char* To avoid encoding problems use key(QString instead),
+ * otherwise it is caller's responsibility to ensure the correct encoding (utf8/latin1).
+ */
+ virtual bool key( const char* key );
+
+protected:
+ /**
+ * Returns the raw key appropriate for use directly with Sword.
+ */
+ virtual const char * rawKey() const;
+
+private:
+ /** Disable assignment operator */
+ CSwordTreeKey& operator= (const CSwordTreeKey&);
+ /** Disable from base class to prevent compiler warnings */
+ inline virtual CSwordTreeKey& operator= (const sword::TreeKeyIdx&) { return (*this); };
+};
+
+#endif
diff --git a/src/backend/keys/cswordversekey.cpp b/src/backend/keys/cswordversekey.cpp
new file mode 100644
index 0000000..424b268
--- /dev/null
+++ b/src/backend/keys/cswordversekey.cpp
@@ -0,0 +1,303 @@
+/*********
+*
+* 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 "cswordversekey.h"
+#include "backend/drivers/cswordbiblemoduleinfo.h"
+#include "backend/drivers/cswordcommentarymoduleinfo.h"
+
+//Qt
+#include <QStringList>
+
+//Sword
+#include <swmodule.h>
+#include <localemgr.h>
+
+CSwordVerseKey::CSwordVerseKey( CSwordModuleInfo* const module ) : CSwordKey(module) {
+ if ( CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(module) ) {
+ key( bible->lowerBound().key() );
+ }
+}
+
+CSwordVerseKey::CSwordVerseKey( const CSwordVerseKey& k ) : CSwordKey(k), VerseKey(k) {}
+
+CSwordVerseKey::CSwordVerseKey( const VerseKey* const k, CSwordModuleInfo* const module ) : CSwordKey(module), VerseKey(*k) {}
+
+/** Clones this object. */
+CSwordKey* CSwordVerseKey::copy() const {
+ return new CSwordVerseKey(*this);
+}
+
+/** Sets the module for this key */
+CSwordModuleInfo* CSwordVerseKey::module( CSwordModuleInfo* const newModule ) {
+ if (newModule && ((newModule->type() == CSwordModuleInfo::Bible) || (newModule->type() == CSwordModuleInfo::Commentary) ) ) {
+ m_module = newModule;
+
+ //check if the module contains the key we present
+ CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(newModule);
+
+ if (_compare(bible->lowerBound()) < 0) {
+ key( bible->lowerBound() );
+ }
+
+ if (_compare(bible->upperBound()) > 0) {
+ key( bible->upperBound() );
+ }
+ }
+
+ return dynamic_cast<CSwordBibleModuleInfo*>(m_module);
+}
+
+/** Returns the current book as Text, not as integer. */
+QString CSwordVerseKey::book( const QString& newBook ) {
+ int min = 0;
+ int max = 1;
+
+ if (CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(module())) {
+ const bool hasOT = bible->hasTestament(CSwordBibleModuleInfo::OldTestament);
+ const bool hasNT = bible->hasTestament(CSwordBibleModuleInfo::NewTestament);
+
+ if (hasOT && hasNT) {
+ min = 0;
+ max = 1;
+ }
+ else if (hasOT && !hasNT) {
+ min = 0;
+ max = 0;
+ }
+ else if (!hasOT && hasNT) {
+ min = 1;
+ max = 1;
+ }
+ else if (!hasOT && !hasNT) {
+ min = 0;
+ max = -1; //no loop
+ }
+ }
+
+ if (!newBook.isEmpty()) {
+
+#ifdef SWORD_MULTIVERSE
+ setBookName(newBook.toUtf8().constData());
+#else
+
+ bool finished = false;
+
+ for (int testament = min; testament <= max && !finished; ++testament) {
+ for (int book = 0; book < BMAX[testament] && !finished; ++book) {
+ if ( !strcmp(newBook.toUtf8().constData(), books[testament][book].name ) ) {
+ Testament(testament+1);
+ Book(book+1);
+ finished = true;
+ }
+ }
+ }
+#endif
+ }
+
+ if ( (Testament() >= min+1) && (Testament() <= max+1) && (Book() <= BMAX[min]) ) {
+ return QString::fromUtf8( getBookName() );
+ }
+
+ //return QString::fromUtf8( books[min][0].name ); //return the first book, i.e. Genesis
+ return QString::null;
+}
+
+/** Sets the key we use to the parameter. */
+QString CSwordVerseKey::key() const {
+ return QString::fromUtf8(getText());
+}
+
+const char * CSwordVerseKey::rawKey() const {
+ return getText();
+}
+
+bool CSwordVerseKey::key( const QString& newKey ) {
+ return key( newKey.toUtf8().constData() );
+}
+
+bool CSwordVerseKey::key( const char* newKey ) {
+ if (newKey && (strlen(newKey)>0) ) {
+ VerseKey::operator = (newKey);
+ }
+ else if (newKey && !strlen(newKey)) {
+ CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(module());
+
+ if ( bible ) {
+ VerseKey::operator = (bible->lowerBound().key().toUtf8().constData());
+ }
+ }
+
+ return !Error();
+}
+
+bool CSwordVerseKey::next( const JumpType type ) {
+ Error(); //clear Error status
+ bool ret = true;
+
+ switch (type) {
+
+ case UseBook: {
+ const int currentTestament = Testament();
+ const int currentBook = Book();
+
+ if ((currentTestament == 2) && (currentBook >= BMAX[currentTestament-1])) { //Revelation, i.e. end of navigation
+ return false;
+ }
+ else if ((currentTestament == 1) && (currentBook >= BMAX[currentTestament-1])) { //Malachi, switch to the NT
+ Testament(currentTestament+1);
+ Book(1);
+ }
+ else {
+ Book(Book()+1);
+ }
+ break;
+ }
+
+ case UseChapter: {
+ Chapter(Chapter()+1);
+ break;
+ }
+
+ case UseVerse: {
+ if (m_module && m_module->module()) {
+ const bool oldStatus = m_module->module()->getSkipConsecutiveLinks();
+ m_module->module()->setSkipConsecutiveLinks(true);
+
+ //disable headings for next verse
+ const bool useHeaders = (Verse() == 0);
+ const bool oldHeadingsStatus = ((VerseKey*)(m_module->module()->getKey()))->Headings( useHeaders );
+ //don't use setKey(), that would create a new key without Headings set
+ m_module->module()->getKey()->setText( key().toUtf8().constData() );
+
+ (*(m_module->module()) )++;
+
+ ((VerseKey*)(m_module->module()->getKey()))->Headings(oldHeadingsStatus);
+ m_module->module()->setSkipConsecutiveLinks(oldStatus);
+
+ if (!m_module->module()->Error()) {
+ key( QString::fromUtf8(m_module->module()->KeyText()) );
+ }
+ else {
+ // Verse(Verse()+1);
+ //don't change the key, restore the module's position
+ m_module->module()->getKey()->setText( key().toUtf8().constData() );
+ ret = false;
+ break;
+ }
+
+ }
+ else {
+ Verse(Verse()+1);
+ }
+
+ break;
+ }
+
+ default:
+ return false;
+ }
+
+ if ( CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(module()) ) {
+ if (_compare(bible->lowerBound()) < 0 ) {
+ key( bible->lowerBound() );
+ ret = false;
+ }
+
+ if (_compare(bible->upperBound()) > 0 ) {
+ key( bible->upperBound() );
+ ret = false;
+ }
+
+ return ret;
+ }
+ else if (Error()) { //we have no module, so take care of VerseKey::Error()
+ return false;
+ }
+
+ return ret;
+}
+
+bool CSwordVerseKey::previous( const JumpType type ) {
+ bool ret = true;
+
+ switch (type) {
+
+ case UseBook: {
+ if ( (Book() == 1) && (Testament() == 1) ) { //Genesis
+ return false;
+ }
+ else if ( (Book() == 1) && (Testament() == 2) ){ //Matthew
+ Testament(1);
+ Book(BMAX[0]);
+ }
+ else{
+ Book( Book()-1 );
+ }
+
+ break;
+ }
+
+ case UseChapter: {
+ Chapter(Chapter()-1);
+ break;
+ }
+
+ case UseVerse: {
+ if (m_module && m_module->module()) {
+ const bool useHeaders = (Verse() == 0);
+ const bool oldHeadingsStatus = ((VerseKey*)(m_module->module()->getKey()))->Headings( useHeaders );
+
+ m_module->module()->getKey()->setText( key().toUtf8().constData() );
+
+ const bool oldStatus = m_module->module()->getSkipConsecutiveLinks();
+ m_module->module()->setSkipConsecutiveLinks(true);
+ ( *( m_module->module() ) )--;
+
+ ((VerseKey*)(m_module->module()->getKey()))->Headings( oldHeadingsStatus );
+ m_module->module()->setSkipConsecutiveLinks(oldStatus);
+
+ if (!m_module->module()->Error()) {
+ key( QString::fromUtf8(m_module->module()->KeyText()) );//don't use fromUtf8
+ }
+ else {
+ ret = false;
+ // Verse(Verse()-1);
+ m_module->module()->getKey()->setText( key().toUtf8().constData() ); //restore module's key
+ }
+ }
+ else {
+ Verse(Verse()-1);
+ }
+
+ break;
+ }
+
+ default:
+ return false;
+ }
+
+ if ( CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(module()) ) {
+ if (_compare(bible->lowerBound()) < 0 ) {
+ key( bible->lowerBound() );
+ ret = false;
+ }
+
+ if (_compare(bible->upperBound()) > 0 ) {
+ key( bible->upperBound() );
+ ret = false;
+ }
+
+ return ret;
+ }
+ else if (Error()) {
+ return false;
+ }
+
+ return ret;
+}
diff --git a/src/backend/keys/cswordversekey.h b/src/backend/keys/cswordversekey.h
new file mode 100644
index 0000000..e421b6c
--- /dev/null
+++ b/src/backend/keys/cswordversekey.h
@@ -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.
+*
+**********/
+
+#ifndef CSWORDVERSEKEY_H
+#define CSWORDVERSEKEY_H
+
+#include "cswordkey.h"
+class CSwordModuleInfo;
+
+//Qt
+#include <QString>
+
+//Sword
+#include <versekey.h>
+
+/**
+ * The CSwordKey implementation for verse based modules (Bibles and Commentaries)
+ *
+ * This class is the implementation of CKey for verse based modules like
+ * Bibles and commentaries.
+ * This class provides the special functions to work with the verse based modules.
+ *
+ * Useful functions are
+ * @see NextBook()
+ * @see PreviousBook()
+ * @see NextChapter()
+ * @see PreviousChapter()
+ * @see NextVerse()
+ * @see PreviousVerse().
+ *
+ * Call the constructor only with a valid verse based modules, otherwise this key will be invalid
+ * and the application will probably crash.
+ *
+ * @version $Id: cswordversekey.h,v 1.26 2006/02/25 11:38:15 joachim Exp $
+ * @short CSwordKey implementation for Sword's VerseKey.
+ * @author The BibleTime team
+ */
+
+class CSwordVerseKey : public CSwordKey, public sword::VerseKey {
+
+public:
+ enum JumpType {
+ UseBook,
+ UseChapter,
+ UseVerse
+ };
+
+ /**
+ * Constructor of this class.
+ *
+ * This function will construct a versekey with the current module position
+ * and it will setup the m_module members.
+ *
+ */
+ CSwordVerseKey( CSwordModuleInfo* const module );
+ /**
+ * Copy constructor.
+ */
+ CSwordVerseKey( const CSwordVerseKey& k );
+ /**
+ * VerseKey based constructor.
+ */
+ CSwordVerseKey( const sword::VerseKey* const k, CSwordModuleInfo* const module );
+ /**
+ * Clones this object.
+ */
+ virtual CSwordKey* copy() const;
+ /**
+ * Set/get the key. If the parameter is not set (means equal to QString::null)
+ * the used key is returned. Otherwise the key is set and the new on ei returned.
+ */
+ virtual QString key() const;
+ /**
+ * Set the current key.
+ */
+ virtual bool key( const QString& );
+ /**
+ * Set/get the key. If the parameter is not set (means equal to QString::null)
+ * the used key is returned. Otherwise the key is set and the new on ei returned.
+ */
+ virtual bool key( const char* key );
+
+ /**
+ * Jumps to the next entry of the given type
+ */
+ bool next( const JumpType type );
+ /**
+ * Jumps to the previous entry of the given type
+ */
+ bool previous ( const JumpType type );
+ /**
+ * This functions returns the current book as localised text, not as book numer.
+ *
+ * Use "char Book()" to retrieve the book number of the current book.
+ * @return The name of the current book
+ */
+ QString book(const QString& newBook = QString::null);
+ /**
+ * Sets the module for this key
+ */
+ virtual CSwordModuleInfo* module( CSwordModuleInfo* const newModule = 0 );
+
+protected:
+ /**
+ * Returns the raw key appropriate for use directly with Sword.
+ */
+ virtual const char * rawKey() const;
+
+private:
+ /** Disable assignment operator */
+ CSwordVerseKey& operator= (const CSwordVerseKey&);
+ /** Disable from base class to prevent compiler warnings */
+ inline virtual CSwordVerseKey& operator= (const sword::VerseKey&) { return (*this); };
+};
+
+#endif
diff --git a/src/backend/managers/btstringmgr.cpp b/src/backend/managers/btstringmgr.cpp
new file mode 100644
index 0000000..9f57258
--- /dev/null
+++ b/src/backend/managers/btstringmgr.cpp
@@ -0,0 +1,139 @@
+/*********
+*
+* 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 "btstringmgr.h"
+
+char* BTStringMgr::upperUTF8(char* text, unsigned int maxlen) const {
+ const int max = (maxlen>0) ? maxlen : strlen(text);
+
+ if (isUtf8(text)) {
+ strncpy(text, (const char*)QString::fromUtf8(text).toUpper().toUtf8(), max);
+
+ return text;
+ }
+ else {
+ char* ret = text;
+
+ while (*text) {
+ *text = toupper(*text);
+ text++;
+ }
+
+ return ret;
+ }
+
+ return text;
+}
+
+char* BTStringMgr::upperLatin1(char* text, unsigned int /*max*/) const {
+ char* ret = text;
+
+ while (*text) {
+ *text = toupper(*text);
+ text++;
+ }
+
+ return ret;
+}
+
+bool BTStringMgr::supportsUnicode() const {
+ return true;
+}
+
+bool BTStringMgr::isUtf8(const char *buf) const {
+ int i, n;
+ register unsigned char c;
+ bool gotone = false;
+
+ #define F 0 /* character never appears in text */
+ #define T 1 /* character appears in plain ASCII text */
+ #define I 2 /* character appears in ISO-8859 text */
+ #define X 3 /* character appears in non-ISO extended ASCII (Mac, IBM PC) */
+
+ static const unsigned char text_chars[256] = {
+ /* BEL BS HT LF FF CR */
+ F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F, /* 0x0X */
+ /* ESC */
+ F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F, /* 0x1X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x2X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x3X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x4X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x5X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x6X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F, /* 0x7X */
+ /* NEL */
+ X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X, /* 0x8X */
+ X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, /* 0x9X */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xaX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xbX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xcX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xdX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xeX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I /* 0xfX */
+ };
+
+ /* *ulen = 0; */
+
+ for (i = 0; (c = buf[i]); i++) {
+ if ((c & 0x80) == 0) { /* 0xxxxxxx is plain ASCII */
+ /*
+ * Even if the whole file is valid UTF-8 sequences,
+ * still reject it if it uses weird control characters.
+ */
+
+ if (text_chars[c] != T)
+ return false;
+
+ }
+ else if ((c & 0x40) == 0) { /* 10xxxxxx never 1st byte */
+ return false;
+ }
+ else { /* 11xxxxxx begins UTF-8 */
+ int following;
+
+ if ((c & 0x20) == 0) { /* 110xxxxx */
+ following = 1;
+ }
+ else if ((c & 0x10) == 0) { /* 1110xxxx */
+ following = 2;
+ }
+ else if ((c & 0x08) == 0) { /* 11110xxx */
+ following = 3;
+ }
+ else if ((c & 0x04) == 0) { /* 111110xx */
+ following = 4;
+ }
+ else if ((c & 0x02) == 0) { /* 1111110x */
+ following = 5;
+ }
+ else
+ return false;
+
+ for (n = 0; n < following; n++) {
+ i++;
+
+ if (!(c = buf[i]))
+ goto done;
+
+ if ((c & 0x80) == 0 || (c & 0x40))
+ return false;
+ }
+
+ gotone = true;
+ }
+ }
+
+done:
+ return gotone; /* don't claim it's UTF-8 if it's all 7-bit */
+}
+
+#undef F
+#undef T
+#undef I
+#undef X
diff --git a/src/backend/managers/btstringmgr.h b/src/backend/managers/btstringmgr.h
new file mode 100644
index 0000000..d202c7f
--- /dev/null
+++ b/src/backend/managers/btstringmgr.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 BTSTRINGMGR_H
+#define BTSTRINGMGR_H
+
+//Sword includes
+#include <stringmgr.h>
+
+//Qt includes
+#include <QString>
+
+/** Unicode string manager implementation.
+ * This is the StringManager implementation which works with QString.
+ * @author The BibleTime developers
+ */
+
+class BTStringMgr : public sword::StringMgr {
+
+public:
+ /** Converts the param to an upper case Utf8 string
+ * @param The text encoded in utf8 which should be turned into an upper case string
+ */
+ virtual char *upperUTF8(char *text, unsigned int max = 0) const;
+
+ /** Converts the param to an uppercase latin1 string
+ * @param The text encoded in latin1 which should be turned into an upper case string
+ */
+ virtual char *upperLatin1(char *text, unsigned int max = 0) const;
+
+protected:
+ /** Enable Unicode support.
+ * Reimplementation to show unicode support.
+ */
+ virtual bool supportsUnicode() const;
+
+ /** CODE TAKEN FROM KDELIBS 3.2, which is licensed under the LGPL 2.
+ *
+ * This code was taken from KStringHandler, which is part of the KDE libraries.
+ *
+ * This function checks whether a string is utf8 or not.
+ * It was taken from kdelibs so we do not depend on KDE 3.2.
+ */
+ bool isUtf8(const char *buf) const;
+};
+
+#endif
diff --git a/src/backend/managers/cdisplaytemplatemgr.cpp b/src/backend/managers/cdisplaytemplatemgr.cpp
new file mode 100644
index 0000000..6ddd6b7
--- /dev/null
+++ b/src/backend/managers/cdisplaytemplatemgr.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 "cdisplaytemplatemgr.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/clanguagemgr.h"
+#include "backend/config/cbtconfig.h"
+#include "util/cpointers.h"
+#include "util/directoryutil.h"
+
+//Qt
+#include <QStringList>
+#include <QFile>
+#include <QFileInfo>
+#include <QTextStream>
+#include <QDebug>
+
+CDisplayTemplateMgr::CDisplayTemplateMgr() {
+ loadTemplates();
+}
+
+CDisplayTemplateMgr::~CDisplayTemplateMgr() {
+}
+
+const QString CDisplayTemplateMgr::fillTemplate( const QString& name, const QString& content, Settings& settings )
+{
+ qDebug() << "CDisplayTemplateMgr::fillTemplate";
+
+ const QString templateName = m_templateMap.contains(name) ? name : defaultTemplate();
+
+ QString displayTypeString;
+
+ if (!settings.pageCSS_ID.isEmpty()) {
+ displayTypeString = settings.pageCSS_ID;
+ }
+ else {
+ if (settings.modules.count()) {
+ switch (settings.modules.first()->type()) {
+
+ case CSwordModuleInfo::Bible:
+ displayTypeString = "bible";
+ break;
+
+ case CSwordModuleInfo::GenericBook:
+ displayTypeString = "book";
+ break;
+
+ case CSwordModuleInfo::Commentary:
+ case CSwordModuleInfo::Lexicon:
+ default:
+ displayTypeString = "singleentry";
+ break;
+ };
+ }
+ else { //use bible as default type if no modules are set
+ displayTypeString = "bible";
+ };
+ }
+
+ QString newContent = content;
+ const int moduleCount = settings.modules.count();
+
+ if (moduleCount >= 2) {
+ //create header for the modules
+ qDebug("There were more than 1 module, create headers");
+ QString header;
+
+ QList<CSwordModuleInfo*>::iterator end_it = settings.modules.end();
+
+ for (QList<CSwordModuleInfo*>::iterator it(settings.modules.begin()); it != end_it; ++it) {
+ header.append("<th style=\"width:")
+ .append(QString::number(int( 100.0 / (float)moduleCount )))
+ .append("%;\">")
+ .append((*it)->name())
+ .append("</th>");
+ }
+
+ newContent = QString("<table><tr>")
+ .append(header)
+ .append("</tr>")
+ .append(content)
+ .append("</table>");
+ }
+
+ QString langCSS;
+ CLanguageMgr::LangMap langMap = CPointers::languageMgr()->availableLanguages();
+
+ qDebug() << "langMap length:" << langMap.count();
+ qDebug("loop through langMap");
+ foreach(const CLanguageMgr::Language* lang, langMap) {
+ //const CLanguageMgr::Language* lang = *it;
+ //qDebug() << "foreach, lang: ";
+ //qDebug() << lang;
+
+ //if (lang->isValid() && CBTConfig::get(lang).first) {
+ if (!lang->abbrev().isEmpty() && CBTConfig::get(lang).first) {
+ const QFont f = CBTConfig::get(lang).second;
+
+ //don't use important, because it would reset the title formatting, etc. to the setup font
+ QString css("{ ");
+ css.append("font-family:").append(f.family())/*.append(" !important")*/;
+ css.append("; font-size:").append(QString::number(f.pointSize())).append("pt /*!important*/");
+ css.append("; font-weight:").append(f.bold() ? "bold" : "normal /*!important*/");
+ css.append("; font-style:").append(f.italic() ? "italic" : "normal /*!important*/");
+ css.append("; }\n");
+
+ langCSS +=
+ QString("\n*[lang=%1] %2")
+ .arg(lang->abbrev())
+ .arg(css);
+ }
+ }
+
+ //at first append the font standard settings for all languages without configured font
+ // Create a dummy language (the langmap may be empty)
+ CLanguageMgr::Language lang_v(QString("en"), QString("English"), QString());
+ CLanguageMgr::Language* lang = &lang_v;
+
+ if (lang && !lang->abbrev().isEmpty()/*&& lang->isValid()*/) {
+ const QFont standardFont = CBTConfig::getDefault(lang); //we just need a dummy lang param
+ langCSS.prepend(
+ QString("\n#content {font-family:%1; font-size:%2pt; font-weight:%3; font-style: %4;}\n")
+ .arg(standardFont.family())
+ .arg(standardFont.pointSize())
+ .arg(standardFont.bold() ? "bold" : "normal")
+ .arg(standardFont.italic() ? "italic" : "normal")
+ );
+ }
+
+// qWarning("Outputing unformated text");
+ const QString t = QString(m_templateMap[ templateName ]) //don't change the map's content directly, use a copy
+ .replace("#TITLE#", settings.title)
+ .replace("#LANG_ABBREV#", settings.langAbbrev.isEmpty() ? QString("en") : settings.langAbbrev)
+ .replace("#DISPLAYTYPE#", displayTypeString)
+ .replace("#LANG_CSS#", langCSS)
+ .replace("#PAGE_DIRECTION#", settings.pageDirection)
+ .replace("#CONTENT#", newContent);
+
+ return t;
+}
+
+void CDisplayTemplateMgr::loadTemplates() {
+ QStringList files;
+ foreach (QString file, util::filesystem::DirectoryUtil::getDisplayTemplatesDir().entryList(QStringList("*.tmpl")))
+ {
+ files += util::filesystem::DirectoryUtil::getDisplayTemplatesDir().canonicalPath() + "/" + file;
+ }
+ foreach (QString file, util::filesystem::DirectoryUtil::getUserDisplayTemplatesDir().entryList(QStringList("*.tmpl")))
+ {
+ files += util::filesystem::DirectoryUtil::getUserDisplayTemplatesDir().canonicalPath() + "/" + file;
+ }
+
+ foreach (QString file, files) {
+ QFile f(file);
+ if (f.exists() && f.open( QIODevice::ReadOnly )) {
+ QString fileContent = QTextStream( &f ).readAll();
+
+ if (!fileContent.isEmpty()) {
+ m_templateMap[ QFileInfo(file).fileName() ] = fileContent;
+ }
+ }
+ }
+}
diff --git a/src/backend/managers/cdisplaytemplatemgr.h b/src/backend/managers/cdisplaytemplatemgr.h
new file mode 100644
index 0000000..c791e16
--- /dev/null
+++ b/src/backend/managers/cdisplaytemplatemgr.h
@@ -0,0 +1,91 @@
+/*********
+*
+* 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 CDISPLAYTEMPLATEMGR_H
+#define CDISPLAYTEMPLATEMGR_H
+
+//BibleTime include
+class CSwordModuleInfo;
+
+//Qt includes
+#include <QMap>
+#include <QString>
+#include <QStringList>
+
+/**
+ * Manages the display templates used in the filters and display classes.
+ * @author The BibleTime team
+*/
+
+class CDisplayTemplateMgr {
+
+public:
+ /** Settings which are used to fill the content into the template.
+ */
+
+ struct Settings {
+ /** Constructor. Constructs the new settings object. The default values are empty.
+ */
+ Settings() {
+ title = QString::null;
+ langAbbrev = QString::null;
+ pageCSS_ID = QString::null;
+ pageDirection = QString("ltr");
+ };
+
+ QList<CSwordModuleInfo*> modules; /**< the list of modules */
+ QString title; /**< the title which is used for the new processed HTML page */
+ QString langAbbrev; /**< the language for the HTML page. */
+ QString pageDirection; /**< the language for the HTML page. */
+ QString pageCSS_ID; /**< the CSS ID which is used in the content part of the page */
+ };
+
+ /** Available templates.
+ * @return The list of templates, which are available.
+ */
+ inline const QStringList availableTemplates();
+ /** Fill template. Fill rendered content into the template given by the name.
+ * @param name The name of the template
+ * @param content The content which should be filled into the template
+ * @param settings The settings which are used to process the templating process
+ * @return The full HTML template HTML code including the CSS data.
+ */
+ const QString fillTemplate( const QString& name, const QString& content, Settings& settings);
+ /** Default template.
+ * @return The i18n'ed name of the default template
+ */
+ inline static const QString defaultTemplate();
+
+protected:
+ friend class CPointers;
+ /** Display template manager constructor. Protected to just allow CPointers to create objects. */
+ CDisplayTemplateMgr();
+ /** Destructor. */
+ ~CDisplayTemplateMgr();
+ /** Does the actual work of loading templates from disk */
+ void loadTemplates();
+
+private:
+ QMap<QString, QString> m_templateMap;
+};
+
+inline const QString CDisplayTemplateMgr::defaultTemplate() {
+ return QString("Blue.tmpl");
+}
+
+/**
+ * CDisplayTemplateMgr::availableTemplates()
+ */
+inline const QStringList CDisplayTemplateMgr::availableTemplates() {
+ return m_templateMap.keys();
+}
+
+
+
+#endif
diff --git a/src/backend/managers/clanguagemgr.cpp b/src/backend/managers/clanguagemgr.cpp
new file mode 100644
index 0000000..4dcc411
--- /dev/null
+++ b/src/backend/managers/clanguagemgr.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 "clanguagemgr.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "cswordbackend.h"
+
+#include "util/cpointers.h"
+
+//KDE
+
+
+CLanguageMgr::Language::Language() {}
+
+CLanguageMgr::Language::Language(const Language& l) {
+ m_abbrev = l.m_abbrev;
+ m_englishName = l.m_englishName;
+ m_translatedName = l.m_translatedName;
+ m_altAbbrevs = l.m_altAbbrevs;
+}
+
+CLanguageMgr::Language::Language( const QString& abbrev, const QString& name, const QString& translatedName, const QStringList& altAbbrevs ) {
+ m_abbrev = abbrev;
+ m_englishName = name;
+ m_translatedName = translatedName;
+ m_altAbbrevs = altAbbrevs;
+}
+
+CLanguageMgr::Language::~Language() {
+}
+
+
+/****************************************************/
+/******************** CLanguageMgr ******************/
+/****************************************************/
+CLanguageMgr::CLanguageMgr() : m_langMap() {
+ m_availableModulesCache.moduleCount = 0;
+ init();
+}
+
+CLanguageMgr::~CLanguageMgr() {
+ qDeleteAll(m_cleanupLangPtrs);
+ m_cleanupLangPtrs.clear();
+ qDeleteAll(m_langList);
+ m_langList.clear();
+}
+
+const CLanguageMgr::LangMap& CLanguageMgr::availableLanguages() {
+ QList<CSwordModuleInfo*> mods = CPointers::backend()->moduleList();
+
+ if ( m_availableModulesCache.moduleCount != (unsigned int)mods.count() ) { //we have to refill the cached map
+ m_availableModulesCache.availableLanguages.clear();
+ m_availableModulesCache.moduleCount = mods.count();
+
+ //collect the languages abbrevs of all modules
+ QStringList abbrevs;
+
+ foreach (const CSwordModuleInfo* mod, mods) {
+ if (!abbrevs.contains(mod->module()->Lang())){
+ abbrevs.append(mod->module()->Lang());
+ }
+ }
+
+ //now create a map of available langs
+ foreach ( QString abbrev, abbrevs ) {
+ const Language* const lang = languageForAbbrev(abbrev);
+
+ if (lang->isValid()) {
+ m_availableModulesCache.availableLanguages.insert( abbrev, lang );
+ }
+ else { //invalid lang used by a module, create a new language using the abbrev
+ Language* newLang = new Language(abbrev, abbrev, abbrev);
+ m_cleanupLangPtrs.append(newLang);
+ m_availableModulesCache.availableLanguages.insert( abbrev, newLang );
+ }
+ }
+ }
+ return m_availableModulesCache.availableLanguages;
+}
+
+const CLanguageMgr::Language* CLanguageMgr::languageForAbbrev( const QString& abbrev ) const {
+ LangMapIterator it = m_langMap.find(abbrev);
+ if (it != m_langMap.constEnd()) return *it; //Language is already here
+
+ //try to search in the alternative abbrevs
+ foreach (const Language* lang, m_langList ) {
+ if (lang->alternativeAbbrevs().contains(abbrev)) return lang;
+ }
+
+ // Invalid lang used by a modules, create a new language using the abbrev
+ Language* newLang = new Language(abbrev, abbrev, abbrev); //return a language which holds the valid abbrev
+ m_cleanupLangPtrs.append(newLang);
+
+ return newLang;
+}
+
+const CLanguageMgr::Language* CLanguageMgr::languageForName( const QString& name ) const {
+ foreach ( const Language* lang, m_langList ) {
+ if (lang->name() == name) return lang;
+ }
+ return &m_defaultLanguage;//invalid language
+}
+
+const CLanguageMgr::Language* CLanguageMgr::languageForTranslatedName( const QString& name ) const {
+ foreach ( const Language* lang, m_langList ) {
+ if (lang->translatedName() == name) return lang;
+ }
+ return &m_defaultLanguage; //invalid language
+}
+
+void CLanguageMgr::init() {
+
+ // The main() sets string literal codec to utf8:
+ // QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
+ // The language names include escape sequences \uxxxx
+
+ //if we've already inserted all items we do not proceed
+ if (m_langMap.count() > 0) return;
+
+ // Developers: It's easy to get a list of used language codes from all modules:
+ // Refresh all sources; go to .sword/InstallMgr/; run:
+ // grep -R -hs Lang= *|cut -c 6-|sort|uniq
+ // Don't remove unused languages from the source code unless you know it won't be used
+ // anymore.in any module ever.
+
+ /*:
+ The string "Names of languages" doesn't actually need translation.
+ It is put here to help translators notice this help text.
+ -------
+ The names of the languages should follow the conventions of your
+ language. You can write the names with a capital first letter even if your language
+ uses non-capitalized language names (they look better with capital
+ first letter when they are listed).
+ -------
+ To find the names of all languages from internet try searching for
+ "names of languages in language_x" but in your own language, e.g.
+ "kielten nimet suomeksi" in Finnish or "names of languages in english"
+ in English.
+ -------
+ You can find the language codes and names by googling for the standards
+ mentioned below.
+ -------
+ Preference order for locale codes are:
+ -------
+ ISO 639-1 -------
+ ISO 639-2 -------
+ ISO 639-3
+ -------
+ x-E-XXX form is deprecated and no modules in repositories use it.
+ If you find a module with x-E-XXX language, update the module.
+ */
+ QObject::tr("Names of languages", "No need to translate - see the longer comment (If there is no longer comment, it doesn't work yet :)) ------ ");
+ // m_langList.append( new Language("aa", "Afar", QObject::tr("Afar")) );
+ // m_langList.append( new Language("ab", "Abkhazian", QObject::tr("Abkhazian")) );
+ // m_langList.append( new Language("ae", "Avestan", QObject::tr("Avestan")) );
+ //: Language name af
+ m_langList.append( new Language("af", "Afrikaans", QObject::tr("Afrikaans")) );
+ // m_langList.append( new Language("am", "Amharic", QObject::tr("Amharic")) );
+ //: Language name amu
+ m_langList.append( new Language("amu", "Amuzgo, Guerrero", QObject::tr("Amuzgo, Guerrero")) );
+ //: Language name ang
+ m_langList.append( new Language("ang", "English, Old (ca.450-1100)", QObject::tr("English, Old (ca.450-1100)")) );
+ //: Language name ar
+ m_langList.append( new Language("ar", "Arabic", QObject::tr("Arabic")) );
+ // m_langList.append( new Language("as", "Assamese", QObject::tr("Assamese")) );
+ //: Language name az
+ m_langList.append( new Language("az", "Azerbaijani", QObject::tr("Azerbaijani")) );
+ //: Language name azb
+ m_langList.append( new Language("azb", "Azerbaijani, South", QObject::tr("Azerbaijani, South")) );
+ // m_langList.append( new Language("ba", "Bashkir", QObject::tr("Bashkir")) );
+ //: Language name bar
+ m_langList.append( new Language("bar", "Bavarian", QObject::tr("Bavarian")) );
+ //: Language name be
+ m_langList.append( new Language("be", "Belarusian", QObject::tr("Belarusian")) );
+ //: Language name bg
+ m_langList.append( new Language("bg", "Bulgarian", QObject::tr("Bulgarian")) );
+ // m_langList.append( new Language("bh", "Bihari", QObject::tr("Bihari")) );
+ // m_langList.append( new Language("bi", "Bislama", QObject::tr("Bislama")) );
+ // m_langList.append( new Language("bn", "Bengali", QObject::tr("Bengali")) );
+ // m_langList.append( new Language("bo", "Tibetan", QObject::tr("Tibetan")) );
+ //: Language name br
+ m_langList.append( new Language("br", "Breton", QObject::tr("Breton")) );
+ //: Language name bs
+ m_langList.append( new Language("bs", "Bosnian", QObject::tr("Bosnian")) );
+ //: Language name ca
+ m_langList.append( new Language("ca", "Catalan", QObject::tr("Catalan")) );
+ // m_langList.append( new Language("ce", "Chechen", QObject::tr("Chechen")) );
+ //: Language name cco
+ m_langList.append( new Language("cco", "Chinantec, Comaltepec", QObject::tr("Chinantec, Comaltepec")) );
+ //: Language name ceb
+ m_langList.append( new Language("ceb", "Cebuano", QObject::tr("Cebuano")) );
+ //: Language name ch
+ m_langList.append( new Language("ch", "Chamorro", QObject::tr("Chamorro")) );
+ //: Language name chd
+ m_langList.append( new Language("chd", "Chontal, Highland Oaxaca", QObject::tr("Chontal, Highland Oaxaca")) );
+ //: Language name chq
+ m_langList.append( new Language("chq", "Chinantec, Quiotepec", QObject::tr("Chinantec, Quiotepec")) );
+ //: Language name chz
+ m_langList.append( new Language("chz", "Chinantec, Ozumac\u00edn", QObject::tr("Chinantec, Ozumac\u00edn")) );
+ // m_langList.append( new Language("co", "Corsican", QObject::tr("Corsican")) );
+ //: Language name ckw
+ m_langList.append( new Language("ckw", "Cakchiquel, Western", QObject::tr("Cakchiquel, Western")) );
+ //: Language name cnl
+ m_langList.append( new Language("cnl", "Chinantec, Lalana", QObject::tr("Chinantec, Lalana")) );
+ //: Language name cnt
+ m_langList.append( new Language("cnt", "Chinantec, Tepetotutla", QObject::tr("Chinantec, Tepetotutla")) );
+ //: Language name cop
+ m_langList.append( new Language("cop", "Coptic", QObject::tr("Coptic")) );
+ //: Language name cs
+ m_langList.append( new Language("cs", "Czech", QObject::tr("Czech")) );
+ //: Language name cso
+ m_langList.append( new Language("cso", "Chinantec, Sochiapan", QObject::tr("Chinantec, Sochiapan")) );
+ //: Language name cti
+ m_langList.append( new Language("cti", "Chol, Tila", QObject::tr("Chol, Tila")) );
+ //: Language name ctp
+ m_langList.append( new Language("ctp", "Chatino, Western Highland", QObject::tr("Chatino, Western Highland")) );
+ //: Language name cu
+ m_langList.append( new Language("cu", "Church Slavic", QObject::tr("Church Slavic")) );
+ // m_langList.append( new Language("cv", "Chuvash", QObject::tr("Chuvash")) );
+ //: Language name cy
+ m_langList.append( new Language("cy", "Welsh", QObject::tr("Welsh")) );
+ //: Language name da
+ m_langList.append( new Language("da", "Danish", QObject::tr("Danish")) );
+ //: Language name de
+ m_langList.append( new Language("de", "German", QObject::tr("German")) );
+ //: Language name dug
+ m_langList.append( new Language("dug", "Duruma", QObject::tr("Duruma")) );
+ // m_langList.append( new Language("dz", "Dzongkha", QObject::tr("Dzongkha")) );
+ //: Language name el
+ m_langList.append( new Language("el", "Greek, Modern (1453-)", QObject::tr("Greek, Modern (1453-)"), makeStringList("gre;ell")) );
+ //: Language name en
+ m_langList.append( new Language("en", "English", QObject::tr("English")) );
+ //: Language name en_US
+ m_langList.append( new Language("en_US","American English", QObject::tr("American English")) );
+ //: Language name enm
+ m_langList.append( new Language("enm", "English, Middle (1100-1500)", QObject::tr("English, Middle (1100-1500)")) );
+ //: Language name eo
+ m_langList.append( new Language("eo", "Esperanto", QObject::tr("Esperanto")) );
+ //: Language name es
+ m_langList.append( new Language("es", "Spanish", QObject::tr("Spanish")) );
+ //: Language name et
+ m_langList.append( new Language("et", "Estonian", QObject::tr("Estonian")) );
+ //: Language name eu
+ m_langList.append( new Language("eu", "Basque", QObject::tr("Basque")) );
+ //: Language name fa
+ m_langList.append( new Language("fa", "Persian", QObject::tr("Persian")) );
+ //: Language name fi
+ m_langList.append( new Language("fi", "Finnish", QObject::tr("Finnish")) );
+ // m_langList.append( new Language("fj", "Fijian", QObject::tr("Fijian")) );
+ // m_langList.append( new Language("fo", "Faroese", QObject::tr("Faroese")) );
+ //: Language name fr
+ m_langList.append( new Language("fr", "French", QObject::tr("French")) );
+ //: Language name fy
+ m_langList.append( new Language("fy", "Frisian", QObject::tr("Frisian")) );
+ //: Language name ga
+ m_langList.append( new Language("ga", "Irish", QObject::tr("Irish")) );
+ //: Language name gd
+ m_langList.append( new Language("gd", "Gaelic (Scots)", QObject::tr("Gaelic (Scots)")) );
+ //: Language name gez
+ m_langList.append( new Language("gez", "Geez", QObject::tr("Geez")) );
+ // m_langList.append( new Language("gl", "Gallegan", QObject::tr("Gallegan")) );
+ // m_langList.append( new Language("gn", "Guarani", QObject::tr("Guarani")) );
+ // m_langList.append( new Language("gn", "Gujarati", QObject::tr("Gujarati")) );
+ //: Language name got
+ m_langList.append( new Language("got", "Gothic", QObject::tr("Gothic")) );
+ //: Language name gv
+ m_langList.append( new Language("gv", "Manx", QObject::tr("Manx")) );
+ //: Language name grc
+ m_langList.append( new Language("grc", "Greek, Ancient (to 1453)", QObject::tr("Greek, Ancient (to 1453)")) );
+ //: Language name he
+ m_langList.append( new Language("he", "Hebrew", QObject::tr("Hebrew")) );
+ //: Language name hau
+ m_langList.append( new Language("hau", "Hausa", QObject::tr("Hausa")) );
+ //: Language name haw
+ m_langList.append( new Language("haw", "Hawaiian", QObject::tr("Hawaiian")) );
+ //: Language name hi
+ m_langList.append( new Language("hi", "Hindi", QObject::tr("Hindi")) );
+ // m_langList.append( new Language("ho", "Hiri Motu", QObject::tr("Hiri Motu")) );
+ //: Language name hr
+ m_langList.append( new Language("hr", "Croatian", QObject::tr("Croatian")) );
+ //: Language name ht
+ m_langList.append( new Language("ht", "Haitian Creole", QObject::tr("Haitian Creole")) );
+ //: Language name hu
+ m_langList.append( new Language("hu", "Hungarian", QObject::tr("Hungarian")) );
+ //: Language name huv
+ m_langList.append( new Language("huv", "Huave, San Mateo Del Mar", QObject::tr("Huave, San Mateo Del Mar")) );
+ //: Language name hy
+ m_langList.append( new Language("hy", "Armenian", QObject::tr("Armenian")) );
+ // m_langList.append( new Language("hz", "Herero", QObject::tr("Herero")) );
+ // m_langList.append( new Language("ia", "Interlingua", QObject::tr("Interlingua")) );
+ //: Language name id
+ m_langList.append( new Language("id", "Indonesian", QObject::tr("Indonesian")) );
+ // m_langList.append( new Language("ie", "Interlingue", QObject::tr("Interlingue")) );
+ // m_langList.append( new Language("ik", "Inupiaq", QObject::tr("Inupiaq")) );
+ //: Language name is
+ m_langList.append( new Language("is", "Icelandic", QObject::tr("Icelandic")) );
+ //: Language name it
+ m_langList.append( new Language("it", "Italian", QObject::tr("Italian")) );
+ //: Language name itz
+ m_langList.append( new Language("itz", "Itz\u00e1", QObject::tr("Itz\u00e1")) );
+ //: Language name ixl
+ m_langList.append( new Language("ixl", "Ixil, San Juan Cotzal", QObject::tr("Ixil, San Juan Cotzal")) );
+ // m_langList.append( new Language("iu", "Inuktitut", QObject::tr("Inuktitut")) );
+ //: Language name ja
+ m_langList.append( new Language("ja", "Japanese", QObject::tr("Japanese")) );
+ //: Language name jac
+ m_langList.append( new Language("jac", "Jacalteco, Eastern", QObject::tr("Jacalteco, Eastern")) );
+ //: Language name jvn
+ m_langList.append( new Language("jvn", "Javanese, Caribbean", QObject::tr("Javanese, Caribbean")) );
+ //: Language name ka
+ m_langList.append( new Language("ka", "Georgian", QObject::tr("Georgian")) );
+ //: Language name kek
+ m_langList.append( new Language("kek", "Kekch\u00ed", QObject::tr("Kekch\u00ed", "kek")) );
+ // m_langList.append( new Language("ki", "Kikuyu", QObject::tr("Kikuyu")) );
+ // m_langList.append( new Language("kj", "Kuanyama", QObject::tr("Kuanyama")) );
+ // m_langList.append( new Language("kk", "Kazakh", QObject::tr("Kazakh")) );
+ // m_langList.append( new Language("kl", "Kalaallisut", QObject::tr("Kalaallisut")) );
+ // m_langList.append( new Language("km", "Khmer", QObject::tr("Khmer")) );
+ // m_langList.append( new Language("kn", "Kannada", QObject::tr("Kannada")) );
+ //: Language name ko
+ m_langList.append( new Language("ko", "Korean", QObject::tr("Korean")) );
+ // m_langList.append( new Language("ks", "Kashmiri", QObject::tr("Kashmiri")) );
+ //: Language name ku
+ m_langList.append( new Language("ku", "Kurdish", QObject::tr("Kurdish")) );
+ // m_langList.append( new Language("kv", "Komi", QObject::tr("Komi")) );
+ // m_langList.append( new Language("kw", "Cornish", QObject::tr("Cornish")) );
+ //: Language name ky
+ m_langList.append( new Language("ky", "Kirghiz", QObject::tr("Kirghiz")) );
+ //: Language name la
+ m_langList.append( new Language("la", "Latin", QObject::tr("Latin")) );
+ //: Language name lac
+ m_langList.append( new Language("lac", "Lacandon", QObject::tr("Lacandon")) );
+ // m_langList.append( new Language("lb", "Letzeburgesch", QObject::tr("Letzeburgesch")) );
+ //: Language name lmo
+ m_langList.append( new Language("lmo", "Lombard", QObject::tr("Lombard")) );
+ // m_langList.append( new Language("ln", "Lingala", QObject::tr("Lingala")) );
+ // m_langList.append( new Language("lo", "Lao", QObject::tr("Lao")) );
+ //: Language name lt
+ m_langList.append( new Language("lt", "Lithuanian", QObject::tr("Lithuanian")) );
+ //: Language name lv
+ m_langList.append( new Language("lv", "Latvian", QObject::tr("Latvian")) );
+ //: Language name mg
+ m_langList.append( new Language("mg", "Malagasy", QObject::tr("Malagasy")) );
+ // m_langList.append( new Language("mh", "Marshall", QObject::tr("Marshall")) );
+ //: Language name mi
+ m_langList.append( new Language("mi", "Maori", QObject::tr("Maori")) );
+ //: Language name mir
+ m_langList.append( new Language("mir", "Mixe, Isthmus", QObject::tr("Mixe, Isthmus")) );
+ //: Language name miz
+ m_langList.append( new Language("miz", "Mixtec, Coatzospan", QObject::tr("Mixtec, Coatzospan")) );
+ //: Language name mk
+ m_langList.append( new Language("mk", "Macedonian", QObject::tr("Macedonian")) );
+ //: Language name mks
+ m_langList.append( new Language("mks", "Mixtec, Silacayoapan", QObject::tr("Mixtec, Silacayoapan")) );
+ // m_langList.append( new Language("ml", "Malayalam", QObject::tr("Malayalam")) );
+ // m_langList.append( new Language("mn", "Mongolian", QObject::tr("Mongolian")) );
+ // m_langList.append( new Language("mo", "Moldavian", QObject::tr("Moldavian")) );
+ //: Language name mos
+ m_langList.append( new Language("mos", "More", QObject::tr("More")) );
+ // m_langList.append( new Language("mr", "Marathi", QObject::tr("Marathi")) );
+ //: Language name ms
+ m_langList.append( new Language("ms", "Malay", QObject::tr("Malay")) );
+ //: Language name mt
+ m_langList.append( new Language("mt", "Maltese", QObject::tr("Maltese")) );
+ //: Language name mul (meaning that the work has multiple languages)
+ m_langList.append( new Language("mul", "(Multiple languages)", QObject::tr("(Multiple languages)")) );
+ //: Language name mvc
+ m_langList.append( new Language("mvc", "Mam, Central", QObject::tr("Mam, Central")) );
+ //: Language name mvj
+ m_langList.append( new Language("mvj", "Mam, Todos Santos Cuchumat\u00e1n", QObject::tr("Mam, Todos Santos Cuchumat\u00e1n")) );
+ //: Language name mxq
+ m_langList.append( new Language("mxq", "Mixe, Juquila", QObject::tr("Mixe, Juquila")) );
+ //: Language name mxt
+ m_langList.append( new Language("mxt", "Mixtec, Jamiltepec", QObject::tr("Mixtec, Jamiltepec")) );
+ //: Language name my
+ m_langList.append( new Language("my", "Burmese", QObject::tr("Burmese")) );
+ // m_langList.append( new Language("na", "Nauru", QObject::tr("Nauru")) );
+ //: Language name nb
+ m_langList.append( new Language("nb", "Norwegian Bokm\u00e5l", QObject::tr("Norwegian Bokm\u00e5l")) );
+ //: Language name ncl
+ m_langList.append( new Language("ncl", "Nahuatl, Michoac\u00e1n", QObject::tr("Nahuatl, Michoac\u00e1n")) );
+ // m_langList.append( new Language("nd", "Ndebele, North", QObject::tr("Ndebele, North")) );
+ //: Language name nds
+ m_langList.append( new Language("nds", "Low German; Low Saxon", QObject::tr("Low German; Low Saxon")) );
+ //: Language name ne
+ m_langList.append( new Language("ne", "Nepali", QObject::tr("Nepali")) );
+ //: Language name ngu
+ m_langList.append( new Language("ngu", "Nahuatl, Guerrero", QObject::tr("Nahuatl, Guerrero")) );
+ //: Language name nhy
+ m_langList.append( new Language("nhy", "Nahuatl, Northern Oaxaca", QObject::tr("Nahuatl, Northern Oaxaca")) );
+ // m_langList.append( new Language("ng", "Ndonga", QObject::tr("Ndonga")) );
+ //: Language name nl
+ m_langList.append( new Language("nl", "Dutch", QObject::tr("Dutch")) );
+ //: Language name nn
+ m_langList.append( new Language("nn", "Norwegian Nynorsk", QObject::tr("Norwegian Nynorsk")) );
+ //: Language name no
+ m_langList.append( new Language("no", "Norwegian", QObject::tr("Norwegian")) );
+ // m_langList.append( new Language("nr", "Ndebele, South", QObject::tr("Ndebele, South")) );
+ // m_langList.append( new Language("nv", "Navajo", QObject::tr("Navajo")) );
+ // m_langList.append( new Language("ny", "Chichewa; Nyanja", QObject::tr("Chichewa; Nyanja")) );
+ // m_langList.append( new Language("oc", "Occitan (post 1500); Provençal", QObject::tr("Occitan (post 1500); Provençal")) );
+ // m_langList.append( new Language("om", "Oromo", QObject::tr("Oromo")) );
+ // m_langList.append( new Language("or", "Oriya", QObject::tr("Oriya")) );
+ // m_langList.append( new Language("os", "Ossetian; Ossetic", QObject::tr("Ossetian; Ossetic")) );
+ //: Language name otq
+ m_langList.append( new Language("otq", "Otomi, Quer\u00e9taro", QObject::tr("Otomi, Quer\u00e9taro")) );
+ // m_langList.append( new Language("pa", "Panjabi", QObject::tr("Panjabi")) );
+ //: Language name pap
+ m_langList.append( new Language("pap", "Papiamento", QObject::tr("Papiamento")) );
+ // m_langList.append( new Language("pi", "Pali", QObject::tr("Pali")) );
+ //: Language name ppk
+ m_langList.append( new Language("ppk", "Uma", QObject::tr("Uma")) );
+ //: Language name pl
+ m_langList.append( new Language("pl", "Polish", QObject::tr("Polish")) );
+ //: Language name pot
+ m_langList.append( new Language("pot", "Potawatomi", QObject::tr("Potawatomi")) );
+ //: Language name ppk
+ m_langList.append( new Language("ppk", "Uma", QObject::tr("Uma")) );
+ //: Language name prs
+ m_langList.append( new Language("prs", "Persian (Dari)", QObject::tr("Persian (Dari)")) );
+
+ // m_langList.append( new Language("ps", "Pushto", QObject::tr("Pushto")) );
+ //: Language name pt
+ m_langList.append( new Language("pt", "Portuguese", QObject::tr("Portuguese")) );
+ //: Language name pt_BR
+ m_langList.append( new Language("pt_BR", "Brasilian Portuguese", QObject::tr("Brasilian Portuguese")) );//added by ourself
+ // m_langList.append( new Language("qu", "Quechua", QObject::tr("Quechua")) );
+ //: Language name qut
+ m_langList.append( new Language("qut", "Quich\u00e9, West Central", QObject::tr("Quich\u00e9, West Central")) );
+ // m_langList.append( new Language("rm", "Raeto-Romance", QObject::tr("Raeto-Romance")) );
+ // m_langList.append( new Language("rn", "Rundi", QObject::tr("Rundi")) );
+ //: Language name ro
+ m_langList.append( new Language("ro", "Romanian", QObject::tr("Romanian")) );
+ //: Language name ru
+ m_langList.append( new Language("ru", "Russian", QObject::tr("Russian")) );
+ // m_langList.append( new Language("rw", "Kinyarwanda", QObject::tr("Kinyarwanda")) );
+ // m_langList.append( new Language("sa", "Sanskrit", QObject::tr("Sanskrit")) );
+ // m_langList.append( new Language("sc", "Sardinian", QObject::tr("Sardinian")) );
+ //: Language name sco
+ m_langList.append( new Language("sco", "Scots", QObject::tr("Scots")) );
+ // m_langList.append( new Language("sd", "Sindhi", QObject::tr("Sindhi")) );
+ // m_langList.append( new Language("se", "Northern Sami", QObject::tr("Northern Sami")) );
+ // m_langList.append( new Language("sg", "Sango", QObject::tr("Sango")) );
+ // m_langList.append( new Language("si", "Sinhalese", QObject::tr("Sinhalese")) );
+ //: Language name sk
+ m_langList.append( new Language("sk", "Slovak", QObject::tr("Slovak")) );
+ //: Language name sl
+ m_langList.append( new Language("sl", "Slovenian", QObject::tr("Slovenian")) );
+ // m_langList.append( new Language("sm", "Samoan", QObject::tr("Samoan")) );
+ // m_langList.append( new Language("sn", "Shona", QObject::tr("Shona")) );
+ //: Language name so
+ m_langList.append( new Language("so", "Somali", QObject::tr("Somali")) );
+ //: Language name sq
+ m_langList.append( new Language("sq", "Albanian", QObject::tr("Albanian")) );
+ // m_langList.append( new Language("sr", "Serbian", QObject::tr("Serbian")) );
+ //: Language name srn
+ m_langList.append( new Language("srn", "Sranan", QObject::tr("Sranan")) );
+ // m_langList.append( new Language("ss", "Swati", QObject::tr("Swati")) );
+ // m_langList.append( new Language("st", "Sotho, Southern", QObject::tr("Sotho, Southern")) );
+ // m_langList.append( new Language("su", "Sundanese", QObject::tr("Sundanese")) );
+ //: Language name sv
+ m_langList.append( new Language("sv", "Swedish", QObject::tr("Swedish")) );
+ //: Language name sw
+ m_langList.append( new Language("sw", "Swahili", QObject::tr("Swahili")) );
+ //: Language name syr
+ m_langList.append( new Language("syr", "Syriac", QObject::tr("Syriac")) );
+ //: Language name ta
+ m_langList.append( new Language("ta", "Tamil", QObject::tr("Tamil")) );
+ // m_langList.append( new Language("te", "Telugu", QObject::tr("Telugu")) );
+ // m_langList.append( new Language("tg", "Tajik", QObject::tr("Tajik")) );
+ //: Language name th
+ m_langList.append( new Language("th", "Thai", QObject::tr("Thai")) );
+ // m_langList.append( new Language("tk", "Turkmen", QObject::tr("Turkmen")) );
+ //: Language name tl
+ m_langList.append( new Language("tl", "Tagalog", QObject::tr("Tagalog")) );
+ //: Language name tlh
+ m_langList.append( new Language("tlh", "Klingon", QObject::tr("Klingon")) );
+ //: Language name tn
+ m_langList.append( new Language("tn", "Tswana", QObject::tr("Tswana")) );
+ //: Language name tr
+ m_langList.append( new Language("tr", "Turkish", QObject::tr("Turkish")) );
+ // m_langList.append( new Language("ts", "Tsonga", QObject::tr("Tsonga")) );
+ // m_langList.append( new Language("tt", "Tatar", QObject::tr("Tatar")) );
+ //: Language name ttc
+ m_langList.append( new Language("ttc", "Tektiteko", QObject::tr("Tektiteko")) );
+ // m_langList.append( new Language("tw", "Twi", QObject::tr("Twi")) );
+ //: Language name ty
+ m_langList.append( new Language("ty", "Tahitian", QObject::tr("Tahitian")) );
+ //: Language name tzz
+ m_langList.append( new Language("tzz", "Tzotzil, Zinacant\u00e1n", QObject::tr("Tzotzil, Zinacant\u00e1n")) );
+ // m_langList.append( new Language("ug", "Uighur", QObject::tr("Uighur")) );
+ //: Language name uk
+ m_langList.append( new Language("uk", "Ukrainian", QObject::tr("Ukrainian")) );
+ // m_langList.append( new Language("ur", "Urdu", QObject::tr("Urdu")) );
+ //: Language name ury
+ m_langList.append( new Language("ury", "Orya", QObject::tr("Orya")) );
+ //: Language name usp
+ m_langList.append( new Language("usp", "Uspanteco", QObject::tr("Uspanteco")) );
+ // m_langList.append( new Language("uz", "Uzbek", QObject::tr("Uzbek")) );
+ //: Language name vi
+ m_langList.append( new Language("vi", "Vietnamese", QObject::tr("Vietnamese")) );
+ // m_langList.append( new Language("vo", "Volapük", QObject::tr("Volapük")) );
+ // m_langList.append( new Language("wo", "Wolof", QObject::tr("Wolof")) );
+ //: Language name xh
+ m_langList.append( new Language("xh", "Xhosa", QObject::tr("Xhosa")) );
+ //: Language name xtd
+ m_langList.append( new Language("xtd", "Mixtec, Diuxi-Tilantongo", QObject::tr("Mixtec, Diuxi-Tilantongo")) );
+ //: Language name yi
+ m_langList.append( new Language("yi", "Yiddish", QObject::tr("Yiddish")) );
+ //: Language name yo
+ m_langList.append( new Language("yo", "Yoruba", QObject::tr("Yoryba")) );
+ // m_langList.append( new Language("za", "Zhuang", QObject::tr("Zhuang")) );
+ //: Language name zab
+ m_langList.append( new Language("zab", "Zapotec, San Juan Guelav\u00eda", QObject::tr("Zapotec, San Juan Guelav\u00eda")) );
+ //: Language name zaw
+ m_langList.append( new Language("zaw", "Zapotec, Mitla", QObject::tr("Zapotec, Mitla")) );
+ //: Language name zh
+ m_langList.append( new Language("zh", "Chinese", QObject::tr("Chinese")) );
+ //: Language name zpo
+ m_langList.append( new Language("zpo", "Zapotec, Amatl\u00e1n", QObject::tr("Zapotec, Amatl\u00e1n")) );
+ //: Language name zpq
+ m_langList.append( new Language("zpq", "Zapotec, Zoogocho", QObject::tr("Zapotec, Zoogocho")) );
+ //: Language name zpu
+ m_langList.append( new Language("zpu", "Zapotec, Yal\u00e1lag", QObject::tr("Zapotec, Yal\u00e1lag")) );
+ //: Language name zpv
+ m_langList.append( new Language("zpv", "Zapotec, Chichicapan", QObject::tr("Zapotec, Chichicapan")) );
+ //: Language name zsr
+ m_langList.append( new Language("zsr", "Zapotec, Southern Rincon", QObject::tr("Zapotec, Southern Rincon")) );
+ //: Language name ztq
+ m_langList.append( new Language("ztq", "Zapotec, Quioquitani-Quier\u00ed", QObject::tr("Zapotec, Quioquitani-Quier\u00ed")) );
+ //: Language name zty
+ m_langList.append( new Language("zty", "Zapotec, Yatee", QObject::tr("Zapotec, Yatee")) );
+ //: Language name zu
+ m_langList.append( new Language("zu", "Zulu", QObject::tr("Zulu")) );
+
+ foreach (Language* lang, m_langList) {
+ m_langMap.insert( lang->abbrev(), lang);
+ }
+}
diff --git a/src/backend/managers/clanguagemgr.h b/src/backend/managers/clanguagemgr.h
new file mode 100644
index 0000000..f421e62
--- /dev/null
+++ b/src/backend/managers/clanguagemgr.h
@@ -0,0 +1,151 @@
+/*********
+*
+* 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 CLANGUAGEMGR_H
+#define CLANGUAGEMGR_H
+
+//Qt includes
+#include <QString>
+#include <QStringList>
+#include <QList>
+#include <QHash>
+
+/** Manages the languages of BibleTime and provides functions to work with them.
+ * @author The BibleTime team
+ */
+
+class CLanguageMgr {
+
+public:
+ /** Language container.
+ * This class (Language) contains the information about the chosen language.
+ */
+ class Language {
+ public:
+ /** Default constructor of a language object.
+ * Uses the abbreviation parameter to lookup the
+ * language name and to be able to return the name, flag etc.
+ * Possible values for abbrev are de, en, fr, it etc.
+ */
+ Language();
+ /** Copy constructor.
+ */
+ Language(const Language&);
+ /** Constructor which takes all necessary data.
+ */
+ Language(const QString& abbrev, const QString& englishName, const QString& translatedName, const QStringList& altAbbrevs = QStringList());
+ /** Destructor.
+ */
+ ~Language();
+ /** Returns the abbreviation.
+ * @return The abbreviation of the chosen language.
+ */
+ inline const QString& abbrev() const {
+ if (m_abbrev.isEmpty() && m_altAbbrevs.count()) { //no standard abbrev but alternative ones
+ return m_altAbbrevs.first();
+ }
+ return m_abbrev;
+ }
+ /** Returns the translated name.
+ * @return The translated name of the language.
+ */
+ inline const QString& translatedName() const {
+ return m_translatedName;
+ }
+ /** The english name of the language.
+ * @return The english name of the chosen language.
+ */
+ inline const QString& name() const {
+ return m_englishName;
+ }
+ /** The alternative abbreviations which are avalable for this language.
+ * @return The List of alternate abbreviations
+ */
+ inline const QStringList alternativeAbbrevs() const {
+ return m_altAbbrevs;
+ }
+ /**
+ * Returns true if this language object is valid, i.e. has an abbrev and name.
+ * @return True if the data is valid for this language.
+ */
+ inline bool isValid() const {
+ return (!abbrev().isEmpty() && !name().isEmpty());
+ }
+
+ private:
+ QString m_abbrev;
+ QString m_englishName;
+ QString m_translatedName;
+ QStringList m_altAbbrevs;
+ };
+
+ typedef QList<Language*> LanguageList;
+ typedef QHash<QString, const Language*> LangMap;
+ typedef QHash<QString, const Language*>::const_iterator LangMapIterator;
+
+ /** Constructor.
+ */
+ CLanguageMgr();
+ /** Destructor
+ */
+ virtual ~CLanguageMgr();
+ /**
+ * Returns the standard languages available as standard. Does nothing for Sword.
+ * @return A LangMap map which contains all known languages
+ */
+ inline const CLanguageMgr::LangMap* languages() const {
+ return &m_langMap;
+ }
+ /**
+ * Returns the languages which are available. The languages cover all available modules, but nothing more.
+ * @return A map of all languages with modules available for them
+ */
+ const CLanguageMgr::LangMap& availableLanguages();
+ /** Language for abbreviation.
+ * @param abbrev The language abbreviation
+ * @return Pointer to a language for the given string abbreviation.
+ */
+ const CLanguageMgr::Language* languageForAbbrev( const QString& abbrev ) const;
+ /** Language for english name.
+ * @param abbrev The english language name.
+ * @return Pointer to a language for the given name
+ */
+ const CLanguageMgr::Language* languageForName( const QString& language ) const;
+ /** Language for translated language name.
+ * @param abbrev The translated language name
+ * @return Pointer to a language for the given translated language name
+ */
+ const CLanguageMgr::Language* languageForTranslatedName( const QString& language ) const;
+ /** Default language so we don't return NULL pointers.
+ * @return Pointer to the default language
+ */
+ inline const CLanguageMgr::Language* defaultLanguage() const {
+ return &m_defaultLanguage;
+ }
+
+private:
+ void init();
+ inline const QStringList makeStringList(const QString& abbrevs) {
+ return abbrevs.split( ";", QString::KeepEmptyParts, Qt::CaseSensitive );
+ }
+
+ Language m_defaultLanguage;
+ mutable LanguageList m_langList;
+ mutable LangMap m_langMap;
+ mutable LanguageList m_cleanupLangPtrs;
+
+ struct ModuleCache {
+ unsigned int moduleCount;
+ LangMap availableLanguages;
+ }
+ m_availableModulesCache;
+};
+
+#endif
+
diff --git a/src/backend/managers/creferencemanager.cpp b/src/backend/managers/creferencemanager.cpp
new file mode 100644
index 0000000..adae180
--- /dev/null
+++ b/src/backend/managers/creferencemanager.cpp
@@ -0,0 +1,422 @@
+/*********
+*
+* 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 "creferencemanager.h"
+#include "backend/keys/cswordversekey.h"
+
+#include "backend/config/cbtconfig.h"
+#include "util/cpointers.h"
+
+//QT
+#include <QRegExp>
+
+//stl
+#include <algorithm> // STL algorithms class library
+
+/** Returns a hyperlink used to be imbedded in the display windows. At the moment the format is sword://module/key */
+const QString CReferenceManager::encodeHyperlink( const QString moduleName, const QString key, const CReferenceManager::Type type) {
+ QString ret = QString::null;
+
+ switch (type) {
+
+ case Bible:
+ ret = QString("sword://Bible/");
+ break;
+ case Commentary:
+ ret = QString("sword://Commentary/");
+ break;
+ case Lexicon:
+ ret = QString("sword://Lexicon/");
+ break;
+ case GenericBook:
+ ret = QString("sword://Book/");
+ break;
+ case MorphHebrew:
+ ret = QString("morph://Hebrew/");
+ break;
+ case MorphGreek:
+ ret = QString("morph://Greek/");
+ break;
+ case StrongsHebrew:
+ ret = QString("strongs://Hebrew/");
+ break;
+ case StrongsGreek:
+ ret = QString("strongs://Greek/");
+ break;
+ default:
+ break;
+ }
+
+ if (!moduleName.isEmpty()) {
+ ret.append( moduleName ).append('/');
+ }
+ else { //if module is empty use fallback module
+ ret.append( preferredModule(type) ).append('/');
+ }
+
+ if (type == GenericBook) {
+ const QString s = (!key.isEmpty() ? key : QString::null);
+ QString newKey = QString::null;
+ //replace all / of the key (e.g. of a CSwordTreeKey) with
+ // the escape sequence \/ so we know it's a link internal divider (e.g. of CSwordTreeKey)!
+
+ QChar c;
+
+ for(int i = 0; i < s.length(); ++i) {
+ c = s.at(i);
+
+ if (c == '/') {
+ newKey.append("\\/");
+ }
+ else {
+ newKey.append(c);
+ }
+ }
+
+ ret.append( newKey );
+ }
+ else { //slashes do not appear in verses and dictionary entries
+
+ switch (type) {
+
+ case Bible: //bibles or commentary keys need parsing
+
+ case Commentary: {
+/* CSwordModuleInfo* mod = CPointers::backend()->findModuleByName(moduleName);
+
+ ParseOptions options;
+ options.refDestinationModule = mod->name();
+ options.refBase =
+ options.sourceLanguage = mod->module()->Lang();
+ options.destinationLanguage = "en";
+
+ ret.append( parseVerseReference(key, options) ); //we add the english key, so drag and drop will work in all cases*/
+ ret.append(key);
+ break;
+ }
+
+ default:
+ ret.append( key ); //use the standard key, no parsing required
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/** Decodes the given hyperlink to module and key. */
+bool CReferenceManager::decodeHyperlink( const QString& hyperlink, QString& module, QString& key, CReferenceManager::Type& type ) {
+ /**
+ * We have to decide between three types of URLS: sword://Type/Module/Key, morph://Testament/key and strongs://Testament/Key
+ */
+ module = QString::null;
+ key = QString::null;
+
+ type = Unknown; //not yet known
+ QString ref = hyperlink;
+ //remove the trailing slash
+
+ if (ref.right(1)=="/" && ref.right(2) != "\\/") //trailing slash, but not escaped
+ ref = ref.left(ref.length()-1);
+
+ //find out which type we have by looking at the beginning (protocoll section of URL)
+ if (ref.left(8).toLower() == "sword://") { //Bible, Commentary or Lexicon
+ ref = ref.mid(8);
+
+ if (ref.left(5).toLower() == "bible") { //a bible hyperlink
+ type = CReferenceManager::Bible;
+ ref = ref.mid(6); //inclusive trailing slash
+ }
+ else if (ref.left(10).toLower() == "commentary") { // a Commentary hyperlink
+ type = CReferenceManager::Commentary;
+ ref = ref.mid(11); //inclusive trailing slash
+ }
+ else if (ref.left(7).toLower() == "lexicon") { // a Lexicon hyperlink
+ type = CReferenceManager::Lexicon;
+ ref = ref.mid(8); //inclusive trailing slash
+ }
+ else if (ref.left(4).toLower() == "book") { // a Book hyperlink
+ type = CReferenceManager::GenericBook;
+ ref = ref.mid(5); //inclusive trailing slash
+ }
+
+ // string up to next slash is the modulename
+ if (ref.at(0) != '/' ) { //we have a module given
+
+ while (true) {
+ const int pos = ref.indexOf("/");
+
+ if ((pos>0) && ref.at(pos-1) != '\\') { //found a slash which is not escaped
+ module = ref.mid(0,pos);
+ ref = ref.mid(pos+1);
+ break;
+ }
+ else if (pos == -1) {
+ break;
+ }
+ }
+
+ // the rest is the key
+ key = ref;
+ }
+ else {
+ key = ref.mid(1);
+ }
+
+ //the key may be an osis key like "NASBLex:Moses", which sets the module, too
+ // const int modPos = key.find(":");
+ // if (modPos != -1 && key.at(modPos-1).isLetter() && key.at(modPos+1).isLetter()) {
+ // module = key.left(modPos);
+ // key = key.mid(modPos+1);
+ //
+ // qWarning("found the module name %s with key %s", module.latin1(), key.latin1());
+ // }
+
+ //replace \/ escapes with /
+ key.replace(QRegExp("\\\\/"), "/");
+ }
+ else if (ref.left(8).toLower() == "morph://" || ref.left(10).toLower() == "strongs://") { //strongs or morph URL have the same format
+ enum PreType {IsMorph, IsStrongs};
+ PreType preType = IsMorph;
+
+ if (ref.left(8).toLower() == "morph://") { //morph code hyperlink
+ ref = ref.mid(8);
+ preType = IsMorph;
+ }
+ else if (ref.left(10).toLower() == "strongs://") {
+ ref = ref.mid(10);
+ preType = IsStrongs;
+ }
+
+ //part up to next slash is the language
+ const int pos = ref.indexOf("/");
+
+ if (pos>0) { //found
+ const QString language = ref.mid(0,pos);
+
+ if (language.toLower() == "hebrew") {
+ switch (preType) {
+
+ case IsMorph:
+ type = CReferenceManager::MorphHebrew;
+ break;
+
+ case IsStrongs:
+ type = CReferenceManager::StrongsHebrew;
+ break;
+ }
+ }
+ else if (language.toLower() == "greek") {
+ switch (preType) {
+
+ case IsMorph:
+ type = CReferenceManager::MorphGreek;
+ break;
+
+ case IsStrongs:
+ type = CReferenceManager::StrongsGreek;
+ break;
+ }
+ }
+
+ ref = ref.mid(pos+1);
+ key = ref; //the remaining part is the key
+
+ module = preferredModule(type);
+ }
+ }
+
+ if (key.isEmpty() && module.isEmpty())
+ return false;
+
+ return true;
+}
+
+const QString CReferenceManager::encodeReference(const QString &module, const QString &reference) {
+ //return QString("(%1)%2").arg(module).arg(reference);
+ return QString("(").append(module).append(")").append(reference);
+}
+
+void CReferenceManager::decodeReference(QString &dragreference, QString &module, QString &reference) {
+ const int pos = dragreference.indexOf(")");
+ const QString fallbackModule = dragreference.mid( 1, pos - 1);
+ dragreference = dragreference.mid(pos+1);
+
+ module = fallbackModule;
+ reference = dragreference;
+}
+
+/** Returns true if the parameter is a hyperlink. */
+bool CReferenceManager::isHyperlink( const QString& hyperlink ) {
+ return ( hyperlink.left(8) == "sword://")
+ || (hyperlink.left(10) == "strongs://")
+ || (hyperlink.left(8) == "morph://");
+}
+
+/** Returns the preferred module name for the given type. */
+const QString CReferenceManager::preferredModule( const CReferenceManager::Type type ) {
+ QString moduleName = QString::null;
+ CSwordModuleInfo* module = 0;
+
+ switch (type) {
+
+ case CReferenceManager::Bible:
+
+ module = CBTConfig::get
+ ( CBTConfig::standardBible );
+
+ break;
+
+ case CReferenceManager::Commentary:
+ module = CBTConfig::get
+ ( CBTConfig::standardCommentary );
+
+ break;
+
+ case CReferenceManager::Lexicon:
+ module = CBTConfig::get
+ ( CBTConfig::standardLexicon );
+
+ break;
+
+ case CReferenceManager::StrongsHebrew:
+ module = CBTConfig::get
+ ( CBTConfig::standardHebrewStrongsLexicon );
+
+ break;
+
+ case CReferenceManager::StrongsGreek:
+ module = CBTConfig::get
+ ( CBTConfig::standardGreekStrongsLexicon );
+
+ break;
+
+ case CReferenceManager::MorphHebrew:
+ module = CBTConfig::get
+ ( CBTConfig::standardHebrewMorphLexicon );
+
+ break;
+
+ case CReferenceManager::MorphGreek:
+ module = CBTConfig::get
+ ( CBTConfig::standardGreekMorphLexicon );
+
+ break;
+
+ default:
+ module = 0;
+
+ break;
+ }
+
+ return module ? module->name() : QString::null;
+}
+
+/** No descriptions */
+CReferenceManager::Type CReferenceManager::typeFromModule( const CSwordModuleInfo::ModuleType type) {
+ switch (type) {
+
+ case CSwordModuleInfo::Bible:
+ return CReferenceManager::Bible;
+
+ case CSwordModuleInfo::Commentary:
+ return CReferenceManager::Commentary;
+
+ case CSwordModuleInfo::Lexicon:
+ return CReferenceManager::Lexicon;
+
+ case CSwordModuleInfo::GenericBook:
+ return CReferenceManager::GenericBook;
+
+ default:
+ return CReferenceManager::Unknown;
+ }
+}
+
+/** Parses the given verse references using the given language and the module.*/
+const QString CReferenceManager::parseVerseReference( const QString& ref, const CReferenceManager::ParseOptions& options) {
+
+ CSwordModuleInfo* const mod = CPointers::backend()->findModuleByName(options.refDestinationModule);
+ //Q_ASSERT(mod); tested later
+
+ if (!mod) {
+ //parsing of non-verse based references is not supported
+ return ref;
+ }
+
+ if ((mod->type() != CSwordModuleInfo::Bible) && (mod->type() != CSwordModuleInfo::Commentary)) {
+ qDebug("CReferenceManager: Only verse based modules are supported as ref destination module");
+ return QString::null;
+ }
+
+ QString sourceLanguage = options.sourceLanguage;
+ QString destinationLanguage = options.destinationLanguage;
+
+ sword::StringList locales = sword::LocaleMgr::getSystemLocaleMgr()->getAvailableLocales();
+ if (/*options.sourceLanguage == "en" ||*/ std::find(locales.begin(), locales.end(), sourceLanguage.toUtf8().constData()) == locales.end()) { //sourceLanguage not available
+ sourceLanguage = "en_US";
+ }
+
+ if (/*options.destinationLanguage == "en" ||*/ std::find(locales.begin(), locales.end(), sourceLanguage.toUtf8().constData()) == locales.end()) { //destination not available
+ destinationLanguage = "en_US";
+ }
+
+ QString ret;
+ QStringList refList = ref.split(";");
+
+ CSwordVerseKey baseKey(0);
+ baseKey.setLocale( sourceLanguage.toUtf8().constData() );
+ baseKey.key( options.refBase ); //probably in the sourceLanguage
+ baseKey.setLocale( "en_US" ); //english works in all environments as base
+
+// CSwordVerseKey dummy(0);
+ //HACK: We have to workaround a Sword bug, we have to set the default locale to the same as the sourceLanguage !
+ const QString oldLocaleName = CPointers::backend()->booknameLanguage();
+ CPointers::backend()->booknameLanguage(sourceLanguage);
+
+ sword::VerseKey dummy;
+ dummy.setLocale( sourceLanguage.toUtf8().constData() );
+ Q_ASSERT( !strcmp(dummy.getLocale(), sourceLanguage.toUtf8().constData()) );
+
+// qDebug("Parsing '%s' in '%s' using '%s' as base, source lang '%s', dest lang '%s'", ref.latin1(), options.refDestinationModule.latin1(), baseKey.key().latin1(), sourceLanguage.latin1(), destinationLanguage.latin1());
+
+ for (QStringList::iterator it = refList.begin(); it != refList.end(); it++) {
+ //The listkey may contain more than one item, because a ref lik "Gen 1:3,5" is parsed into two single refs
+ sword::ListKey lk = dummy.ParseVerseList((*it).toUtf8().constData(), baseKey.key().toUtf8().constData(), true);
+ Q_ASSERT(!dummy.Error());
+
+ //Q_ASSERT(lk.Count());
+ if (!lk.Count()) {
+ ret.append( *it ); //don't change the original
+ continue;
+ }
+
+ for (int i = 0; i < lk.Count(); ++i) {
+ if (dynamic_cast<sword::VerseKey*>(lk.getElement(i))) { // a range
+ sword::VerseKey* k = dynamic_cast<sword::VerseKey*>(lk.getElement(i));
+ Q_ASSERT(k);
+ k->setLocale( destinationLanguage.toUtf8().constData() );
+
+ ret.append( QString::fromUtf8(k->getRangeText()) ).append("; ");
+ }
+ else { // a single ref
+ sword::VerseKey vk;
+ vk.setLocale( sourceLanguage.toUtf8().constData() );
+ vk = lk.getElement(i)->getText();
+ vk.setLocale( destinationLanguage.toUtf8().constData() );
+
+ ret.append( QString::fromUtf8(vk.getText()) ).append("; ");
+ }
+ }
+
+ }
+
+ CPointers::backend()->booknameLanguage(oldLocaleName);
+ return ret;
+}
diff --git a/src/backend/managers/creferencemanager.h b/src/backend/managers/creferencemanager.h
new file mode 100644
index 0000000..19baae7
--- /dev/null
+++ b/src/backend/managers/creferencemanager.h
@@ -0,0 +1,110 @@
+/*********
+*
+* 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 CREFERENCEMANAGER_H
+#define CREFERENCEMANAGER_H
+
+#include "backend/drivers/cswordmoduleinfo.h"
+
+//Qt includes
+#include <QString>
+
+/** Contains static functions to work with references used for Drag & Drop and for hyperlinks used in our
+ * rendered HTML code.
+ * @author The BibleTime team
+ */
+
+class CReferenceManager {
+
+public:
+ enum Type {
+ Bible, /**< Bibles */
+ Commentary, /**< Commentary */
+ Lexicon, /**< Lexicon */
+ GenericBook, /**< Generic Book */
+ MorphHebrew, /**< Module for hebrew morphology*/
+ MorphGreek, /**< Module for greek morphology */
+ StrongsHebrew, /**< Module for hebrew strongs */
+ StrongsGreek, /**< Module for greek strongs */
+ Unknown /**< Unknown */
+ };
+
+ /** Turn a hyperlink into module, key and type.
+ * Decodes the given hyperlink into module, key and type.
+ * @param hyperlink The hyperlink to decode
+ * @param module The string which will contain the module name after decoding
+ * @param key The string which will contain the key after decoding
+ * @param type The type param will contain the reference type after decoding
+ */
+ static bool decodeHyperlink( const QString& hyperlink, QString& module, QString& key, Type& type);
+ /**
+ * Returns a hyperlink used to be embedded in the display windows.
+ * At the moment the format is sword://module/key
+ * @param module The module which is used to encode the hyperlink
+ * @param key The key which is used to encode the hyperlink
+ * @param type The type which is used to encode the hyperlink
+ * @return The encoded hyperlink
+ */
+ static const QString encodeHyperlink( const QString module, const QString key, const Type type);
+ /**
+ * Puts a module Name and a Reference together in the 'draggable' form
+ * (module)reference
+ * @param module The name of the module
+ * @param reference The key reference as text
+ * @return The encoded reference using module and reference
+ * @author Martin Gruner
+ */
+ static const QString encodeReference(const QString &module, const QString &reference);
+ /**
+ * decodes a 'draggable' reference into a modulename and a reference
+ * @author Martin Gruner
+ */
+ static void decodeReference(QString &dragreference, QString &module, QString &reference);
+ /**
+ * Returns true if the parameter is a hyperlink.
+ * @param hyperlink The string which is tested
+ * @return True if the passed string is a hyperlink
+ */
+ static bool isHyperlink( const QString& hyperlink );
+ /**
+ * Returns the preferred module name for the given type.
+ * @param type The type which is used to find the module
+ * @return The default module name for the passed type
+ */
+ static const QString preferredModule( const Type type );
+ /**
+ * Returns the type of the passed module type
+ * @param type The CSwordModuleInfo module typpe
+ * @return The ReferenceManager type
+ */
+ static CReferenceManager::Type typeFromModule( const CSwordModuleInfo::ModuleType type );
+
+
+ struct ParseOptions {
+ QString refDestinationModule;
+ QString refBase; /* only valid for verse based destination modules*/
+ QString sourceLanguage; /* only valid for verse based destination modules*/
+ QString destinationLanguage; /* only valid for verse based destination modules*/
+
+ ParseOptions() {
+ destinationLanguage = "en";
+ };
+ };
+
+ /** Parses the given verse references using the given language and the module.
+ * @param moduleName The name of the module to use. Required for the language checking before parsing the key.
+ * @param ref The verse reference.
+ * @param lang The language of the verse reference
+ * @param newLang The language of the reference, which will be returned. For example: If BibleTime using an english environment parses a spanish ref (lang=es) the returned ref should be in english (newLang=en), because his english standard module only understands en.
+ */
+ static const QString parseVerseReference( const QString& ref, const ParseOptions& options);
+};
+
+#endif
+
diff --git a/src/backend/managers/cswordbackend.cpp b/src/backend/managers/cswordbackend.cpp
new file mode 100644
index 0000000..0afe467
--- /dev/null
+++ b/src/backend/managers/cswordbackend.cpp
@@ -0,0 +1,555 @@
+/*********
+*
+* 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 "cswordbackend.h"
+
+#include "backend/rendering/centrydisplay.h"
+#include "backend/rendering/cbookdisplay.h"
+#include "backend/rendering/cchapterdisplay.h"
+#include "backend/drivers/cswordbiblemoduleinfo.h"
+#include "backend/drivers/cswordcommentarymoduleinfo.h"
+#include "backend/drivers/cswordlexiconmoduleinfo.h"
+#include "backend/drivers/cswordbookmoduleinfo.h"
+#include "backend/filters/bt_thmlhtml.h"
+#include "backend/filters/bt_thmlplain.h"
+#include "backend/filters/bt_osishtml.h"
+#include "backend/filters/bt_gbfhtml.h"
+#include "backend/filters/bt_plainhtml.h"
+#include "backend/filters/osismorphsegmentation.h"
+
+#include "backend/config/cbtconfig.h"
+
+#include "util/directoryutil.h"
+
+#include <dirent.h>
+
+//Qt
+#include <QString>
+#include <QDir>
+#include <QFileInfo>
+#include <QSet>
+#include <QDebug>
+
+//Sword
+#include <swdisp.h>
+#include <swfiltermgr.h>
+#include <encfiltmgr.h>
+#include <rtfhtml.h>
+#include <filemgr.h>
+#include <utilstr.h>
+#include <swfilter.h>
+
+using namespace Filters;
+using namespace Rendering;
+
+CSwordBackend::CSwordBackend()
+ : sword::SWMgr(0, 0, false, new sword::EncodingFilterMgr( sword::ENC_UTF8 ), true)
+{
+ m_filters.gbf = new BT_GBFHTML();
+ m_filters.plain = new BT_PLAINHTML();
+ m_filters.thml = new BT_ThMLHTML();
+ m_filters.osis = new BT_OSISHTML();
+
+ m_displays.entry = new CEntryDisplay();
+ m_displays.chapter = new CChapterDisplay();
+ m_displays.book = new CBookDisplay();
+
+ filterInit();
+}
+
+CSwordBackend::CSwordBackend(const QString& path, const bool augmentHome)
+ : sword::SWMgr(!path.isEmpty() ? path.toLocal8Bit().constData() : 0, false, new sword::EncodingFilterMgr( sword::ENC_UTF8 ), false, augmentHome) // don't allow module renaming, because we load from a path
+{
+ m_filters.gbf = new BT_GBFHTML();
+ m_filters.plain = new BT_PLAINHTML();
+ m_filters.thml = new BT_ThMLHTML();
+ m_filters.osis = new BT_OSISHTML();
+
+ m_displays.entry = new CEntryDisplay();
+ m_displays.chapter = new CChapterDisplay();
+ m_displays.book = new CBookDisplay();
+
+ filterInit();
+}
+
+CSwordBackend::~CSwordBackend() {
+ shutdownModules();
+
+ delete m_filters.gbf;
+ delete m_filters.plain;
+ delete m_filters.thml;
+ delete m_filters.osis;
+
+ delete m_displays.book;
+ delete m_displays.chapter;
+ delete m_displays.entry;
+}
+
+void CSwordBackend::filterInit() {
+ //HACK: replace Sword's OSISMorphSegmentation filter, seems to be buggy, ours works
+ if (sword::SWOptionFilter* filter = optionFilters["OSISMorphSegmentation"])
+ {
+ cleanupFilters.remove(filter);
+ optionFilters.erase("OSISMorphSegmentation");
+ delete filter;
+ }
+ sword::SWOptionFilter* tmpFilter = new OSISMorphSegmentation();
+ optionFilters.insert(sword::OptionFilterMap::value_type("OSISMorphSegmentation", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ //HACK: replace Sword's ThML strip filter with our own version
+ //remove this hack as soon as Sword is fixed
+ cleanupFilters.remove(thmlplain);
+ delete thmlplain;
+ thmlplain = new BT_ThMLPlain();
+ cleanupFilters.push_back(thmlplain);
+}
+
+QList<CSwordModuleInfo*> CSwordBackend::takeModulesFromList(QStringList names)
+{
+ int numberOfRemoved = 0;
+ QList<CSwordModuleInfo*> list;
+ foreach(QString name, names) {
+ CSwordModuleInfo* mInfo = findModuleByName(name);
+ if (mInfo) {
+ m_moduleList.removeAll(mInfo);
+ ++numberOfRemoved;
+ list.append(mInfo);
+ }
+ }
+ if (numberOfRemoved > 0)
+ emit sigSwordSetupChanged(RemovedModules);
+ return list;
+}
+
+/** Initializes the Sword modules. */
+CSwordBackend::LoadError CSwordBackend::initModules(SetupChangedReason reason) {
+ // qWarning("globalSwordConfigPath is %s", globalConfPath);
+ LoadError ret = NoError;
+
+ shutdownModules(); //remove previous modules
+ m_moduleList.clear();
+
+ sword::ModMap::iterator end = Modules.end();
+ ret = LoadError( Load() );
+
+ for (sword::ModMap::iterator it = Modules.begin(); it != end; it++) {
+ sword::SWModule* const curMod = (*it).second;
+ CSwordModuleInfo* newModule = 0;
+
+ if (!strcmp(curMod->Type(), "Biblical Texts")) {
+ newModule = new CSwordBibleModuleInfo(curMod, this);
+ newModule->module()->Disp(m_displays.chapter);
+ }
+ else if (!strcmp(curMod->Type(), "Commentaries")) {
+ newModule = new CSwordCommentaryModuleInfo(curMod, this);
+ newModule->module()->Disp(m_displays.entry);
+ }
+ else if (!strcmp(curMod->Type(), "Lexicons / Dictionaries")) {
+ newModule = new CSwordLexiconModuleInfo(curMod, this);
+ newModule->module()->Disp(m_displays.entry);
+ }
+ else if (!strcmp(curMod->Type(), "Generic Books")) {
+ newModule = new CSwordBookModuleInfo(curMod, this);
+ newModule->module()->Disp(m_displays.book);
+ }
+
+ if (newModule) {
+ //Append the new modules to our list, but only if it's supported
+ //The constructor of CSwordModuleInfo prints a warning on stdout
+ if (!newModule->hasVersion() || (newModule->minimumSwordVersion() <= sword::SWVersion::currentVersion)) {
+ m_moduleList.append( newModule );
+ }
+ else
+ {
+ delete newModule;
+ }
+ }
+ }
+
+ QList<CSwordModuleInfo*>::iterator end_it = m_moduleList.end();
+
+ foreach (CSwordModuleInfo* mod, m_moduleList) {
+ m_moduleDescriptionMap.insert( mod->config(CSwordModuleInfo::Description), mod->name() );
+ //unlock modules if keys are present
+ if ( mod->isEncrypted() ) {
+ const QString unlockKey = CBTConfig::getModuleEncryptionKey( mod->name() );
+ if (!unlockKey.isNull()) {
+ setCipherKey( mod->name().toUtf8().constData(), unlockKey.toUtf8().constData() );
+ }
+ }
+ }
+
+ emit sigSwordSetupChanged(reason);
+ return ret;
+}
+
+void CSwordBackend::AddRenderFilters(sword::SWModule *module, sword::ConfigEntMap &section) {
+ sword::SWBuf moduleDriver;
+ sword::SWBuf sourceformat;
+ sword::ConfigEntMap::iterator entry;
+ bool noDriver = true;
+
+ sourceformat = ((entry = section.find("SourceType")) != section.end()) ? (*entry).second : (sword::SWBuf) "";
+ moduleDriver = ((entry = section.find("ModDrv")) != section.end()) ? (*entry).second : (sword::SWBuf) "";
+
+ if (sourceformat == "GBF") {
+ module->AddRenderFilter(m_filters.gbf);
+ noDriver = false;
+ }
+ else if (sourceformat == "PLAIN") {
+ module->AddRenderFilter(m_filters.plain);
+ noDriver = false;
+ }
+ else if (sourceformat == "ThML") {
+ module->AddRenderFilter(m_filters.thml);
+ noDriver = false;
+ }
+ else if (sourceformat == "OSIS") {
+ module->AddRenderFilter(m_filters.osis);
+ noDriver = false;
+ }
+
+ if (noDriver) { //no driver found
+ if ( (moduleDriver == "RawCom") || (moduleDriver == "RawLD") ) {
+ module->AddRenderFilter(m_filters.plain);
+ noDriver = false;
+ }
+ }
+}
+
+/** This function deinitializes the modules and deletes them. */
+bool CSwordBackend::shutdownModules() {
+ QList<CSwordModuleInfo*>::iterator it = m_moduleList.begin();
+ QList<CSwordModuleInfo*>::iterator end = m_moduleList.end();
+
+ while (it != end) {
+ CSwordModuleInfo* current = (*it);
+ it = m_moduleList.erase(it);
+ delete current;
+ }
+
+ Q_ASSERT(m_moduleList.count() == 0);
+ //BT mods are deleted now, delete Sword mods, too.
+ DeleteMods();
+
+ /* Cipher filters must be handled specially, because SWMgr creates them,
+ * stores them in cipherFilters and cleanupFilters and attaches them to locked
+ * modules. If these modules are removed, the filters need to be removed as well,
+ * so that they are re-created for the new module objects.
+ */
+ sword::FilterMap::iterator cipher_it;
+ for (cipher_it = cipherFilters.begin(); cipher_it != cipherFilters.end(); cipher_it++)
+ {
+ //Delete the Filter and remove it from the cleanup list
+ cleanupFilters.remove(cipher_it->second);
+ delete cipher_it->second;
+ }
+ cipherFilters.clear();
+
+ return true;
+}
+
+void CSwordBackend::setOption( const CSwordModuleInfo::FilterTypes type, const int state ) {
+ sword::SWBuf value;
+
+ switch (type) {
+
+ case CSwordModuleInfo::textualVariants:
+
+ if (state == 0) {
+ value = "Primary Reading";
+ }
+ else if (state == 1) {
+ value = "Secondary Reading";
+ }
+ else {
+ value = "All Readings";
+ }
+
+ break;
+
+ default:
+ value = state ? "On": "Off";
+ break;
+ };
+
+ if (value.length())
+ setGlobalOption(optionName(type).toUtf8().constData(), value.c_str());
+}
+
+void CSwordBackend::setFilterOptions( const CSwordBackend::FilterOptions options) {
+ setOption( CSwordModuleInfo::footnotes, options.footnotes );
+ setOption( CSwordModuleInfo::strongNumbers, options.strongNumbers );
+ setOption( CSwordModuleInfo::headings, options.headings );
+ setOption( CSwordModuleInfo::morphTags, options.morphTags );
+ setOption( CSwordModuleInfo::lemmas, options.lemmas );
+ setOption( CSwordModuleInfo::hebrewPoints, options.hebrewPoints );
+ setOption( CSwordModuleInfo::hebrewCantillation, options.hebrewCantillation );
+ setOption( CSwordModuleInfo::greekAccents, options.greekAccents );
+ setOption( CSwordModuleInfo::redLetterWords, options.redLetterWords );
+ setOption( CSwordModuleInfo::textualVariants, options.textualVariants );
+ setOption( CSwordModuleInfo::morphSegmentation, options.morphSegmentation );
+ // setOption( CSwordModuleInfo::transliteration, options.transliteration );
+ setOption( CSwordModuleInfo::scriptureReferences, options.scriptureReferences);
+}
+
+/** This function searches for a module with the specified description */
+CSwordModuleInfo* CSwordBackend::findModuleByDescription(const QString& description) {
+ foreach(CSwordModuleInfo* mod, m_moduleList) {
+ if (mod->config(CSwordModuleInfo::Description) == description) return mod;
+ }
+ return 0;
+}
+
+/** This function searches for a module with the specified description */
+const QString CSwordBackend::findModuleNameByDescription(const QString& description) {
+ if (m_moduleDescriptionMap.contains(description)) {
+ return m_moduleDescriptionMap[description];
+ }
+ return QString::null;
+}
+
+/** This function searches for a module with the specified name */
+CSwordModuleInfo* CSwordBackend::findModuleByName(const QString& name) {
+ foreach(CSwordModuleInfo* mod, m_moduleList) {
+ if (mod->name() == name) return mod;
+ }
+ return 0;
+}
+
+CSwordModuleInfo* CSwordBackend::findSwordModuleByPointer(const sword::SWModule* const swmodule) {
+ foreach(CSwordModuleInfo* mod, m_moduleList) {
+ if (mod->module() == swmodule ) return mod;
+ }
+ return 0;
+}
+
+CSwordModuleInfo* CSwordBackend::findModuleByPointer(const CSwordModuleInfo* const module) {
+ foreach(CSwordModuleInfo* mod, m_moduleList) {
+ if (mod == module) return mod;
+ }
+ return 0;
+}
+
+/** Returns our local config object to store the cipher keys etc. locally for each user. The values of the config are merged with the global config. */
+bool CSwordBackend::moduleConfig(const QString& module, sword::SWConfig& moduleConfig) {
+ sword::SectionMap::iterator section;
+ DIR *dir = opendir(configPath);
+
+ struct dirent *ent;
+
+ bool foundConfig = false;
+ QString modFile;
+
+ if (dir) { // find and update .conf file
+ rewinddir(dir);
+
+ while ((ent = readdir(dir)) && !foundConfig) {
+ if ((strcmp(ent->d_name, ".")) && (strcmp(ent->d_name, ".."))) {
+ modFile = QString(configPath);
+ modFile.append("/");
+ modFile.append( QString::fromLocal8Bit(ent->d_name) );
+
+ moduleConfig = sword::SWConfig( modFile.toLocal8Bit().constData() );
+ section = moduleConfig.Sections.find( module.toLocal8Bit().constData() );
+ foundConfig = ( section != moduleConfig.Sections.end() );
+ }
+ }
+
+ closedir(dir);
+ }
+ else { //try to read mods.conf
+ moduleConfig = sword::SWConfig("");//global config
+ section = config->Sections.find( module.toLocal8Bit().constData() );
+ foundConfig = ( section != config->Sections.end() );
+
+ sword::ConfigEntMap::iterator entry;
+
+ if (foundConfig) { //copy module section
+
+ for (entry = section->second.begin(); entry != section->second.end(); entry++) {
+ moduleConfig.Sections[section->first].insert(sword::ConfigEntMap::value_type(entry->first, entry->second));
+ }
+ }
+ }
+
+ if (!foundConfig && configType != 2) { //search in $HOME/.sword/
+
+ QString myPath = util::filesystem::DirectoryUtil::getUserHomeDir().absolutePath();
+ myPath.append("/.sword/mods.d");
+ dir = opendir(myPath.toUtf8().constData());
+
+ if (dir) {
+ rewinddir(dir);
+
+ while ((ent = readdir(dir)) && !foundConfig) {
+ if ((strcmp(ent->d_name, ".")) && (strcmp(ent->d_name, ".."))) {
+ modFile = myPath;
+ modFile.append('/');
+ modFile.append(ent->d_name);
+ moduleConfig = sword::SWConfig( modFile.toLocal8Bit().constData() );
+ section = moduleConfig.Sections.find( module.toLocal8Bit().constData() );
+ foundConfig = ( section != moduleConfig.Sections.end() );
+ }
+ }
+
+ closedir(dir);
+ }
+ }
+
+ return foundConfig;
+}
+
+/** Returns the text used for the option given as parameter. */
+const QString CSwordBackend::optionName( const CSwordModuleInfo::FilterTypes option ) {
+ switch (option) {
+ case CSwordModuleInfo::footnotes: return QString("Footnotes");
+ case CSwordModuleInfo::strongNumbers: return QString("Strong's Numbers");
+ case CSwordModuleInfo::headings: return QString("Headings");
+ case CSwordModuleInfo::morphTags: return QString("Morphological Tags");
+ case CSwordModuleInfo::lemmas: return QString("Lemmas");
+ case CSwordModuleInfo::hebrewPoints: return QString("Hebrew Vowel Points");
+ case CSwordModuleInfo::hebrewCantillation: return QString("Hebrew Cantillation");
+ case CSwordModuleInfo::greekAccents: return QString("Greek Accents");
+ case CSwordModuleInfo::redLetterWords: return QString("Words of Christ in Red");
+ case CSwordModuleInfo::textualVariants: return QString("Textual Variants");
+ case CSwordModuleInfo::scriptureReferences: return QString("Cross-references");
+ case CSwordModuleInfo::morphSegmentation: return QString("Morph Segmentation");
+ }
+ return QString::null;
+}
+
+/** Returns the translated name of the option given as parameter. */
+const QString CSwordBackend::translatedOptionName(const CSwordModuleInfo::FilterTypes option) {
+ switch (option) {
+ case CSwordModuleInfo::footnotes: return QObject::tr("Footnotes");
+ case CSwordModuleInfo::strongNumbers: return QObject::tr("Strong's numbers");
+ case CSwordModuleInfo::headings: return QObject::tr("Headings");
+ case CSwordModuleInfo::morphTags: return QObject::tr("Morphological tags");
+ case CSwordModuleInfo::lemmas: return QObject::tr("Lemmas");
+ case CSwordModuleInfo::hebrewPoints: return QObject::tr("Hebrew vowel points");
+ case CSwordModuleInfo::hebrewCantillation: return QObject::tr("Hebrew cantillation marks");
+ case CSwordModuleInfo::greekAccents: return QObject::tr("Greek accents");
+ case CSwordModuleInfo::redLetterWords: return QObject::tr("Red letter words");
+ case CSwordModuleInfo::textualVariants: return QObject::tr("Textual variants");
+ case CSwordModuleInfo::scriptureReferences: return QObject::tr("Scripture cross-references");
+ case CSwordModuleInfo::morphSegmentation: return QObject::tr("Morph segmentation");
+ }
+ return QString::null;
+}
+
+
+const QString CSwordBackend::configOptionName( const CSwordModuleInfo::FilterTypes option ) {
+ switch (option) {
+ case CSwordModuleInfo::footnotes: return QString("Footnotes");
+ case CSwordModuleInfo::strongNumbers: return QString("Strongs");
+ case CSwordModuleInfo::headings: return QString("Headings");
+ case CSwordModuleInfo::morphTags: return QString("Morph");
+ case CSwordModuleInfo::lemmas: return QString("Lemma");
+ case CSwordModuleInfo::hebrewPoints: return QString("HebrewPoints");
+ case CSwordModuleInfo::hebrewCantillation: return QString("Cantillation");
+ case CSwordModuleInfo::greekAccents: return QString("GreekAccents");
+ case CSwordModuleInfo::redLetterWords: return QString("RedLetterWords");
+ case CSwordModuleInfo::textualVariants: return QString("Variants");
+ case CSwordModuleInfo::scriptureReferences: return QString("Scripref");
+ case CSwordModuleInfo::morphSegmentation: return QString("MorphSegmentation");
+ }
+ return QString::null;
+}
+
+const QString CSwordBackend::booknameLanguage( const QString& language ) {
+ if (!language.isEmpty()) {
+ sword::LocaleMgr::getSystemLocaleMgr()->setDefaultLocaleName( language.toUtf8().constData() );
+
+ //refresh the locale of all Bible and commentary modules!
+ //use what sword returns, language may be different
+ QString newLocaleName( sword::LocaleMgr::getSystemLocaleMgr()->getDefaultLocaleName() );
+
+ foreach(CSwordModuleInfo* mod, m_moduleList) {
+ if ( (mod->type() == CSwordModuleInfo::Bible) || (mod->type() == CSwordModuleInfo::Commentary) ) {
+ //Create a new key, it will get the default bookname language
+ ((sword::VerseKey*)(mod->module()->getKey()))->setLocale( newLocaleName.toUtf8().constData() );
+ }
+ }
+
+ }
+ return QString( sword::LocaleMgr::getSystemLocaleMgr()->getDefaultLocaleName() );
+}
+
+
+/** Reload all Sword modules. */
+void CSwordBackend::reloadModules(SetupChangedReason reason) {
+ shutdownModules();
+
+ //delete Sword's config to make Sword reload it!
+
+ if (myconfig) { // force reload on config object because we may have changed the paths
+ delete myconfig;
+ config = myconfig = 0;
+ // we need to call findConfig to make sure that augPaths are reloaded
+#ifdef SWORD_SYSCONF_CHANGED
+ findConfig(&configType, &prefixPath, &configPath, &augPaths, &sysConfig);
+#else
+ findConfig(&configType, &prefixPath, &configPath, &augPaths, sysconfig);
+#endif
+ // now re-read module configuration files
+ loadConfigDir(configPath);
+ }
+ else if (config) {
+ config->Load();
+ }
+
+ initModules(reason);
+}
+
+const QStringList CSwordBackend::swordDirList() {
+ QSet<QString> ret;
+ const QString home = util::filesystem::DirectoryUtil::getUserHomeDir().absolutePath();
+
+ //return a list of used Sword dirs. Useful for the installer
+ QString configPath = QString("%1/.sword/sword.conf").arg(home);
+
+ if (!QFile(configPath).exists()) {
+ configPath = globalConfPath; //e.g. /etc/sword.conf, /usr/local/etc/sword.conf
+ }
+
+ QStringList configs = configPath.split(":");
+
+ for (QStringList::const_iterator it = configs.begin(); it != configs.end(); ++it) {
+ if (!QFileInfo(*it).exists()) {
+ continue;
+ }
+
+ //get all DataPath and AugmentPath entries from the config file and add them to the list
+ sword::SWConfig conf( (*it).toUtf8().constData() );
+ ret << conf["Install"]["DataPath"].c_str();
+ sword::ConfigEntMap group = conf["Install"];
+ sword::ConfigEntMap::iterator start = group.equal_range("AugmentPath").first;
+ sword::ConfigEntMap::iterator end = group.equal_range("AugmentPath").second;
+
+ for (sword::ConfigEntMap::const_iterator it = start; it != end; ++it) {
+ ret << QDir(it->second.c_str()).absolutePath(); //added augment path
+ }
+ }
+
+ if (!home.isEmpty()) {
+ // This is added to the set if not there already. Notice that
+ // this prevents duplication only if the QDir::absolutePath() returns
+ // string without the prepended "/".
+ ret << home + "/.sword";
+ }
+
+ return ret.values();
+}
+
+void CSwordBackend::notifyChange(SetupChangedReason reason)
+{
+ emit sigSwordSetupChanged(reason);
+}
diff --git a/src/backend/managers/cswordbackend.h b/src/backend/managers/cswordbackend.h
new file mode 100644
index 0000000..0ffb484
--- /dev/null
+++ b/src/backend/managers/cswordbackend.h
@@ -0,0 +1,273 @@
+/*********
+*
+* 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 CSWORDBACKEND_H
+#define CSWORDBACKEND_H
+
+//BibleTime includes
+#include "backend/drivers/cswordmoduleinfo.h"
+
+//Qt includes
+#include <QObject>
+#include <QMap>
+#include <QString>
+#include <QStringList>
+
+//Sword includes
+#include <swmgr.h>
+#include <swbuf.h>
+#include <swmodule.h>
+#include <swversion.h>
+#include <localemgr.h>
+#include <utilstr.h>
+
+//forward declarations
+namespace Rendering {
+ class CEntryDisplay;
+ class CChapterDisplay;
+ class CBookDisplay;
+}
+
+/** The backend layer main class.
+ * This is the implementation of CBackend for Sword. It's additionally derived from SWMgr
+ * to provide functions of Sword.
+ *
+ * @short The backend implementation of Sword
+ * @author The BibleTime team
+ * @version $Id: cswordbackend.h,v 1.58 2007/03/14 21:32:47 joachim Exp $
+ */
+
+class CSwordBackend : public QObject, public sword::SWMgr
+{
+ Q_OBJECT
+public:
+
+ /** The reason for the sigSwordSetupChanged signal, i.e. why the module list has changed. */
+ enum SetupChangedReason {
+ AddedModules = 1,
+ RemovedModules = 2,
+ HidedModules = 4,
+ PathChanged = 8,
+ OtherChange = 16
+ };
+
+ /** Filter options. Filter options to
+ * control the text display of modules. Uses int and not bool because not all
+ * options have just two toggle values.
+ */
+ struct FilterOptions {
+ int footnotes; /**< 0 for disabled, 1 for enabled */
+ int strongNumbers; /**< 0 for disabled, 1 for enabled */
+ int headings; /**< 0 for disabled, 1 for enabled */
+ int morphTags; /**< 0 for disabled, 1 for enabled */
+ int lemmas; /**< 0 for disabled, 1 for enabled */
+ int hebrewPoints; /**< 0 for disabled, 1 for enabled */
+ int hebrewCantillation; /**< 0 for disabled, 1 for enabled */
+ int greekAccents; /**< 0 for disabled, 1 for enabled */
+ int textualVariants; /**< Number n to enabled the n-th variant */
+ int redLetterWords; /**< 0 for disabled, 1 for enabled */
+ int scriptureReferences; /**< 0 for disabled, 1 for enabled */
+ int morphSegmentation; /**< 0 for disabled, 1 for enabled */
+ };
+
+ /** Control the display of a text.
+ */
+ struct DisplayOptions {
+ int lineBreaks;
+ int verseNumbers;
+ };
+
+ /** The error codes which may be returned by the @ref Load() call.
+ */
+ enum LoadError { // the values exist to cast from the char return of SWMgr::Load
+ NoSwordConfig = -1,
+ NoError = 0,
+ NoModules = 1
+ };
+ /**
+ * The constructor of the Sword backend.
+ * It creates the SWModule objects using SWMgr's methods, it adds the necessary
+ * filters for the module format.
+ */
+ CSwordBackend();
+ /**
+ * The constructor of the Sword backend. This is actually used nowhere.
+ * Notice that using augmentHome=false can mess up the system because it is true elsewhere.
+ * @param path The path which is used to load modules
+ * @param augmentHome True if the $HOME/.sword/ modules should be augmented with the other modules
+ */
+ CSwordBackend( const QString& path, const bool augmentHome = true );
+
+ /**
+ * The destrctor of this backend. This function shuts the modules down using @ref shutdownModules.
+ */
+ virtual ~CSwordBackend();
+
+ /**
+ * This function returns the list of available modules managed by this backend.
+ * You have to call initModules() first;
+ *
+ * @return The list of modules managed by this backend
+ */
+ inline virtual QList<CSwordModuleInfo*>& moduleList();
+ /**
+ * Initializes the Sword modules.
+ *
+ * @return True if the initializiation was succesful, otherwise return false.
+ */
+ virtual CSwordBackend::LoadError initModules(SetupChangedReason reason);
+ /**
+ * This function deinitializes the modules and deletes them.
+ *
+ * @return True if it was succesful, otherwise return false
+ */
+ virtual bool shutdownModules();
+ /**
+ * Sets the given options enabled or disabled depending on the second parameter.
+ *
+ * @param type This is the type this function should set enabled or disabled
+ * @param enable If this is true the option will be enabled, otherwise it will be disabled.
+ */
+ void setOption( const CSwordModuleInfo::FilterTypes type, const int state );
+ /** */
+ void setFilterOptions( const CSwordBackend::FilterOptions options );
+ /**
+ * Sets the language for the international booknames of Sword.
+ * @param langName The abbreviation string which should be used for the Sword backend
+ */
+ const QString booknameLanguage( const QString& langName = QString::null );
+ /**
+ * This function searches for a module with the specified description
+ * @param description The description of the desired module
+ * @return pointer to the desired module; null if no module has the specified description
+ */
+ virtual CSwordModuleInfo* findModuleByDescription(const QString& description);
+ /**
+ * This function searches for a module with the specified description
+ * @param description The description of the desired module
+ * @return pointer to the desired module; null if no module has the specified description
+ */
+ const QString findModuleNameByDescription(const QString& description);
+ /**
+ * This function searches for a module with the specified name
+ * @param name The name of the desired module
+ * @return Pointer to the desired module; null if no module has the specified name
+ */
+ CSwordModuleInfo* findModuleByName(const QString& name);
+ /**
+ * This function searches for a module with the specified sword module as module() object!
+ * @param swmodule to a Sword module
+ * @return pointer to the desired module; null if no module has the specified name
+ */
+ CSwordModuleInfo* findSwordModuleByPointer(const sword::SWModule* const swmodule);
+ /**
+ * This function searches for a module which is the same as the passed module.
+ * @param module The module which should be used for searching the new one. May be child of a different backend.
+ * @return Pointer to the desired module; null if no module has the specified name
+ */
+ CSwordModuleInfo* findModuleByPointer(const CSwordModuleInfo* const module);
+ /**
+ * @return Our global config object which contains the configs of all modules merged together.
+ */
+ inline sword::SWConfig* getConfig() const;
+ /**
+ * Tries to find the config object for the module. The second paramter will be the found config.
+ * @return True if the config was found, false if not. If false is returned the moduleConfig object is in undefined/unknwon state.
+ */
+ bool moduleConfig(const QString& module, sword::SWConfig& moduleConfig );
+ /**
+ * Returns the text used for the option given as parameter.
+ * @param The paramter enum
+ * @return The name of the option given by the parameter
+ */
+ static const QString optionName( const CSwordModuleInfo::FilterTypes option );
+ /**
+ * Returns the text used for the option given as parameter.
+ */
+ static const QString configOptionName( const CSwordModuleInfo::FilterTypes option );
+ /**
+ * Returns the translated name of the option given as parameter.
+ * @param The translated option name
+ */
+ static const QString translatedOptionName(const CSwordModuleInfo::FilterTypes option );
+ /**
+ * Returns the version of the Sword library.
+ * @return The version used by this backend
+ */
+ inline virtual const sword::SWVersion Version();
+ /**
+ * Reload all Sword modules.
+ */
+ void reloadModules(SetupChangedReason reason);
+
+ /**
+ * Takes off the given modules from the list and returns them.
+ * User must take care of the deletion of the returned CSwordModuleInfo pointers.
+ */
+ QList<CSwordModuleInfo*> takeModulesFromList(QStringList names);
+
+ /** Sword prefix list.
+ * @return A list of all known Sword prefix dirs
+ */
+ const QStringList swordDirList();
+
+ /** Emits the sigSwordSetupChanged signal.
+ * This can be called directly from outside if there is no need to reload the backend.
+ */
+ void notifyChange(SetupChangedReason reason);
+
+signals:
+ void sigSwordSetupChanged(CSwordBackend::SetupChangedReason reason);
+
+protected:
+ /**
+ * Adds a render filter to the module.
+ * This is used to apply our own render filters to our modules instead of the sword filters
+ */
+ virtual void AddRenderFilters(sword::SWModule *module, sword::ConfigEntMap &section);
+ /**
+ * Overrides Sword filters which appear to be buggy.
+ */
+ virtual void filterInit();
+
+private:
+ // Filters
+ struct Filters {
+ sword::SWFilter* gbf;
+ sword::SWFilter* plain;
+ sword::SWFilter* thml;
+ sword::SWFilter* osis;
+ } m_filters;
+
+ struct Displays {
+ Rendering::CChapterDisplay* chapter;
+ Rendering::CEntryDisplay* entry;
+ Rendering::CBookDisplay* book;
+ } m_displays;
+
+ QList<CSwordModuleInfo*> m_moduleList;
+ QMap<QString, QString> m_moduleDescriptionMap;
+};
+
+/**Returns The list of modules managed by this backend*/
+inline QList<CSwordModuleInfo*>& CSwordBackend::moduleList() {
+ return m_moduleList;
+}
+
+/** Returns our local config object to store the cipher keys etc. locally for each user. The values of the config are merged with the global config. */
+inline sword::SWConfig* CSwordBackend::getConfig() const {
+ return config;
+}
+
+/** Returns the version of the Sword library. */
+inline const sword::SWVersion CSwordBackend::Version() {
+ return sword::SWVersion::currentVersion;
+}
+
+#endif
diff --git a/src/backend/rendering/cbookdisplay.cpp b/src/backend/rendering/cbookdisplay.cpp
new file mode 100644
index 0000000..fd57034
--- /dev/null
+++ b/src/backend/rendering/cbookdisplay.cpp
@@ -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.
+*
+**********/
+
+//Backend
+#include "cbookdisplay.h"
+#include "cdisplayrendering.h"
+#include "backend/drivers/cswordbookmoduleinfo.h"
+#include "backend/keys/cswordtreekey.h"
+
+//Util
+#include <boost/scoped_ptr.hpp>
+
+/** Returns the rendered text using the modules in the list and using the key parameter. The displayoptions and filter options are used, too. */
+const QString Rendering::CBookDisplay::text( const QList<CSwordModuleInfo*>& modules, const QString& keyName, const CSwordBackend::DisplayOptions displayOptions, const CSwordBackend::FilterOptions filterOptions ) {
+ CSwordBookModuleInfo* book = dynamic_cast<CSwordBookModuleInfo*>(modules.first());
+ Q_ASSERT(book);
+
+ CSwordBackend::DisplayOptions dOpts = displayOptions;
+ dOpts.lineBreaks = true; //books should render with blocks, not with inlined sections
+
+ CDisplayRendering render(dOpts, filterOptions);
+ CDisplayRendering::KeyTree tree;
+ CDisplayRendering::KeyTreeItem::Settings itemSettings;
+
+ // the number of levels which should be display together, 1 means display no entries together
+ int displayLevel = book->config( CSwordModuleInfo::DisplayLevel ).toInt();
+
+ boost::scoped_ptr<CSwordTreeKey> key (
+ dynamic_cast<CSwordTreeKey*>( CSwordKey::createInstance(book) )
+ );
+ key->key(keyName); //set the key to position we'd like to get
+
+ const unsigned long offset = key->getOffset();
+
+ // standard of DisplayLevel, display nothing together
+ // if the current key is the root entry don't display anything together!
+
+ if ((displayLevel <= 1) || (key->key().isEmpty() || (key->key() == "/") )) {
+ tree.append( new CDisplayRendering::KeyTreeItem( key->key(), modules, itemSettings ) );
+
+ const QString renderedText = render.renderKeyTree(tree);
+ key->setOffset( offset );
+ return renderedText;
+ };
+
+ /**
+ * Check whether displaying displayLevel levels together is possible.
+ * For this count the childs and parents
+ * of the required position
+ */
+
+ int possibleLevels = 1; //we start with the default value of displayLevel, which means no entries together
+
+ while( key->parent() && (key->key() != "/") && !key->key().isEmpty() ) {//add parents
+ ++possibleLevels;
+ };
+
+ // key->key(keyName); //set the key to the start position
+
+ key->setOffset( offset );
+
+ while( key->firstChild( )) { //add childs
+ ++possibleLevels;
+ };
+
+ if (possibleLevels < displayLevel) { //too few levels available!
+ //display current level, we could also decide to display the available levels together
+ tree.append( new CDisplayRendering::KeyTreeItem( key->key(), modules, itemSettings ) );
+
+ const QString renderedText = render.renderKeyTree(tree);
+ key->setOffset( offset );
+ return renderedText;
+ };
+
+ if ((displayLevel > 2) && (displayLevel == possibleLevels)) { //fix not to diplay the whole module
+ --displayLevel;
+ }
+
+ // at this point we're sure that we can display the required levels toogether
+ // at the moment we're at the lowest level, so we only have to go up!
+ for (int currentLevel = 1; currentLevel < displayLevel; ++currentLevel) { //we start again with 1 == standard of displayLevel
+
+ if ( !key->parent() ) { //something went wrong although we checked before! Be safe and return entry's text
+ tree.append( new CDisplayRendering::KeyTreeItem( key->key(), modules, itemSettings ) );
+
+ const QString renderedText = render.renderKeyTree(tree);
+ key->setOffset( offset );
+ return renderedText;
+ };
+ };
+
+ // no we can display all sub levels together! We checked before that this is possible!
+ itemSettings.highlight = (key->key() == keyName);
+
+ tree.append( new CDisplayRendering::KeyTreeItem( key->key(), modules, itemSettings ) );
+
+ //const bool hasToplevelText = !key->strippedText().isEmpty();
+ key->firstChild(); //go to the first sibling on the same level
+
+ setupRenderTree(key.get(), &tree, keyName);
+
+ const QString renderedText = render.renderKeyTree(tree);
+
+ key->setOffset( offset ); //restore key
+
+ return renderedText;
+}
+
+void Rendering::CBookDisplay::setupRenderTree(CSwordTreeKey * swordTree, CTextRendering::KeyTree * renderTree, const QString& highlightKey) {
+
+ const QString key = swordTree->key();
+ const unsigned long offset = swordTree->getOffset();
+
+ CTextRendering::KeyTreeItem::Settings settings;
+ settings.highlight = (key == highlightKey);
+
+ CTextRendering::KeyTreeItem* item = new CTextRendering::KeyTreeItem(key, swordTree->module(0), settings );
+ renderTree->append( item );
+
+ if (swordTree->hasChildren()) { //print tree for the child items
+ swordTree->firstChild();
+ setupRenderTree(swordTree, item->childList(), highlightKey);
+ swordTree->setOffset( offset ); //go back where we came from
+ }
+
+ if (swordTree->nextSibling()) { //print tree for next entry on the same depth
+ setupRenderTree(swordTree, renderTree, highlightKey);
+ swordTree->setOffset( offset ); //return to the value we had at the beginning of this block!
+ }
+}
diff --git a/src/backend/rendering/cbookdisplay.h b/src/backend/rendering/cbookdisplay.h
new file mode 100644
index 0000000..6f0b031
--- /dev/null
+++ b/src/backend/rendering/cbookdisplay.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 RENDERINGCBOOKDISPLAY_H
+#define RENDERINGCBOOKDISPLAY_H
+
+#include "centrydisplay.h"
+#include "ctextrendering.h"
+//TODO: It would be sufficient to forward declare CTextRendering and CTextRendering::KeyTree
+//but I don't know how :(
+
+class CSwordTreeKey;
+
+namespace Rendering {
+
+ /**
+ * A CEntryDisplay implementation which works on tree-based GenBook modules
+ * of Sword.
+ * @short CEntryDisplay implementation for GenBook modules,
+ * @author The BibleTime team
+ */
+
+class CBookDisplay : public CEntryDisplay {
+public: // Public methods
+ virtual ~CBookDisplay() {}
+
+ /**
+ * Returns the rendered text using the modules in the list and using the key parameter.
+ * The displayoptions and filter options are used, too.
+ */
+ virtual const QString text( const QList<CSwordModuleInfo*>& modules, const QString& key, const CSwordBackend::DisplayOptions displayOptions, const CSwordBackend::FilterOptions filterOptions);
+
+protected:
+ void setupRenderTree(CSwordTreeKey* swordTree, CTextRendering::KeyTree* renderTree, const QString& highlightKey);
+};
+
+}
+
+#endif
diff --git a/src/backend/rendering/cchapterdisplay.cpp b/src/backend/rendering/cchapterdisplay.cpp
new file mode 100644
index 0000000..921ed78
--- /dev/null
+++ b/src/backend/rendering/cchapterdisplay.cpp
@@ -0,0 +1,59 @@
+/*********
+*
+* 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.
+*
+**********/
+
+//Backend
+#include "cchapterdisplay.h"
+#include "cdisplayrendering.h"
+#include "backend/keys/cswordversekey.h"
+#include "backend/drivers/cswordbiblemoduleinfo.h"
+
+const QString Rendering::CChapterDisplay::text( const QList<CSwordModuleInfo*>& modules, const QString& keyName, const CSwordBackend::DisplayOptions displayOptions, const CSwordBackend::FilterOptions filterOptions ) {
+ Q_ASSERT( modules.count() >= 1 );
+ Q_ASSERT( !keyName.isEmpty() );
+
+ CSwordModuleInfo* module = modules.first();
+
+ if (modules.count() == 1) module->module()->setSkipConsecutiveLinks( true ); //skip empty, linked verses
+
+ CTextRendering::KeyTreeItem::Settings settings;
+ settings.keyRenderingFace =
+ displayOptions.verseNumbers
+ ? CTextRendering::KeyTreeItem::Settings::SimpleKey
+ : CTextRendering::KeyTreeItem::Settings::NoKey;
+
+ QString startKey = keyName;
+ QString endKey = startKey;
+
+ //check whether there's an intro we have to include
+ Q_ASSERT((module->type() == CSwordModuleInfo::Bible));
+
+ if (module->type() == CSwordModuleInfo::Bible) {
+ ((sword::VerseKey*)(module->module()->getKey()))->Headings(1); //HACK: enable headings for VerseKeys
+
+ CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(module);
+ Q_ASSERT(bible);
+
+ CSwordVerseKey k1(module);
+ k1.Headings(1);
+ k1.key(keyName);
+
+ if (k1.Chapter() == 1) k1.Chapter(0); //Chapter 1, start with 0:0, otherwise X:0
+
+ k1.Verse(0);
+
+ startKey = k1.key();
+
+ if (k1.Chapter() == 0) k1.Chapter(1);
+ k1.Verse(bible->verseCount(k1.book(), k1.Chapter()));
+ endKey = k1.key();
+ }
+
+ CDisplayRendering render(displayOptions, filterOptions);
+ return render.renderKeyRange( startKey, endKey, modules, keyName, settings );
+}
diff --git a/src/backend/rendering/cchapterdisplay.h b/src/backend/rendering/cchapterdisplay.h
new file mode 100644
index 0000000..cf00adf
--- /dev/null
+++ b/src/backend/rendering/cchapterdisplay.h
@@ -0,0 +1,37 @@
+/*********
+*
+* 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 RENDERINGCCHAPTERDISPLAY_H
+#define RENDERINGCCHAPTERDISPLAY_H
+
+#include "centrydisplay.h"
+
+namespace Rendering {
+
+/** Chapter rendering.
+* A CEntryDisplay implementation mde for Bibles to display whole chapters
+* at once.
+* @author The BibleTime team
+*/
+
+class CChapterDisplay : public CEntryDisplay {
+
+public: // Public methods
+ virtual ~CChapterDisplay() {}
+
+ /**
+ * Returns the rendered text using the modules in the list and using the key parameter.
+ * The displayoptions and filter options are used, too.
+ */
+ virtual const QString text( const QList<CSwordModuleInfo*>& modules, const QString& key, const CSwordBackend::DisplayOptions displayOptions, const CSwordBackend::FilterOptions filterOptions);
+};
+
+}
+
+#endif
diff --git a/src/backend/rendering/cdisplayrendering.cpp b/src/backend/rendering/cdisplayrendering.cpp
new file mode 100644
index 0000000..8c6c525
--- /dev/null
+++ b/src/backend/rendering/cdisplayrendering.cpp
@@ -0,0 +1,158 @@
+/*********
+*
+* 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 "cdisplayrendering.h"
+
+#include "backend/managers/cdisplaytemplatemgr.h"
+#include "backend/managers/creferencemanager.h"
+#include "backend/keys/cswordkey.h"
+#include "backend/keys/cswordversekey.h"
+
+#include "util/cpointers.h"
+
+//Qt
+#include <QString>
+#include <QRegExp>
+
+namespace Rendering {
+
+ CDisplayRendering::CDisplayRendering(CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions)
+: CHTMLExportRendering(CHTMLExportRendering::Settings(true), displayOptions, filterOptions) {}
+
+ const QString CDisplayRendering::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
+ vk.Headings(true);
+
+ if (isBible) {
+ vk.key(item.key());
+ }
+
+ if (isBible && (vk.Verse() == 0)) {
+ return QString::null; //Warning: return already here
+ }
+
+ 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()) {
+ return QString("<a name=\"").append(keyToHTMLAnchor(item.key())).append("\" />");
+ }
+ else {
+ return QString("<a name=\"").append(keyToHTMLAnchor(item.key())).append("\" ")
+ .append("href=\"")
+ .append(CReferenceManager::encodeHyperlink(
+ module->name(), item.key(), CReferenceManager::typeFromModule(module->type()))
+ )
+ .append("\">").append(linkText).append("</a>\n");
+ }
+
+ return QString::null;
+ }
+
+ const QString CDisplayRendering::keyToHTMLAnchor(const QString& key) {
+ QString ret = key;
+ ret = ret.trimmed().remove(QRegExp("[^A-Za-z0-9]+"));
+ ret = ret.remove(QRegExp("^\\d+|"));
+
+ return ret;
+ }
+
+ const QString CDisplayRendering::finishText( const QString& oldText, KeyTree& tree ) {
+ QList<CSwordModuleInfo*> modules = collectModules(&tree);
+ qDebug("CDisplayRendering::finishText");
+
+ //marking words is very slow, we have to find a better solution
+
+ /*
+ //mark all words by spans
+
+ QString text = oldText;
+
+ QRegExp re("(\\b)(?=\\w)"); //word begin marker
+ int pos = text.find(re, 0);
+
+ while (pos != -1) { //word begin found
+ //qWarning("found word at %i in %i", pos, text.length());
+ int endPos = pos + 1;
+ if (!CToolClass::inHTMLTag(pos+1, text)) { //the re has a positive look ahead which matches one char before the word start
+ //qWarning("matched %s", text.mid(pos+1, 4).latin1());
+
+ //find end of word and put a marker around it
+ endPos = text.find(QRegExp("\\b|[,.:]"), pos+1);
+ if ((endPos != -1) && !CToolClass::inHTMLTag(endPos, text) && (endPos - pos >= 3)) { //reuire wordslonger than 3 chars
+ text.insert(endPos, "</span>");
+ text.insert(pos, "<span class=\"word\">");
+
+ endPos += 26;
+ }
+ }
+ pos = text.find(re, endPos);
+ }
+ */
+ const CLanguageMgr::Language* const lang =
+ (modules.count() >= 1)
+ ? modules.first()->language()
+ : CPointers::languageMgr()->defaultLanguage();
+
+ CDisplayTemplateMgr* tMgr = CPointers::displayTemplateManager();
+
+ //Q_ASSERT(modules.count() >= 1);
+
+ CDisplayTemplateMgr::Settings settings;
+ settings.modules = modules;
+ settings.langAbbrev = ((modules.count() == 1) && lang->isValid()) ? lang->abbrev() : QString::null;
+
+ if (modules.count() == 1)
+ settings.pageDirection = (modules.first()->textDirection() == CSwordModuleInfo::LeftToRight) ? "ltr" : "rtl";
+ else
+ settings.pageDirection = QString::null;
+
+ return tMgr->fillTemplate(CBTConfig::get(CBTConfig::displayStyle), oldText, settings);
+ }
+}
diff --git a/src/backend/rendering/cdisplayrendering.h b/src/backend/rendering/cdisplayrendering.h
new file mode 100644
index 0000000..9c4451b
--- /dev/null
+++ b/src/backend/rendering/cdisplayrendering.h
@@ -0,0 +1,38 @@
+/*********
+*
+* 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 RENDERINGCDISPLAYRENDERING_H
+#define RENDERINGCDISPLAYRENDERING_H
+
+#include "chtmlexportrendering.h"
+
+namespace Rendering {
+
+/** HTML rendering for the text display widgets.
+ * @short Rendering for the html display widget.
+ * @author The BibleTime team
+ */
+
+class CDisplayRendering : public CHTMLExportRendering {
+public:
+ static const QString keyToHTMLAnchor(const QString& key);
+
+ CDisplayRendering(
+ CSwordBackend::DisplayOptions displayOptions = CBTConfig::getDisplayOptionDefaults(),
+ CSwordBackend::FilterOptions filterOptions = CBTConfig::getFilterOptionDefaults()
+ );
+
+protected:
+ virtual const QString entryLink( const KeyTreeItem& item, CSwordModuleInfo* const module );
+ virtual const QString finishText( const QString&, KeyTree& tree );
+};
+
+}
+
+#endif
diff --git a/src/backend/rendering/centrydisplay.cpp b/src/backend/rendering/centrydisplay.cpp
new file mode 100644
index 0000000..7a4626c
--- /dev/null
+++ b/src/backend/rendering/centrydisplay.cpp
@@ -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.
+*
+**********/
+
+//BibleTime includes
+#include "centrydisplay.h"
+
+#include "backend/keys/cswordkey.h"
+#include "backend/keys/cswordversekey.h"
+#include "backend/drivers/cswordbookmoduleinfo.h"
+#include "backend/managers/creferencemanager.h"
+#include "backend/managers/cdisplaytemplatemgr.h"
+#include "cdisplayrendering.h"
+
+#include "backend/config/cbtconfig.h"
+#include <boost/scoped_ptr.hpp>
+
+//Qt includes
+#include <QApplication>
+#include <QRegExp>
+
+using namespace Rendering;
+
+/** Returns the rendered text using the modules in the list and using the key parameter.
+ * The displayoptions and filter options are used, too.
+ */
+const QString CEntryDisplay::text( const QList<CSwordModuleInfo*>& modules, const QString& keyName, const CSwordBackend::DisplayOptions displayOptions, const CSwordBackend::FilterOptions filterOptions ) {
+ CDisplayRendering render(displayOptions, filterOptions);
+
+ //no highlighted key and no extra key link in the text
+ CTextRendering::KeyTreeItem::Settings normal_settings(false, CTextRendering::KeyTreeItem::Settings::CompleteShort);
+ CSwordModuleInfo* module = modules.first();
+ QString result;
+
+ //in Bibles and Commentaries we need to check if 0:0 and X:0 contain something
+ if (module->type() == CSwordModuleInfo::Bible || module->type() == CSwordModuleInfo::Commentary) {
+ ((sword::VerseKey*)(module->module()->getKey()))->Headings(1); //HACK: enable headings for VerseKeys
+
+ CSwordVerseKey k1(module);
+ k1.Headings(1);
+ k1.key(keyName);
+
+ // don't print the key
+ CTextRendering::KeyTreeItem::Settings preverse_settings(false, CTextRendering::KeyTreeItem::Settings::NoKey);
+
+ if (k1.Verse() == 1){ //X:1, prepend X:0
+ if (k1.Chapter() == 1){ //1:1, also prepend 0:0 before that
+ k1.Chapter(0);
+ k1.Verse(0);
+ if ( k1.rawText().length() > 0 ) result.append( render.renderSingleKey(k1.key(), modules, preverse_settings ) );
+ k1.Chapter(1);
+ }
+ k1.Verse(0);
+ if ( k1.rawText().length() > 0 ) result.append( render.renderSingleKey(k1.key(), modules, preverse_settings ) );
+ }
+ }
+ return result.append( render.renderSingleKey(keyName, modules, normal_settings) );
+}
diff --git a/src/backend/rendering/centrydisplay.h b/src/backend/rendering/centrydisplay.h
new file mode 100644
index 0000000..96f0dba
--- /dev/null
+++ b/src/backend/rendering/centrydisplay.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 CENTRYDISPLAY_H
+#define CENTRYDISPLAY_H
+
+//BibleTime
+//#include "ctextrendering.h"
+class CSwordModuleInfo;
+#include "backend/managers/cswordbackend.h"
+
+#include "util/cpointers.h"
+
+//Sword
+#include <swdisp.h>
+
+//Qt
+#include <QString>
+
+class CSwordModuleInfo;
+
+namespace Rendering {
+
+/**
+* The reimplementation of SWDisplay to fit our needs.
+* @short Display implementation
+* @author The BibleTime team
+*/
+
+class CEntryDisplay : public sword::SWDisplay, public CPointers {
+
+public:
+ virtual ~CEntryDisplay() {}
+
+ /**
+ * Returns the rendered text using the modules in the list and using the key parameter.
+ * The displayoptions and filter options are used, too.
+ */
+ virtual const QString text( const QList<CSwordModuleInfo*>& modules, const QString& key, const CSwordBackend::DisplayOptions displayOptions, const CSwordBackend::FilterOptions filterOptions);
+};
+
+
+}
+
+#endif
diff --git a/src/backend/rendering/chtmlexportrendering.cpp b/src/backend/rendering/chtmlexportrendering.cpp
new file mode 100644
index 0000000..38a83d3
--- /dev/null
+++ b/src/backend/rendering/chtmlexportrendering.cpp
@@ -0,0 +1,234 @@
+/*********
+*
+* 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 "chtmlexportrendering.h"
+
+#include "backend/managers/cdisplaytemplatemgr.h"
+#include "backend/managers/clanguagemgr.h"
+#include "backend/keys/cswordkey.h"
+#include "backend/keys/cswordversekey.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+
+#include "util/cpointers.h"
+#include <boost/scoped_ptr.hpp>
+
+#include <iostream>
+
+namespace {
+
+/*
+ * Helper function to dump a verse with all its enty attributes
+ */
+
+void dumpEntryAttributes(sword::SWModule *module) {
+ std::cout << "Attributes for key: " << module->getKeyText() << std::endl;
+ sword::AttributeTypeList::iterator i1;
+ sword::AttributeList::iterator i2;
+ sword::AttributeValue::iterator i3;
+ for (i1 = module->getEntryAttributes().begin(); i1 != module->getEntryAttributes().end(); i1++) {
+ std::cout << "[ " << i1->first << " ]\n";
+ for (i2 = i1->second.begin(); i2 != i1->second.end(); i2++) {
+ std::cout << "\t[ " << i2->first << " ]\n";
+ for (i3 = i2->second.begin(); i3 != i2->second.end(); i3++) {
+ std::cout << "\t\t" << i3->first << " = " << i3->second << "\n";
+ }
+ }
+ }
+ std::cout << std::endl;
+}
+
+}
+
+namespace Rendering {
+
+ CHTMLExportRendering::CHTMLExportRendering(const CHTMLExportRendering::Settings& settings, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions)
+: m_displayOptions(displayOptions),
+ m_filterOptions(filterOptions),
+ m_settings(settings) {}
+
+ CHTMLExportRendering::~CHTMLExportRendering() {}
+
+ const QString CHTMLExportRendering::renderEntry( const KeyTreeItem& i, CSwordKey* k) {
+
+ if (i.hasAlternativeContent()) {
+ QString ret = QString(i.settings().highlight ? "<div class=\"currententry\">" : "<div class=\"entry\">");
+ ret.append(i.getAlternativeContent());
+
+ // Q_ASSERT(i.hasChildItems());
+
+ if (!i.childList()->isEmpty()) {
+ KeyTree * const tree = i.childList();
+
+ const QList<CSwordModuleInfo*> modules = collectModules(tree);
+
+ if (modules.count() == 1) { //insert the direction into the sorrounding div
+ ret.insert( 5, QString("dir=\"%1\" ").arg((modules.first()->textDirection() == CSwordModuleInfo::LeftToRight) ? "ltr" : "rtl" ));
+ }
+
+ foreach ( KeyTreeItem* c, (*tree) ) {
+ ret.append( renderEntry( *c ) );
+ }
+ }
+
+ ret.append("</div>");
+ return ret; //WARNING: Return already here!
+ }
+
+
+ const QList<CSwordModuleInfo*>& modules( i.modules() );
+ if (modules.count() == 0) {
+ return QString(""); //no module present for rendering
+ }
+
+ boost::scoped_ptr<CSwordKey> scoped_key( !k ? CSwordKey::createInstance(modules.first()) : 0 );
+ CSwordKey* key = k ? k : scoped_key.get();
+ Q_ASSERT(key);
+
+ CSwordVerseKey* myVK = dynamic_cast<CSwordVerseKey*>(key);
+
+ if ( myVK ) myVK->Headings(1);
+
+ QString renderedText( (modules.count() > 1) ? "\n\t\t<tr>\n" : "\n" );
+ // Only insert the table stuff if we are displaying parallel.
+
+ //declarations out of the loop for optimization
+ QString entry;
+ QString keyText;
+ bool isRTL;
+ QString preverseHeading;
+ QString langAttr;
+ QString key_renderedText;
+
+ QList<CSwordModuleInfo*>::const_iterator end_modItr = modules.end();
+
+ for (QList<CSwordModuleInfo*>::const_iterator mod_Itr(modules.begin()); mod_Itr != end_modItr; ++mod_Itr) {
+ key->module(*mod_Itr);
+ key->key( i.key() );
+
+ keyText = key->key();
+ isRTL = ((*mod_Itr)->textDirection() == CSwordModuleInfo::RightToLeft);
+ entry = QString::null;
+
+ if ((*mod_Itr)->language()->isValid()) {
+ langAttr = QString("xml:lang=\"")
+ .append((*mod_Itr)->language()->abbrev())
+ .append("\" lang=\"")
+ .append((*mod_Itr)->language()->abbrev())
+ .append("\"");
+ }
+ else {
+ langAttr = QString("xml:lang=\"")
+ .append((*mod_Itr)->module()->Lang())
+ .append("\" lang=\"")
+ .append((*mod_Itr)->module()->Lang())
+ .append("\"");
+ }
+
+ key_renderedText = key->renderedText();
+
+ if (m_filterOptions.headings) {
+ (*mod_Itr)->module()->RenderText();
+ sword::AttributeValue::const_iterator it =
+ (*mod_Itr)->module()->getEntryAttributes()["Heading"]["Preverse"].begin();
+ const sword::AttributeValue::const_iterator end =
+ (*mod_Itr)->module()->getEntryAttributes()["Heading"]["Preverse"].end();
+
+ for (; it != end; ++it) {
+ preverseHeading = QString::fromUtf8(it->second.c_str());
+ //TODO: Take care of the heading type!
+ if (!preverseHeading.isEmpty()) {
+ entry.append("<div ")
+ .append(langAttr)
+ .append(" class=\"sectiontitle\">")
+ .append(preverseHeading)
+ .append("</div>");
+ }
+ }
+ }
+
+ entry.append(m_displayOptions.lineBreaks ? "<div " : "<div style=\"display: inline;\" ");
+
+ if (modules.count() == 1) { //insert only the class if we're not in a td
+ entry.append( i.settings().highlight ? "class=\"currententry\" " : "class=\"entry\" " );
+ }
+
+ entry.append(langAttr).append(isRTL ? " dir=\"rtl\"" : " dir=\"ltr\"").append(">");
+
+ //keys should normally be left-to-right, but this doesn't apply in all cases
+ entry.append("<span class=\"entryname\" dir=\"ltr\">").append(entryLink(i, *mod_Itr)).append("</span>");
+
+ if (m_settings.addText) {
+ //entry.append( QString::fromLatin1("<span %1>%2</span>").arg(langAttr).arg(key_renderedText) );
+ entry.append( key_renderedText );
+ }
+
+ if (!i.childList()->isEmpty()) {
+ KeyTree* tree(i.childList());
+
+ foreach (KeyTreeItem* c, (*tree)) {
+ entry.append( renderEntry(*c) );
+ }
+ }
+
+ entry.append("</div>");
+
+ if (modules.count() == 1) {
+ renderedText.append( "\t\t" ).append( entry ).append("\n");
+ }
+ else {
+ renderedText.append("\t\t<td class=\"")
+ .append(i.settings().highlight ? "currententry" : "entry")
+ .append("\" ")
+ .append(langAttr)
+ .append(" dir=\"")
+ .append(isRTL ? "rtl" : "ltr")
+ .append("\">\n")
+ .append( "\t\t\t" ).append( entry ).append("\n")
+ .append("\t\t</td>\n");
+ }
+ }
+
+ if (modules.count() > 1) {
+ renderedText.append("\t\t</tr>\n");
+ }
+
+ // qDebug("CHTMLExportRendering: %s", renderedText.latin1());
+ return renderedText;
+}
+
+void CHTMLExportRendering::initRendering() {
+ //CPointers::backend()->setDisplayOptions( m_displayOptions );
+ CPointers::backend()->setFilterOptions( m_filterOptions );
+}
+
+const QString CHTMLExportRendering::finishText( const QString& text, KeyTree& tree ) {
+ const QList<CSwordModuleInfo*> modules = collectModules(&tree);
+
+ const CLanguageMgr::Language* const lang = modules.first()->language();
+
+ CDisplayTemplateMgr* tMgr = CPointers::displayTemplateManager();
+ CDisplayTemplateMgr::Settings settings;
+ settings.modules = modules;
+ settings.langAbbrev = ((modules.count() == 1) && lang->isValid()) ? lang->abbrev() : "unknown";
+ if (modules.count() == 1)
+ settings.pageDirection = ((modules.first()->textDirection() == CSwordModuleInfo::LeftToRight) ? "ltr" : "rtl");
+ else
+ settings.pageDirection = QString::null;
+
+ return tMgr->fillTemplate(QObject::tr("Export"), text, settings);
+}
+
+/*!
+ \fn CHTMLExportRendering::entryLink( KeyTreeItem& item )
+ */
+const QString CHTMLExportRendering::entryLink( const KeyTreeItem& item, CSwordModuleInfo* ) {
+ return item.key();
+}
+
+}//end of namespace "Rendering"
diff --git a/src/backend/rendering/chtmlexportrendering.h b/src/backend/rendering/chtmlexportrendering.h
new file mode 100644
index 0000000..6a8153e
--- /dev/null
+++ b/src/backend/rendering/chtmlexportrendering.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 RENDERINGCHTMLEXPORTRENDERING_H
+#define RENDERINGCHTMLEXPORTRENDERING_H
+
+#include "backend/managers/cswordbackend.h"
+#include "ctextrendering.h"
+
+#include "backend/config/cbtconfig.h"
+
+namespace Rendering {
+
+ /**
+ * This CTextRenerding implementation
+ * creates HTML specially made for export as HTML files.
+ * @short HTML rendering for export.
+ * @author The BibleTime team
+ */
+
+class CHTMLExportRendering : public CTextRendering {
+
+public:
+ struct Settings {
+ Settings(const bool text = true) {
+ addText = text;
+ };
+
+ bool addText;
+ };
+
+ CHTMLExportRendering(
+ const Settings& settings,
+ CSwordBackend::DisplayOptions displayOptions = CBTConfig::getDisplayOptionDefaults(),
+ CSwordBackend::FilterOptions filterOptions = CBTConfig::getFilterOptionDefaults()
+ );
+ virtual ~CHTMLExportRendering();
+
+protected:
+ virtual const QString renderEntry( const KeyTreeItem&, CSwordKey* = 0 );
+ virtual const QString finishText( const QString&, KeyTree& tree );
+ virtual const QString entryLink( const KeyTreeItem& item, CSwordModuleInfo* module );
+ virtual void initRendering();
+
+ CSwordBackend::DisplayOptions m_displayOptions;
+ CSwordBackend::FilterOptions m_filterOptions;
+ Settings m_settings;
+};
+
+}
+
+#endif
diff --git a/src/backend/rendering/cplaintextexportrendering.cpp b/src/backend/rendering/cplaintextexportrendering.cpp
new file mode 100644
index 0000000..d99cff3
--- /dev/null
+++ b/src/backend/rendering/cplaintextexportrendering.cpp
@@ -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.
+*
+**********/
+
+//Backend includes
+#include "cplaintextexportrendering.h"
+#include "backend/keys/cswordkey.h"
+
+//Util
+#include <boost/scoped_ptr.hpp>
+
+namespace Rendering {
+
+CPlainTextExportRendering::CPlainTextExportRendering(const CPlainTextExportRendering::Settings& settings, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions)
+ : CHTMLExportRendering(settings, displayOptions, filterOptions) {}
+
+CPlainTextExportRendering::~CPlainTextExportRendering() {}
+
+const QString CPlainTextExportRendering::renderEntry( const KeyTreeItem& i, CSwordKey* ) {
+ if (!m_settings.addText) {
+ return QString(i.key()).append("\n");
+ }
+
+ QList<CSwordModuleInfo*> modules = i.modules();
+ boost::scoped_ptr<CSwordKey> key( CSwordKey::createInstance(modules.first()) );
+ QString renderedText = QString(i.key()).append(":\n");
+
+ QString entry;
+ // for (CSwordModuleInfo* m = modules.first(); m; m = modules.next()) {
+ QList<CSwordModuleInfo*>::iterator end_it = modules.end();
+
+ for (QList<CSwordModuleInfo*>::iterator it(modules.begin()); it != end_it; ++it) {
+ key->module(*it);
+ key->key( i.key() );
+
+ //ToDo: Check this code
+ entry.append(key->strippedText()).append("\n");
+ renderedText.append( entry );
+ }
+
+ return renderedText;
+}
+
+const QString CPlainTextExportRendering::finishText( const QString& oldText, KeyTree& ) {
+ return oldText;
+}
+
+}
diff --git a/src/backend/rendering/cplaintextexportrendering.h b/src/backend/rendering/cplaintextexportrendering.h
new file mode 100644
index 0000000..9ec388b
--- /dev/null
+++ b/src/backend/rendering/cplaintextexportrendering.h
@@ -0,0 +1,40 @@
+/*********
+*
+* 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 RENDERINGCPLAINTEXTEXPORTRENDERING_H
+#define RENDERINGCPLAINTEXTEXPORTRENDERING_H
+
+#include "chtmlexportrendering.h"
+
+namespace Rendering {
+
+ /**
+ * This implementation can be used to export content as plain text.
+ * @short Text rendering as plain text.
+ * @author The BibleTime team
+ */
+
+class CPlainTextExportRendering : public CHTMLExportRendering {
+
+public:
+ CPlainTextExportRendering(
+ const Settings& settings,
+ CSwordBackend::DisplayOptions displayOptions = CBTConfig::getDisplayOptionDefaults(),
+ CSwordBackend::FilterOptions filterOptions = CBTConfig::getFilterOptionDefaults()
+ );
+ virtual ~CPlainTextExportRendering();
+
+protected:
+ virtual const QString renderEntry( const KeyTreeItem&, CSwordKey* = 0 );
+ virtual const QString finishText( const QString&, KeyTree& tree );
+};
+
+}
+
+#endif
diff --git a/src/backend/rendering/ctextrendering.cpp b/src/backend/rendering/ctextrendering.cpp
new file mode 100644
index 0000000..c7ac0bd
--- /dev/null
+++ b/src/backend/rendering/ctextrendering.cpp
@@ -0,0 +1,263 @@
+/*********
+*
+* 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 "ctextrendering.h"
+
+//BibleTime
+#include "backend/keys/cswordkey.h"
+#include "backend/keys/cswordversekey.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/cdisplaytemplatemgr.h"
+#include "backend/managers/creferencemanager.h"
+
+#include <boost/scoped_ptr.hpp>
+#include "util/ctoolclass.h"
+
+//Sword
+#include <swkey.h>
+
+//Qt
+#include <QRegExp>
+
+
+using namespace Rendering;
+
+CTextRendering::KeyTreeItem::KeyTreeItem(const QString& key, CSwordModuleInfo const * mod, const Settings settings )
+ : m_settings( settings ),
+ m_moduleList(),
+ m_key( key ),
+ m_childList(),
+ m_stopKey( QString::null ),
+ m_alternativeContent( QString::null )
+{
+ m_moduleList.append( const_cast<CSwordModuleInfo*>(mod) ); //BAD CODE
+}
+
+CTextRendering::KeyTreeItem::KeyTreeItem(const QString& content, const Settings settings )
+ : m_settings( settings ),
+ m_moduleList(),
+ m_key( QString::null ),
+ m_childList(),
+ m_stopKey( QString::null ),
+ m_alternativeContent( content )
+{
+}
+
+CTextRendering::KeyTreeItem::KeyTreeItem(const QString& key, const QList<CSwordModuleInfo*>& mods, const Settings settings )
+ : m_settings( settings ),
+ m_moduleList( mods ),
+ m_key( key ),
+ m_childList(),
+ m_stopKey( QString::null ),
+ m_alternativeContent( QString::null )
+{
+}
+
+CTextRendering::KeyTreeItem::KeyTreeItem()
+ : m_settings(),
+ m_moduleList(),
+ m_key(QString::null),
+ m_childList(),
+ m_stopKey(QString::null),
+ m_alternativeContent(QString::null)
+{
+}
+
+CTextRendering::KeyTreeItem::KeyTreeItem(const KeyTreeItem& i)
+ : m_settings( i.m_settings ),
+ m_moduleList( i.m_moduleList ),
+ m_key( i.m_key ),
+ m_childList(),
+ m_stopKey( i.m_stopKey ),
+ m_alternativeContent( i.m_alternativeContent )
+{
+ foreach(KeyTreeItem* item, (*i.childList())){
+ m_childList.append(new KeyTreeItem((*item))); //deep copy
+ }
+
+}
+
+CTextRendering::KeyTreeItem::~KeyTreeItem() {
+ qDeleteAll(m_childList);
+}
+
+CTextRendering::KeyTreeItem::KeyTreeItem(const QString& startKey, const QString& stopKey, CSwordModuleInfo* module, const Settings settings)
+: m_settings( settings ),
+m_moduleList(),
+m_key( startKey ),
+m_childList(),
+m_stopKey( stopKey ),
+m_alternativeContent( QString::null ) {
+ Q_ASSERT(module);
+ m_moduleList.append(module);
+
+ //use the start and stop key to ceate our child items
+
+ if (module->type() == CSwordModuleInfo::Bible) {
+ CSwordVerseKey start(module);
+ start.key(startKey);
+
+ CSwordVerseKey stop(module);
+ stop.key(stopKey);
+
+ if (!m_key.isEmpty() && !m_stopKey.isEmpty()) { //we have a range of keys
+ bool ok = true;
+
+ while (ok && ((start < stop) || (start == stop)) ) { //range
+ m_childList.append(
+ new KeyTreeItem(start.key(), module, KeyTreeItem::Settings(false, settings.keyRenderingFace))
+ );
+
+
+ ok = start.next(CSwordVerseKey::UseVerse);
+ }
+ }
+ else if (m_key.isEmpty()) {
+ m_childList.append( new KeyTreeItem(startKey, module, KeyTreeItem::Settings(false, settings.keyRenderingFace)) );
+ }
+ }
+ else if ((module->type() == CSwordModuleInfo::Lexicon) || (module->type() == CSwordModuleInfo::Commentary) ) {
+ m_childList.append( new KeyTreeItem(startKey, module, KeyTreeItem::Settings(false, KeyTreeItem::Settings::NoKey)) );
+ }
+ else if (module->type() == CSwordModuleInfo::GenericBook) {
+ m_childList.append( new KeyTreeItem(startKey, module, KeyTreeItem::Settings(false, KeyTreeItem::Settings::NoKey)) );
+ }
+
+ //make it into "<simple|range> (modulename)"
+
+ if (startKey == stopKey) {
+ m_alternativeContent = startKey;
+ }
+ else {
+ sword::VerseKey vk(startKey.toUtf8().constData(), stopKey.toUtf8().constData());
+
+ if (vk.LowerBound().Book() != vk.UpperBound().Book()) {
+ m_alternativeContent = QString::fromUtf8(vk.getRangeText());
+ }
+ else if (vk.LowerBound().Chapter() != vk.UpperBound().Chapter()) {
+ m_alternativeContent = QString("%1 - %2:%3")
+ .arg(QString::fromUtf8(vk.LowerBound().getText()))
+ .arg(vk.UpperBound().Chapter())
+ .arg(vk.UpperBound().Verse());
+ }
+ else { //only verses differ (same book, same chapter)
+ m_alternativeContent = QString("%1 - %2")
+ .arg(QString::fromUtf8(vk.LowerBound().getText()))
+ .arg(vk.UpperBound().Verse());
+ }
+ }
+
+ m_alternativeContent.append(" (").append(module->name()).append(")");
+ m_alternativeContent.prepend("<div class=\"rangeheading\" dir=\"ltr\">").append("</div>"); //insert the right tags
+}
+
+const QString& CTextRendering::KeyTreeItem::getAlternativeContent() const {
+ return m_alternativeContent;
+}
+
+const QList<CSwordModuleInfo*> CTextRendering::collectModules(KeyTree* const tree) const {
+ //collect all modules which are available and used by child items
+ QList<CSwordModuleInfo*> modules;
+
+ foreach (KeyTreeItem* c, (*tree)) {
+ Q_ASSERT(c);
+ foreach (CSwordModuleInfo* mod, c->modules()) {
+ if (!modules.contains(mod)) {
+ modules.append(mod);
+ }
+ }
+ }
+ return modules;
+}
+
+const QString CTextRendering::renderKeyTree( KeyTree& tree ) {
+ initRendering();
+
+ QList<CSwordModuleInfo*> modules = collectModules(&tree);
+ QString t;
+
+ //optimization for entries with the same key
+ boost::scoped_ptr<CSwordKey> key(
+ (modules.count() == 1) ? CSwordKey::createInstance(modules.first()) : 0
+ );
+
+ foreach (KeyTreeItem* c, tree) {
+ if (modules.count() == 1) { //this optimizes the rendering, only one key created for all items
+ key->key( c->key() );
+ t.append( renderEntry( *c, key.get()) );
+ }
+ else {
+ t.append( renderEntry( *c ) );
+ }
+ }
+
+ return finishText(t, tree);
+}
+
+const QString CTextRendering::renderKeyRange( const QString& start, const QString& stop, const QList<CSwordModuleInfo*>& modules, const QString& highlightKey, const KeyTreeItem::Settings& keySettings ) {
+
+ CSwordModuleInfo* module = modules.first();
+ //qWarning( "renderKeyRange start %s stop %s \n", start.latin1(), stop.latin1() );
+
+ boost::scoped_ptr<CSwordKey> lowerBound( CSwordKey::createInstance(module) );
+ lowerBound->key(start);
+
+ boost::scoped_ptr<CSwordKey> upperBound( CSwordKey::createInstance(module) );
+ upperBound->key(stop);
+
+ sword::SWKey* sw_start = dynamic_cast<sword::SWKey*>(lowerBound.get());
+ sword::SWKey* sw_stop = dynamic_cast<sword::SWKey*>(upperBound.get());
+
+ Q_ASSERT((*sw_start == *sw_stop) || (*sw_start < *sw_stop));
+
+ if (*sw_start == *sw_stop) { //same key, render single key
+ return renderSingleKey(lowerBound->key(), modules);
+ }
+ else if (*sw_start < *sw_stop) { // Render range
+ KeyTree tree;
+ KeyTreeItem::Settings settings = keySettings;
+
+ CSwordVerseKey* vk_start = dynamic_cast<CSwordVerseKey*>(lowerBound.get());
+ Q_ASSERT(vk_start);
+
+ CSwordVerseKey* vk_stop = dynamic_cast<CSwordVerseKey*>(upperBound.get());
+ Q_ASSERT(vk_stop);
+
+ bool ok = true;
+ while (ok && ((*vk_start < *vk_stop) || (*vk_start == *vk_stop))) {
+ //make sure the key given by highlightKey gets marked as current key
+ settings.highlight = (!highlightKey.isEmpty() ? (vk_start->key() == highlightKey) : false);
+
+ /*TODO: We need to take care of linked verses if we render one or (esp) more modules
+ If the verses 2,3,4,5 are linked to 1, it should be displayed as one entry with the caption 1-5 */
+
+ if (vk_start->Chapter() == 0){ //range was 0:0-1:x, render 0:0 first and jump to 1:0
+ vk_start->Verse(0);
+ tree.append( new KeyTreeItem(vk_start->key(), modules, settings) );
+ vk_start->Chapter(1);
+ vk_start->Verse(0);
+ }
+ tree.append( new KeyTreeItem(vk_start->key(), modules, settings) );
+ ok = vk_start->next(CSwordVerseKey::UseVerse);
+ }
+
+ return renderKeyTree(tree);
+ }
+
+ return QString::null;
+}
+
+const QString CTextRendering::renderSingleKey( const QString& key, const QList<CSwordModuleInfo*>& moduleList, const KeyTreeItem::Settings& settings ) {
+ KeyTree tree;
+ tree.append( new KeyTreeItem(key, moduleList, settings) );
+
+ return renderKeyTree(tree);
+}
+
+
diff --git a/src/backend/rendering/ctextrendering.h b/src/backend/rendering/ctextrendering.h
new file mode 100644
index 0000000..403962b
--- /dev/null
+++ b/src/backend/rendering/ctextrendering.h
@@ -0,0 +1,128 @@
+/*********
+*
+* 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 CTEXTRENDERING_H
+#define CTEXTRENDERING_H
+
+//BT includes
+class CSwordModuleInfo;
+//#include "util/autoptrvector.h"
+
+//QT includes
+#include <QString>
+#include <QList>
+
+class CSwordKey;
+
+/**
+ * CTextRendering is BibleTime's place where the actual rendering takes place.
+ * It provides several methods to convert an abstract tree of items
+ * into a string of html.
+ *
+ * See the implementations @ref CHTMLExportRendering and especially @ref CDisplayRendering.
+ * @short Text rendering based on trees
+ * @author The BibleTime team
+*/
+
+namespace Rendering {
+
+class CTextRendering {
+
+public:
+
+ class KeyTreeItem;
+ typedef QList<KeyTreeItem*> KeyTree;
+
+ class KeyTreeItem {
+ public:
+
+ struct Settings {
+ enum KeyRenderingFace {
+ NoKey, //< means no key shown at all
+ SimpleKey, //< means only versenumber or only lexicon entry name
+ CompleteShort, //< means key like "Gen 1:1"
+ CompleteLong //< means "Genesis 1:1"
+ };
+
+ Settings(const bool highlight = false, KeyRenderingFace keyRendering = SimpleKey) : highlight(highlight), keyRenderingFace(keyRendering) {}
+
+ bool highlight;
+ KeyRenderingFace keyRenderingFace;
+ };
+
+ KeyTreeItem(const QString& key, CSwordModuleInfo const * module, const Settings settings);
+ KeyTreeItem(const QString& key, const QList<CSwordModuleInfo*>& modules, const Settings settings);
+ KeyTreeItem(const QString& startKey, const QString& stopKey, CSwordModuleInfo* module, const Settings settings);
+ KeyTreeItem(const QString& content, const Settings settings);
+ KeyTreeItem(const KeyTreeItem& i);
+
+ virtual ~KeyTreeItem();
+
+ const QString& getAlternativeContent() const;
+ inline void setAlternativeContent(const QString& newContent) {
+ m_alternativeContent = newContent;
+ };
+
+ inline bool hasAlternativeContent() const {
+ return !m_alternativeContent.isNull();
+ };
+
+ inline const QList<CSwordModuleInfo*>& modules() const {
+ return m_moduleList;
+ };
+
+ inline const QString& key() const {
+ return m_key;
+ };
+
+ inline const Settings& settings() const {
+ return m_settings;
+ };
+
+ inline KeyTree* childList() const;
+// inline const bool hasChildItems() const;
+
+ protected:
+ KeyTreeItem();
+
+ Settings m_settings;
+ QList<CSwordModuleInfo*> m_moduleList;
+ QString m_key;
+ mutable KeyTree m_childList;
+
+ QString m_stopKey;
+ QString m_alternativeContent;
+ };
+
+ virtual ~CTextRendering() {}
+
+ const QString renderKeyTree( KeyTree& );
+
+ const QString renderKeyRange( const QString& start, const QString& stop, const QList<CSwordModuleInfo*>& modules, const QString& hightlightKey = QString::null, const KeyTreeItem::Settings& settings = KeyTreeItem::Settings() );
+
+ const QString renderSingleKey( const QString& key, const QList<CSwordModuleInfo*>&, const KeyTreeItem::Settings& settings = KeyTreeItem::Settings() );
+
+protected:
+ const QList<CSwordModuleInfo*> collectModules(KeyTree* const tree) const;
+ virtual const QString renderEntry( const KeyTreeItem&, CSwordKey* = 0 ) = 0;
+ virtual const QString finishText( const QString&, KeyTree& tree ) = 0;
+ virtual void initRendering() = 0;
+};
+
+inline CTextRendering::KeyTree* CTextRendering::KeyTreeItem::childList() const{
+ return &m_childList;
+}
+//
+//inline const bool CTextRendering::KeyTreeItem::hasChildItems() const {
+// return !m_childList.isEmpty();
+//}
+
+}
+
+#endif
diff --git a/src/bibletime.cpp b/src/bibletime.cpp
new file mode 100644
index 0000000..c4510f6
--- /dev/null
+++ b/src/bibletime.cpp
@@ -0,0 +1,314 @@
+/*********
+*
+* 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 "bibletime.h"
+
+#include "frontend/cmdiarea.h"
+#include "frontend/mainindex/cmainindex.h"
+#include "frontend/mainindex/bookshelf/cbookshelfindex.h"
+#include "frontend/displaywindow/cdisplaywindow.h"
+#include "frontend/displaywindow/cdisplaywindowfactory.h"
+#include "frontend/displaywindow/creadwindow.h"
+#include "frontend/displaywindow/cwritewindow.h"
+#include "frontend/keychooser/ckeychooser.h"
+#include "backend/config/cbtconfig.h"
+
+#include "util/ctoolclass.h"
+#include "util/cpointers.h"
+#include "util/directoryutil.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/drivers/cswordbiblemoduleinfo.h"
+#include "backend/drivers/cswordcommentarymoduleinfo.h"
+#include "backend/drivers/cswordlexiconmoduleinfo.h"
+#include "backend/drivers/cswordbookmoduleinfo.h"
+#include "backend/keys/cswordversekey.h"
+#include "backend/keys/cswordldkey.h"
+
+//Qt includes
+#include <QSplitter>
+#include <QDebug>
+#include <QAction>
+#include <QApplication>
+#include <QMdiSubWindow>
+#include <QCloseEvent>
+#include <QSplashScreen>
+
+#include <cstdlib>
+#include <ctime>
+
+using namespace Profile;
+
+BibleTime::BibleTime() :
+ QMainWindow(0),
+ m_dock0(0),
+ m_dock1(0),
+ m_dock2(0),
+ m_initialized(false),
+ m_moduleList(0),
+ m_currentProfile(0),
+ m_mdi(0),
+ m_profileMgr()
+{
+ QPixmap pm;
+ if ( !pm.load( util::filesystem::DirectoryUtil::getPicsDir().canonicalPath().append( "/startuplogo.png")) )
+ {
+ qWarning("Can't load startuplogo! Check your installation.");
+ }
+ QSplashScreen splash(pm);
+ QString splashHtml("<div style='background:transparent;color:white;font-weight:bold'>%1</div>");
+ if (CBTConfig::get(CBTConfig::logo))
+ {
+ splash.show();
+ }
+ splash.showMessage(splashHtml.arg(tr("Initializing the SWORD engine...")), Qt::AlignCenter);
+ initBackends();
+ splash.showMessage(splashHtml.arg(tr("Creating BibleTime's user interface...")), Qt::AlignCenter);
+ initView();
+ splash.showMessage(splashHtml.arg(tr("Initializing menu- and toolbars...")), Qt::AlignCenter);
+ initActions();
+ initConnections();
+ readSettings();
+ setPlainCaption(QString());
+}
+
+BibleTime::~BibleTime()
+{
+ // delete m_dcopInterface;
+ // The backend is deleted by the BibleTimeApp instance
+}
+
+/** Saves the properties of BibleTime to the application wide configfile */
+void BibleTime::saveSettings()
+{
+ //TODO: how to write settings?
+ //accel()->writeSettings(CBTConfig::getConfig());
+
+ CBTConfig::set(CBTConfig::toolbar, m_viewToolbar_action->isChecked());
+
+ // set the default to false
+ /* CBTConfig::set(CBTConfig::autoTileVertical, false);
+ CBTConfig::set(CBTConfig::autoTileHorizontal, false);
+ CBTConfig::set(CBTConfig::autoCascade, false);
+ */
+ CBTConfig::set(CBTConfig::autoTileVertical, m_windowAutoTileVertical_action->isChecked());
+ CBTConfig::set(CBTConfig::autoTileHorizontal, m_windowAutoTileHorizontal_action->isChecked());
+ CBTConfig::set(CBTConfig::autoCascade, m_windowAutoCascade_action->isChecked());
+
+ CProfile* p = m_profileMgr.startupProfile();
+ if (p)
+ {
+ saveProfile(p);
+ }
+}
+
+/** Reads the settings from the configfile and sets the right properties. */
+void BibleTime::readSettings()
+{
+ qDebug("******************BibleTime::readSettings******************************");
+ // accel()->readSettings(CBTConfig::getConfig());
+// CBTConfig::setupAccelSettings(CBTConfig::application, actionCollection());
+
+ m_viewToolbar_action->setChecked( CBTConfig::get(CBTConfig::toolbar) );
+ slotToggleToolbar();
+
+ if ( CBTConfig::get(CBTConfig::autoTileVertical) )
+ {
+ m_windowAutoTileVertical_action->setChecked( true );
+ m_windowManualMode_action->setChecked(false);
+ slotAutoTileVertical();
+ }
+ else if ( CBTConfig::get(CBTConfig::autoTileHorizontal) )
+ {
+ m_windowAutoTileHorizontal_action->setChecked( true );
+ m_windowManualMode_action->setChecked(false);
+ slotAutoTileHorizontal();
+ }
+ else if ( CBTConfig::get(CBTConfig::autoCascade) )
+ {
+ m_windowAutoCascade_action->setChecked(true);
+ m_windowManualMode_action->setChecked(false);
+ slotAutoCascade();
+ }
+ else
+ {
+ m_windowManualMode_action->setChecked(true);
+ slotManualArrangementMode();
+ }
+}
+
+/** Creates a new presenter in the MDI area according to the type of the module. */
+CDisplayWindow* BibleTime::createReadDisplayWindow(QList<CSwordModuleInfo*> modules, const QString& key)
+{
+ qApp->setOverrideCursor( QCursor(Qt::WaitCursor) );
+ qDebug("BibleTime::createReadDisplayWindow(QList<CSwordModuleInfo*> modules, const QString& key)");
+ CDisplayWindow* displayWindow = CDisplayWindowFactory::createReadInstance(modules, m_mdi);
+ if ( displayWindow )
+ {
+ displayWindow->init();
+ if (m_mdi->subWindowList().count() == 0)
+ displayWindow->showMaximized();
+ else
+ displayWindow->show();
+ // if (!key.isEmpty())
+ displayWindow->lookupKey(key);
+ }
+ // We have to process pending events here, otherwise displayWindow is not fully painted
+ qApp->processEvents();
+ // Now all events, including mouse clicks for the displayWindow have been handled
+ // and we can let the user click the same module again
+ m_bookshelfPage->unfreezeModules(modules);
+ qApp->restoreOverrideCursor();
+ return displayWindow;
+}
+
+
+/** Creates a new presenter in the MDI area according to the type of the module. */
+CDisplayWindow* BibleTime::createReadDisplayWindow(CSwordModuleInfo* module, const QString& key)
+{
+ QList<CSwordModuleInfo*> list;
+ list.append(module);
+
+ return createReadDisplayWindow(list, key);
+}
+
+CDisplayWindow* BibleTime::createWriteDisplayWindow(CSwordModuleInfo* module, const QString& key, const CDisplayWindow::WriteWindowType& type)
+{
+ qApp->setOverrideCursor( QCursor(Qt::WaitCursor) );
+
+ QList<CSwordModuleInfo*> modules;
+ modules.append(module);
+
+ CDisplayWindow* displayWindow = CDisplayWindowFactory::createWriteInstance(modules, m_mdi, type);
+ if ( displayWindow )
+ {
+ displayWindow->init();
+ if (m_mdi->subWindowList().count() == 0)
+ displayWindow->showMaximized();
+ else
+ displayWindow->show();
+ displayWindow->lookupKey(key);
+ }
+
+ qApp->restoreOverrideCursor();
+ return displayWindow;
+}
+
+/** Refreshes all presenters.*/
+void BibleTime::refreshDisplayWindows()
+{
+ foreach (QMdiSubWindow* subWindow, m_mdi->subWindowList())
+ {
+ if (CDisplayWindow* window = dynamic_cast<CDisplayWindow*>(subWindow->widget()))
+ {
+ window->reload(CSwordBackend::OtherChange);
+ }
+ }
+}
+
+/** Called before quit. */
+void BibleTime::slot_aboutToQuit()
+{
+ saveSettings();
+}
+
+/** Called before a window is closed */
+bool BibleTime::queryClose()
+{
+ qDebug("BibleTime::queryClose");
+ bool ret = true;
+
+ foreach(QMdiSubWindow* subWindow, m_mdi->subWindowList())
+ {
+ if (CDisplayWindow* window = dynamic_cast<CDisplayWindow*>(subWindow->widget()))
+ {
+ ret = ret && window->queryClose();
+ }
+ qDebug() << "return value:" << ret;
+ }
+ qDebug() << "final return value:" << ret;
+ return ret;
+}
+
+/** Restores the workspace if the flag for this is set in the config. */
+void BibleTime::restoreWorkspace()
+{
+ if (CProfile* p = m_profileMgr.startupProfile())
+ {
+ loadProfile(p);
+ }
+}
+
+/** Sets the plain caption of the main window */
+void BibleTime::setPlainCaption(const QString& title)
+{
+ QString suffix;
+ //Watch out, subtitles must be appended with the form " - [%s]", otherwise
+ //QMdiSubWindow will mess up when it is maximized
+ if (!title.isEmpty())
+ {
+ suffix = QString(" - [").append(title).append("]");
+ }
+ QMainWindow::setWindowTitle( QString("BibleTime ").append(BT_VERSION) + suffix );
+}
+
+/** Processes the commandline options given to BibleTime. */
+void BibleTime::processCommandline()
+{
+ QStringList args = qApp->QCoreApplication::arguments();
+
+ if ( !CBTConfig::get(CBTConfig::crashedTwoTimes) &&
+ !args.contains("--ignore-session") )
+ {
+ restoreWorkspace();
+ }
+
+ if ( args.contains("--open-default-bible") &&
+ !CBTConfig::get(CBTConfig::crashedLastTime) &&
+ !CBTConfig::get(CBTConfig::crashedTwoTimes))
+ {
+ int index = args.indexOf("--open-default-bible");
+ QString bibleKey;
+ if (index >= 0 && (index+1) < args.size())
+ {
+ bibleKey = args.at(index+1);
+ }
+ CSwordModuleInfo* bible = CBTConfig::get(CBTConfig::standardBible);
+ if (bibleKey == "random")
+ {
+ CSwordVerseKey vk(0);
+ const int maxIndex = 31100;
+ time_t seconds;
+ seconds = time (NULL);
+ srand(seconds);
+ int newIndex = rand() % maxIndex;
+ vk.setPosition(sword::TOP);
+ vk.Index(newIndex);
+ bibleKey = vk.key();
+ }
+ createReadDisplayWindow(bible, bibleKey);
+ m_mdi->myTileVertical();//we are sure only one window is open, which should be displayed fullscreen in the working area
+ }
+}
+
+bool BibleTime::event(QEvent* e)
+{
+// /* if (e->type() == QEvent::Polish) {
+// qWarning("BibleTime::event type Polish");
+// m_initialized = true;
+// }*/
+ if (e->type() == QEvent::Close)
+ {
+ }
+ return QMainWindow::event(e);
+}
+
+void BibleTime::closeEvent(QCloseEvent* e)
+{
+ QMainWindow::closeEvent(e);
+}
diff --git a/src/bibletime.h b/src/bibletime.h
new file mode 100644
index 0000000..bf27ccd
--- /dev/null
+++ b/src/bibletime.h
@@ -0,0 +1,380 @@
+/*********
+*
+* 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 BIBLETIME_H
+#define BIBLETIME_H
+
+#include "frontend/profile/cprofilemgr.h"
+#include "frontend/profile/cprofile.h"
+#include "frontend/displaywindow/cdisplaywindow.h"
+
+class CSwordModuleInfo;
+
+#include <QList>
+#include <QMainWindow>
+
+class CMDIArea;
+class CDisplayWindow;
+class CMainIndex;
+class CBookmarkIndex;
+class CBookshelfIndex;
+
+namespace InfoDisplay {
+ class CInfoDisplay;
+}
+class QAction;
+class QMenu;
+class QToolBar;
+class QSplitter;
+
+/**
+ * @page backend The structure of the backend
+ * <p>
+ * The backend implementation for Sword is called CSwordBackend, the classes we use
+ * to work with keys are called CSwordVerseKey and CSwordLDKey, both are derived from
+ * the class CSwordKey.
+ * The CSwordKey derived classes used for Sword do also inherit the classes
+ * VerseKey (CSwordVerseKey)
+ * and SWKey (CSwordLDKey).
+ * </p>
+ * <p>
+ * The classes used to handle all module based stuff are derived from CModuleInfo.
+ * The module classes are: CSwordModuleInfo (for Sword modules),
+ * CSwordBibleModuleInfo (for bibles), CSwordCommentaryModuleInfo (for commentaries) and
+ * CSwordLexiconModuleInfo (for lexicons).
+ * Have a look at the class documentation of the mentioned classes to learn how the
+ * structure of them looks like and which class inherits which other class.
+ * </p>
+ * <p>
+ * The first objects which should be created in the application is the backend
+ * (for Sword the class is called CSwordBackend).
+ * Then create all the different module classes for the correct Sword modules.
+ * Have a look at
+ * BibleTime::initBackens() to see how it's done in BibleTime.@br
+ * Later you can work with them for example by using the CSwordKey and
+ * CSwordModuleInfo derived class.
+ * </p>
+ */
+
+/**
+ * @page frontend The structure of the frontend
+ *
+ * <p>
+ * The frontend contains the classes which interact with the user. For example the main index,
+ * the display windows, the searchdialog or the other parts.
+ * </p><p>
+ * The main index is implemented in the class CGroupManager, the items of the
+ * main index are implemented in the class CGroupManagerItem.
+ * Each CGroupManagerItem has a type() function which returns the type of
+ * the object (Module, Bookmark or Group).<BR>
+ * The display windows are all derived from the base class CPresenter.
+ * The display windows which handle Sword modules are all derived from the
+ * CSwordPresenter class.
+ * The display windows which provide functionality are CBiblePresenter for
+ * Bibles, CCommentaryPresenter for commentaries and CLexiconPresenter for
+ * lexicon and dictionaries.
+ * CSwordPresenter provides the essential base functions which are
+ * reimplemented in the derived classes (for example CSwordPresenter::lookup).<BR>
+ * </p><p>
+ * Another important part of the frontend are the keychoosers.
+ * They provide an interface to choose a key of a module.
+ * The interface for different module types is different.
+ * The base class is CKeyChooser which is the factory for the derived classes.
+ * Use the function CKeyChooser::createInstance to get the correct
+ * keychooser implementation for the desired module.<BR>
+ * </p>
+ */
+
+/** @mainpage BibleTime - sourcecode documentation
+ * BibleTime main page.
+ * <p>This is the sourcecode documentation of BibleTime, a Bible study tool for KDE/Linux.
+ * BibleTime is devided in two major parts, the backend and the frontend.
+ * The backend is mainly a wrapper around Sword's classes to use Qt functionality
+ * to allow easy access to it's functionality and to have it in a (more or less :)
+ * object oriented structure.</p><BR>
+ * <p>
+ * -Introduction to the backend: @ref backend<BR>
+ * -Introduction to the frontend: @ref frontend.<BR>
+ * The main class of BibleTime is called @ref BibleTime, which is the main window
+ * and initializes all important parts at startup. The text display windows
+ * belong to the @ref frontend.
+ * </p>
+ */
+
+/** BibleTime's main class.
+ * The main class of BibleTime. Here are the main widgets created.
+ *
+ * This is the main class of BibleTime! This class creates the GUI, the QAction objects
+ * and connects to some slots. Please insert the creation of actions in initActions,
+ * the creation of widgets into initView and the connect(...) calls into initConnections.
+ * Reading from a config file on creation time should go into readSettings(), saving into
+ * saveSettings().
+ * This is the general way of all BibleTime classes.
+ */
+class BibleTime : public QMainWindow
+{
+ friend class CMDIArea;
+ friend class BibleTimeDBusAdaptor;
+ Q_OBJECT
+public:
+ /**
+ * construtor of BibleTime
+ */
+ BibleTime();
+ /**
+ * destructor of BibleTime
+ */
+ virtual ~BibleTime();
+
+ /**
+ * Reads the settings from the configfile and sets the right properties.
+ */
+ void readSettings();
+ /**
+ * Saves the settings of this class
+ */
+ void saveSettings();
+ /**
+ * Restores the workspace if the flaf for this is set in the config.
+ */
+ void restoreWorkspace();
+ /**
+ * Apply the settings given by the profile p
+ */
+ void applyProfileSettings( Profile::CProfile* p );
+ /**
+ * Stores the settings of the mainwindow in the profile p
+ */
+ void storeProfileSettings( Profile::CProfile* p );
+
+public slots:
+ /**
+ * Opens the optionsdialog of BibleTime.
+ */
+ void slotSettingsOptions();
+ /**
+ * Opens the optionsdialog of BibleTime.
+ */
+ void slotSwordSetupDialog();
+ /**
+ * Opens the handbook.
+ */
+ void openOnlineHelp_Handbook();
+ /**
+ * Opens the bible study howto.
+ */
+ void openOnlineHelp_Howto();
+ /**
+ * Sets the plain caption of the main window
+ */
+ virtual void setPlainCaption( const QString& );
+ /**
+ * Processes the commandline options given to BibleTime.
+ */
+ void processCommandline();
+
+protected: // Protected methods
+ /**
+ * Initializes the view of this widget
+ */
+ void initView();
+ /**
+ * Initializes the menubar of BibleTime.
+ */
+ void initMenubar();
+ /**
+ * Initializes the SIGNAL / SLOT connections
+ */
+ void initConnections();
+ /**
+ * Initializes the backend
+ */
+ void initBackends();
+ /**
+ * Initializes the action objects of the GUI
+ */
+ void initActions();
+ /**
+ * Initializes one action object
+ */
+ QAction* initAction(QAction* action, QString text, QString icon, QKeySequence accel, QString tooltip, const char* slot );
+ /**
+ * Refreshes all presenter supporting at least in of the features given as parameter.
+ */
+ void refreshDisplayWindows();
+ /**
+ * Called before a window is closed
+ */
+ bool queryClose();
+
+ virtual bool event(QEvent*);
+
+ virtual void closeEvent(QCloseEvent* e);
+
+protected slots:
+ /**
+ * Creates a new presenter in the MDI area according to the type of the module.
+ */
+ CDisplayWindow* createReadDisplayWindow(QList<CSwordModuleInfo*> modules, const QString& key);
+ CDisplayWindow* createReadDisplayWindow(CSwordModuleInfo* module, const QString& key);
+ CDisplayWindow* createWriteDisplayWindow(CSwordModuleInfo* module, const QString& key, const CDisplayWindow::WriteWindowType& type);
+ /**
+ * Is called when the window menu is about to show ;-)
+ */
+ void slotWindowMenuAboutToShow();
+ /**
+ * This slot is connected with the windowAutoTile_action object
+ */
+ void slotAutoTileVertical();
+ /**
+ * This slot is connected with the windowAutoTile_action object
+ */
+ void slotAutoTileHorizontal();
+ /**
+ * This slot is connected with the windowAutoCascade_action object
+ */
+ void slotAutoCascade();
+ void slotUpdateWindowArrangementActions( QAction* );
+
+ void slotCascade();
+ void slotTileVertical();
+ void slotTileHorizontal();
+
+ void slotManualArrangementMode();
+
+ /**
+ * Is called when a client was selected in the window menu
+ */
+ void slotWindowMenuActivated();
+ /**
+ * Shows/hides the toolbar
+ */
+ void slotToggleToolbar();
+ /**
+ * Saves to the profile with the menu id ID
+ */
+ void saveProfile(QAction* action);
+ /**
+ * Saves the current settings into the currently activatred profile.
+ */
+ void saveProfile(Profile::CProfile* p);
+ /**
+ * Deletes the chosen session from the menu and from disk.
+ */
+ void deleteProfile(QAction* action);
+ /**
+ * Loads the profile with the menu id ID
+ */
+ void loadProfile(QAction* action);
+ /**
+ * Loads the profile with the menu ID id
+ */
+ void loadProfile(Profile::CProfile* p);
+ /**
+ * Toggles between normal and fullscreen mode.
+ */
+ void toggleFullscreen();
+ /**
+ * Is called when settings in the optionsdialog have been
+ * changed (ok or apply)
+ */
+ void slotSettingsChanged();
+ /**
+ * Is called when settings in the sword setup dialog have been
+ * changed (ok or apply)
+ */
+ void slotSwordSetupChanged();
+ /**
+ * Called when search button is pressed
+ **/
+ void slotSearchModules();
+ /**
+ * Called for search default bible
+ **/
+ void slotSearchDefaultBible();
+ /**
+ Saves current settings into a new profile.
+ */
+ void saveToNewProfile();
+ /**
+ * Slot to refresh the save profile and load profile menus.
+ */
+ void refreshProfileMenus();
+ /**
+ * Called before quit.
+ */
+ void slot_aboutToQuit();
+ /**
+ * Open the About Dialog
+ */
+ void slotOpenAboutDialog();
+
+private:
+ // docking widgets
+ QDockWidget* m_dock0;
+ QDockWidget* m_dock1;
+ QDockWidget* m_dock2;
+ QToolBar* m_mainToolBar;
+ // VIEW menu actions
+ QAction* m_viewToolbar_action;
+ QMenu* m_windowMenu;
+ /** WINDOW menu actions */
+ QAction* m_windowCascade_action;
+ QAction* m_windowTileHorizontal_action;
+ QAction* m_windowTileVertical_action;
+ QMenu* m_windowArrangementModeMenu;
+ QAction* m_windowManualMode_action;
+ QAction* m_windowAutoCascade_action;
+ QAction* m_windowAutoTileVertical_action;
+ QAction* m_windowAutoTileHorizontal_action;
+ QAction* m_windowCloseAll_action;
+
+ QMenu* m_windowSaveProfileMenu;
+ QAction* m_windowSaveToNewProfile_action;
+ QMenu* m_windowLoadProfileMenu;
+ QMenu* m_windowDeleteProfileMenu;
+ QAction* m_windowFullscreen_action;
+
+ QList<QAction*> m_windowOpenWindowsList;
+
+ bool m_initialized;
+ /**
+ * The list of installed SWORD modules
+ */
+ QList<CSwordModuleInfo*>* m_moduleList;
+
+ Profile::CProfile* m_currentProfile;
+ CMDIArea* m_mdi;
+
+ Profile::CProfileMgr m_profileMgr;
+
+ // docking windows
+ CBookmarkIndex* m_bookmarksPage;
+ CBookshelfIndex* m_bookshelfPage;
+ InfoDisplay::CInfoDisplay* m_infoDisplay;
+
+protected: //DBUS interface implementation
+ void closeAllModuleWindows();
+ void syncAllBibles(const QString& key);
+ void syncAllCommentaries(const QString& key);
+ void syncAllLexicons(const QString& key);
+ void syncAllVerseBasedModules(const QString& key);
+ void openWindow(const QString& moduleName, const QString& key);
+ void openDefaultBible(const QString& key);
+ QString getCurrentReference();
+ QStringList searchInModule(const QString& module, const QString& searchText);
+ QStringList searchInOpenModules(const QString& searchText);
+ QStringList searchInDefaultBible(const QString& searchText);
+ QStringList getModulesOfType(const QString& type);
+ void reloadModules();
+ //helper function
+ void syncAllModulesByType(const CSwordModuleInfo::ModuleType type, const QString& key);
+};
+
+#endif
diff --git a/src/bibletime_dbus.cpp b/src/bibletime_dbus.cpp
new file mode 100644
index 0000000..e2976b5
--- /dev/null
+++ b/src/bibletime_dbus.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.
+*
+**********/
+
+
+//BibleTime includes
+#include "bibletime.h"
+
+#include "frontend/cmdiarea.h"
+#include "backend/config/cbtconfig.h"
+
+#include "backend/keys/cswordversekey.h"
+
+//Sword includes
+#include <versekey.h>
+#include <listkey.h>
+
+//QT
+#include <QList>
+#include <QDebug>
+#include <QMdiSubWindow>
+
+//helper function
+void BibleTime::syncAllModulesByType(const CSwordModuleInfo::ModuleType type, const QString& key) {
+ qDebug() << "Syncing modules by type to key" << key.toLatin1();
+ foreach (QMdiSubWindow* w, m_mdi->usableWindowList()) {
+ CDisplayWindow* d = dynamic_cast<CDisplayWindow*>(w->widget());
+ if (d && d->modules().count() && d->modules().first()->type() == type) {
+ d->lookupKey(key);
+ }
+ }
+}
+
+void BibleTime::closeAllModuleWindows() {
+ qDebug() << "DBUS: close all windows now...";
+ m_mdi->deleteAll();
+}
+
+void BibleTime::syncAllBibles(const QString& key) {
+ qDebug() << "DBUS: syncing all bibles ...";
+ syncAllModulesByType(CSwordModuleInfo::Bible, key);
+}
+
+void BibleTime::syncAllCommentaries(const QString& key) {
+ qDebug() << "DBUS: syncing all commentaries ...";
+ syncAllModulesByType(CSwordModuleInfo::Commentary, key);
+}
+
+void BibleTime::syncAllLexicons(const QString& key) {
+ qDebug() << "DBUS: syncing all lexicons ...";
+ syncAllModulesByType(CSwordModuleInfo::Lexicon, key);
+}
+
+void BibleTime::syncAllVerseBasedModules(const QString& key) {
+ qDebug() << "DBUS: syncing all verse based modules ...";
+ syncAllModulesByType(CSwordModuleInfo::Bible, key);
+ syncAllModulesByType(CSwordModuleInfo::Commentary, key);
+}
+
+void BibleTime::openWindow(const QString& moduleName, const QString& key) {
+ qDebug() << "DBUS: open window for module" << moduleName.toLatin1() << "and key" << key.toLatin1();
+ CSwordModuleInfo* module = CPointers::backend()->findModuleByName(moduleName);
+ if (module) {
+ createReadDisplayWindow(module, key);
+ }
+}
+
+void BibleTime::openDefaultBible(const QString& key) {
+ qDebug() << "DBUS: open default bible ...";
+ CSwordModuleInfo* mod = CBTConfig::get(CBTConfig::standardBible);
+ if (mod) {
+ openWindow(mod->name(), key);
+ }
+}
+
+QStringList BibleTime::searchInModule(const QString& moduleName, const QString& searchText) {
+ qDebug() << "DBUS: searchInModule" << moduleName.toLatin1();
+ QStringList ret;
+ CSwordModuleInfo* mod = CPointers::backend()->findModuleByName(moduleName);
+
+ if (mod) {
+ //mod->search(searchText, CSwordModuleSearch::multipleWords, sword::ListKey());
+ sword::ListKey scope;
+ mod->searchIndexed( searchText, scope );
+
+ sword::ListKey result = mod->searchResult();
+ const QString lead = QString("[%1] ").arg(moduleName);
+ ;
+ for ( int i = 0; i < result.Count(); ++i ) {
+ sword::SWKey* key = result.getElement(i);
+ Q_ASSERT(key);
+
+
+ if (mod->type() == CSwordModuleInfo::Bible || mod->type() == CSwordModuleInfo::Commentary) {
+ sword::VerseKey vk(key->getText());
+ ret << lead + QString::fromUtf8( vk.getOSISRef() );
+ }
+ else {
+ ret << lead + QString::fromUtf8( key->getText() );
+ }
+ }
+ }
+
+ return ret;
+
+}
+
+QStringList BibleTime::searchInOpenModules(const QString& searchText) {
+ qDebug() << "DBUS: search in open modules ...";
+ QStringList ret;
+ foreach (QMdiSubWindow* subWindow, m_mdi->subWindowList()) {
+ if (CDisplayWindow* w = dynamic_cast<CDisplayWindow*>(subWindow->widget())) {
+ QList<CSwordModuleInfo*> windowModules = w->modules();
+ QList<CSwordModuleInfo*>::iterator end_it = windowModules.end();
+ for (QList<CSwordModuleInfo*>::iterator it(windowModules.begin()); it != end_it; ++it) {
+ ret += searchInModule((*it)->name(), searchText);
+ }
+ }
+ }
+ return ret;
+}
+
+QStringList BibleTime::searchInDefaultBible(const QString& searchText) {
+ CSwordModuleInfo* bible = CBTConfig::get(CBTConfig::standardBible);
+ return searchInModule(bible->name(), searchText);
+}
+
+QString BibleTime::getCurrentReference() {
+ qDebug() << "BibleTime::getCurrentReference";
+ QString ret = QString::null;
+
+ QMdiSubWindow* activeSubWindow = m_mdi->activeSubWindow();
+ if (!activeSubWindow) return ret;
+
+ CDisplayWindow* w = dynamic_cast<CDisplayWindow*>(activeSubWindow->widget());
+
+ if (w) {
+ QString modType;
+ Q_ASSERT(w->modules().first());
+ switch (w->modules().first()->type()) {
+ case CSwordModuleInfo::Bible:
+ modType = "BIBLE";
+ break;
+ case CSwordModuleInfo::Commentary:
+ modType = "COMMENTARY";
+ break;
+ case CSwordModuleInfo::GenericBook:
+ modType = "BOOK";
+ break;
+ case CSwordModuleInfo::Lexicon:
+ modType = "LEXICON";
+ break;
+ default:
+ modType = "UNSUPPORTED";
+ break;
+ }
+
+ ret.append("[").append(w->modules().first()->name()).append("] ");
+ ret.append("[").append(modType).append("] ");
+
+ CSwordVerseKey* vk = dynamic_cast<CSwordVerseKey*>( w->key() );
+ if (vk) {
+ ret.append( vk->getOSISRef() );
+ }
+ else {
+ ret.append( w->key()->key() );
+ }
+ }
+
+ return ret;
+}
+
+QStringList BibleTime::getModulesOfType(const QString& type) {
+ QStringList ret;
+
+ CSwordModuleInfo::ModuleType modType = CSwordModuleInfo::Unknown;
+ if (type == "BIBLES") {
+ modType = CSwordModuleInfo::Bible;
+ }
+ else if (type == "COMMENTARIES") {
+ modType = CSwordModuleInfo::Commentary;
+ }
+ else if (type == "LEXICONS") {
+ modType = CSwordModuleInfo::Lexicon;
+
+ }
+ else if (type == "BOOKS") {
+ modType = CSwordModuleInfo::GenericBook;
+ }
+
+ QList<CSwordModuleInfo*> modList = CPointers::backend()->moduleList();
+ for (QList<CSwordModuleInfo*>::iterator it( modList.begin() ); it != modList.end(); ++it) {
+ if ((*it)->type() == modType) {
+ ret.append( (*it)->name() );
+ }
+ }
+
+ return ret;
+}
+
+void BibleTime::reloadModules() {
+ slotSwordSetupChanged();
+}
diff --git a/src/bibletime_dbus_adaptor.cpp b/src/bibletime_dbus_adaptor.cpp
new file mode 100644
index 0000000..ac32c47
--- /dev/null
+++ b/src/bibletime_dbus_adaptor.cpp
@@ -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 NO_DBUS
+
+#include "bibletime_dbus_adaptor.h"
+
+BibleTimeDBusAdaptor::BibleTimeDBusAdaptor(BibleTime *bibletime_ptr) :
+ QDBusAbstractAdaptor(bibletime_ptr),
+ m_bibletime(bibletime_ptr)
+{
+}
+
+void BibleTimeDBusAdaptor::syncAllBibles(const QString& key){
+ m_bibletime->syncAllBibles(key);
+}
+
+void BibleTimeDBusAdaptor::syncAllCommentaries(const QString& key){
+ m_bibletime->syncAllCommentaries(key);
+}
+void BibleTimeDBusAdaptor::syncAllLexicons(const QString& key){
+ m_bibletime->syncAllLexicons(key);
+}
+
+void BibleTimeDBusAdaptor::syncAllVerseBasedModules(const QString& key){
+ m_bibletime->syncAllVerseBasedModules(key);
+}
+
+void BibleTimeDBusAdaptor::reloadModules(){
+ m_bibletime->reloadModules();
+}
+
+void BibleTimeDBusAdaptor::openWindow(const QString& moduleName, const QString& key){
+ m_bibletime->openWindow(moduleName, key);
+}
+
+void BibleTimeDBusAdaptor::openDefaultBible(const QString& key){
+ m_bibletime->openDefaultBible(key);
+}
+
+void BibleTimeDBusAdaptor::closeAllModuleWindows(){
+ m_bibletime->closeAllModuleWindows();
+}
+
+QString BibleTimeDBusAdaptor::getCurrentReference(){
+ return m_bibletime->getCurrentReference();
+}
+
+QStringList BibleTimeDBusAdaptor::searchInModule(const QString& moduleName, const QString& searchText){
+ return m_bibletime->searchInModule(moduleName, searchText);
+}
+
+QStringList BibleTimeDBusAdaptor::searchInOpenModules(const QString& searchText){
+ return m_bibletime->searchInOpenModules(searchText);
+}
+
+QStringList BibleTimeDBusAdaptor::searchInDefaultBible(const QString& searchText){
+ return m_bibletime->searchInDefaultBible(searchText);
+}
+
+QStringList BibleTimeDBusAdaptor::getModulesOfType(const QString& type){
+ return m_bibletime->getModulesOfType(type);
+}
+
+#endif //NO_DBUS
diff --git a/src/bibletime_dbus_adaptor.h b/src/bibletime_dbus_adaptor.h
new file mode 100644
index 0000000..dc238db
--- /dev/null
+++ b/src/bibletime_dbus_adaptor.h
@@ -0,0 +1,110 @@
+/*********
+*
+* 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 NO_DBUS
+
+#ifndef BIBLETIME_DBUS_ADAPTOR_H
+#define BIBLETIME_DBUS_ADAPTOR_H
+
+#include "bibletime.h"
+
+//Qt includes
+#include <QString>
+#include <QStringList>
+#ifndef NO_DBUS
+#include <QDBusAbstractAdaptor>
+#endif
+
+class BibleTimeDBusAdaptor : QDBusAbstractAdaptor
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "info.bibletime.BibleTime")
+
+private:
+ BibleTime* m_bibletime;
+
+public:
+ BibleTimeDBusAdaptor(BibleTime *bibletime_ptr);
+
+public slots:
+ /** Sync all open Bible windows to the key.
+ * @param key The key which is set to all Bible windows.
+ */
+ void syncAllBibles(const QString& key);
+ /** Sync all open commentary windows to the key.
+ * @param key The key which is set to all Commentary windows.
+ */
+ void syncAllCommentaries(const QString& key);
+ /** Sync all open lexicon windows to the key.
+ * @param key The key which is set to all Lexicon windows.
+ */
+ void syncAllLexicons(const QString& key);
+ /** Sync all open verse based (i.e. Bibles and commentaries) windows to the key.
+ * @param key The key which is set to all Bible and Commentary windows.
+ */
+ void syncAllVerseBasedModules(const QString& key);
+ /** Reload all modules
+ */
+ void reloadModules();
+ /** Open a new read window for the module moduleName using the given key
+ * @param moduleName The name of the module which is opened in a new module window.
+ * @param key The key to set to the newly opened window.
+ */
+ void openWindow(const QString& moduleName, const QString& key);
+ /** Open a new read window for the default Bible module using the given key
+ * @param key The key to set to the newly opened window.
+ */
+ void openDefaultBible(const QString& key);
+ /** Close all open windows.
+ */
+ void closeAllModuleWindows();
+ /** Returns the reference used in the current window.
+ * The format of the returned reference is
+ * [Module] [Type] OSIS_Reference,
+ * wtih type one of BIBLE/COMMENTARY/BOOK/LEXICON/UNSUPPORTED
+ * If the type is BIBLE or COMMENTARY the reference is an OSIS ref
+ * in the other cases it's the key name, for books /Chapter/Subsection
+ * for Lexicons just the plain key, e.g. "ADAM".
+ * e.g.
+ * [KJV] [BIBLE] Gen.1.1
+ * [MHC] [COMMENTARY] Gen.1.1
+ * [ISBE] [LEXICON] REDEMPTION
+ * @return The reference displayed in the currently active module window. Empty if none is active.
+ */
+ QString getCurrentReference();
+ /** Seach the searchText in the specified module.
+ * @param moduleName The module to search in
+ * @param searchText Search for this in the modules
+ * @return The search result. It's in the format [modulename] osis_ref_of_the_found_key. For example "[KJV] Gen.1.1".
+ */
+ QStringList searchInModule(const QString& moduleName, const QString& searchText) ;
+ /** Search in all open modules and return the search result.
+ * The result is in the same format as searchInModule
+ * @param searchText Search for this in the modules
+ * @return The search result for a searchin all opened module windows
+ * @see searchInModule For the search result format.
+ */
+ QStringList searchInOpenModules(const QString& searchText);
+ /** Search in the default Bible module and return the search result.
+ * The result is in the same format as searchInModule
+ * @param searchText Search for this in the modules
+ * @return The search result for a search in the default Bible
+ * @see searchInModule
+ */
+ QStringList searchInDefaultBible(const QString& searchText);
+ /** Return a list of modules of the given type.
+ * @param type One of BIBLES, COMMENTARIES, LEXICONS, BOOKS
+ * @return The list of modules of the given type, may be empty
+ */
+ QStringList getModulesOfType(const QString& type);
+};
+
+#endif
+
+#endif //NO_DBUS
diff --git a/src/bibletime_init.cpp b/src/bibletime_init.cpp
new file mode 100644
index 0000000..5effe7e
--- /dev/null
+++ b/src/bibletime_init.cpp
@@ -0,0 +1,481 @@
+/*********
+*
+* 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 "bibletime.h"
+#include "util/cpointers.h"
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+#include "backend/managers/btstringmgr.h"
+#include "backend/managers/cswordbackend.h"
+#include "backend/managers/clanguagemgr.h"
+#include "frontend/mainindex/cmainindex.h"
+#include "frontend/profile/cprofilemgr.h"
+#include "frontend/profile/cprofile.h"
+#include "frontend/cmdiarea.h"
+#include "frontend/cprinter.h"
+#include "backend/config/cbtconfig.h"
+#include "frontend/cinfodisplay.h"
+#include "frontend/mainindex/bookshelf/cbookshelfindex.h"
+#include "frontend/mainindex/bookmarks/cbookmarkindex.h"
+
+// Qt includes
+#include <QSplitter>
+#include <QPointer>
+#include <QLabel>
+#include <QVBoxLayout>
+#include <QMenu>
+#include <QMenuBar>
+#include <QToolBar>
+#include <QApplication>
+#include <QDebug>
+#include <QDockWidget>
+
+// Sword includes
+#include <swlog.h>
+
+using namespace InfoDisplay;
+using namespace Profile;
+
+/**Initializes the view of this widget*/
+void BibleTime::initView()
+{
+ m_mdi = new CMDIArea(this);
+ setCentralWidget(m_mdi);
+
+ m_dock0 = new QDockWidget(tr("Bookshelf"), this);
+ m_dock0->setObjectName("BookshelfDock");
+ m_bookshelfPage = new CBookshelfIndex(0);
+ m_dock0->setWidget(m_bookshelfPage);
+ addDockWidget(Qt::LeftDockWidgetArea, m_dock0);
+
+ m_dock1 = new QDockWidget(tr("Bookmarks"), this);
+ m_dock1->setObjectName("BookmarksDock");
+ m_bookmarksPage = new CBookmarkIndex(0);
+ m_dock1->setWidget(m_bookmarksPage);
+ addDockWidget(Qt::LeftDockWidgetArea, m_dock1);
+ tabifyDockWidget(m_dock1, m_dock0);
+
+ m_dock2 = new QDockWidget(tr("Mag"), this);
+ m_dock2->setObjectName("MagDock");
+ m_infoDisplay = new CInfoDisplay(this);
+ m_infoDisplay->resize(150,150);
+ m_dock2->setWidget(m_infoDisplay);
+ addDockWidget(Qt::LeftDockWidgetArea, m_dock2);
+
+ CPointers::setInfoDisplay(m_infoDisplay);
+ m_mdi->setMinimumSize(100, 100);
+ m_mdi->setFocusPolicy(Qt::ClickFocus);
+}
+
+QAction* BibleTime::initAction(QAction* action, QString text, QString icon, QKeySequence accel, QString tooltip, const char* slot )
+{
+ action->setText(text);
+ if ( ! icon.isEmpty() )
+ action->setIcon(util::filesystem::DirectoryUtil::getIcon(icon));
+ action->setShortcut(accel);
+ if (tooltip != QString::null) action->setToolTip(tooltip);
+// actionCollection()->addAction(actionName, action);
+ if (slot) QObject::connect( action, SIGNAL(triggered()), this, slot );
+ return action;
+}
+
+/** Initializes the action objects of the GUI */
+void BibleTime::initActions()
+{
+ //:Main menu item
+ QMenu* fileMenu = menuBar()->addMenu(tr("&File"));
+ //:Main menu item
+ QMenu* viewMenu = menuBar()->addMenu(tr("&View"));
+ //:Main menu item
+ QMenu* searchMenu = menuBar()->addMenu(tr("&Search"));
+ //:Main menu item
+ m_windowMenu = menuBar()->addMenu(tr("&Window"));
+ //:Main menu item
+ QMenu* settingsMenu = menuBar()->addMenu(tr("Se&ttings"));
+ //:Main menu item
+ QMenu* helpMenu = menuBar()->addMenu(tr("&Help"));
+
+ //:Name of the main toolbar
+ m_mainToolBar = addToolBar(tr("Main Toolbar"));
+ m_mainToolBar->setObjectName("MainToolBar");
+ m_mainToolBar->setFloatable(false);
+ m_mainToolBar->setMovable(false);
+
+ QAction* tmp = new QAction(this);
+ initAction(
+ tmp,
+ tr("&Quit"),
+ QString("exit.svg"),
+ QKeySequence(Qt::CTRL + Qt::Key_Q),
+ tr("Quit BibleTime"),
+ SLOT( close() )
+ );
+ fileMenu->addAction(tmp);
+ m_mainToolBar->addAction(tmp);
+ m_mainToolBar->addSeparator();
+
+ m_windowFullscreen_action = new QAction(this);
+ m_windowFullscreen_action->setCheckable(true);
+ viewMenu->addAction(initAction(
+ m_windowFullscreen_action,
+ tr("&Fullscreen mode"),
+ CResMgr::mainMenu::window::showFullscreen::icon,
+ CResMgr::mainMenu::window::showFullscreen::accel,
+ tr("Toggle fullscreen mode of the main window"),
+ SLOT(toggleFullscreen()))
+ );
+ m_mainToolBar->addAction(m_windowFullscreen_action);
+
+ m_viewToolbar_action = new QAction(this);
+ m_viewToolbar_action->setCheckable(true);
+ m_viewToolbar_action->setChecked(true);
+ viewMenu->addAction(initAction(
+ m_viewToolbar_action,
+ tr("&Show toolbar"),
+ "",
+ QKeySequence(Qt::Key_F6),
+ "",
+ SLOT(slotToggleToolbar())));
+
+ QAction* action = m_dock0->toggleViewAction();
+ action->setText(tr("Show Bookshelf"));
+ viewMenu->addAction(action);
+
+ action = m_dock1->toggleViewAction();
+ action->setText(tr("Show Bookmarks"));
+ viewMenu->addAction(action);
+
+ action = m_dock2->toggleViewAction();
+ action->setText(tr("Show Mag"));
+ viewMenu->addAction(action);
+
+ m_mainToolBar->addSeparator();
+
+ tmp = initAction(
+ new QAction(this),
+ tr("Search in &open works..."),
+ CResMgr::mainMenu::mainIndex::search::icon,
+ CResMgr::mainMenu::mainIndex::search::accel,
+ tr("Search in all works that are currently open"),
+ SLOT( slotSearchModules() )
+ );
+ searchMenu->addAction(tmp);
+ m_mainToolBar->addAction(tmp);
+ m_mainToolBar->addSeparator();
+
+ searchMenu->addAction(initAction(
+ new QAction(this),
+ tr("Search in standard &Bible..."),
+ CResMgr::mainMenu::mainIndex::searchdefaultbible::icon,
+ CResMgr::mainMenu::mainIndex::searchdefaultbible::accel,
+ tr("Search in the standard Bible"),
+ SLOT(slotSearchDefaultBible())));
+
+ m_windowSaveProfileMenu = new QMenu(tr("&Save session"));
+ m_windowMenu->addMenu(m_windowSaveProfileMenu);
+
+ m_windowSaveToNewProfile_action = new QAction(this);
+ m_windowMenu->addAction(initAction(
+ m_windowSaveToNewProfile_action,
+ tr("Save as &new session..."),
+ CResMgr::mainMenu::window::saveToNewProfile::icon,
+ CResMgr::mainMenu::window::saveToNewProfile::accel,
+ tr("Create and save a new session"),
+ SLOT( saveToNewProfile() ))
+ );
+
+ m_windowLoadProfileMenu = new QMenu(tr("&Load session"));
+ m_windowMenu->addMenu(m_windowLoadProfileMenu);
+
+ m_windowDeleteProfileMenu = new QMenu(tr("&Delete session"));
+ m_windowMenu->addMenu(m_windowDeleteProfileMenu);
+
+ QObject::connect(m_windowLoadProfileMenu, SIGNAL(triggered(QAction*)), SLOT(loadProfile(QAction*)));
+ QObject::connect(m_windowSaveProfileMenu, SIGNAL(triggered(QAction*)), SLOT(saveProfile(QAction*)));
+ QObject::connect(m_windowDeleteProfileMenu, SIGNAL(triggered(QAction*)), SLOT(deleteProfile(QAction*)));
+
+ refreshProfileMenus();
+
+ m_windowMenu->addSeparator();
+
+//--------------------------Window arrangement actions---------------------------------------
+
+ QMenu* arrangementMenu = new QMenu(tr("&Arrangement mode"));
+ m_windowMenu->addMenu(arrangementMenu);
+
+ m_windowManualMode_action = new QAction(this);
+ m_windowManualMode_action->setCheckable(true);
+ arrangementMenu->addAction(initAction(
+ m_windowManualMode_action,
+ tr("&Manual mode"),
+ CResMgr::mainMenu::window::arrangementMode::manual::icon,
+ CResMgr::mainMenu::window::arrangementMode::manual::accel,
+ "",
+ SLOT( slotManualArrangementMode() ))
+ );
+
+ m_windowAutoTileVertical_action = new QAction(this);
+ m_windowAutoTileVertical_action->setCheckable(true);
+ //: Vertical tiling means that windows are vertical, placed side by side
+ arrangementMenu->addAction(initAction(
+ m_windowAutoTileVertical_action,
+ tr("Auto-tile &vertically"),
+ CResMgr::mainMenu::window::arrangementMode::autoTileVertical::icon,
+ CResMgr::mainMenu::window::arrangementMode::autoTileVertical::accel,
+ tr("Automatically tile the open windows vertically (arrange side by side)"),
+ SLOT( slotAutoTileVertical() ))
+ );
+
+ m_windowAutoTileHorizontal_action = new QAction(this);
+ m_windowAutoTileHorizontal_action->setCheckable(true);
+ arrangementMenu->addAction(initAction(
+ m_windowAutoTileHorizontal_action,
+ //: Horizontal tiling means that windows are horizontal, placed on top of each other
+ tr("Auto-tile &horizontally"),
+ CResMgr::mainMenu::window::arrangementMode::autoTileHorizontal::icon,
+ CResMgr::mainMenu::window::arrangementMode::autoTileHorizontal::accel,
+ tr("Automatically tile the open windows horizontally (arrange on top of each other)"),
+ SLOT( slotAutoTileHorizontal() ))
+ );
+
+ m_windowAutoCascade_action = new QAction(this);
+ m_windowAutoCascade_action->setCheckable(true);
+ arrangementMenu->addAction(initAction(
+ m_windowAutoCascade_action,
+ //: Cascading means that only one window is visible, others are behind that
+ tr("Auto-&cascade"),
+ CResMgr::mainMenu::window::arrangementMode::autoCascade::icon,
+ CResMgr::mainMenu::window::arrangementMode::autoCascade::accel,
+ tr("Automatically cascade the open windows"),
+ SLOT( slotAutoCascade() ))
+ );
+
+ m_windowCascade_action = new QAction(this);
+ m_windowMenu->addAction(initAction(
+ m_windowCascade_action,
+ tr("&Cascade"),
+ CResMgr::mainMenu::window::cascade::icon,
+ CResMgr::mainMenu::window::cascade::accel,
+ tr("Cascade the open windows"),
+ SLOT( slotCascade() ))
+ );
+
+ m_windowTileVertical_action = new QAction(this);
+ m_windowMenu->addAction(initAction(
+ m_windowTileVertical_action,
+ tr("Tile &vertically"),
+ CResMgr::mainMenu::window::tileVertical::icon,
+ CResMgr::mainMenu::window::tileVertical::accel,
+ tr("Vertically tile (arrange side by side) the open windows"),
+ SLOT( slotTileVertical() ))
+ );
+
+ m_windowTileHorizontal_action = new QAction(this);
+ m_windowMenu->addAction(initAction(
+ m_windowTileHorizontal_action,
+ tr("Tile &horizontally"),
+ CResMgr::mainMenu::window::tileHorizontal::icon,
+ CResMgr::mainMenu::window::tileHorizontal::accel,
+ tr("Horizontally tile (arrange on top of each other) the open windows"),
+ SLOT( slotTileHorizontal() ))
+ );
+
+ m_windowCloseAll_action = new QAction(this);
+ m_windowMenu->addAction(initAction(
+ m_windowCloseAll_action,
+ tr("Cl&ose all windows"),
+ CResMgr::mainMenu::window::closeAll::icon,
+ CResMgr::mainMenu::window::closeAll::accel,
+ tr("Close all open windows inside BibleTime"),
+ 0)
+ );
+ QObject::connect(m_windowCloseAll_action, SIGNAL(triggered()), m_mdi, SLOT( deleteAll() ) );
+
+ settingsMenu->addAction(initAction(
+ new QAction(this),
+ tr("&Configure BibleTime..."),
+ "configure.svg",
+ QKeySequence(),
+ tr("Set BibleTime's preferences"),
+ SLOT( slotSettingsOptions() )));
+ settingsMenu->addSeparator();
+
+ settingsMenu->addAction(initAction(
+ new QAction(this),
+ tr("Bookshelf &Manager..."),
+ CResMgr::mainMenu::settings::swordSetupDialog::icon,
+ CResMgr::mainMenu::settings::swordSetupDialog::accel,
+ tr("Configure your bookshelf and install/update/remove/index works"),
+ SLOT( slotSwordSetupDialog() )));
+
+ tmp = initAction(
+ new QAction(this),
+ tr("&Handbook"),
+ CResMgr::mainMenu::help::handbook::icon,
+ CResMgr::mainMenu::help::handbook::accel,
+ tr("Open BibleTime's handbook"),
+ SLOT( openOnlineHelp_Handbook() )
+ );
+ helpMenu->addAction(tmp);
+ m_mainToolBar->addAction(tmp);
+
+ helpMenu->addAction(initAction(
+ new QAction(this),
+ //: "Howto" is a guide; if there's no natural translation for HowTo, translate it as Guide
+ tr("&Bible Study Howto"),
+ CResMgr::mainMenu::help::bibleStudyHowTo::icon,
+ CResMgr::mainMenu::help::bibleStudyHowTo::accel,
+ tr("Open the Bible study HowTo included with BibleTime.<BR>This HowTo is an introduction on how to study the Bible in an efficient way."),
+ SLOT( openOnlineHelp_Howto() ))
+ );
+
+ helpMenu->addSeparator();
+
+ helpMenu->addAction( initAction(
+ new QAction(this),
+ tr("&About BibleTime"),
+ "",
+ QKeySequence(),
+ "",
+ SLOT(slotOpenAboutDialog()))
+ );
+}
+
+/** Initializes the SIGNAL / SLOT connections */
+void BibleTime::initConnections() {
+ QObject::connect(m_mdi, SIGNAL(sigSetToplevelCaption(const QString&)),
+ this, SLOT(setPlainCaption(const QString&)));
+ QObject::connect(m_mdi, SIGNAL(createReadDisplayWindow(QList<CSwordModuleInfo*>, const QString&)),
+ this, SLOT(createReadDisplayWindow(QList<CSwordModuleInfo*>, const QString&)));
+
+ if (m_windowMenu) {
+ QObject::connect(m_windowMenu, SIGNAL(aboutToShow()), this, SLOT(slotWindowMenuAboutToShow()));
+ }
+ else {
+ qWarning() << "Main window: can't find window menu";
+ }
+
+ bool ok;
+ ok = connect(m_bookmarksPage, SIGNAL(createReadDisplayWindow(QList<CSwordModuleInfo*>, const QString&)),
+ this, SLOT(createReadDisplayWindow(QList<CSwordModuleInfo*>,const QString&)));
+ Q_ASSERT(ok);
+ ok = connect(m_bookshelfPage, SIGNAL(createReadDisplayWindow(QList<CSwordModuleInfo*>, const QString&)),
+ this, SLOT(createReadDisplayWindow(QList<CSwordModuleInfo*>,const QString&)));
+ Q_ASSERT(ok);
+ ok = connect(m_bookshelfPage, SIGNAL(createWriteDisplayWindow(CSwordModuleInfo*, const QString&, const CDisplayWindow::WriteWindowType&)),
+ this, SLOT(createWriteDisplayWindow(CSwordModuleInfo*,const QString&, const CDisplayWindow::WriteWindowType&)));
+ Q_ASSERT(ok);
+
+ connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(slot_aboutToQuit()));
+}
+
+/** Initializes the backend */
+void BibleTime::initBackends() {
+ qDebug("BibleTime::initBackends");
+
+ sword::StringMgr::setSystemStringMgr( new BTStringMgr() );
+ sword::SWLog::getSystemLog()->setLogLevel(1);
+
+ CSwordBackend* backend = new CSwordBackend();
+ backend->booknameLanguage(CBTConfig::get(CBTConfig::language) );
+
+ CPointers::setBackend(backend);
+ const CSwordBackend::LoadError errorCode = CPointers::backend()->initModules(CSwordBackend::OtherChange);
+
+ m_moduleList = 0;
+ if ( errorCode == CSwordBackend::NoError ) { //no error
+ m_moduleList = &(CPointers::backend()->moduleList());
+ }
+ else {
+ m_moduleList = 0;
+ //show error message that initBackend failed
+ //TODO:
+// switch (errorCode) {
+// case CSwordBackend::NoSwordConfig: //mods.d or mods.conf missing
+// {
+// KStartupLogo::hideSplash();
+// qDebug("case CSwordBackend::NoSwordConfig");
+// BookshelfManager::CSwordSetupDialog dlg;
+// dlg.showPart( BookshelfManager::CSwordSetupDialog::Sword );
+// dlg.exec();
+// break;
+// }
+//
+// case CSwordBackend::NoModules: //no modules installed, but config exists
+// {
+// KStartupLogo::hideSplash();
+// qDebug("case CSwordBackend::NoModules");
+// BookshelfManager::CSwordSetupDialog dlg;
+// dlg.showPart( BookshelfManager::CSwordSetupDialog::Install );
+// dlg.exec();
+// break;
+// }
+//
+// default: //unknown error
+// {
+// KStartupLogo::hideSplash();
+// qDebug("unknown error");
+// BookshelfManager::CSwordSetupDialog dlg;
+// dlg.showPart( BookshelfManager::CSwordSetupDialog::Sword );
+// dlg.exec();
+// break;
+// }
+// }
+ }
+
+ //This function will
+ // - delete all orphaned indexes (no module present) if autoDeleteOrphanedIndices is true
+ // - delete all indices of modules where hasIndex() returns false
+ //BookshelfManager::CManageIndicesWidget::deleteOrphanedIndices();
+ //TODO: //backend::deleteOrphanedIndices();
+
+}
+
+void BibleTime::applyProfileSettings( CProfile* p ) {
+ qDebug("BibleTime::applyProfileSettings");
+ Q_ASSERT(p);
+ if (!p) return;
+
+ //first Main Window state
+ m_windowFullscreen_action->setChecked( p->fullscreen() ); //set the fullscreen button state
+ toggleFullscreen(); //either showFullscreen or showNormal
+ if (p->maximized()) QMainWindow::showMaximized(); //if maximized, then also call showMaximized
+ //Then Main Window geometry
+ QMainWindow::resize( p->geometry().size() ); //Don't use QMainWindowInterface::resize
+ QMainWindow::move( p->geometry().topLeft() );//Don't use QMainWindowInterface::move
+ restoreState(p->getMainwindowState());
+
+ const CMDIArea::MDIArrangementMode newArrangementMode = p->getMDIArrangementMode();
+ //make sure actions are updated by calling the slot functions
+ //updatesEnabled in the MDI area is false atm, so changes won't actually be displayed yet
+ switch(newArrangementMode){
+ case CMDIArea::ArrangementModeTileVertical: slotAutoTileVertical(); break;
+ case CMDIArea::ArrangementModeTileHorizontal: slotAutoTileHorizontal(); break;
+ case CMDIArea::ArrangementModeCascade: slotAutoCascade(); break;
+ default: slotManualArrangementMode(); break;
+ }
+}
+
+void BibleTime::storeProfileSettings( CProfile* p ) {
+ Q_ASSERT(p && m_windowFullscreen_action);
+ if (!p || !m_windowFullscreen_action) return;
+
+ p->setMainwindowState(saveState());
+ p->setFullscreen( m_windowFullscreen_action->isChecked() );
+ p->setMaximized( this->QMainWindow::isMaximized() );
+
+ QRect geometry;
+ geometry.setTopLeft(pos());
+ geometry.setSize(size());
+ p->setGeometry(geometry);
+
+ p->setMDIArrangementMode(m_mdi->getMDIArrangementMode());
+}
+
diff --git a/src/bibletime_slots.cpp b/src/bibletime_slots.cpp
new file mode 100644
index 0000000..3e054af
--- /dev/null
+++ b/src/bibletime_slots.cpp
@@ -0,0 +1,510 @@
+/*********
+*
+* 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 "bibletime.h"
+
+#include "backend/keys/cswordversekey.h"
+
+#include "util/ctoolclass.h"
+#include "util/directoryutil.h"
+
+#include "frontend/cmdiarea.h"
+#include "frontend/profile/cprofilemgr.h"
+#include "frontend/profile/cprofile.h"
+#include "frontend/profile/cprofilewindow.h"
+#include "frontend/settingsdialogs/cconfigurationdialog.h"
+#include "backend/config/cbtconfig.h"
+#include "frontend/cinputdialog.h"
+#include "frontend/cinfodisplay.h"
+#include "frontend/mainindex/cmainindex.h"
+#include "frontend/displaywindow/cdisplaywindow.h"
+#include "frontend/displaywindow/cbiblereadwindow.h"
+#include "frontend/searchdialog/csearchdialog.h"
+#include "frontend/bookshelfmanager/btmodulemanagerdialog.h"
+#include "frontend/htmldialogs/btaboutdialog.h"
+
+//QT includes
+#include <QClipboard>
+#include <QInputDialog>
+#include <QList>
+#include <QAction>
+#include <QMenu>
+#include <QToolBar>
+#include <QApplication>
+#include <QProcess>
+#include <QMdiSubWindow>
+#include <QtGlobal>
+#include <QDesktopServices>
+
+using namespace Profile;
+
+// /* An action which stores a user defined pointer to a widget.
+// * @author Joachim Ansorg
+// */
+// class KUserDataAction : public KToggleAction {
+// public:
+// KUserDataAction( QString caption, const KShortcut& shortcut, const QObject* receiver, const char* slot, KActionCollection* actionCollection)
+// : KToggleAction(caption, actionCollection), m_userData(0)
+// {
+// setShortcut(shortcut);
+// QObject::connect(this, SIGNAL(triggered()), receiver, slot);
+// };
+//
+// void setUserData(QWidget* const data) {
+// m_userData = data;
+// };
+// QWidget* const getUserData() const {
+// return m_userData;
+// };
+//
+// private:
+// QWidget* m_userData;
+// };
+
+/** Opens the optionsdialog of BibleTime. */
+void BibleTime::slotSettingsOptions() {
+ qDebug("BibleTime::slotSettingsOptions");
+ CConfigurationDialog *dlg = new CConfigurationDialog(this, 0 /*actionCollection()*/);
+ QObject::connect(dlg, SIGNAL(signalSettingsChanged()), this, SLOT(slotSettingsChanged()) );
+
+ dlg->show();
+}
+
+/** Is called when settings in the optionsdialog were changed (ok or apply) */
+void BibleTime::slotSettingsChanged() {
+ qDebug("BibleTime::slotSettingsChanged");
+ const QString language = CBTConfig::get
+ (CBTConfig::language);
+ //m_backend->booknameLanguage(language);
+ CPointers::backend()->booknameLanguage(language);
+// TODO: update the bookmarks after Bible bookname language has been changed
+// QTreeWidgetItemIterator it(m_mainIndex);
+// while (*it) {
+// CIndexItemBase* citem = dynamic_cast<CIndexItemBase*>(*it);
+// if (citem) {
+// citem->update();
+// }
+// ++it;
+// }
+
+ refreshDisplayWindows();
+ refreshProfileMenus();
+ qDebug("BibleTime::slotSettingsChanged");
+}
+
+/** Opens the sword setup dialog of BibleTime. */
+void BibleTime::slotSwordSetupDialog() {
+ //TODO: nonmodal dialog, memory management (one instance only!
+ //BtModuleManagerDialog *dlg = new BtModuleManagerDialog(this);
+ BtModuleManagerDialog* dlg = BtModuleManagerDialog::getInstance(this);
+ //disconnect first because it may be connected already
+ //QObject::disconnect(dlg, SIGNAL(swordSetupChanged()), this, SLOT(slotSwordSetupChanged()) );
+ //connect(dlg, SIGNAL(swordSetupChanged()), SLOT(slotSwordSetupChanged()) );
+
+ dlg->showNormal();
+ dlg->show();
+ dlg->raise();
+ dlg->activateWindow();
+}
+
+/** Is called when settings in the sword setup dialog were changed (ok or apply) */
+void BibleTime::slotSwordSetupChanged() {
+ /*
+ Refresh everything here what might have changed
+ these are the mainindex, the searchdialog, the displaywindows
+ But at first we have to reset the Sword backend to reload the modules
+
+ TODO: should bookshelf manager be updated?
+ Should there be different signals/slots for visual changes,
+ i.e. grouping/hiding?
+
+ */
+
+
+ //CPointers::deleteBackend();
+ //m_backend = new CSwordBackend();
+ //CPointers::setBackend(new CSwordBackend());
+ //CPointers::backend()->reloadModules();
+
+ //m_mainIndex->reloadSword();
+
+ // refresh display windows
+ //refreshDisplayWindows();
+}
+
+/** Is called just before the window menu is ahown. */
+void BibleTime::slotWindowMenuAboutToShow() {
+ Q_ASSERT(m_windowMenu);
+ if (!m_windowMenu) {
+ return;
+ }
+
+ if ( m_mdi->subWindowList().isEmpty() ) {
+ m_windowCascade_action->setEnabled(false);
+ m_windowTileVertical_action->setEnabled(false);
+ m_windowTileHorizontal_action->setEnabled(false);
+ m_windowCloseAll_action->setEnabled(false);
+ }
+ else if (m_mdi->subWindowList().count() == 1) {
+ m_windowTileVertical_action->setEnabled( false );
+ m_windowTileHorizontal_action->setEnabled( false );
+ m_windowCascade_action->setEnabled( false );
+ m_windowCloseAll_action->setEnabled( true );
+ // m_windowMenu->insertSeparator();
+ }
+ else {
+ slotUpdateWindowArrangementActions(0); //update the window tile/cascade states
+ m_windowCloseAll_action->setEnabled( true );
+ }
+
+ QList<QAction*>::iterator end = m_windowOpenWindowsList.end();
+ for (QList<QAction*>::iterator it = m_windowOpenWindowsList.begin(); it != end; ++it ) {
+ //(*it)->unplugAll(); //see kde porting doc
+ foreach (QWidget *w, (*it)->associatedWidgets() ) {
+ w->removeAction(*it);
+ }
+ }
+
+ //m_windowOpenWindowsList.setAutoDelete(true);
+ qDeleteAll(m_windowOpenWindowsList);
+ m_windowOpenWindowsList.clear();
+
+// if (!m_windowActionCollection) {
+// m_windowActionCollection = new KActionCollection(this, KComponentData());
+// }
+
+// QList<QWidget*> windows = m_mdi->windowList();
+// const int count = windows.count();
+// for ( int i = 0; i < count; ++i ) {
+// QWidget* w = windows.at(i);
+// Q_ASSERT(w);
+//
+// KUserDataAction* action = new KUserDataAction(w->windowTitle(), KShortcut(), this, SLOT(slotWindowMenuActivated()), m_windowActionCollection);
+// Q_ASSERT(action);
+// action->setUserData(w);
+//
+// m_windowOpenWindowsList.append(action);
+// action->setChecked( w == m_mdi->activeWindow() );
+// m_windowMenu->addAction(action);
+// }
+}
+
+/** This slot is connected with the windowAutoTile_action object */
+void BibleTime::slotUpdateWindowArrangementActions( QAction* clickedAction ) {
+ /* If a toggle action was clicked we see if it checked ot unchecked and
+ * enable/disable the simple cascade and tile options accordingly
+ */
+ m_windowTileVertical_action->setEnabled( m_windowManualMode_action->isChecked() );
+ m_windowTileHorizontal_action->setEnabled( m_windowManualMode_action->isChecked() );
+ m_windowCascade_action->setEnabled( m_windowManualMode_action->isChecked() );
+
+ if (clickedAction) {
+ m_windowManualMode_action->setEnabled(
+ m_windowManualMode_action != clickedAction
+ && m_windowTileHorizontal_action != clickedAction
+ && m_windowTileVertical_action != clickedAction
+ && m_windowCascade_action != clickedAction
+ );
+ m_windowAutoTileVertical_action->setEnabled( m_windowAutoTileVertical_action != clickedAction );
+ m_windowAutoTileHorizontal_action->setEnabled( m_windowAutoTileHorizontal_action != clickedAction );
+ m_windowAutoCascade_action->setEnabled( m_windowAutoCascade_action != clickedAction );
+ }
+
+ if (clickedAction == m_windowManualMode_action) {
+ m_windowAutoTileVertical_action->setChecked(false);
+ m_windowAutoTileHorizontal_action->setChecked(false);
+ m_windowAutoCascade_action->setChecked(false);
+
+ m_mdi->setMDIArrangementMode( CMDIArea::ArrangementModeManual );
+ }
+ else if (clickedAction == m_windowAutoTileVertical_action) {
+ m_windowManualMode_action->setChecked(false);
+ m_windowAutoTileHorizontal_action->setChecked(false);
+ m_windowAutoCascade_action->setChecked(false);
+
+ m_mdi->setMDIArrangementMode( CMDIArea::ArrangementModeTileVertical );
+ }
+ else if (clickedAction == m_windowAutoTileHorizontal_action) {
+ m_windowManualMode_action->setChecked(false);
+ m_windowAutoTileVertical_action->setChecked(false);
+ m_windowAutoCascade_action->setChecked(false);
+
+ m_mdi->setMDIArrangementMode( CMDIArea::ArrangementModeTileHorizontal );
+ }
+ else if (clickedAction == m_windowAutoCascade_action) {
+ m_windowManualMode_action->setChecked(false);
+ m_windowAutoTileHorizontal_action->setChecked(false);
+ m_windowAutoTileVertical_action->setChecked(false);
+
+ m_mdi->setMDIArrangementMode( CMDIArea::ArrangementModeCascade );
+ }
+ else if (clickedAction == m_windowCascade_action) {
+ m_mdi->setMDIArrangementMode( CMDIArea::ArrangementModeManual );
+ m_mdi->myCascade();
+ }
+ else if (clickedAction == m_windowTileVertical_action) {
+ m_mdi->setMDIArrangementMode( CMDIArea::ArrangementModeManual );
+ m_mdi->myTileVertical();
+ }
+ else if (clickedAction == m_windowTileHorizontal_action) {
+ m_mdi->setMDIArrangementMode( CMDIArea::ArrangementModeManual );
+ m_mdi->myTileHorizontal();
+ }
+}
+
+void BibleTime::slotManualArrangementMode() {
+ slotUpdateWindowArrangementActions( m_windowManualMode_action );
+}
+
+/** This slot is connected with the windowAutoTile_action object */
+void BibleTime::slotAutoTileHorizontal() {
+ slotUpdateWindowArrangementActions( m_windowAutoTileHorizontal_action );
+}
+
+/** This slot is connected with the windowAutoTile_action object */
+void BibleTime::slotAutoTileVertical() {
+ slotUpdateWindowArrangementActions( m_windowAutoTileVertical_action );
+}
+
+void BibleTime::slotCascade() {
+ slotUpdateWindowArrangementActions( m_windowCascade_action );
+}
+
+void BibleTime::slotTileVertical() {
+ slotUpdateWindowArrangementActions( m_windowTileVertical_action );
+}
+
+void BibleTime::slotTileHorizontal() {
+ slotUpdateWindowArrangementActions( m_windowTileHorizontal_action );
+}
+
+/** This slot is connected with the windowAutoCascade_action object */
+void BibleTime::slotAutoCascade() {
+ slotUpdateWindowArrangementActions( m_windowAutoCascade_action );
+}
+
+void BibleTime::slotWindowMenuActivated() {
+ if (!m_windowMenu) {
+ return;
+ }
+
+/* const KUserDataAction* action = dynamic_cast<const KUserDataAction*>(sender());
+ Q_ASSERT(action);
+ if (action) {
+ QWidget* const window = action->getUserData();
+ Q_ASSERT(window);
+ if ( window ) {
+ window->setFocus();
+ }
+ }*/
+}
+
+/** Shows/hides the toolbar */
+void BibleTime::slotToggleToolbar() {
+ Q_ASSERT(m_mainToolBar);
+ if (m_viewToolbar_action->isChecked()) {
+ m_mainToolBar->show();
+ }
+ else {
+ m_mainToolBar->hide();
+ }
+}
+
+void BibleTime::slotSearchModules() {
+ //get the modules of the open windows
+ QList<CSwordModuleInfo*> modules;
+
+ foreach(QMdiSubWindow* subWindow, m_mdi->subWindowList()){
+ if (CDisplayWindow* w = dynamic_cast<CDisplayWindow*>(subWindow->widget())) {
+ modules << w->modules();
+ }
+ }
+ Search::CSearchDialog::openDialog(modules, QString::null);
+}
+
+/* Search default Bible slot
+ * Call CSearchDialog::openDialog with only the default bible module
+ */
+void BibleTime::slotSearchDefaultBible() {
+ QList<CSwordModuleInfo*> module;
+ CSwordModuleInfo* bible = CBTConfig::get(CBTConfig::standardBible);
+ if (bible) {
+ module.append(bible);
+ }
+ Search::CSearchDialog::openDialog(module, QString::null);
+}
+
+void BibleTime::openOnlineHelp_Handbook()
+{
+ QString urlPath = "file://" + util::filesystem::DirectoryUtil::getHandbookDir().canonicalPath() +"/index.html";
+ QDesktopServices::openUrl(QUrl(urlPath));
+}
+
+void BibleTime::openOnlineHelp_Howto()
+{
+ QString urlPath = "file://" + util::filesystem::DirectoryUtil::getHowtoDir().canonicalPath() +"/index.html";
+ QDesktopServices::openUrl(QUrl(urlPath));
+}
+
+void BibleTime::slotOpenAboutDialog()
+{
+ BtAboutDialog* dlg = new BtAboutDialog(this);
+ dlg->show();
+}
+
+/** Saves the current settings into the currently activated profile. */
+void BibleTime::saveProfile(QAction* action) {
+ m_mdi->setUpdatesEnabled(false);
+
+ const QString profileName = action->text().remove("&");
+ CProfile* p = m_profileMgr.profile( profileName );
+ Q_ASSERT(p);
+ if ( p ) {
+ saveProfile(p);
+ }
+
+ m_mdi->setUpdatesEnabled(true);
+}
+
+void BibleTime::saveProfile(CProfile* profile) {
+ if (!profile) {
+ return;
+ }
+ //save mainwindow settings
+ storeProfileSettings(profile);
+
+ QList<CProfileWindow*> profileWindows;
+ foreach (QMdiSubWindow* w, m_mdi->subWindowList()) {
+ CDisplayWindow* displayWindow = dynamic_cast<CDisplayWindow*>(w->widget());
+ if (!displayWindow) {
+ continue;
+ }
+
+ CProfileWindow* profileWindow = new CProfileWindow();
+ displayWindow->storeProfileSettings(profileWindow);
+ profileWindows.append(profileWindow);
+ }
+ profile->save(profileWindows);
+
+ //clean up memory - delete all created profile windows
+ //profileWindows.setAutoDelete(true);
+ qDeleteAll(profileWindows);
+ profileWindows.clear();
+}
+
+void BibleTime::loadProfile(QAction* action) {
+ const QString profileName = action->text().remove("&");
+ CProfile* p = m_profileMgr.profile( profileName );
+ Q_ASSERT(p);
+ if ( p ) {
+ m_mdi->deleteAll();
+ loadProfile(p);
+ }
+}
+
+void BibleTime::loadProfile(CProfile* p) {
+ if (!p) return;
+
+ QList<CProfileWindow*> windows = p->load();
+
+ m_mdi->setUpdatesEnabled(false);//don't auto tile or auto cascade, this would mess up everything!!
+
+ //load mainwindow setttings
+ applyProfileSettings(p);
+
+ QWidget* focusWindow = 0;
+
+ // for (CProfileWindow* w = windows.last(); w; w = windows.prev()) { //from the last one to make sure the order is right in the mdi area
+ foreach (CProfileWindow* w, windows) {
+ const QString key = w->key();
+ QStringList usedModules = w->modules();
+
+ QList<CSwordModuleInfo*> modules;
+ for ( QStringList::Iterator it = usedModules.begin(); it != usedModules.end(); ++it ) {
+ if (CSwordModuleInfo* m = CPointers::backend()->findModuleByName(*it)) {
+ modules.append(m);
+ }
+ }
+ if (!modules.count()) { //are the modules still installed? If not continue wih next session window
+ continue;
+ }
+
+ //is w->isWriteWindow is false we create a write window, otherwise a read window
+ CDisplayWindow* displayWindow = 0;
+ if (w->writeWindowType() > 0) { //create a write window
+ displayWindow = createWriteDisplayWindow(modules.first(), key, CDisplayWindow::WriteWindowType(w->writeWindowType()) );
+ }
+ else { //create a read window
+ displayWindow = createReadDisplayWindow(modules, key);
+ }
+
+ if (displayWindow) { //if a window was created initialize it.
+ if (w->hasFocus()) {
+ focusWindow = displayWindow;
+ }
+
+ displayWindow->applyProfileSettings(w);
+ }
+ }
+
+ m_mdi->setUpdatesEnabled(true);
+ m_mdi->triggerWindowUpdate();
+
+ if (focusWindow) {
+ focusWindow->setFocus();
+ }
+}
+
+void BibleTime::deleteProfile(QAction* action) {
+ //HACK: work around the inserted & char by KPopupMenu
+ const QString profileName = action->text().remove("&");
+ CProfile* p = m_profileMgr.profile( profileName );
+ Q_ASSERT(p);
+ if ( p ) m_profileMgr.remove(p);
+ refreshProfileMenus();
+}
+
+void BibleTime::toggleFullscreen() {
+ m_windowFullscreen_action->isChecked() ? showFullScreen() : showNormal();
+ m_mdi->triggerWindowUpdate();
+}
+
+/** Saves current settings into a new profile. */
+void BibleTime::saveToNewProfile() {
+ bool ok = false;
+ const QString name = QInputDialog::getText(this, tr("New Session"), tr("Please enter a name for the new session."), QLineEdit::Normal, QString::null, &ok);
+ if (ok && !name.isEmpty()) {
+ CProfile* profile = m_profileMgr.create(name);
+ saveProfile(profile);
+ }
+ refreshProfileMenus();
+}
+
+/** Slot to refresh the save profile and load profile menus. */
+void BibleTime::refreshProfileMenus() {
+ m_windowSaveProfileMenu->clear();
+ m_windowLoadProfileMenu->clear();
+ m_windowDeleteProfileMenu->clear();
+
+ //refresh the load, save and delete profile menus
+ m_profileMgr.refresh();
+ QList<CProfile*> profiles = m_profileMgr.profiles();
+
+ const bool enableActions = bool(profiles.count() != 0);
+ m_windowSaveProfileMenu->setEnabled(enableActions);
+ m_windowLoadProfileMenu->setEnabled(enableActions);
+ m_windowDeleteProfileMenu->setEnabled(enableActions);
+
+ foreach (CProfile* p, profiles) {
+ m_windowSaveProfileMenu->addAction(p->name());
+ m_windowLoadProfileMenu->addAction(p->name());
+ m_windowDeleteProfileMenu->addAction(p->name());
+ }
+}
diff --git a/src/bibletimeapp.cpp b/src/bibletimeapp.cpp
new file mode 100644
index 0000000..13451fc
--- /dev/null
+++ b/src/bibletimeapp.cpp
@@ -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.
+*
+**********/
+
+#include "bibletimeapp.h"
+#include "backend/config/cbtconfig.h"
+#include "util/cresmgr.h"
+
+//KDE includes
+//#include <dcopclient.h> #TODO: USE DBUS INSTEAD OF DCOP
+
+BibleTimeApp::BibleTimeApp( int & argc, char ** argv ) : QApplication(argc, argv)
+{
+// initDCOP();
+ CResMgr::init_tr();
+}
+
+BibleTimeApp::~BibleTimeApp() {
+
+ //we can set this safely now because we close now (hopyfully without crash)
+ CBTConfig::set(CBTConfig::crashedLastTime, false);
+ CBTConfig::set(CBTConfig::crashedTwoTimes, false);
+
+ deleteDisplayTemplateMgr();
+ deleteLanguageMgr();
+ deleteBackend();
+}
+
+/*
+void BibleTimeApp::initDCOP() {
+ const bool dcopOk = dcopClient()->attach();
+ Q_ASSERT(dcopOk);
+ if (dcopOk) {
+ const Q3CString appId = dcopClient()->registerAs(kapp->name(), false);
+ // dcopClient()->setDefaultObject("BibleTimeInterface");
+ }
+}
+*/
diff --git a/src/bibletimeapp.h b/src/bibletimeapp.h
new file mode 100644
index 0000000..b4036a3
--- /dev/null
+++ b/src/bibletimeapp.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 BIBLETIMEAPP_H
+#define BIBLETIMEAPP_H
+
+//BibleTime
+#include "util/cpointers.h"
+
+#include <QApplication>
+
+/** The BibleTimeApp class is used to clean up all instances of the backend and to delete all created module objects.
+ * @author The BibleTime team
+ */
+class BibleTimeApp : public QApplication, public CPointers {
+public:
+ BibleTimeApp( int & argc, char ** argv );
+ virtual ~BibleTimeApp();
+
+protected:
+// void initDCOP();
+};
+
+#endif
diff --git a/src/display-templates/Blue.tmpl b/src/display-templates/Blue.tmpl
new file mode 100644
index 0000000..db5844f
--- /dev/null
+++ b/src/display-templates/Blue.tmpl
@@ -0,0 +1,338 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>#TITLE#</title>
+ <meta name="GENERATOR" content="BibleTime - www.bibletime.info" />
+ <meta name="AUTHOR" content="BibleTime - www.bibletime.info" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+
+ <style type="text/css">
+ /* <![CDATA[ */
+#LANG_CSS#
+
+#content {
+ margin:10px;
+}
+#content > table {
+ margin: 0;
+ padding: 0;
+ border-spacing:10px;
+}
+#content > table th {
+ padding: 0 0 2px 0;
+ text-align: center;
+ font-weight: bold;
+ font-size: 110%;
+ border-bottom: 1px dotted #7B7B7B;
+}
+
+a {
+ text-decoration:none;
+ font-weight:normal;
+ color: #7B7B7B;
+ padding:0 2px;
+}
+a:hover {
+ text-decoration:none;
+ color: #0000FF;
+ padding:0 2px;
+}
+
+
+/* Settings which apply to all entries in all modules */
+.entry {
+ padding: 2px;
+ /*vertical-align: middle;*/
+ text-align: justify;
+}
+td.entry, td.currententry {
+ vertical-align: top;
+ text-align: justify !important;
+}
+#printer .entry {
+ font-size: 90%;
+ text-align: left;
+}
+.entry[dir=rtl] {
+ text-align: right !important;
+}
+#printer .entry[dir=rtl] {
+ text-align:right !important;
+}
+
+/* Keep the values the same as in .entry (take the border into account!) */
+.currententry {
+ padding: 2px;
+ /*vertical-align: middle;*/
+ text-align: justify;
+ background-color: #E6E4FF;
+}
+.currententry[dir=rtl] {
+ text-align:right !important;
+}
+div.currententry {
+}
+span.currententry {
+ background-color: #EDEFFF !important;
+}
+
+/* Space between the columns of modules displayed side by side */
+td.entry + td.entry {
+ margin-left: 5px;
+}
+
+/* Several additional settings for display of modules*/
+#bible div.currententry, #bible td.currententry {
+ border: 1px solid #B7B7B7;
+ padding: 2px;
+}
+
+
+/*Same for books!*/
+#book div.currententry, #book td.currententry {
+ border: 1px solid #B7B7B7;
+ padding: 2px;
+}
+#book .entryname + .entry {
+ margin-top:2px;
+ padding-top:1px;
+}
+/* To remove the gap between the entrynam and the entry's content*/
+#book .entry > *, #book .currententry > * {
+ margin-top:0px;
+ padding-top:0px;
+}
+
+.entryname {
+ font-size:80%;
+ padding:0 2px 0 0;
+ vertical-align:super;
+}
+.entry[dir=rtl] .entryname, .currententry[dir=rtl] .entryname {
+ padding: 0 0 0 2px;
+ font-size: 80%;
+ vertical-align: super;
+}
+.entryname a, #printer .entryname {
+}
+
+#printer .entry .entry, #printer .entry .sectiontitle , #printer .entry .booktitle {
+ padding-top: 0.05em;
+ margin-left: 10px;
+}
+
+.footnote {
+ vertical-align:super;
+ font-weight: normal;
+ color: blue;
+ font-size: 80%;
+ cursor: help;
+}
+
+.footnote:before { content:"("; }
+.footnote:after { content:")"; }
+
+.footnotepre {
+ font-style: italic;
+}
+
+
+.crossreference {
+ font-size: 80%;
+ color: blue;
+}
+#bible .crossreference:before { content:" ["; }
+#bible .crossreference:after { content:"]"; }
+
+.crossreference a {
+ color: blue;
+}
+.crossreference a:hover {
+ color: blue;
+}
+
+.alternative {}
+.alternative:before { content:"'"attr(alternative); }
+.alternative:after{ content:"'";}
+
+.abbreviation {
+
+}
+
+.sectiontitle {
+ font-weight: bold;
+ font-size: 110%;
+}
+#printer .sectiontitle {
+ font-weight: bold;
+ font-size: 100%;
+}
+* + .sectiontitle {
+ margin-top:15px;
+}
+
+.booktitle {
+ font-weight: bold;
+ font-size: 120%;
+ font-variant: small-caps;
+}
+#printer .booktitle {
+ font-weight: bold;
+ font-size: 120%;
+ font-variant: small-caps;
+}
+.foreign {
+}
+.jesuswords {
+ color:#9C2323;
+}
+
+.introduction {
+ font-size:80%;
+ text-align:justify;
+}
+
+.quotation {
+}
+.poetry {
+}
+.sup {
+ vertical-align: super;
+}
+.sub {
+ vertical-align: sub;
+}
+.right {
+ text-align: right;
+}
+.center {
+ text-align: center;
+}
+
+.bold {
+ font-weight:bold;
+}
+.illuminated {
+}
+.italic {
+ font-style:italic;
+}
+.line-through {
+}
+.normal {
+}
+.small-caps{
+}
+.underline {
+ font-style:underline;
+}
+
+.inscription {
+}
+.mentioned {
+}
+.name > .geographic {
+}
+.name > .holiday {
+}
+.name > .nonhuman {
+}
+.name > .person {
+}
+.name > .ritual {
+}
+.name > .divine {
+ font-variant: small-caps;
+}
+
+.transchange {
+ font-style:italic;
+}
+.transchange > .added {
+ background-color:inherit;
+}
+.transchange > .amplified {
+}
+.transchange > .changed {
+}
+.transchange > .deleted {
+}
+.transchange > .moved {
+}
+.transchange > .tenseChange {
+}
+
+.morphSegmentation {
+ border-right: 2px solid gray;
+}
+
+#infodisplay {
+ margin:0;
+ padding:0;
+}
+
+#infodisplay .footnoteinfo h3, #infodisplay .strongsinfo h3, #infodisplay .morphinfo h3, #infodisplay .translationinfo h3, #infodisplay .crossrefinfo h3 {
+ padding:4px 4px 2px 0;
+ color:darkGray;
+ font-weight:bold;
+ border-bottom:1px solid gray;
+ font-size:90%;
+ text-align: right;
+}
+
+#infodisplay > p, #infodisplay * > p,
+#infodisplay > .para, #infodisplay * > .para
+{ /* We only format the first p child in a special way */
+ font-size:95%;
+ text-align:justify !important;
+ color:black;
+ margin:0px;
+ padding:0px;
+}
+
+/*Required for cross references*/
+#infodisplay .entry {
+ padding:2px;
+ text-align:justify !important;
+ font-size:95%;
+ margin-bottom:10px;
+ margin-left:15px;
+}
+#infodisplay .entry[dir=rtl] {
+ text-align: right !important;
+}
+#infodisplay .entry .entry { /*No smaller font size for nested entries*/
+ font-size:100%;
+ margin:0px;
+}
+#infodisplay .entry .entry[dir=rtl] { /*No smaller font size for nested entries*/
+ text-align: right !important;
+}
+#infodisplay .entryname {
+ padding:2px;
+ margin:0px;
+ text-align:left !important;
+ font-weight:bold;
+ font-size:100%;
+}
+
+#infodisplay .rangeheading {
+ color:black;
+ font-weight:bold;
+ margin-left:-10px;
+}
+
+#printer .rangeheading {
+ border-bottom:1px solid black;
+ color:black;
+}
+
+ /* ]]> */
+ </style>
+</head>
+
+<body id="#DISPLAYTYPE#">
+ <div id="content" lang="#LANG_ABBREV#" xml:lang="#LANG_ABBREV#" dir="#PAGE_DIRECTION#">#CONTENT#</div>
+</body>
+</html> \ No newline at end of file
diff --git a/src/display-templates/Crazy.tmpl b/src/display-templates/Crazy.tmpl
new file mode 100644
index 0000000..c0e9b63
--- /dev/null
+++ b/src/display-templates/Crazy.tmpl
@@ -0,0 +1,311 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <!--TODO: This needs a better title than "Crazy"-->
+ <title>#TITLE#</title>
+ <meta name="GENERATOR" content="BibleTime - www.bibletime.info" />
+ <meta name="AUTHOR" content="BibleTime - www.bibletime.info" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+
+ <style type="text/css">
+/* <![CDATA[ */
+body {
+ margin:0px;
+ padding:0;
+ padding:1em;
+}
+
+/* content wraps all of the displayed elements */
+#content {
+ margin:0px;
+ padding:0px;
+ font-size:12pt;
+ text-align:justify;
+}
+
+/* The table contains the Bible verses, each verse on an own row, each Bible module in an own column */
+#content > table {
+ margin:0;
+ padding:3px;
+ border-spacing:0;
+ vertical-align:top;
+ text-align:justify;
+}
+/* The heading contains the name of the module and may contain additional information like the display keys */
+#content > table th {
+ text-shadow:black 1px 1px 3px;
+ font-size:1.3em;
+ background-color:#F0F0F0;
+ padding:8px;
+ border-bottom:1px solid black;
+}
+
+#content tr:nth-child(odd) { background-color: white; }
+#content tr:nth-child(even) { background-color: #EDEDED; }
+
+/* The a links are the normal HTML hyperlinks. Links without a class attribute are hyperlinks into the web */
+a { color:#FF0004; padding:0; }
+a:hover { }
+
+/* An entry is the generic element used for all content items.
+ In Bibles an entry contains a verse, in commentaries the comment to a verse range,
+ in lexicons an simple item and in book the text of an item with other .entry elements as childs.
+
+ If just one module is chosen, all entries are put together in one sourrounding table column. In this case the elements div and span may have the class "entry". If it's a div each entry should be on it's own line. span.entry should not add a linebreak.
+
+ If more than one module (Bibles) was chosen, the entry class applies to "td" elements, one column for a verse
+ */
+.entry {
+ padding:0.3em;
+}
+table .entry:nth-child(odd) {
+ border-left:10px solid #DEE6F6;
+}
+
+table .entry:nth-child(even) {
+ border-left:10px solid #E6EEFF;
+}
+
+#printer .entry { text-indent:15px; }
+/* Often needed to format BiDi text in the right way */
+/* .entry[dir=rtl] { text-align:right !important; } */b
+/* #printer .entry[dir=rtl] { } */
+
+/* Special formatting for the block element entries */
+div.entry, td.entry { }
+td.entry, td.currententry {
+ vertical-align:top;
+}
+
+/* Currententry is chosen when the entry should be highlighted as the current entry chosen by the user
+ currententry may apply to span, div, td (just like .entry)
+ */
+.currententry {
+ padding:0.3em;
+ line-height:1.6em;
+ background-color:#D3E5FF;
+ /*border: thin solid black;*/
+
+}
+
+table .currententry:nth-child(1) {
+ margin-left:0;
+ border-left:10px solid #99B4FF;
+ /*border-left:10px solid #F5FF6A;*/
+}
+/* .currententry[dir=rtl] { */
+/* } */
+div.currententry { }
+span.currententry { }
+
+/* You may use this to format the space between two columns */
+td.entry + td.entry {
+ margin:0;
+}
+
+/* Several additional settings for displaying Bible modules*/
+#bible div.entry {
+ border-left:10px solid white;
+}
+#bible div.entry[dir=rtl] {
+ border-left:none;
+ border-right:10px solid white;
+ text-align:right;
+}
+#bible div.currententry {
+ border-left:10px solid #99B4FF;
+}
+#bible div.currententry[dir=rtl] {
+ border-left:none;
+ border-right:10px solid #99B4FF;
+}
+#bible div.currententry, #bible td.currententry { }
+#bible td.currententry { }
+
+/* Same for books! */
+#book div.currententry, #book td.currententry { }
+#book .entryname + .entry { }
+/* To remove the gap between the entryname and the entry's content*/
+#book .entry > *, #book .currententry > * { }
+
+/* An entryname is embedded in an .entry tag and contains the name of the key, which belongs to the text of the .entry */
+.entryname { size:60%; vertical-align:super;}
+.entryname a { text-decoration:none !important; color:#8F2627 !important; font-style:italic; padding:0; }
+
+.entry[dir=rtl] .entryname, .currententry[dir=rtl] .entryname { }
+.entryname a, #printer .entryname { }
+/* As you can see #printer is used to format pages which are send to the printer. Printer pages should be clean and easy to read */
+#printer .entry .entry, #printer .entry .sectiontitle , #printer .entry .booktitle { }
+
+/* Footnote formatting options */
+/* A footnote is displayed as an asterisk or another small character. You can set the colors, font-size, etc. for the footnote. */
+.footnote { color:#8F2627; vertical-align:super; font-size:70%;}
+/* You may use this to add sourrounding brackets in Bible modules. To do this the content command of CSS */
+#bible .footnote:before { content:" ["; color:#8F2627; }
+#bible .footnote:after { content:"]"; color:#8F2627; }
+
+/* Crossreferences. The same as footnotes */
+.crossreference { color:#8f2627;}
+#bible .crossreference:before { content:" {" }
+#bible .crossreference:after { content:"}" }
+
+/*Keep in mind that for cross references it is not enough to
+*set only the cross reference colour, you must also set the
+*cross reference anchor marker with .crossreference a
+*This way both the non linked and linked text will show
+*as desired. Additionally, you can have seperate formatting
+*for linked and non linked text in the cross reference*/
+.crossreference a {
+ color:#8f2627;
+ /*Get rid of underlines on the notes when not hovered*/
+ text-decoration: none;
+}
+.crossreference a:hover {}
+
+/* Alternative reading as defined in the OSIS specs. The information about the alternative text is displayed in the info display. It's
+often a good idea to format this the same as footnotes
+The text which is the alternative of the displayed text is available in the attribute "alternative"
+so something like .alternative:before { content:"'"attr(alternative); } is possible
+*/
+.alternative {}
+.alternative:before { }
+.alternative:after { }
+
+/* An abbreviation. */
+.abbreviation { }
+
+/* A title within the text. This is the formatting which applies to a title of a section, as you can find them in Bibles */
+.sectiontitle {
+ padding:0.3em;
+ /*text-shadow:gray 0px 0px 3px;*/
+ font-size:1.3em;
+ font-weight:bold;
+ text-transform:uppercase;
+ padding-bottom:2px;
+}
+#printer .sectiontitle { }
+/* You may want to format elements before section titles in a special way. */
+* + .sectiontitle { }
+
+/* The title of a book, e.g. "The gospel of Matthew" */
+.booktitle { }
+#printer .booktitle { }
+
+/* A foreign word */
+.foreign { }
+
+/* Words spoken by Jesus Christ */
+/*.jesuswords { color: red; }*/
+.jesuswords { color: #B60000; }
+
+/* An introduction to a module, book or chapter */
+.introduction { }
+/* A quotation without a special speaker */
+.quotation { }
+/* Poetry formatting */
+.poetry { }
+/* Text displayed above. It's like the sup tag in HTML */
+.sup { }
+/* Sub text, the opposite of .sup */
+.sub { }
+/* Display the text inside as right aligned text */
+.right { }
+/* Display as centered text */
+.center { }
+
+/* Visual attributes to the text */
+.bold {
+ font-weight: bold;
+}
+.illuminated { }
+.italic {
+ font-style: italic;
+}
+.line-through { }
+.normal { }
+.small-caps{ }
+.underline { }
+
+/* An inscription */
+.inscription { }
+
+.mentioned { }
+
+/* Special formatting rules for names, see the OSIS specs for detailed information */
+.name {}
+.name > .geographic { }
+.name > .holiday { }
+.name > .nonhuman { }
+.name > .person { }
+.name > .ritual { }
+.name > .divine { font-variant: small-caps; }
+
+/* Information added by the translator */
+.transchange {}
+.transchange > .added { }
+.transchange > .amplified {}
+.transchange > .changed { }
+.transchange > .deleted { }
+.transchange > .moved { }
+.transchange > .tenseChange { }
+
+/* Special text markup */
+/* Morph segmentation is a special feature for hebrew to markup the word divisions in the text */
+/* .morphSegmentation { border-left:1px solid red; } */
+.morphSegmentation + .morphSegmentation {
+ border-right: 1px red solid;
+}
+
+/* The formatting of all things displayed in the information window */
+#infodisplay {background:white; font-size:10pt; padding:5px; margin:0px;}
+
+/* The headings of a section, several sections may be displayed together at the same time */
+#infodisplay .footnoteinfo h3,
+#infodisplay .strongsinfo h3,
+#infodisplay .morphinfo h3,
+#infodisplay .translationinfo h3,
+#infodisplay .crossrefinfo h3 {
+ font-size:12pt;
+ font-weight:bold;
+ text-transform:uppercase;
+ text-align:right;
+ color:gray;
+ border-bottom:1px solid black;
+ padding:4px;
+}
+
+#infodisplay > p, #infodisplay * > p { /* We only format the first p child in a special way */
+ font-size:80%;
+}
+
+/*Required for cross references*/
+#infodisplay .entry {
+ font-size:80%;
+}
+#infodisplay .entry .entry { /* No smaller font size for nested entries */
+ font-size:100% !important;
+}
+#infodisplay .entryname {
+ font-weight:bold;
+}
+#infodisplay .rangeheading {
+ font-weight:bold;
+}
+
+#printer .rangeheading {}
+
+*[dir=rtl] { text-align:right !important; }
+
+/* Here's the marker for the language specific fotn information. BibleTime replaces this by the CSS for the fonts */
+#LANG_CSS#
+
+/* ]]> */
+ </style>
+</head>
+
+<!-- The display type may be bible, book, printer -->
+<body id="#DISPLAYTYPE#">
+ <div id="content" lang="#LANG_ABBREV#" xml:lang="#LANG_ABBREV#" dir="#PAGE_DIRECTION#">#CONTENT#</div>
+</body>
+</html> \ No newline at end of file
diff --git a/src/display-templates/Green.tmpl b/src/display-templates/Green.tmpl
new file mode 100644
index 0000000..4616030
--- /dev/null
+++ b/src/display-templates/Green.tmpl
@@ -0,0 +1,320 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>#TITLE#</title>
+ <meta name="GENERATOR" content="BibleTime - www.bibletime.info" />
+ <meta name="AUTHOR" content="BibleTime - www.bibletime.info" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+
+ <style type="text/css">
+ /* <![CDATA[ */
+
+#content {
+ margin:10px;
+}
+
+#content > table {
+ margin: 0;
+ padding: 0;
+ border-spacing:10px;
+ vertical-align:top;
+}
+
+#content > table th {
+ padding: 0 0 2px 0;
+ text-align: center;
+ font-weight: bold;
+ font-size: 110%;
+ border-bottom: 1px solid #6B6B6B;
+}
+
+a {
+ text-decoration:none;
+ font-weight:normal;
+ color: #3B11AE;
+ padding:0 2px;
+}
+a:hover {
+ color: #AE1518;
+ padding:0 2px;
+}
+
+
+/* Settings which apply to all entries in all modules */
+.entry {
+ padding: 3px;
+ vertical-align: middle;
+ text-align: justify;
+}
+#printer .entry {
+ font-size:90%;
+ text-align:left;
+}
+.entry[dir=rtl] {
+ text-align:right !important;
+}
+#printer .entry[dir=rtl] {
+ text-align:right !important;
+}
+td.entry, td.currententry {
+ vertical-align:top;
+}
+
+/* Keep the values the same as in .entry (take the border into account!) */
+.currententry {
+ padding:3px;
+ text-align:justify;
+}
+.currententry[dir=rtl] {
+ text-align:right !important;
+}
+div.currententry {
+}
+span.currententry {
+ background-color:#D4FFCB;
+}
+
+
+/*Space between the columns of modules displayed side by side*/
+td.entry + td.entry {
+ margin-left: 5px;
+}
+
+/* Several additional settings for display of modules*/
+#bible div.currententry, #bible td.currententry {
+ border:1px solid black;
+ padding:2px;
+ background-color:#F6FFF7;
+}
+#bible span.currententry {
+ background-color:#C8FFB6;
+}
+
+/*Same for books!*/
+#book div.currententry, #book td.currententry {
+ border:1px solid black;
+ background-color:#F6FFF7;
+}
+#book span.currententry {
+ background-color:#C8FFB6;
+}
+
+
+.entryname {
+ font-size:80%;
+ padding:0 2px 0 0;
+ vertical-align:super;
+}
+.entry[dir=rtl] .entryname, .currententry[dir=rtl] .entryname {
+ padding: 0 0 0 2px;
+ font-size: 80%;
+ vertical-align:super;
+}
+.entryname a, #printer .entryname {
+ vertical-align: middle
+}
+
+#printer .entry .entry, #printer .entry .sectiontitle , #printer .entry .booktitle {
+ padding-top: 0.05em;
+ margin-left: 10px;
+}
+
+.footnote {
+ vertical-align:super;
+ color: blue;
+ font-size: 70%;
+}
+.footnote:before { content:"("; }
+.footnote:after { content:")"; }
+
+.crossreference {
+ font-size: 80%;
+ /*vertical-align:middle;*/
+ color: blue;
+}
+
+.crossreference a {
+ font-size: 80%;
+ /*vertical-align:middle;*/
+ color: blue;
+}
+
+.crossreference a:hover {
+ font-size: 80%;
+ /*vertical-align:middle;*/
+ color: blue;
+}
+
+
+
+.sectiontitle {
+ font-weight: bold;
+ font-size: 110%;
+}
+#printer .sectiontitle {
+ font-weight: bold;
+ font-size: 100%;
+}
+* + .sectiontitle {
+ margin-top:15px;
+}
+
+.booktitle {
+ font-weight: bold;
+ font-size: 120%;
+ font-variant: small-caps;
+}
+#printer .booktitle {
+ font-weight: bold;
+ font-size: 120%;
+ font-variant: small-caps;
+}
+.foreign {
+}
+.jesuswords {
+ color:#9C2323;
+}
+
+.quotation {
+}
+.poetry {
+}
+.sup {
+ vertical-align: super;
+}
+.sub {
+ vertical-align: sub;
+}
+.right {
+ text-align: right;
+}
+.center {
+ text-align: center;
+}
+
+.bold {
+ font-weight:bold;
+}
+.illuminated {
+}
+.italic {
+ font-style:italic;
+}
+.line-through {
+}
+.normal {
+}
+.small-caps{
+}
+.underline {
+ font-style:underline;
+}
+
+.inscription {
+}
+.mentioned {
+}
+.name > .geographic {
+}
+.name > .holiday {
+}
+.name > .nonhuman {
+}
+.name > .person {
+}
+.name > .ritual {
+}
+.name > .divine {
+ font-variant: small-caps;
+}
+
+.transchange {
+ font-style:italic;
+}
+.transchange > .added {
+ background-color:inherit;
+}
+.transchange > .amplified {
+}
+.transchange > .changed {
+}
+.transchange > .deleted {
+}
+.transchange > .moved {
+}
+.transchange > .tenseChange {
+}
+
+.morphSegmentation {
+ border: 1px solid gray;
+ margin-top: 1px; /* Don`t let the boxes touch here, between the lines */
+ margin-left: -1px; /* But here, for better reading of the text,
+ this will only occur within a word consisting of several segments.*/
+ margin-right: 0px;
+}
+
+#infodisplay {
+ margin:0;
+ padding:0;
+ font-size:100%;
+}
+
+#infodisplay .footnoteinfo h3, #infodisplay .strongsinfo h3, #infodisplay .morphinfo h3, #infodisplay .translationinfo h3, #infodisplay .crossrefinfo h3 {
+ padding:4px 4px 2px 0;
+ color:darkGray;
+ font-weight:bold;
+ border-bottom:1px solid gray;
+ font-size:100%;
+ text-align:left !important;
+}
+
+#infodisplay > p, #infodisplay * > p { /* We only format the first p child in a special way */
+ font-size:100%;
+ text-align:justify;
+ color:black;
+ margin:0px;
+ padding:0px;
+}
+
+/*Required for cross references*/
+#infodisplay .entry {
+ padding:2px;
+ text-align:justify;
+ font-size:100%;
+ margin-bottom:10px;
+ margin-left:15px;
+}
+#infodisplay .entry .entry { /*No smaller font size for nested entries*/
+ font-size:100%;
+ margin:0px;
+}
+#infodisplay .entryname {
+ padding:2px;
+ margin:0px;
+ text-align:left;
+ font-weight:bold;
+ font-size:100%;
+}
+
+#infodisplay .rangeheading {
+ color:black;
+ font-weight:bold;
+ margin-left:-10px;
+}
+
+#printer .rangeheading {
+ border-bottom:1px solid black;
+ color:black;
+}
+
+#LANG_CSS#
+
+ /* ]]> */
+ </style>
+</head>
+
+<body id="#DISPLAYTYPE#">
+ <div id="content" lang="#LANG_ABBREV#" xml:lang="#LANG_ABBREV#" dir="#PAGE_DIRECTION#">#CONTENT#</div>
+</body>
+</html> \ No newline at end of file
diff --git a/src/display-templates/HighContrast.tmpl b/src/display-templates/HighContrast.tmpl
new file mode 100644
index 0000000..4baf59d
--- /dev/null
+++ b/src/display-templates/HighContrast.tmpl
@@ -0,0 +1,332 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>#TITLE#</title>
+ <meta name="GENERATOR" content="BibleTime - www.bibletime.info" />
+ <meta name="AUTHOR" content="BibleTime - www.bibletime.info" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+
+ <style type="text/css">
+ /* <![CDATA[ */
+
+* {
+ /* To work around a KDE 3.2 bug / problem */
+ /* background-color:white; #this seems to break*/
+}
+
+#content {
+ background-color:white;
+ margin:10px;
+}
+#content > table {
+ margin: 0;
+ padding: 0;
+ border-spacing:10px;
+ vertical-align:top;
+}
+#content > table th {
+ padding: 0 0 2px 0;
+ text-align: center;
+ /*font-weight: bold;*/
+ font-size: 110%;
+ border-bottom: 1px solid #6B6B6B;
+}
+
+a {
+ text-decoration:none;
+ font-weight:normal;
+ /*color: #F98100;*/
+ padding:1px;
+}
+a:hover {
+ color: #FF0000;
+ padding:1px;
+ text-decoration:underline;
+}
+
+/* Settings which apply to all entries in all modules */
+.entry {
+ padding: 2px;
+ /*vertical-align: top;*/
+ text-align: justify;
+}
+#printer .entry {
+ font-size: 90%;
+ text-align: left;
+}
+.entry[dir=rtl],#printer .entry[dir=rtl] {
+ text-align: right;
+}
+div.entry, td.entry, td.currententry {
+ vertical-align:top;
+}
+
+/* Keep the values the same as in .entry (take the border into account!) */
+.currententry {
+ padding: 2px;
+ text-align: justify;
+ /*color:white;*/
+ /*The background colour of selected text as of kde 3.5.2*/
+ background-color: #A5A5FF;
+}
+.currententry[dir=rtl] {
+ text-align: right;
+}
+div.currententry {
+}
+span.currententry {
+
+}
+
+
+/*Space between the columns of modules displayed side by side*/
+td.entry + td.entry {
+ margin-left: 5px;
+}
+
+/* Several additional settings for display of modules*/
+#bible div.currententry, #bible td.currententry {
+ /*border: 1px solid black;*/
+ padding: 4px;
+}
+#bible span.currententry {
+}
+
+/*Same for books!*/
+#book div.currententry, #book td.currententry {
+ border: 1px solid black;
+}
+#book span.currententry {
+}
+
+.entryname {
+ font-size:70%;
+ padding:0 1px 0 0;
+ vertical-align:top;
+ /*color: #F98100;*/
+ color: black;
+ /*font-style: italic;*/
+}
+.entry[dir=rtl] .entryname, .currententry[dir=rtl] .entryname {
+ padding:0 0 0 1px;
+ font-size:60%;
+ /*vertical-align:top; */
+}
+.entryname a, #printer .entryname {
+ vertical-align: top;
+ font-size: 100%;
+ font-weight: bold;
+ color: black;
+}
+
+#printer .entry .entry, #printer .entry .sectiontitle , #printer .entry .booktitle {
+ padding-top:0.05em;
+ margin-left:10px;
+}
+
+.footnote {
+ vertical-align:super;
+ font-weight:bold;
+ /*color: #00B7FF;*/ /*This one is kind of blinding on white*/
+ /*color: #F98100;*/
+ font-size:80%;
+ color: black;
+}
+
+
+.footnote:before {
+ content: "(";
+}
+
+.footnote:after {
+ content: ")";
+}
+
+.crossreference {
+ font-size: 80%;
+ /*vertical-align:middle;*/
+ /*color: blue;*/
+ /*color: #F98100;*/
+}
+
+.crossreference:before {
+ content: "[";
+}
+
+.crosreference:after {
+ content: "]";
+}
+
+.sectiontitle {
+ font-weight: bold;
+ font-size: 110%;
+}
+#printer .sectiontitle {
+ font-weight: bold;
+ font-size: 100%;
+}
+* + .sectiontitle {
+ margin-top:15px;
+}
+
+.booktitle {
+ font-weight: bold;
+ font-size: 120%;
+ font-variant: small-caps;
+}
+#printer .booktitle {
+ font-weight: bold;
+ font-size: 120%;
+ font-variant: small-caps;
+}
+.foreign {
+}
+.jesuswords {
+ /*color:red;*/
+ /*color: #7500AC;*/
+ /*color: #F98100;*/
+ font-style:italic;
+ /*font-weight: bold;*/
+ font-size:0.9em;
+}
+
+.quotation {
+}
+.poetry {
+}
+.sup {
+ vertical-align: super;
+}
+.sub {
+ vertical-align: sub;
+}
+.right {
+ text-align: right;
+}
+.center {
+ text-align: center;
+}
+
+.bold {
+ font-weight:bold;
+}
+.illuminated {
+}
+.italic {
+ font-style:italic;
+}
+.line-through {
+}
+.normal {
+}
+.small-caps{
+}
+.underline {
+ font-style:underline;
+}
+
+.inscription {
+}
+.mentioned {
+}
+.name > .geographic {
+}
+.name > .holiday {
+}
+.name > .nonhuman {
+}
+.name > .person {
+}
+.name > .ritual {
+}
+.name > .divine {
+ font-variant: small-caps;
+}
+
+.transchange {
+ font-style:italic;
+}
+.transchange > .added {
+ background-color:inherit;
+}
+.transchange > .amplified {
+}
+.transchange > .changed {
+}
+.transchange > .deleted {
+}
+.transchange > .moved {
+}
+.transchange > .tenseChange {
+}
+
+.morphSegmentation {
+ border: 1px solid grey;
+ margin-top: 1px; /* Don`t let the boxes touch here, between the lines */
+ margin-left: -1px; /* But here, for better reading of the text,
+ this will only occur within a word consisting of several segments.*/
+ margin-right: 0px;
+}
+
+#infodisplay {
+ margin:0;
+ padding:0;
+}
+
+#infodisplay .footnoteinfo h3, #infodisplay .strongsinfo h3, #infodisplay .morphinfo h3, #infodisplay .translationinfo h3, #infodisplay .crossrefinfo h3 {
+ padding: 2px 0 0 0;
+ color: black;
+ font-weight: bold;
+ border-bottom: 1px solid black;
+ font-size: 90%;
+ margin: 0 0 3px 0;
+}
+
+#infodisplay > p { /* We only format the first p child in a special way */
+ font-size: 90%;
+ color: black;
+ margin: 0px;
+ padding: 0px;
+}
+
+/*Required for cross references*/
+#infodisplay .entry {
+ padding: 2px;
+ text-align: justify;
+ font-size: 80%;
+ margin: 0 0 10px 10px;
+}
+#infodisplay .entry .entry { /*No smaller font size for nested entries*/
+ font-size: 100%;
+ margin: 0px;
+}
+#infodisplay .entryname {
+ padding: 2px;
+ margin: 0px;
+ text-align: left;
+ font-weight: bold;
+ font-size: 90%;
+}
+
+#infodisplay .rangeheading {
+ color: black;
+ font-weight: bold;
+ margin-left: -5px;
+}
+
+#printer .rangeheading {
+ border-bottom: 1px solid black;
+ color: black;
+}
+
+#LANG_CSS#
+
+ /* ]]> */
+ </style>
+</head>
+
+<body id="#DISPLAYTYPE#">
+ <div id="content" lang="#LANG_ABBREV#" xml:lang="#LANG_ABBREV#">#CONTENT#</div>
+</body>
+</html>
diff --git a/src/display-templates/Simple.tmpl b/src/display-templates/Simple.tmpl
new file mode 100644
index 0000000..9d9e6c8
--- /dev/null
+++ b/src/display-templates/Simple.tmpl
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>#TITLE#</title>
+ <meta name="GENERATOR" content="BibleTime " VERSION "" />
+ <meta name="AUTHOR" content="BibleTime " VERSION "" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+
+ <style type="text/css">
+/* <![CDATA[ */
+body {
+ margin:5px;
+}
+#content {
+ background-color:white;
+}
+#content table {
+ margin:0;
+ padding:0;
+ border-spacing:10px;
+ border-collapse: collapse;
+ vertical-align: top;
+}
+#content table th {
+ padding: 0 0 2px 0;
+ text-align: center;
+ font-weight: bold;
+ font-size: 115%;
+}
+
+a {
+ text-decoration:none;
+ font-weight:normal;
+ color: blue;
+ padding:2px;
+}
+
+td.entry, div.entry {
+ padding: 5px;
+ vertical-align: top;
+}
+div.entry {
+ padding: 5px;
+}
+
+td.currententry, div.currententry {
+ padding: 5px;
+ vertical-align: top;
+ font-weight:bold;
+}
+td.entry + td.entry {
+ margin-left: 5px;
+}
+div.currententry {
+ font-weight:bold;
+ /*vertical-align: middle;*/
+ padding: 5px;
+}
+
+.footnote {
+ color: gray;
+}
+
+.strongnumber {
+ vertical-align: top;
+ font-size: 60%;
+ color: blue;
+}
+.morphcode {
+ vertical-align: top;
+ font-size: 60%;
+ color: blue;
+}
+.lemma {
+}
+
+.sectiontitle {
+ font-weight: bold;
+ font-size: 120%;
+}
+.entry + .sectiontitle {
+ margin-top:35px;
+ padding-top:35px;
+}
+
+.booktitle {
+ font-weight: bold;
+ font-size: 140%;
+}
+.foreign {
+}
+.jesuswords {
+ color: red;
+ font-size: 0.9em;
+}
+
+.name > .divine {
+ font-variant: small-caps;
+}
+
+.quotation {
+}
+.poetry {
+}
+.sup {
+ vertical-align: super;
+}
+.sub {
+ vertical-align: sub;
+}
+.right {
+ text-align: right;
+}
+.center {
+ text-align: center;
+}
+/*TODO: Think of something better here since this will get confusing*/
+/* on verses but, is needed for things inthe Mag/Info window*/
+.bold {
+ font-weight: bold;
+}
+.italic {
+ font-style: italic;
+}
+#LANG_CSS#
+/* ]]> */
+ </style>
+</head>
+
+<body>
+ <div id="content" lang="#LANG_ABBREV#" xml:lang="#LANG_ABBREV#" dir="#PAGE_DIRECTION#">#CONTENT#</div>
+</body>
+</html> \ No newline at end of file
diff --git a/src/display-templates/basic_template.txt b/src/display-templates/basic_template.txt
new file mode 100644
index 0000000..16ed394
--- /dev/null
+++ b/src/display-templates/basic_template.txt
@@ -0,0 +1,205 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>#TITLE#</title>
+ <meta name="GENERATOR" content="BibleTime - www.bibletime.info" />
+ <meta name="AUTHOR" content="BibleTime - www.bibletime.info" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+
+ <style type="text/css">
+/* <![CDATA[ */
+* {
+ background-color:inherit; /* To work around a KDE 3.2 bug / problem */
+}
+
+/* content wraps all of the displayed elements */
+#content { }
+/* The table contains the Bible verses, each verse on an own row, each Bible module in an own column */
+#content > table { }
+/* The heading contains the name of the module and may contain additional information like the display keys */
+#content > table th { }
+
+/* The a links are the normal HTML hyperlinks. Links without a class attribute are hyperlinks into the web */
+a { }
+a:hover { }
+
+/* An entry is the generic element used for all content items.
+ In Bibles an entry contains a verse, in commentaries the comment to a verse range,
+ in lexicons an simple item and in book the text of an item with other .entry elements as childs.
+
+ If just one module is chosen, all entries are put together in one sourrounding table column. In this case the elements div and span may have the class "entry". If it's a div each entry should be on it's own line. span.entry should not add a linebreak.
+
+ If more than one module (Bibles) was chosen, the entry class applies to "td" elements, one column for a verse
+ */
+.entry { }
+#printer .entry { }
+/* Often needed to format BiDi text in the right way */
+.entry[dir=rtl] { }
+#printer .entry[dir=rtl] { }
+/* Special formatting for the block element entries */
+div.entry, td.entry { }
+
+td.currententry { }
+
+/* Currententry is chosen when the entry should be highlighted as the current entry chosen by the user
+ currententry may apply to span, div, td (just like .entry)
+ */
+.currententry {
+}
+.currententry[dir=rtl] {
+}
+div.currententry { }
+span.currententry { }
+
+/* You may use this to format the space between two columns */
+td.entry + td.entry { }
+
+/* Several additional settings for displaying Bible modules*/
+#bible div.currententry, #bible td.currententry { }
+#bible td.currententry { }
+
+/*Same for books!*/
+#book div.currententry, #book td.currententry { }
+#book .entryname + .entry { }
+/* To remove the gap between the entryname and the entry's content*/
+#book .entry > *, #book .currententry > * { }
+
+/* An entryname is embedded in an .entry tag and contains the name of the key, which belongs to the text of the .entry */
+.entryname { }
+.entry[dir=rtl] .entryname, .currententry[dir=rtl] .entryname { }
+.entryname a, #printer .entryname { }
+/* As you can see #printer is used to format pages which are send to the printer. Printer pages should be clean and easy to read */
+#printer .entry .entry, #printer .entry .sectiontitle , #printer .entry .booktitle { }
+
+/* Footnote formatting options */
+/* A footnote is displayed as an asterisk or another small character. You can set the colors, font-size, etc. for the footnote. */
+.footnote { }
+/* You may use this to add sourrounding brackets in Bible modules. To do this the content command of CSS */
+#bible .footnote:before { }
+#bible .footnote:after { }
+
+/* Crossreferences. The same as footnotes */
+.crossreference { }
+#bible .crossreference:before { }
+#bible .crossreference:after { }
+
+/*Keep in mind that for cross references it is not enough to
+*set only the cross reference colour, you must also set the
+*cross reference anchor marker with .crossreference a
+*This way both the non linked and linked text will show
+*as desired. Additionally, you can have seperate formatting
+*for linked and non linked text in the cross reference*/
+.crossreference a { }
+.crossreference a:hover { }
+
+/* Alternative reading as defined in the OSIS specs. The information about the alternative text is displayed in the info display. It's
+often a good idea to format this the same as footnotes
+The text which is the alternative of the displayed text is available in the attribute "alternative"
+so something like .alternative:before { content:"'"attr(alternative); } is possible
+*/
+.alternative {}
+.alternative:before { }
+.alternative:after { }
+
+/* An abbreviation. */
+.abbreviation { }
+
+/* A title within the text. This is the formatting which applies to a title of a section, as you can find them in Bibles */
+.sectiontitle { }
+#printer .sectiontitle { }
+/* You may want to format elements before section titles in a special way. */
+* + .sectiontitle { }
+
+/* The title of a book, e.g. "The gospel of Matthew" */
+.booktitle { }
+#printer .booktitle { }
+
+/* A foreign word */
+.foreign { }
+
+/* Words spoken by Jesus Christ */
+.jesuswords { }
+
+/* An introduction to a module, book or chapter */
+.introduction { }
+/* A quotation without a special speaker */
+.quotation { }
+/* Poetry formatting */
+.poetry { }
+/* Text displayed above. It's like the sup tag in HTML */
+.sup { }
+/* Sub text, the opposite of .sup */
+.sub { }
+/* Display the text inside as right aligned text */
+.right { }
+/* Display as centered text */
+.center { }
+
+/* Visual attributes to the text */
+.bold { }
+.illuminated { }
+.italic { }
+.line-through { }
+.normal { }
+.small-caps{ }
+.underline { }
+
+/* An inscription */
+.inscription { }
+
+.mentioned { }
+
+/* Special formatting rules for names, see the OSIS specs for detailed information */
+.name {}
+.name > .geographic { }
+.name > .holiday { }
+.name > .nonhuman { }
+.name > .person { }
+.name > .ritual { }
+.name > .divine { }
+
+/* Information added by the translator */
+.transchange {}
+.transchange > .added { }
+.transchange > .amplified {}
+.transchange > .changed { }
+.transchange > .deleted { }
+.transchange > .moved { }
+.transchange > .tenseChange { }
+
+/* Special text markup */
+/* Morph segmentation is a special feature for hebrew to markup the word divisions in the text */
+.morphSegmentation {}
+
+/* The formatting of all things displayed in the information window */
+#infodisplay { }
+
+/* The headings of a section, several sections may be displayed together at the same time */
+#infodisplay .footnoteinfo h3,
+#infodisplay .strongsinfo h3,
+#infodisplay .morphinfo h3,
+#infodisplay .translationinfo h3,
+#infodisplay .crossrefinfo h3 { }
+
+#infodisplay > p, #infodisplay * > p { /* We only format the first p child in a special way */ }
+
+/*Required for cross references*/
+#infodisplay .entry { }
+#infodisplay .entry .entry { /* No smaller font size for nested entries */ }
+#infodisplay .entryname { }
+#infodisplay .rangeheading {}
+
+#printer .rangeheading {}
+
+/* Here's the marker for the language specific fotn information. BibleTime replaces this by the CSS for the fonts */
+#LANG_CSS#
+
+/* ]]> */
+ </style>
+</head>
+
+<!-- The display type may be bible, book, printer -->
+<body id="#DISPLAYTYPE#">
+ <div id="content" lang="#LANG_ABBREV#" xml:lang="#LANG_ABBREV#">#CONTENT#</div></body>
+</html> \ No newline at end of file
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(thre