/*************************************************************************** copyright : (C) 2003-2006 by Robby Stephenson email : robby@periapsis.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of version 2 of the GNU General Public License as * * published by the Free Software Foundation; * * * ***************************************************************************/ #include "entryview.h" #include "entry.h" #include "field.h" #include "filehandler.h" #include "translators/xslthandler.h" #include "translators/tellicoxmlexporter.h" #include "collection.h" #include "imagefactory.h" #include "tellico_kernel.h" #include "tellico_utils.h" #include "core/tellico_config.h" #include "newstuff/manager.h" #include "document.h" #include "latin1literal.h" #include "../core/drophandler.h" #include "../tellico_debug.h" #include #include #include #include #include #include #include #include #include #include using Tellico::EntryView; using Tellico::EntryViewWidget; EntryViewWidget::EntryViewWidget(TDEHTMLPart* part, TQWidget* parent) : TDEHTMLView(part, parent) {} // for the life of me, I could not figure out how to call the actual // TDEHTMLPartBrowserExtension::copy() slot, so this will have to do void EntryViewWidget::copy() { TQString text = part()->selectedText(); TQApplication::clipboard()->setText(text, TQClipboard::Clipboard); } EntryView::EntryView(TQWidget* parent_, const char* name_) : TDEHTMLPart(new EntryViewWidget(this, parent_), parent_, name_), m_entry(0), m_handler(0), m_run(0), m_tempFile(0), m_useGradientImages(true), m_checkCommonFile(true) { setJScriptEnabled(false); setJavaEnabled(false); setMetaRefreshEnabled(false); setPluginsEnabled(false); clear(); // needed for initial layout view()->setAcceptDrops(true); DropHandler* drophandler = new DropHandler(this); view()->installEventFilter(drophandler); connect(browserExtension(), TQ_SIGNAL(openURLRequest(const KURL&, const KParts::URLArgs&)), TQ_SLOT(slotOpenURL(const KURL&))); connect(kapp, TQ_SIGNAL(tdedisplayPaletteChanged()), TQ_SLOT(slotResetColors())); } EntryView::~EntryView() { if(m_run) { m_run->abort(); } delete m_handler; m_handler = 0; delete m_tempFile; m_tempFile = 0; } void EntryView::clear() { m_entry = 0; // just clear the view begin(); if(!m_textToShow.isEmpty()) { write(m_textToShow); } end(); view()->layout(); // I need this because some of the margins and widths may get messed up } void EntryView::showEntry(Data::EntryPtr entry_) { if(!entry_) { clear(); return; } m_textToShow = TQString(); #if 0 kdWarning() << "EntryView::showEntry() - turn me off!" << endl; m_entry = 0; setXSLTFile(m_xsltFile); #endif if(!m_handler || !m_handler->isValid()) { setXSLTFile(m_xsltFile); } m_entry = entry_; // by setting the xslt file as the URL, any images referenced in the xslt "theme" can be found // by simply using a relative path in the xslt file KURL u; u.setPath(m_xsltFile); begin(u); Export::TellicoXMLExporter exporter(entry_->collection()); exporter.setEntries(entry_); long opt = exporter.options(); // verify images for the view opt |= Export::ExportVerifyImages; // on second thought, don't auto-format everything, just clean it // if(Data::Field::autoFormat()) { // opt = Export::ExportFormatted; // } if(entry_->collection()->type() == Data::Collection::Bibtex) { opt |= Export::ExportClean; } exporter.setOptions(opt); TQDomDocument dom = exporter.exportXML(); // myDebug() << dom.toString() << endl; #if 0 kdWarning() << "EntryView::showEntry() - turn me off!" << endl; TQFile f1(TQString::fromLatin1("/tmp/test.xml")); if(f1.open(IO_WriteOnly)) { TQTextStream t(&f1); t << dom.toString(); } f1.close(); #endif TQString html = m_handler->applyStylesheet(dom.toString()); // write out image files Data::FieldVec fields = entry_->collection()->imageFields(); for(Data::FieldVec::Iterator field = fields.begin(); field != fields.end(); ++field) { TQString id = entry_->field(field); if(id.isEmpty()) { continue; } if(Data::Document::self()->allImagesOnDisk()) { ImageFactory::writeCachedImage(id, ImageFactory::DataDir); } else { ImageFactory::writeCachedImage(id, ImageFactory::TempDir); } } #if 0 kdWarning() << "EntryView::showEntry() - turn me off!" << endl; TQFile f2(TQString::fromLatin1("/tmp/test.html")); if(f2.open(IO_WriteOnly)) { TQTextStream t(&f2); t << html; } f2.close(); #endif // myDebug() << html << endl; write(html); end(); // not need anymore? view()->layout(); // I need this because some of the margins and widths may get messed up } void EntryView::showText(const TQString& text_) { m_textToShow = text_; begin(); write(text_); end(); } void EntryView::setXSLTFile(const TQString& file_) { TQString oldFile = m_xsltFile; // if starts with slash, then absolute path if(file_.at(0) == '/') { m_xsltFile = file_; } else { const TQString templateDir = TQString::fromLatin1("entry-templates/"); m_xsltFile = locate("appdata", templateDir + file_); if(m_xsltFile.isEmpty()) { if(!file_.isEmpty()) { kdWarning() << "EntryView::setXSLTFile() - can't locate " << file_ << endl; } m_xsltFile = locate("appdata", templateDir + TQString::fromLatin1("Fancy.xsl")); if(m_xsltFile.isEmpty()) { TQString str = TQString::fromLatin1(""); str += i18n("Tellico is unable to locate the default entry stylesheet."); str += TQChar(' '); str += i18n("Please check your installation."); str += TQString::fromLatin1(""); KMessageBox::error(view(), str); clear(); return; } } } const int type = m_entry ? m_entry->collection()->type() : Kernel::self()->collectionType(); // we need to know if the colors changed from last time, in case // we need to do that ugly hack to reload the cache bool reloadImages = m_useGradientImages; // if m_useGradientImages is false, then we don't even need to check // if there's no handler, there there's _no way_ to check if(m_handler && reloadImages) { // the only two colors that matter for the gradients are the base color // and highlight base color const TQCString& oldBase = m_handler->param("bgcolor"); const TQCString& oldHigh = m_handler->param("color2"); // remember the string params have apostrophes on either side, so we can start search at pos == 1 reloadImages = oldBase.find(TQString(Config::templateBaseColor(type).name()).latin1(), 1) == -1 || oldHigh.find(TQString(Config::templateHighlightedBaseColor(type).name()).latin1(), 1) == -1; } if(!m_handler || m_xsltFile != oldFile) { delete m_handler; // must read the file name to get proper context m_handler = new XSLTHandler(TQFile::encodeName(m_xsltFile)); if(m_checkCommonFile && !m_handler->isValid()) { NewStuff::Manager::checkCommonFile(); m_checkCommonFile = false; delete m_handler; m_handler = new XSLTHandler(TQFile::encodeName(m_xsltFile)); } if(!m_handler->isValid()) { kdWarning() << "EntryView::setXSLTFile() - invalid xslt handler" << endl; clear(); delete m_handler; m_handler = 0; return; } } m_handler->addStringParam("font", TQString(Config::templateFont(type).family()).latin1()); m_handler->addStringParam("fontsize", TQCString().setNum(Config::templateFont(type).pointSize())); m_handler->addStringParam("bgcolor", TQString(Config::templateBaseColor(type).name()).latin1()); m_handler->addStringParam("fgcolor", TQString(Config::templateTextColor(type).name()).latin1()); m_handler->addStringParam("color1", TQString(Config::templateHighlightedTextColor(type).name()).latin1()); m_handler->addStringParam("color2", TQString(Config::templateHighlightedBaseColor(type).name()).latin1()); if(Data::Document::self()->allImagesOnDisk()) { m_handler->addStringParam("imgdir", TQFile::encodeName(ImageFactory::dataDir())); } else { m_handler->addStringParam("imgdir", TQFile::encodeName(ImageFactory::tempDir())); } // look for a file that gets installed to know the installation directory TQString appdir = TDEGlobal::dirs()->findResourceDir("appdata", TQString::fromLatin1("pics/tellico.png")); m_handler->addStringParam("datadir", TQFile::encodeName(appdir)); // if we don't have to reload the images, then just show the entry and we're done if(!reloadImages) { showEntry(m_entry); return; } // now, have to recreate images and refresh tdehtml cache resetColors(); } void EntryView::slotRefresh() { setXSLTFile(m_xsltFile); showEntry(m_entry); view()->repaint(); } // do some contortions in case the url is relative // need to interpret it relative to document URL instead of xslt file // the current node under the mouse vould be the text node inside // the anchor node, so iterate up the parents void EntryView::slotOpenURL(const KURL& url_) { if(url_.protocol() == Latin1Literal("tc")) { // handle this internally emit signalAction(url_); return; } KURL u = url_; for(DOM::Node node = nodeUnderMouse(); !node.isNull(); node = node.parentNode()) { if(node.nodeType() == DOM::Node::ELEMENT_NODE && static_cast(node).tagName() == "a") { TQString href = static_cast(node).getAttribute("href").string(); if(!href.isEmpty() && KURL::isRelativeURL(href)) { // interpet url relative to document url u = KURL(Kernel::self()->URL(), href); } break; } } // open the url, m_run gets auto-deleted m_run = new KRun(u); } void EntryView::slotReloadEntry() { // this slot should only be connected in setXSLTFile() // must disconnect the signal first, otherwise, get an infinite loop disconnect(TQ_SIGNAL(completed())); closeURL(); // this is needed to stop everything, for some reason view()->setUpdatesEnabled(true); if(m_entry) { showEntry(m_entry); } else { // setXSLTFile() writes some html to clear the image cache // but we don't want to see that, so just clear everything clear(); } delete m_tempFile; m_tempFile = 0; } void EntryView::setXSLTOptions(const StyleOptions& opt_) { m_handler->addStringParam("font", opt_.fontFamily.latin1()); m_handler->addStringParam("fontsize", TQCString().setNum(opt_.fontSize)); m_handler->addStringParam("bgcolor", TQString(opt_.baseColor.name()).latin1()); m_handler->addStringParam("fgcolor", TQString(opt_.textColor.name()).latin1()); m_handler->addStringParam("color1", TQString(opt_.highlightedTextColor.name()).latin1()); m_handler->addStringParam("color2", TQString(opt_.highlightedBaseColor.name()).latin1()); m_handler->addStringParam("imgdir", TQFile::encodeName(opt_.imgDir)); } void EntryView::slotResetColors() { // this will delete and reread the default colors, assuming they changed // better to do this elsewhere, but do it here for now Config::deleteAndReset(); delete m_handler; m_handler = 0; setXSLTFile(m_xsltFile); } void EntryView::resetColors() { ImageFactory::createStyleImages(); // recreate gradients TQString dir = m_handler ? m_handler->param("imgdir") : TQString(); if(dir.isEmpty()) { dir = Data::Document::self()->allImagesOnDisk() ? ImageFactory::dataDir() : ImageFactory::tempDir(); } else { // it's a string param, so it has quotes on both sides dir = dir.mid(1); dir.truncate(dir.length()-1); } // this is a rather bad hack to get around the fact that the image cache is not reloaded when // the gradient files are changed on disk. Setting the URLArgs for write() calls doesn't seem to // work. So force a reload with a temp file, then catch the completed signal and repaint TQString s = TQString::fromLatin1("") .arg(dir + TQString::fromLatin1("gradient_bg.png")) .arg(dir + TQString::fromLatin1("gradient_header.png")); delete m_tempFile; m_tempFile = new KTempFile; m_tempFile->setAutoDelete(true); *m_tempFile->textStream() << s; m_tempFile->file()->close(); // have to close it KParts::URLArgs args = browserExtension()->urlArgs(); args.reload = true; // tell the cache to reload images browserExtension()->setURLArgs(args); // don't flicker view()->setUpdatesEnabled(false); openURL(m_tempFile->name()); connect(this, TQ_SIGNAL(completed()), TQ_SLOT(slotReloadEntry())); } #include "entryview.moc"