diff --git a/grantleeformatter.cpp b/grantleeformatter.cpp index a3f31a16..10a2b860 100644 --- a/grantleeformatter.cpp +++ b/grantleeformatter.cpp @@ -1,148 +1,148 @@ /* This file is part of the KDE Help Center Copyright (c) 2016 Pino Toscano This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "grantleeformatter.h" #include "khc_debug.h" #include "glossary.h" #include "docentry.h" #include #include #include #include #include #include using namespace KHC; class PlainOutputStream : public Grantlee::OutputStream { public: PlainOutputStream( QTextStream *stream ) : Grantlee::OutputStream( stream ) { } QString escape( const QString& input ) const override { return input; } QSharedPointer clone( QTextStream *stream ) const override { return QSharedPointer( new PlainOutputStream( stream ) ); } }; struct GrantleeFormatter::Private { QString format( Grantlee::Template t, Grantlee::Context *ctx ); Grantlee::Engine engine; }; QString GrantleeFormatter::Private::format( Grantlee::Template t, Grantlee::Context *ctx ) { QString result; QTextStream textStream( &result ); PlainOutputStream stream( &textStream ); t->render( &stream, ctx ); if ( t->error() ) { qCWarning(KHC_LOG) << "GrantleeFormatter rendering error:" << t->errorString(); } return result; } GrantleeFormatter::GrantleeFormatter() : d( new Private ) { QSharedPointer< Grantlee::FileSystemTemplateLoader > loader( new Grantlee::FileSystemTemplateLoader ); loader->setTemplateDirs( QStandardPaths::locateAll( QStandardPaths::DataLocation, QStringLiteral("templates"), QStandardPaths::LocateDirectory ) ); d->engine.addTemplateLoader( loader ); } GrantleeFormatter::~GrantleeFormatter() { delete d; } QString GrantleeFormatter::formatOverview( const QString& title, const QString& name, const QString& content ) { Grantlee::Template t = d->engine.loadByName( QStringLiteral("index.html") ); Grantlee::Context ctx; ctx.insert( QStringLiteral("title"), title ); ctx.insert( QStringLiteral("name"), name ); ctx.insert( QStringLiteral("content"), content ); return d->format( t, &ctx ); } QString GrantleeFormatter::formatGlossaryEntry( const GlossaryEntry& entry ) { Grantlee::Template t = d->engine.loadByName( QStringLiteral("glossary.html") ); const GlossaryEntryXRef::List entrySeeAlso = entry.seeAlso(); QStringList seeAlso; seeAlso.reserve( entrySeeAlso.count() ); foreach ( const GlossaryEntryXRef &xref, entrySeeAlso ) { seeAlso += QStringLiteral( "%2" ).arg( xref.id(), xref.term() ); } Grantlee::Context ctx; ctx.insert( QStringLiteral("htmltitle"), i18nc( "%1 is a glossary term", "KDE Glossary: %1", entry.term() ) ); ctx.insert( QStringLiteral("title"), i18n( "KDE Glossary" ) ); ctx.insert( QStringLiteral("term"), entry.term() ); ctx.insert( QStringLiteral("definition"), entry.definition() ); ctx.insert( QStringLiteral("seeAlsoCount"), seeAlso.count() ); - ctx.insert( QStringLiteral("seeAlso"), i18n( "See also: %1", seeAlso.join( QStringLiteral(", ") ) ) ); + ctx.insert( QStringLiteral("seeAlso"), i18n( "See also: %1", seeAlso.join(QLatin1String(", ") ) ) ); return d->format( t, &ctx ); } QString GrantleeFormatter::formatSearchResults( const QString& words, const QList >& results ) { Grantlee::Template t = d->engine.loadByName( QStringLiteral("search.html") ); typedef QPair Iter; QVariantList list; list.reserve( results.count() ); foreach ( const Iter& it, results ) { QVariantHash h; h.insert( QStringLiteral("title"), it.first->name() ); h.insert( QStringLiteral("content"), it.second ); list += h; } Grantlee::Context ctx; ctx.insert( QStringLiteral("htmltitle"), i18n( "Search Results" ) ); ctx.insert( QStringLiteral("title"), i18n( "Search Results for '%1':", words.toHtmlEscaped() ) ); ctx.insert( QStringLiteral("results"), list ); return d->format( t, &ctx ); } diff --git a/navigatorappgroupitem.cpp b/navigatorappgroupitem.cpp index df7a4e7c..f4139878 100644 --- a/navigatorappgroupitem.cpp +++ b/navigatorappgroupitem.cpp @@ -1,148 +1,148 @@ /* * This file is part of the KDE Help Center * * Copyright (C) 2001 Waldo Bastian * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 or at your option version 3 as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "navigatorappgroupitem.h" #include "navigatorappitem.h" #include "docentry.h" #include "khc_debug.h" #include #include using namespace KHC; NavigatorAppGroupItem::NavigatorAppGroupItem( DocEntry *entry, QTreeWidget *parent, const QString &relPath ) : NavigatorItem( entry, parent ), mRelpath( relPath ), mPopulated( false ) { populate(); } NavigatorAppGroupItem::NavigatorAppGroupItem( DocEntry *entry, QTreeWidgetItem *parent, const QString &relPath ) : NavigatorItem( entry, parent ), mRelpath( relPath ), mPopulated( false ) { populate(); } NavigatorAppGroupItem::NavigatorAppGroupItem( DocEntry *entry, QTreeWidget *parent, QTreeWidgetItem *after ) : NavigatorItem( entry, parent, after ), mPopulated( false ) { populate(); } NavigatorAppGroupItem::NavigatorAppGroupItem( DocEntry *entry, QTreeWidgetItem *parent, QTreeWidgetItem *after ) : NavigatorItem( entry, parent, after ), mPopulated( false ) { populate(); } void NavigatorAppGroupItem::setRelpath( const QString &relpath ) { mRelpath = relpath; } void NavigatorAppGroupItem::itemExpanded(bool open) { qCDebug(KHC_LOG) << "NavigatorAppGroupItem::itemExpanded()"; if ( open && (childCount() == 0) && !mPopulated ) { qCDebug(KHC_LOG) << " -> populate:" << this << "-" << mRelpath; populate(); } NavigatorItem::itemExpanded(open); } void NavigatorAppGroupItem::populate( bool recursive ) { if ( mPopulated ) return; KServiceGroup::Ptr root = KServiceGroup::group(mRelpath); if ( !root ) { qCWarning(KHC_LOG) << "No Service groups for" << mRelpath; return; } KServiceGroup::List list = root->entries(); for ( KServiceGroup::List::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it ) { const KSycocaEntry::Ptr e = *it; QString url; switch ( e->sycocaType() ) { case KST_KService: { const KService::Ptr s(static_cast(e.data())); url = documentationURL( s.data() ); if ( !url.isEmpty() ) { DocEntry *entry = new DocEntry( s->name(), url, s->icon() ); NavigatorAppItem *item = new NavigatorAppItem( entry, this ); item->setAutoDeleteDocEntry( true ); } break; } case KST_KServiceGroup: { const KServiceGroup::Ptr g(static_cast(e.data())); if ( ( g->childCount() == 0 ) || g->name().startsWith( QLatin1Char('.') ) ) continue; DocEntry *entry = new DocEntry( g->caption(), QString(), g->icon() ); NavigatorAppGroupItem *appItem; appItem = new NavigatorAppGroupItem( entry, this, g->relPath() ); appItem->setAutoDeleteDocEntry( true ); if ( recursive ) appItem->populate( recursive ); break; } default: break; } } sortChildren( 0, Qt::AscendingOrder /* ascending */ ); mPopulated = true; } QString NavigatorAppGroupItem::documentationURL( const KService *s ) { QString docPath = s->property( QStringLiteral("DocPath") ).toString(); if ( docPath.isEmpty() ) { docPath = s->property( QStringLiteral("X-DocPath") ).toString(); if ( docPath.isEmpty() ) { return QString(); } } - if ( docPath.startsWith( QStringLiteral("file:")) || docPath.startsWith( QStringLiteral("http:") ) ) + if ( docPath.startsWith(QLatin1String("file:")) || docPath.startsWith(QLatin1String("http:") ) ) return docPath; return QStringLiteral( "help:/" ) + docPath; } // vim:ts=2:sw=2:et diff --git a/searchhandlers/xapiansearch.cpp b/searchhandlers/xapiansearch.cpp index bdaea9b9..0ec916ec 100644 --- a/searchhandlers/xapiansearch.cpp +++ b/searchhandlers/xapiansearch.cpp @@ -1,151 +1,151 @@ /* This file is part of the KDE Help Center Copyright (c) 2016 Pino Toscano This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "xapiancommon.h" #include #include #include #include #include namespace { Q_LOGGING_CATEGORY( LOG, "org.kde.khelpcenter.xapian.search", QtWarningMsg ) } Xapian::Query queryFromWordlist( const QString& words, Xapian::Query::op op ) { QVector wordlist; const QStringList splitlist = words.split( QLatin1Char( '+' ) ); wordlist.reserve( splitlist.size() ); Q_FOREACH ( const QString& word, splitlist ) { wordlist.append( word.toStdString() ); } return Xapian::Query( op, wordlist.constBegin(), wordlist.constEnd() ); } int main( int argc, char *argv[] ) { QCoreApplication app( argc, argv ); QCommandLineParser parser; const QCommandLineOption indexdirOption( QStringLiteral("indexdir"), QStringLiteral("Index directory"), QStringLiteral("dir") ); parser.addOption( indexdirOption ); const QCommandLineOption identifierOption( QStringLiteral("identifier"), QStringLiteral("Index identifier"), QStringLiteral("identifier") ); parser.addOption( identifierOption ); const QCommandLineOption wordsOption( QStringLiteral("words"), QStringLiteral("Words to search"), QStringLiteral("words") ); parser.addOption( wordsOption ); const QCommandLineOption methodOption( QStringLiteral("method"), QStringLiteral("Method"), QStringLiteral("and|or") ); parser.addOption( methodOption ); const QCommandLineOption maxnumOption( QStringLiteral("maxnum"), QStringLiteral("Maximum number of results"), QStringLiteral("maxnum") ); parser.addOption( maxnumOption ); const QCommandLineOption langOption( QStringLiteral("lang"), QStringLiteral("Language"), QStringLiteral("lang") ); parser.addOption( langOption ); parser.process( app ); const QString indexdir = parser.value( indexdirOption ); const QString identifier = parser.value( identifierOption ); const QString words = parser.value( wordsOption ); const QString method = parser.value( methodOption ); const QString maxnumString = parser.value( maxnumOption ); if ( indexdir.isEmpty() || identifier.isEmpty() || words.isEmpty() || method.isEmpty() ) { qCCritical(LOG) << "Missing arguments."; parser.showHelp( 1 ); } Xapian::Query::op op; - if ( method == QStringLiteral( "and" ) ) { + if ( method == QLatin1String( "and" ) ) { op = Xapian::Query::OP_AND; - } else if ( method == QStringLiteral( "or" ) ) { + } else if ( method == QLatin1String( "or" ) ) { op = Xapian::Query::OP_OR; } else { qCCritical(LOG) << "Unrecognized method:" << method; parser.showHelp( 1 ); } bool ok; const Xapian::doccount maxnum = maxnumString.toUInt( &ok ); if ( !ok ) { qCCritical(LOG) << "--maxnum is not a number"; parser.showHelp( 1 ); } QString lang = parser.value( langOption ); if ( lang.isEmpty() || lang == QLatin1String( "C" ) ) { lang = QStringLiteral("en"); } Xapian::Database db; try { db = openDb( indexdir + QLatin1Char('/') + identifier ); } catch ( const DatabaseVersionMismatch& e ) { qCWarning(LOG) << "Own version mismatch in Xapian DB: found" << e.version << "vs wanted" << e.refVersion; return 1; } catch ( const Xapian::Error& e ) { qCCritical(LOG) << "Xapian error:" << e.get_description(); return 1; } try { Xapian::Query query( Xapian::Query::OP_AND, Xapian::Query( "L" + lang.toStdString() ), queryFromWordlist( words, op ) ); qCDebug(LOG) << "query:" << query.get_description(); Xapian::Enquire enquire( db ); enquire.set_query( query ); const Xapian::MSet mset = enquire.get_mset( 0, maxnum ); std::cout << "
    " << std::endl; qCDebug(LOG) << "got" << mset.size() << "results"; for ( Xapian::MSetIterator i = mset.begin(); i != mset.end(); ++i ) { const Xapian::Document doc = i.get_document(); std::string uid; std::string html; getDocInfo( doc, nullptr, &uid, &html ); const std::string title = doc.get_value( VALUE_TITLE ); const std::string::size_type slash = uid.find_last_of( '/' ); const std::string html_id = slash != std::string::npos ? uid.substr( 0, slash + 1 ) + html : html; const std::string partial_id = html_id.substr(0, html_id.rfind("/")); std::cout << "
  • " << partial_id << " - " << title << "
  • " << std::endl; } std::cout << "
