summaryrefslogtreecommitdiff
path: root/src/frontend/cinfodisplay.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/cinfodisplay.cpp')
-rw-r--r--src/frontend/cinfodisplay.cpp466
1 files changed, 466 insertions, 0 deletions
diff --git a/src/frontend/cinfodisplay.cpp b/src/frontend/cinfodisplay.cpp
new file mode 100644
index 0000000..0c167c4
--- /dev/null
+++ b/src/frontend/cinfodisplay.cpp
@@ -0,0 +1,466 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+// BibleTime includes
+#include "cinfodisplay.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/keys/cswordkey.h"
+#include "backend/keys/cswordversekey.h"
+#include "backend/managers/creferencemanager.h"
+#include "backend/managers/cdisplaytemplatemgr.h"
+
+#include "backend/config/cbtconfig.h"
+#include "frontend/crossrefrendering.h"
+
+#include "frontend/display/cdisplay.h"
+#include "frontend/display/creaddisplay.h"
+
+#include <boost/scoped_ptr.hpp>
+
+// Sword includes
+#include <listkey.h>
+
+// Qt includes
+#include <QLayout>
+#include <QLabel>
+#include <QRegExp>
+#include <QVBoxLayout>
+#include <QAction>
+#include <QDebug>
+#include <QSize>
+
+using namespace Rendering;
+using namespace sword;
+
+namespace InfoDisplay {
+
+CInfoDisplay::CInfoDisplay(QWidget *parent) : QWidget(parent)
+{
+ QVBoxLayout* layout = new QVBoxLayout(this);
+ setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);
+
+ m_htmlPart = CDisplay::createReadInstance(0, this);
+ m_htmlPart->setMouseTracking(false); //we don't want strong/lemma/note mouse infos
+ m_htmlPart->view()->setAcceptDrops(false);
+
+ m_copyAction = new QAction(tr("Copy"), this);
+ m_copyAction->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_C) );
+ QObject::connect(m_copyAction, SIGNAL(triggered()), m_htmlPart->connectionsProxy(), SLOT(copySelection()) );
+
+ connect(
+ m_htmlPart->connectionsProxy(),
+ SIGNAL(referenceClicked(const QString&, const QString&)),
+ SLOT(lookupInfo(const QString&, const QString&))
+ );
+
+ layout->addWidget(m_htmlPart->view());
+ QString initialMagText = tr("<small>This is the Mag viewer area. Hover the mouse over links or other items which include some data and the contents appear in the Mag after a short delay. Move the mouse into Mag rapidly or lock the view by pressing and holding Shift while moving the mouse.</small>");
+ m_htmlPart->setText(initialMagText);
+}
+
+
+CInfoDisplay::~CInfoDisplay() {
+ delete m_copyAction;
+}
+
+void CInfoDisplay::lookupInfo(const QString &mod_name, const QString &key_text) {
+ qDebug("CInfoDisplay::lookup");
+ qDebug() << mod_name << key_text;
+ CSwordModuleInfo* m = CPointers::backend()->findModuleByName(mod_name);
+ Q_ASSERT(m);
+ if (!m)
+ return;
+
+ boost::scoped_ptr<CSwordKey> key( CSwordKey::createInstance(m) );
+ key->key( key_text );
+
+ CDisplayTemplateMgr* mgr = CPointers::displayTemplateManager();
+ CDisplayTemplateMgr::Settings settings;
+ settings.pageCSS_ID = "infodisplay";
+ // settings.langAbbrev = "";
+ QString content = mgr->fillTemplate(CBTConfig::get
+ (CBTConfig::displayStyle), key->renderedText(), settings);
+ m_htmlPart->setText(content);
+ // qWarning("setting text:\n%s", content.latin1());
+}
+
+void CInfoDisplay::setInfo(const InfoType type, const QString& data) {
+ ListInfoData list;
+ list.append( qMakePair(type, data) );
+
+ setInfo(list);
+}
+
+
+void CInfoDisplay::setInfo(const ListInfoData& list) {
+ //if the widget is hidden it would be inefficient to render and display the data
+ if (!isVisible()) {
+ return;
+ }
+
+ if (list.count() == 0) {
+ m_htmlPart->setText("<html></html>");
+ return;
+ }
+
+ QString text;
+
+ ListInfoData::const_iterator end = list.end();
+ for (ListInfoData::const_iterator it = list.begin(); it != end; ++it) {
+ switch ( (*it).first ) {
+ case Lemma:
+ text.append( decodeStrongs( (*it).second ) );
+ continue;
+ case Morph:
+ text.append( decodeMorph( (*it).second ) );
+ continue;
+ case CrossReference:
+ text.append( decodeCrossReference( (*it).second ) );
+ continue;
+ case Footnote:
+ text.append( decodeFootnote( (*it).second ) );
+ continue;
+ case WordTranslation:
+ text.append( getWordTranslation( (*it).second ) );
+ continue;
+ case WordGloss:
+ //text.append( getWordTranslation( (*it).second ) );
+ continue;
+ case Abbreviation:
+ text.append( decodeAbbreviation( (*it).second ) );
+ continue;
+ case Text:
+ text.append( (*it).second );
+ continue;
+ default:
+ continue;
+ };
+ }
+
+ CDisplayTemplateMgr* mgr = CPointers::displayTemplateManager();
+ CDisplayTemplateMgr::Settings settings;
+ settings.pageCSS_ID = "infodisplay";
+ // settings.langAbbrev = "";
+ QString content = mgr->fillTemplate(CBTConfig::get
+ (CBTConfig::displayStyle), text, settings);
+
+ // qWarning("setting text:\n%s", content.latin1());
+
+ m_htmlPart->setText(content);
+}
+
+
+const QString CInfoDisplay::decodeAbbreviation( const QString& data ) {
+ // QStringList strongs = QStringList::split("|", data);
+ QString ret;
+ QString text = data;
+
+ ret.append(
+ QString("<div class=\"abbreviation\"><h3>%1: %2</h3><p>%3</p></div>")
+ .arg(tr("Abbreviation"))
+ .arg("text")
+ .arg(text));
+
+ return ret;
+}
+
+const QString CInfoDisplay::decodeCrossReference( const QString& data ) {
+ Q_ASSERT(!data.isEmpty());
+ if (data.isEmpty()) {
+ return QString("<div class=\"crossrefinfo\"><h3>%1</h3></div>")
+ .arg(tr("Cross references"));
+ }
+
+ // qWarning("setting crossref %s", data.latin1());
+
+ CSwordBackend::DisplayOptions dispOpts;
+ dispOpts.lineBreaks = false;
+ dispOpts.verseNumbers = true;
+
+ CSwordBackend::FilterOptions filterOpts;
+ filterOpts.headings = false;
+ filterOpts.strongNumbers = false;
+ filterOpts.morphTags = false;
+ filterOpts.lemmas = false;
+ filterOpts.footnotes = false;
+ filterOpts.scriptureReferences = false;
+
+ CrossRefRendering renderer(dispOpts, filterOpts);
+ CTextRendering::KeyTree tree;
+
+ // const bool isBible = true;
+ CSwordModuleInfo* module = CBTConfig::get
+ (CBTConfig::standardBible);
+
+ //a prefixed module gives the module to look into
+ QRegExp re("^[^ ]+:");
+ // re.setMinimal(true);
+ int pos = re.indexIn(data);
+ if (pos != -1) {
+ pos += re.matchedLength()-1;
+ }
+
+ if (pos > 0) {
+ const QString moduleName = data.left(pos);
+ // qWarning("found module %s", moduleName.latin1());
+ module = CPointers::backend()->findModuleByName(moduleName);
+ if (!module) {
+ module = CBTConfig::get
+ (CBTConfig::standardBible);
+ }
+ // Q_ASSERT(module);
+ }
+
+ //Q_ASSERT(module); //why? the existense of the module is tested later
+ CTextRendering::KeyTreeItem::Settings settings (
+ false,
+ CTextRendering::KeyTreeItem::Settings::CompleteShort
+ );
+
+ if (module && (module->type() == CSwordModuleInfo::Bible)) {
+ VerseKey vk;
+ sword::ListKey refs = vk.ParseVerseList((const char*)data.mid((pos == -1) ? 0 : pos+1).toUtf8(), "Gen 1:1", true);
+
+ for (int i = 0; i < refs.Count(); ++i) {
+ SWKey* key = refs.getElement(i);
+ Q_ASSERT(key);
+ VerseKey* vk = dynamic_cast<VerseKey*>(key);
+
+ CTextRendering::KeyTreeItem* itm = (CTextRendering::KeyTreeItem*)0; //explicit conversion for MS VS
+ if (vk && vk->isBoundSet()) { //render a range of keys
+ itm = new CTextRendering::KeyTreeItem(
+ QString::fromUtf8(vk->LowerBound().getText()),
+ QString::fromUtf8(vk->UpperBound().getText()),
+ module,
+ settings
+ );
+ }
+ else {
+ itm = new CTextRendering::KeyTreeItem(
+ QString::fromUtf8(key->getText()),
+ QString::fromUtf8(key->getText()),
+ module,
+ settings
+ );
+ }
+
+ Q_ASSERT(itm);
+
+ tree.append( itm );
+ }
+ }
+ else if (module) {
+ CTextRendering::KeyTreeItem* itm = new CTextRendering::KeyTreeItem(
+ data.mid((pos == -1) ? 0 : pos+1),
+ module,
+ settings
+ );
+ tree.append( itm );
+ }
+
+ // qWarning("rendered the tree: %s", renderer.renderKeyTree(tree).latin1());
+ //spanns containing rtl text need dir=rtl on their parent tag to be aligned properly
+ return QString("<div class=\"crossrefinfo\"><h3>%1</h3><div class=\"para\" dir=\"%2\">%3</div></div>")
+ .arg(tr("Cross references"))
+ .arg(module ? ((module->textDirection() == CSwordModuleInfo::LeftToRight) ? "ltr" : "rtl") : "")
+ .arg(renderer.renderKeyTree(tree));
+}
+
+/*!
+ \fn CInfoDisplay::decodeFootnote( const QString& data )
+ */
+const QString CInfoDisplay::decodeFootnote( const QString& data ) {
+ QStringList list = data.split("/");
+ Q_ASSERT(list.count() >= 3);
+ if (!list.count()) {
+ return QString::null;
+ }
+
+ const QString modulename = list.first();
+ const QString swordFootnote = list.last();
+
+ // remove the first and the last and then rejoin it to get a key
+ list.pop_back(); list.pop_front();
+ const QString keyname = list.join("/");
+
+ CSwordModuleInfo* module = CPointers::backend()->findModuleByName(modulename);
+ if (!module) {
+ return QString::null;
+ }
+
+ boost::scoped_ptr<CSwordKey> key( CSwordKey::createInstance(module) );
+ key->key(keyname);
+ key->renderedText(); //force entryAttributes
+
+ const char* note =
+ module->module()->getEntryAttributes()
+ ["Footnote"][swordFootnote.toLatin1().data()]["body"].c_str();
+
+ QString text = module->isUnicode() ? QString::fromUtf8(note) : QString(note);
+ text = QString::fromUtf8(module->module()->RenderText(
+ module->isUnicode()
+ ? (const char*)text.toUtf8()
+ : (const char*)text.toLatin1()
+ ));
+
+ return QString("<div class=\"footnoteinfo\"><h3>%1</h3><p>%2</p></div>")
+ .arg(tr("Footnote"))
+ .arg(text);
+}
+
+const QString CInfoDisplay::decodeStrongs( const QString& data ) {
+ QStringList strongs = data.split("|");
+ QString ret;
+
+ QStringList::const_iterator end = strongs.end();
+ for (QStringList::const_iterator it = strongs.begin(); it != end; ++it) {
+ CSwordModuleInfo* const module = CBTConfig::get
+ (
+ ((*it).left(1) == QString("H")) ?
+ CBTConfig::standardHebrewStrongsLexicon :
+ CBTConfig::standardGreekStrongsLexicon
+ );
+
+ QString text;
+ if (module) {
+ boost::scoped_ptr<CSwordKey> key( CSwordKey::createInstance(module) );
+ key->key( (*it).mid(1) ); //skip H or G (language sign), will have to change later if we have better modules
+ text = key->renderedText();
+ }
+ //if the module could not be found just display an empty lemma info
+
+ ret.append(
+ QString("<div class=\"strongsinfo\"><h3>%1: %2</h3><p>%3</p></div>")
+ .arg(tr("Strongs"))
+ .arg(*it)
+ .arg(text)
+ );
+ }
+
+ return ret;
+}
+
+const QString CInfoDisplay::decodeMorph( const QString& data ) {
+ QStringList morphs = data.split("|");
+ QString ret;
+
+ foreach(QString morph, morphs) {
+ //qDebug() << "CInfoDisplay::decodeMorph, morph: " << morph;
+ CSwordModuleInfo* module = 0;
+ bool skipFirstChar = false;
+ QString value = "";
+ QString valueClass = "";
+
+ int valStart = morph.indexOf(':');
+ if (valStart > -1) {
+ valueClass = morph.mid(0, valStart);
+ //qDebug() << "valueClass: " << valueClass;
+ module = CPointers::backend()->findModuleByName( valueClass );
+ }
+ value = morph.mid(valStart+1); //works for prepended module and without (-1 +1 == 0).
+
+ // if we don't have a class assigned or desired one isn't installed...
+ if (!module) {
+ // Morphs usually don't have [GH] prepended, but some old OLB
+ // codes do. We should check if we're digit after first char
+ // to better guess this.
+ if (value.size() > 1 && value.at(1).isDigit()) {
+ switch (value.at(0).toLatin1()) {
+ case 'G':
+ module = CBTConfig::get
+ (CBTConfig::standardGreekMorphLexicon);
+ skipFirstChar = true;
+ break;
+ case 'H':
+ module = CBTConfig::get
+ (CBTConfig::standardHebrewMorphLexicon);
+ skipFirstChar = true;
+ break;
+ default:
+ skipFirstChar = false;
+ //TODO: we can't tell here if it's a greek or hebrew moprh code, that's a problem we have to solve
+ // module = CBTConfig::get(CBTConfig::standardGreekMorphLexicon);
+ break;
+ }
+ }
+ //if it is still not set use the default
+ if (!module) {
+ module = CBTConfig::get
+ (CBTConfig::standardGreekMorphLexicon);
+ }
+ }
+
+ QString text;
+ //Q_ASSERT(module);
+ if (module) {
+ boost::scoped_ptr<CSwordKey> key( CSwordKey::createInstance(module) );
+
+ //skip H or G (language sign) if we have to skip it
+ const bool isOk = key->key( skipFirstChar ? value.mid(1) : value );
+ //Q_ASSERT(isOk);
+ if (!isOk) { //try to use the other morph lexicon, because this one failed with the current morph code
+ key->module(CBTConfig::get
+ (CBTConfig::standardHebrewMorphLexicon));
+ key->key( skipFirstChar ? value.mid(1) : value );
+ }
+
+ text = key->renderedText();
+ }
+
+ //if the module wasn't found just display an empty morph info
+ ret.append( QString("<div class=\"morphinfo\"><h3>%1: %2</h3><p>%3</p></div>")
+ .arg(tr("Morphology"))
+ .arg(value)
+ .arg(text)
+ );
+ }
+
+ return ret;
+}
+
+const QString CInfoDisplay::getWordTranslation( const QString& data ) {
+ CSwordModuleInfo* const module = CBTConfig::get
+ (CBTConfig::standardLexicon);
+ if (!module) {
+ return QString::null;
+ }
+
+ boost::scoped_ptr<CSwordKey> key( CSwordKey::createInstance(module) );
+ key->key( data );
+ if (key->key().toUpper() != data.toUpper()) { //key not present in the lexicon
+ return QString::null;
+ }
+
+ QString ret = QString("<div class=\"translationinfo\"><h3>%1: %2</h3><p>%3</p></div>")
+ .arg(tr("Word lookup"))
+ .arg(data)
+ .arg(key->renderedText());
+
+ return ret;
+}
+
+
+/*!
+ \fn CInfoDisplay::clearInfo()
+ */
+void CInfoDisplay::clearInfo() {
+ CDisplayTemplateMgr* tmgr = CPointers::displayTemplateManager();
+ CDisplayTemplateMgr::Settings settings;
+ settings.pageCSS_ID = "infodisplay";
+
+ m_htmlPart->setText( tmgr->fillTemplate(CBTConfig::get(CBTConfig::displayStyle), QString::null, settings) );
+}
+
+QSize CInfoDisplay::sizeHint() const
+{
+ return QSize(100,150);
+}
+
+} //end of namespace InfoDisplay