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";

    // lookup text and wrap in a "div" with language set to module language
    QString lang = m->language()->abbrev();
    QString renderedText = key->renderedText();
    QString divText = "<div class=\"infodisplay\" lang=\"";
        divText.append(lang);
        divText.append("\">");
        divText.append(renderedText);
        divText.append("</div>");

	QString content = mgr->fillTemplate(CBTConfig::get
				(CBTConfig::displayStyle), divText, settings);

	m_htmlPart->setText(content);
}
QString ModuleInterface::language(int index) {
    if (index < 0 || index >= m_modules.count())
        return "";
    CSwordModuleInfo* module = m_modules.at(index);
    if (module == 0)
        return "";
    const CLanguageMgr::Language* language = module->language();
    if (language == 0)
        return "";
    return language->translatedName();
}
/*!
	\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\" lang=\"%1\"><h3>%2</h3><p>%3</p></div>")
            .arg(module->language()->abbrev())
			.arg(tr("Footnote"))
			.arg(text);
}
void ModuleInterface::updateWorksModel() {
    m_worksModel.clear();
    m_modules.clear();

    QString currentLang = currentLanguage();
    QString currentCat = currentCategory();

    QHash<int, QByteArray> roleNames;
    roleNames[TextRole] =  "modelText";
    m_worksModel.setRoleNames(roleNames);

    BtBookshelfModel* bookshelfModel = CSwordBackend::instance()->model();
    if (bookshelfModel == 0)
        return;
    int count = bookshelfModel->rowCount();
    for (int row=0; row<count; ++row) {
        QModelIndex index = bookshelfModel->index(row);
        CSwordModuleInfo* module = getModule(bookshelfModel, index);
        CSwordModuleInfo::Category category = module->category();
        QString categoryName = module->categoryName(category);
        const CLanguageMgr::Language* language = module->language();
        QString languageName = language->translatedName();
        if (languageName == currentLang &&
                categoryName == currentCat) {
            m_modules << module;
            QString moduleName = module->name();
            QStandardItem* item = new QStandardItem();
            item->setData(moduleName, TextRole);
            m_worksModel.appendRow(item);
        }
    }

    QQuickItem* object = findQmlObject("moduleChooser");
    if (object == 0)
        return;
    object->setProperty("worksModel", QVariant::fromValue(&m_worksModel));
}
void ModuleInterface::getCategoriesAndLanguages() {

    m_categories.clear();
    m_languages.clear();

    QQuickItem* object = findQmlObject("moduleChooser");
    if (object == 0)
        return;

    BtBookshelfModel* bookshelfModel = CSwordBackend::instance()->model();
    if (bookshelfModel == 0)
        return;
    int count = bookshelfModel->rowCount();
    for (int row=0; row<count; ++row) {
        QModelIndex index = bookshelfModel->index(row);
        CSwordModuleInfo* module = getModule(bookshelfModel, index);
        CSwordModuleInfo::Category category = module->category();
        QString categoryName = module->categoryName(category);
        const CLanguageMgr::Language* language = module->language();
        QString languageName = language->translatedName();
        m_categories.insert(categoryName);
        m_languages.insert(languageName);
    }
}
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
        QString lang = "en";  // default to english
        if (module)
            lang = module->language()->abbrev();
		ret.append( QString("<div class=\"morphinfo\" lang=\"%1\"><h3>%2: %3</h3><p>%4</p></div>")
                    .arg(lang)
					.arg(tr("Morphology"))
					.arg(value)
					.arg(text)
					);
	}
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
    QString lang = "en";  // default english
    if (module)
        lang = module->language()->abbrev();
	return QString("<div class=\"crossrefinfo\" lang=\"%1\"><h3>%2</h3><div class=\"para\" dir=\"%3\">%4</div></div>")
            .arg(lang)
			.arg(tr("Cross references"))
	        .arg(module ? ((module->textDirection() == CSwordModuleInfo::LeftToRight) ? "ltr" : "rtl") : "")
			.arg(renderer.renderKeyTree(tree));
}