/********* * * This file is part of BibleTime's source code, http://www.bibletime.info/. * * Copyright 1999-2016 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ #include "frontend/cexportmanager.h" #include #include #include #include #include #include #include "backend/drivers/cswordmoduleinfo.h" #include "backend/keys/cswordkey.h" #include "backend/keys/cswordversekey.h" #include "backend/managers/referencemanager.h" #include "backend/managers/cdisplaytemplatemgr.h" #include "backend/rendering/centrydisplay.h" #include "backend/rendering/chtmlexportrendering.h" #include "backend/rendering/cplaintextexportrendering.h" #include "frontend/btprinter.h" #include "util/btassert.h" #include "util/tool.h" // Sword includes: #include #include using namespace Rendering; using KTI = CTextRendering::KeyTreeItem; namespace { QTextCodec * getCodec(CExportManager::Format const format) { if (format == CExportManager::HTML) return QTextCodec::codecForName("UTF-8"); return QTextCodec::codecForLocale(); } } // anonymous namespace CExportManager::CExportManager(bool const showProgress, QString const & progressLabel, FilterOptions const & filterOptions, DisplayOptions const & displayOptions) { m_filterOptions = filterOptions; m_displayOptions = displayOptions; if (showProgress) { m_progressDialog = new QProgressDialog{nullptr, Qt::Dialog}; m_progressDialog->setWindowTitle("BibleTime"); m_progressDialog->setLabelText(progressLabel); } else { m_progressDialog = nullptr; } } CExportManager::~CExportManager() { delete m_progressDialog; } bool CExportManager::saveKey(CSwordKey const * const key, Format const format, bool const addText) { if (!key || !key->module()) return false; QString const filename = getSaveFileName(format); if (filename.isEmpty()) return false; QString text; { BtConstModuleList modules; modules.append(key->module()); CSwordVerseKey const * const vk = dynamic_cast(key); auto const render = newRenderer(format, addText); if (vk && vk->isBoundSet()) { text = render->renderKeyRange( QString::fromUtf8(vk->getLowerBound()), QString::fromUtf8(vk->getUpperBound()), modules); } else { // no range supported text = render->renderSingleKey(key->key(), modules); } } util::tool::savePlainFile(filename, text, false, getCodec(format)); return true; } bool CExportManager::saveKeyList(sword::ListKey const & l, CSwordModuleInfo const * module, Format const format, bool const addText) { if (!l.getCount()) return false; QString const filename = getSaveFileName(format); if (filename.isEmpty()) return false; CTextRendering::KeyTree tree; /// \todo Verify that items in tree are properly freed. setProgressRange(l.getCount()); KTI::Settings itemSettings; itemSettings.highlight = false; sword::ListKey list(l); list.setPosition(sword::TOP); while (!list.popError()) { if (progressWasCancelled()) return false; tree.append(new KTI(QString::fromLocal8Bit(list.getText()), module, itemSettings)); incProgress(); list.increment(); } QString const text = newRenderer(format, addText)->renderKeyTree(tree); util::tool::savePlainFile(filename, text, false, getCodec(format)); closeProgressDialog(); return true; } bool CExportManager::saveKeyList(QList const & list, Format const format, bool const addText) { if (list.empty()) return false; const QString filename = getSaveFileName(format); if (filename.isEmpty()) return false; CTextRendering::KeyTree tree; /// \todo Verify that items in tree are properly freed. KTI::Settings itemSettings; itemSettings.highlight = false; setProgressRange(list.count()); for (CSwordKey const * const k : list) { if (progressWasCancelled()) return false; tree.append(new KTI(k->key(), k->module(), itemSettings)); incProgress(); }; QString const text = newRenderer(format, addText)->renderKeyTree(tree); util::tool::savePlainFile(filename, text, false, getCodec(format)); closeProgressDialog(); return true; } namespace { template inline void copyToClipboard(Arg && arg) { QApplication::clipboard()->setText(std::forward(arg)); } } // anonymous namespace bool CExportManager::copyKey(CSwordKey const * const key, Format const format, bool const addText) { if (!key || !key->module()) return false; QString text; BtConstModuleList modules; modules.append(key->module()); { auto const render = newRenderer(format, addText); CSwordVerseKey const * const vk = dynamic_cast(key); if (vk && vk->isBoundSet()) { text = render->renderKeyRange( QString::fromUtf8(vk->getLowerBound()), QString::fromUtf8(vk->getUpperBound()), modules ); } else { // no range supported text = render->renderSingleKey(key->key(), modules); } } copyToClipboard(text); return true; } bool CExportManager::copyKeyList(sword::ListKey const & l, CSwordModuleInfo const * const module, Format const format, bool const addText) { sword::ListKey list = l; if (!list.getCount()) return false; CTextRendering::KeyTree tree; /// \todo Verify that items in tree are properly freed. KTI::Settings itemSettings; itemSettings.highlight = false; list.setPosition(sword::TOP); while (!list.popError()) { if (progressWasCancelled()) return false; tree.append(new KTI(QString::fromLocal8Bit(list.getText()), module, itemSettings)); list.increment(); } copyToClipboard(newRenderer(format, addText)->renderKeyTree(tree)); closeProgressDialog(); return true; } bool CExportManager::copyKeyList(QList const & list, Format const format, bool const addText) { if (list.empty()) return false; CTextRendering::KeyTree tree; /// \todo Verify that items in tree are properly freed. KTI::Settings itemSettings; itemSettings.highlight = false; setProgressRange(list.count()); for (CSwordKey const * const k : list) { if (progressWasCancelled()) return false; tree.append(new KTI(k->key(), k->module(), itemSettings)); incProgress(); }; copyToClipboard(newRenderer(format, addText)->renderKeyTree(tree)); closeProgressDialog(); return true; } namespace { struct PrintSettings: BtPrinter::KeyTreeItem::Settings { PrintSettings(DisplayOptions const & displayOptions) : BtPrinter::KeyTreeItem::Settings{ false, displayOptions.verseNumbers ? Settings::SimpleKey : Settings::NoKey} {} }; } // anonymous namespace bool CExportManager::printKey(CSwordKey const * const key, DisplayOptions const & displayOptions, FilterOptions const & filterOptions) { PrintSettings settings{displayOptions}; BtPrinter::KeyTree tree; /// \todo Verify that items in tree are properly freed. tree.append(new BtPrinter::KeyTreeItem(key->key(), key->module(), settings)); BtPrinter{displayOptions, filterOptions}.printKeyTree(tree); return true; } bool CExportManager::printKey(CSwordModuleInfo const * const module, QString const & startKey, QString const & stopKey, DisplayOptions const & displayOptions, FilterOptions const & filterOptions) { PrintSettings settings{displayOptions}; BtPrinter::KeyTree tree; /// \todo Verify that items in tree are properly freed. if (startKey != stopKey) { tree.append(new BtPrinter::KeyTreeItem(startKey, stopKey, module, settings)); } else { tree.append(new BtPrinter::KeyTreeItem(startKey, module, settings)); } BtPrinter{displayOptions, filterOptions}.printKeyTree(tree); return true; } bool CExportManager::printByHyperlink(QString const & hyperlink, DisplayOptions const & displayOptions, FilterOptions const & filterOptions) { QString moduleName; QString keyName; ReferenceManager::Type type; ReferenceManager::decodeHyperlink(hyperlink, moduleName, keyName, type); if (moduleName.isEmpty()) moduleName = ReferenceManager::preferredModule(type); BtPrinter::KeyTree tree; /// \todo Verify that items in tree are properly freed. PrintSettings settings{displayOptions}; CSwordModuleInfo const * module = CSwordBackend::instance()->findModuleByName(moduleName); BT_ASSERT(module); //check if we have a range of entries or a single one if ((module->type() == CSwordModuleInfo::Bible) || (module->type() == CSwordModuleInfo::Commentary)) { sword::ListKey const verses = sword::VerseKey().parseVerseList( keyName.toUtf8().constData(), "Genesis 1:1", true); for (int i = 0; i < verses.getCount(); i++) { if (sword::VerseKey const * const element = dynamic_cast(verses.getElement(i))) { tree.append( new BtPrinter::KeyTreeItem( QString::fromUtf8( element->getLowerBound().getText()), QString::fromUtf8( element->getUpperBound().getText()), module, settings) ); } else if (verses.getElement(i)) { tree.append( new BtPrinter::KeyTreeItem( QString::fromUtf8(verses.getElement(i)->getText()), module, settings) ); } } } else { tree.append(new BtPrinter::KeyTreeItem(keyName, module, settings)); } BtPrinter{displayOptions, filterOptions}.printKeyTree(tree); return true; } bool CExportManager::printKeyList(sword::ListKey const & list, CSwordModuleInfo const * const module, DisplayOptions const & displayOptions, FilterOptions const & filterOptions) { if (!list.getCount()) return false; PrintSettings settings{displayOptions}; BtPrinter::KeyTree tree; /// \todo Verify that items in tree are properly freed. setProgressRange(list.getCount()); for (int i = 0; i < list.getCount(); i++) { if (progressWasCancelled()) return false; sword::SWKey const * const swKey = list.getElement(i); if (sword::VerseKey const * const vKey = dynamic_cast(swKey)) { QString const startKey = vKey->getText(); tree.append(new KTI(startKey, startKey, module, settings)); } else { QString const key = swKey->getText(); tree.append(new KTI(key, key, module, settings)); } incProgress(); } BtPrinter{displayOptions, filterOptions}.printKeyTree(tree); closeProgressDialog(); return true; } bool CExportManager::printKeyList(QStringList const & list, CSwordModuleInfo const * const module, DisplayOptions const & displayOptions, FilterOptions const & filterOptions) { if (list.empty()) return false; PrintSettings settings{displayOptions}; BtPrinter::KeyTree tree; /// \todo Verify that items in tree are properly freed. setProgressRange(list.count()); for (QString const & key: list) { if (progressWasCancelled()) return false; tree.append(new BtPrinter::KeyTreeItem(key, module, settings)); incProgress(); } BtPrinter{displayOptions, filterOptions}.printKeyTree(tree); closeProgressDialog(); return true; } /** Returns the string for the filedialogs to show the correct files. */ const QString CExportManager::filterString( const Format format ) { QString const allFiles = QObject::tr("All files") + QString(" (*.*)"); switch (format) { case HTML: return allFiles + QObject::tr("HTML files") + QString(" (*.html *.htm);;"); case Text: return allFiles + QObject::tr("Text files") + QString(" (*.txt);;"); default: return allFiles; } } /** Returns a filename to save a file. */ const QString CExportManager::getSaveFileName(const Format format) { return QFileDialog::getSaveFileName(nullptr, QObject::tr("Save file"), "", filterString(format), nullptr); } std::unique_ptr CExportManager::newRenderer(Format const format, bool const addText) { FilterOptions filterOptions = m_filterOptions; filterOptions.footnotes = false; filterOptions.strongNumbers = false; filterOptions.morphTags = false; filterOptions.lemmas = false; filterOptions.scriptureReferences = false; filterOptions.textualVariants = false; using R = std::unique_ptr; BT_ASSERT((format == Text) || (format == HTML)); if (format == HTML) return R{new CHTMLExportRendering(addText, m_displayOptions, filterOptions)}; return R{new CPlainTextExportRendering(addText, m_displayOptions, filterOptions)}; } void CExportManager::setProgressRange(int const items) { if (!m_progressDialog) return; m_progressDialog->setMaximum(items); m_progressDialog->setValue(0); m_progressDialog->setMinimumDuration(0); m_progressDialog->show(); // m_progressDialog->repaint(); qApp->processEvents(); //do not lock the GUI! } /** Increments the progress by one item. */ void CExportManager::incProgress() { if (m_progressDialog) m_progressDialog->setValue(m_progressDialog->value() + 1); } bool CExportManager::progressWasCancelled() { return m_progressDialog ? m_progressDialog->wasCanceled() : false; } /** Closes the progress dialog immediatly. */ void CExportManager::closeProgressDialog() { if (m_progressDialog) { m_progressDialog->close(); m_progressDialog->reset(); } qApp->processEvents(); //do not lock the GUI! }