You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bibletime/bibletime/backend/ctextrendering.cpp

279 lines
8.3 KiB

//
// C++ Implementation: ctextrendering
//
// Description:
//
//
// Author: The BibleTime team <info@bibletime.info>, (C) 2004
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "ctextrendering.h"
//BibleTime includes
#include "backend/cswordkey.h"
#include "backend/cswordversekey.h"
#include "backend/cswordmoduleinfo.h"
#include "backend/cdisplaytemplatemgr.h"
#include "backend/creferencemanager.h"
#include "util/scoped_resource.h"
#include "util/ctoolclass.h"
//Sword includes
#include <swkey.h>
//TQt includes
#include <tqregexp.h>
//KDE includes
#include <klocale.h>
#include <kurl.h>
using namespace Rendering;
CTextRendering::KeyTreeItem::KeyTreeItem(const TQString& key, CSwordModuleInfo const * mod, const Settings settings )
: m_settings( settings ),
m_moduleList(),
m_key( key ),
m_childList( 0 ),
m_stopKey( TQString() ),
m_alternativeContent( TQString() ) {
m_moduleList.append( const_cast<CSwordModuleInfo*>(mod) ); //BAD CODE
}
CTextRendering::KeyTreeItem::KeyTreeItem(const TQString& content, const Settings settings )
: m_settings( settings ),
m_moduleList(),
m_key( TQString() ),
m_childList( 0 ),
m_stopKey( TQString() ),
m_alternativeContent( content ) {}
CTextRendering::KeyTreeItem::KeyTreeItem(const TQString& key, const ListCSwordModuleInfo& mods, const Settings settings )
: m_settings( settings ),
m_moduleList( mods ),
m_key( key ),
m_childList( 0 ),
m_stopKey( TQString() ),
m_alternativeContent( TQString() ) {}
CTextRendering::KeyTreeItem::KeyTreeItem()
: m_settings(),
m_moduleList(),
m_key(TQString()),
m_childList(0),
m_stopKey(TQString()),
m_alternativeContent(TQString()) {}
CTextRendering::KeyTreeItem::KeyTreeItem(const KeyTreeItem& i)
: m_settings( i.m_settings ),
m_moduleList( i.m_moduleList ),
m_key( i.m_key ),
m_childList( 0 ),
m_stopKey( i.m_stopKey ),
m_alternativeContent( i.m_alternativeContent ) {
if (i.hasChildItems()) {
m_childList = new KeyTree();
*m_childList = *(i.childList()); //deep copy
}
}
CTextRendering::KeyTreeItem::~KeyTreeItem() {
delete m_childList;
m_childList = 0;
}
CTextRendering::KeyTreeItem::KeyTreeItem(const TQString& startKey, const TQString& stopKey, CSwordModuleInfo* module, const Settings settings)
: m_settings( settings ),
m_moduleList(),
m_key( startKey ),
m_childList( 0 ),
m_stopKey( stopKey ),
m_alternativeContent( TQString() ) {
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 = startKey;
CSwordVerseKey stop(module);
stop = stopKey;
if (!m_key.isEmpty() && !m_stopKey.isEmpty()) { //we have a range of keys
bool ok = true;
while (ok && ((start < stop) || (start == stop)) ) { //range
childList()->append(
new KeyTreeItem(start.key(), module, KeyTreeItem::Settings(false, settings.keyRenderingFace))
);
ok = start.next(CSwordVerseKey::UseVerse);
}
}
else if (m_key.isEmpty()) {
childList()->append( new KeyTreeItem(startKey, module, KeyTreeItem::Settings(false, settings.keyRenderingFace)) );
}
}
else if ((module->type() == CSwordModuleInfo::Lexicon) || (module->type() == CSwordModuleInfo::Commentary) ) {
childList()->append( new KeyTreeItem(startKey, module, KeyTreeItem::Settings(false, KeyTreeItem::Settings::NoKey)) );
}
else if (module->type() == CSwordModuleInfo::GenericBook) {
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.utf8(), stopKey.utf8());
if (vk.LowerBound().Book() != vk.UpperBound().Book()) {
m_alternativeContent = TQString::fromUtf8(vk.getRangeText());
}
else if (vk.LowerBound().Chapter() != vk.UpperBound().Chapter()) {
m_alternativeContent = TQString("%1 - %2:%3")
.arg(TQString::fromUtf8(vk.LowerBound().getText()))
.arg(vk.UpperBound().Chapter())
.arg(vk.UpperBound().Verse());
}
else { //only verses differ (same book, same chapter)
m_alternativeContent = TQString("%1 - %2")
.arg(TQString::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 TQString& CTextRendering::KeyTreeItem::getAlternativeContent() const {
return m_alternativeContent;
}
ListCSwordModuleInfo CTextRendering::KeyTree::collectModules() const {
//collect all modules which are available and used by child items
ListCSwordModuleInfo modules;
for (KeyTreeItem* c = first(); c; c = next()) {
Q_ASSERT(c);
ListCSwordModuleInfo childMods = c->modules();
/*ToDo: Use the const iterators as soon as we use TQt > 3.1
const ListCSwordModuleInfo::const_iterator c_end = childMods.end();
for (ListCSwordModuleInfo::const_iterator c_it = childMods.constBegin(); c_it != c_end; ++c_it) {
if (!modules.contains(*c_it)) {
modules.append(*c_it);
}
}*/
// for (CSwordModuleInfo* m = childMods.first(); m; m = childMods.next()) {
ListCSwordModuleInfo::iterator end_it = childMods.end();
for (ListCSwordModuleInfo::iterator it(childMods.begin()); it != end_it; ++it) {
if (!modules.contains(*it)) {
modules.append(*it);
}
}
}
return modules;
}
const TQString CTextRendering::renderKeyTree( KeyTree& tree ) {
initRendering();
ListCSwordModuleInfo modules = tree.collectModules();
TQString t;
//optimization for entries with the same key
util::scoped_ptr<CSwordKey> key(
(modules.count() == 1) ? CSwordKey::createInstance(modules.first()) : 0
);
for (KeyTreeItem* c = tree.first(); c; c = tree.next()) {
if (modules.count() == 1) { //this optimizes the rendering, only one key created for all items
key->key( c->key() );
t.append( renderEntry( *c, key) );
}
else {
t.append( renderEntry( *c ) );
}
}
return finishText(t, tree);
}
const TQString CTextRendering::renderKeyRange( const TQString& start, const TQString& stop, const ListCSwordModuleInfo& modules, const TQString& highlightKey, const KeyTreeItem::Settings& keySettings ) {
CSwordModuleInfo* module = modules.first();
//tqWarning( "renderKeyRange start %s stop %s \n", start.latin1(), stop.latin1() );
util::scoped_ptr<CSwordKey> lowerBound( CSwordKey::createInstance(module) );
lowerBound->key(start);
util::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 TQString();
}
const TQString CTextRendering::renderSingleKey( const TQString& key, const ListCSwordModuleInfo& moduleList, const KeyTreeItem::Settings& settings ) {
KeyTree tree;
tree.append( new KeyTreeItem(key, moduleList, settings) );
return renderKeyTree(tree);
}