Пример #1
0
QString Import::toString(bool addSemicolon, bool skipAlias) const
{
    QString result = QLatin1String("import ");

    if (isFileImport())
        result += '"' + file() + '"';
    else if (isLibraryImport())
        result += url();
    else
        return QString();

    if (hasVersion())
        result += ' ' + version();

    if (hasAlias() && !skipAlias)
        result += " as " + alias();

    if (addSemicolon)
        result += ';';

    return result;
}
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());
}
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;
}
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.
        // turn on these options, they are needed for the EntryAttributes population
        backend()->setOption( CSwordModuleInfo::strongNumbers,  true );
        backend()->setOption( CSwordModuleInfo::morphTags,  true );
        backend()->setOption( CSwordModuleInfo::footnotes,  true );
        backend()->setOption( CSwordModuleInfo::headings,  true );
        // we don't want the following in the text, the do not carry searchable information
        backend()->setOption( CSwordModuleInfo::morphSegmentation,  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)++) {

            // Also index Chapter 0 and Verse 0, because they might have information in the entry attributes
            // We used to just put their content into the textBuffer and continue to the next verse, but
            // with entry attributes this doesn't work any more.
            // Hits in the search dialog will show up as 1:1 (instead of 0)

            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(*(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) {
            deleteIndex();
            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);
            emit hasIndexChanged(true);
        }
    }
    catch (...) {
        qWarning("CLucene exception occurred while indexing");
        util::showWarning(0, QCoreApplication::tr("Indexing aborted"), QCoreApplication::tr("An internal error occurred while building the index."));
        deleteIndex();
        m_cancelIndexing = false;
    }
}