" << std::endl; } catch ( const Xapian::Error& e ) { qCCritical(LOG) << "Xapian error: " << e.get_description(); return 1; } return 0; } diff --git a/toc.cpp b/toc.cpp index ae91e1a8..15b77b9b 100644 --- a/toc.cpp +++ b/toc.cpp @@ -1,309 +1,309 @@ /* * This file is part of the KDE Help Center * * Copyright (C) 2002 Frerich Raabe (raabe@kde.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "toc.h" #include "docentry.h" #include "khc_debug.h" #include #include #include #include #include #include #include #include #include using namespace KHC; class TOCItem : public NavigatorItem { public: TOCItem( TOC *parent, QTreeWidgetItem *parentItem, QTreeWidgetItem *after, const QString &text ); const TOC *toc() const { return m_toc; } private: TOC *m_toc; }; class TOCChapterItem : public TOCItem { public: TOCChapterItem( TOC *toc, NavigatorItem *parent, QTreeWidgetItem *after, const QString &title, const QString &name ); virtual QString url(); private: QString m_name; }; class TOCSectionItem : public TOCItem { public: TOCSectionItem( TOC *toc, TOCChapterItem *parent, QTreeWidgetItem *after, const QString &title, const QString &name ); virtual QString url(); private: QString m_name; }; bool TOC::m_alreadyWarned = false; TOC::TOC( NavigatorItem *parentItem ) { m_parentItem = parentItem; } void TOC::build( const QString &file ) { QFileInfo fileInfo( file ); QString fileName = fileInfo.absoluteFilePath(); const QStringList resourceDirs = KDocTools::documentationDirs(); QStringList::ConstIterator it = resourceDirs.begin(); QStringList::ConstIterator end = resourceDirs.end(); for ( ; it != end; ++it ) { if ( fileName.startsWith( *it ) ) { fileName.remove( 0, ( *it ).length() ); break; } } QString cacheFile = fileName.replace( QLatin1Char('/'), QStringLiteral("__") ); #ifdef Q_WS_WIN - cacheFile = cacheFile.replace( QLatin1Char(':'), QStringLiteral("_") ); + cacheFile.replace( QLatin1Char(':'), QStringLiteral("_") ); #endif m_cacheFile = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QStringLiteral("/help/") + cacheFile ; m_sourceFile = file; if ( cacheStatus() == NeedRebuild ) buildCache(); else fillTree(); } TOC::CacheStatus TOC::cacheStatus() const { if ( !QFile::exists( m_cacheFile ) || sourceFileCTime() != cachedCTime() ) return NeedRebuild; return CacheOk; } int TOC::sourceFileCTime() const { struct stat stat_buf; stat( QFile::encodeName( m_sourceFile ).data(), &stat_buf ); return stat_buf.st_ctime; } int TOC::cachedCTime() const { QFile f( m_cacheFile ); if ( !f.open( QIODevice::ReadOnly ) ) return 0; QDomDocument doc; if ( !doc.setContent( &f ) ) return 0; QDomComment timestamp = doc.documentElement().lastChild().toComment(); return timestamp.data().trimmed().toInt(); } void TOC::buildCache() { KXmlGuiWindow *mainWindow = dynamic_cast( qobject_cast(qApp)->activeWindow() ); KProcess *meinproc = new KProcess; connect(meinproc, QOverload::of(&KProcess::finished), this, &TOC::meinprocExited); *meinproc << QStandardPaths::findExecutable(QStringLiteral("meinproc5")); *meinproc << QStringLiteral("--stylesheet") << QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("khelpcenter/table-of-contents.xslt") ); *meinproc << QStringLiteral("--output") << m_cacheFile; *meinproc << m_sourceFile; meinproc->setOutputChannelMode(KProcess::OnlyStderrChannel); meinproc->start(); if (!meinproc->waitForStarted()) { qCWarning(KHC_LOG) << "could not start process" << meinproc->program(); if (mainWindow && !m_alreadyWarned) { ; // add warning message box with don't display again option // http://api.kde.org/4.0-api/kdelibs-apidocs/kdeui/html/classKDialog.html m_alreadyWarned = true; } delete meinproc; } } void TOC::meinprocExited( int exitCode, QProcess::ExitStatus exitStatus) { KProcess *meinproc = static_cast(sender()); KXmlGuiWindow *mainWindow = dynamic_cast( qobject_cast(qApp)->activeWindow() ); if ( exitStatus == QProcess::CrashExit || exitCode != 0 ) { qCWarning(KHC_LOG) << "running" << meinproc->program() << "failed with exitCode" << exitCode; qCWarning(KHC_LOG) << "stderr output:" << meinproc->readAllStandardError(); if (mainWindow && !m_alreadyWarned) { ; // add warning message box with don't display again option // http://api.kde.org/4.0-api/kdelibs-apidocs/kdeui/html/classKDialog.html m_alreadyWarned = true; } delete meinproc; return; } delete meinproc; // add a timestamp to the meinproc4 created xml file QFile f( m_cacheFile ); if ( !f.open( QIODevice::ReadWrite ) ) return; QDomDocument doc; if ( !doc.setContent( &f ) ) return; QDomComment timestamp = doc.createComment( QString::number( sourceFileCTime() ) ); doc.documentElement().appendChild( timestamp ); // write back updated xml content f.seek( 0 ); QTextStream stream( &f ); stream.setCodec( "UTF-8" ); #ifdef Q_WS_WIN /* the problem that on german systems umlauts are displayed as '?' for unknown (Qt'r related ?) reasons is caused by wrong encoding type conversations and has been fixed in kdelibs/kdoctools To have propper encoding tags in the xml file, QXmlDocument::save() is used. */ doc.save(stream, 1, QDomNode::EncodingFromTextStream); #else stream << doc.toString(); #endif f.close(); fillTree(); } void TOC::fillTree() { QFile f( m_cacheFile ); if ( !f.open( QIODevice::ReadOnly ) ) return; QDomDocument doc; if ( !doc.setContent( &f ) ) return; TOCChapterItem *chapItem = nullptr; QDomNodeList chapters = doc.documentElement().elementsByTagName( QStringLiteral("chapter") ); for ( int chapterCount = 0; chapterCount < chapters.count(); chapterCount++ ) { QDomElement chapElem = chapters.item( chapterCount ).toElement(); QDomElement chapTitleElem = childElement( chapElem, QStringLiteral( "title" ) ); QString chapTitle = chapTitleElem.text().simplified(); QDomElement chapRefElem = childElement( chapElem, QStringLiteral( "anchor" ) ); QString chapRef = chapRefElem.text().trimmed(); chapItem = new TOCChapterItem( this, m_parentItem, chapItem, chapTitle, chapRef ); TOCSectionItem *sectItem = nullptr; QDomNodeList sections = chapElem.elementsByTagName( QStringLiteral("section") ); for ( int sectCount = 0; sectCount < sections.count(); sectCount++ ) { QDomElement sectElem = sections.item( sectCount ).toElement(); QDomElement sectTitleElem = childElement( sectElem, QStringLiteral( "title" ) ); QString sectTitle = sectTitleElem.text().simplified(); QDomElement sectRefElem = childElement( sectElem, QStringLiteral( "anchor" ) ); QString sectRef = sectRefElem.text().trimmed(); sectItem = new TOCSectionItem( this, chapItem, sectItem, sectTitle, sectRef ); } } } QDomElement TOC::childElement( const QDomElement &element, const QString &name ) { QDomElement e; for ( e = element.firstChild().toElement(); !e.isNull(); e = e.nextSibling().toElement() ) if ( e.tagName() == name ) break; return e; } void TOC::slotItemSelected( QTreeWidgetItem *item ) { TOCItem *tocItem; if ( ( tocItem = dynamic_cast( item ) ) ) emit itemSelected( tocItem->entry()->url() ); item->setExpanded( !item->isExpanded() ); } TOCItem::TOCItem( TOC *toc, QTreeWidgetItem *parentItem, QTreeWidgetItem *after, const QString &text ) : NavigatorItem( new DocEntry( text ), parentItem, after ) { setAutoDeleteDocEntry( true ); m_toc = toc; } TOCChapterItem::TOCChapterItem( TOC *toc, NavigatorItem *parent, QTreeWidgetItem *after, const QString &title, const QString &name ) : TOCItem( toc, parent, after, title ), m_name( name ) { setExpanded( false ); entry()->setUrl(url()); } QString TOCChapterItem::url() { return QLatin1String("help:") + toc()->application() + QLatin1Char('/') + m_name + QLatin1String(".html"); } TOCSectionItem::TOCSectionItem( TOC *toc, TOCChapterItem *parent, QTreeWidgetItem *after, const QString &title, const QString &name ) : TOCItem( toc, parent, after, title ), m_name( name ) { setIcon( 0, QIcon::fromTheme( QStringLiteral("text-plain") ) ); entry()->setUrl(url()); } QString TOCSectionItem::url() { if ( static_cast( parent()->child(0) ) == this ) return static_cast( parent() )->url() + QLatin1Char('#') + m_name; return QStringLiteral("help:") + toc()->application() + QLatin1Char('/') + m_name + QStringLiteral(".html"); } // vim:ts=2:sw=2:et