/********* * * This file is part of BibleTime's source code, http://www.bibletime.info/. * * Copyright 1999-2009 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ #include "bthtmlreaddisplay.h" #include "bthtmljsobject.h" #include "frontend/displaywindow/cdisplaywindow.h" #include "frontend/displaywindow/creadwindow.h" #include "frontend/cdragdrop.h" #include "frontend/cinfodisplay.h" #include "backend/managers/creferencemanager.h" #include "backend/keys/cswordkey.h" #include "backend/config/cbtconfig.h" #include "util/ctoolclass.h" #include "util/cpointers.h" #include "util/directoryutil.h" #include #include #include using namespace InfoDisplay; void showBtHtmlFindText(CMDIArea*); static const QString body = ""; static const QString jsBegin = ""; static QString javascript; // Initialized from file bthtml.js BtHtmlReadDisplay::BtHtmlReadDisplay(CReadWindow* readWindow, QWidget* parentWidget) : QWebPage(parentWidget),CReadDisplay(readWindow), m_magTimerId(0), m_view(0), m_jsObject(0) { settings()->setAttribute(QWebSettings::JavascriptEnabled, true); m_view = new BtHtmlReadDisplayView(this, parentWidget ? parentWidget : readWindow); m_view->setAcceptDrops(true); m_view->setPage(this); setParent(m_view); m_view->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_view->setHtml(""); initJavascript(); bool ok = connect(this, SIGNAL(loadFinished(bool)), this, SLOT(slotLoadFinished(bool))); Q_ASSERT(ok); } BtHtmlReadDisplay::~BtHtmlReadDisplay() { setView(0); } // Read javascript into memory once and create the c++ javascript object void BtHtmlReadDisplay::initJavascript() { // read bthtml.js javascript file once if (javascript.size() == 0) { QString jsFile = util::filesystem::DirectoryUtil::getJavascriptDir().canonicalPath() + "/bthtml.js"; QFile file(jsFile); if (file.open(QFile::ReadOnly)) { while (!file.atEnd()) { QByteArray line = file.readLine(); javascript = javascript + line; } file.close(); } } // Setup BtHtmlJsObject which will be called from javascript m_jsObject = new BtHtmlJsObject(this); m_jsObject->setObjectName("btHtmlJsObject"); } // When the QWebFrame is cleared, this function is called to install the // javascript object (BtHtmlJsObject class) into the Javascript model void BtHtmlReadDisplay::loadJSObject() { mainFrame()->addToJavaScriptWindowObject(m_jsObject->objectName(), m_jsObject); } const QString BtHtmlReadDisplay::text( const CDisplay::TextType format, const CDisplay::TextPart part) { switch (part) { case Document: { if (format == HTMLText) { return mainFrame()->toHtml(); } else { CDisplayWindow* window = parentWindow(); CSwordKey* const key = window->key(); CSwordModuleInfo* module = key->module(); //This is never used for Bibles, so it is not implemented for //them. If it should be, see CReadDisplay::print() for example //code. Q_ASSERT(module->type() == CSwordModuleInfo::Lexicon || module->type() == CSwordModuleInfo::Commentary || module->type() == CSwordModuleInfo::GenericBook); if (module->type() == CSwordModuleInfo::Lexicon || module->type() == CSwordModuleInfo::Commentary || module->type() == CSwordModuleInfo::GenericBook){ //TODO: This is a BAD HACK, we have to fnd a better solution to manage the settings now CSwordBackend::FilterOptions filterOptions; filterOptions.footnotes = false; filterOptions.strongNumbers = false; filterOptions.morphTags = false; filterOptions.lemmas = false; filterOptions.scriptureReferences = false; filterOptions.textualVariants = false; CPointers::backend()->setFilterOptions(filterOptions); return QString(key->strippedText()).append("\n(") .append(key->key()) .append(", ") .append(key->module()->name()) .append(")"); } } } case SelectedText: { if (!hasSelection()) { return QString::null; } else if (format == HTMLText) { // TODO: It does not appear this is ever called } else { //plain text requested return selectedText(); } } case AnchorOnly: { QString moduleName; QString keyName; CReferenceManager::Type type; CReferenceManager::decodeHyperlink(activeAnchor(), moduleName, keyName, type); return keyName; } case AnchorTextOnly: { QString moduleName; QString keyName; CReferenceManager::Type type; CReferenceManager::decodeHyperlink(activeAnchor(), moduleName, keyName, type); if (CSwordModuleInfo* module = backend()->findModuleByName(moduleName)) { boost::scoped_ptr key( CSwordKey::createInstance(module) ); key->key( keyName ); return key->strippedText(); } return QString::null; } case AnchorWithText: { QString moduleName; QString keyName; CReferenceManager::Type type; CReferenceManager::decodeHyperlink(activeAnchor(), moduleName, keyName, type); if (CSwordModuleInfo* module = backend()->findModuleByName(moduleName)) { boost::scoped_ptr key( CSwordKey::createInstance(module) ); key->key( keyName ); //TODO: This is a BAD HACK, we have to fnd a better solution to manage the settings now CSwordBackend::FilterOptions filterOptions; filterOptions.footnotes = false; filterOptions.strongNumbers = false; filterOptions.morphTags = false; filterOptions.lemmas = false; filterOptions.scriptureReferences = false; filterOptions.textualVariants = false; CPointers::backend()->setFilterOptions(filterOptions); return QString(key->strippedText()).append("\n(") .append(key->key()) .append(", ") .append(key->module()->name()) .append(")"); /* ("%1\n(%2, %3)") .arg() .arg(key->key()) .arg(key->module()->name());*/ } return QString::null; } default: return QString::null; } return QString(); } // Puts html text and javascript into QWebView void BtHtmlReadDisplay::setText( const QString& newText ) { QString jsText = newText; jsText.replace(body,jsBegin+javascript+jsEnd+body); // Disconnect any previous connect and connect to slot that loads the javascript object QWebFrame* frame = mainFrame(); disconnect(frame,SIGNAL(javaScriptWindowObjectCleared()),0,0); bool ok = connect(frame,SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(loadJSObject())); Q_ASSERT(ok); // Send text to the html viewer m_view->setHtml(jsText); } // See if any text is selected bool BtHtmlReadDisplay::hasSelection() { if (selectedText().isEmpty()) return false; return true; } // Reimplementation // Returns the BtHtmlReadDisplayView object QWidget* BtHtmlReadDisplay::view() { return m_view; } // Select all text in the viewer void BtHtmlReadDisplay::selectAll() { m_jsObject->setBodyEditable(true); m_view->triggerPageAction( QWebPage::MoveToStartOfDocument, true ); m_view->triggerPageAction( QWebPage::SelectEndOfDocument, true ); m_jsObject->setBodyEditable(false); } // Scroll QWebView to the correct location as specified by the anchor void BtHtmlReadDisplay::moveToAnchor( const QString& anchor ) { slotGoToAnchor(anchor); } // Scroll the QWebView to the correct location specified by anchor void BtHtmlReadDisplay::slotGoToAnchor(const QString& anchor) { m_jsObject->moveToAnchor(anchor); } // Save the Lemma (Strongs number) attribute void BtHtmlReadDisplay::setLemma(const QString& lemma) { m_nodeInfo[ CDisplay::Lemma ] = lemma; } // Open the Find text dialog void BtHtmlReadDisplay::openFindTextDialog() { CMDIArea* mdiArea = parentWindow()->mdi(); showBtHtmlFindText(mdiArea); } // Send "completed" signal when the text is finished loading into the viewer void BtHtmlReadDisplay::slotLoadFinished(bool) { emit completed(); } // For debugging javascript - set breakpoint in this function to catch javascript error messages #if DEBUG_JS void BtHtmlReadDisplay::javaScriptConsoleMessage (const QString& message, int lineNumber, const QString& sourceID ) { } #endif // ----------------- BtHtmlReadDisplayView ------------------------------------- BtHtmlReadDisplayView::BtHtmlReadDisplayView(BtHtmlReadDisplay* displayWidget, QWidget* parent) : QWebView(parent), m_display(displayWidget) { } BtHtmlReadDisplayView::~BtHtmlReadDisplayView() { setPage(0); } // Create the right mouse context menus void BtHtmlReadDisplayView::contextMenuEvent(QContextMenuEvent* event) { if (QMenu* popup = m_display->installedPopup()) { popup->exec(event->globalPos()); } } // Reimplementation from QWidget void BtHtmlReadDisplayView::dropEvent( QDropEvent* e ) { if (e->mimeData()->hasFormat("BibleTime/Bookmark")) { //see docs for BTMimeData and QMimeData const QMimeData* mimedata = e->mimeData(); if (mimedata != 0) { const BTMimeData* btmimedata = qobject_cast(mimedata); if (btmimedata != 0) { BookmarkItem item = (qobject_cast(e->mimeData()))->bookmark(); m_display->connectionsProxy()->emitReferenceDropped(item.key()); e->acceptProposedAction(); return; } } }; //don't accept the action! e->ignore(); } // Reimplementation from QWebView void BtHtmlReadDisplayView::dragEnterEvent( QDragEnterEvent* e ) { if (e->mimeData()->hasFormat("BibleTime/Bookmark")) { e->acceptProposedAction(); return; } //don't accept the action! e->ignore(); } // Reimplementation from QWebView void BtHtmlReadDisplayView::dragMoveEvent( QDragMoveEvent* e ) { if (e->mimeData()->hasFormat("BibleTime/Bookmark")) { e->acceptProposedAction(); return; } //don't accept the action! e->ignore(); } bool BtHtmlReadDisplayView::event(QEvent* e) { // If the mouse leaves the widget clear the previous attribute // in bthtmljsobject. This cancels any time out event that // is in progress. if ( e->type() == QEvent::Leave ) m_display->m_jsObject->clearPrevAttribute(); return QWidget::event(e); }