From 92e2317251fb24ed9473c7783e129c5b39685c43 Mon Sep 17 00:00:00 2001 From: Konstantin Isakov Date: Sun, 29 May 2011 10:36:30 -0700 Subject: [PATCH] Add the missing files. --- programs.cc | 209 ++++++++++++++++++++++++++++++++++++++++++++++++++++ programs.hh | 43 +++++++++++ 2 files changed, 252 insertions(+) create mode 100644 programs.cc create mode 100644 programs.hh diff --git a/programs.cc b/programs.cc new file mode 100644 index 00000000..87d9ff6b --- /dev/null +++ b/programs.cc @@ -0,0 +1,209 @@ +/* This file is (c) 2008-2011 Konstantin Isakov + * Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */ + +#include +#include "programs.hh" +#include "audiolink.hh" +#include "htmlescape.hh" +#include "utf8.hh" +#include "wstring_qt.hh" + +namespace Programs { + +using namespace Dictionary; + +namespace { + +class ProgramsDictionary: public Dictionary::Class +{ + Config::Program prg; +public: + + ProgramsDictionary( Config::Program const & prg_ ): + Dictionary::Class( prg_.id.toStdString(), vector< string >() ), + prg( prg_ ) + { + } + + virtual string getName() throw() + { return prg.name.toUtf8().data(); } + + virtual map< Property, string > getProperties() throw() + { return map< Property, string >(); } + + virtual unsigned long getArticleCount() throw() + { return 0; } + + virtual unsigned long getWordCount() throw() + { return 0; } + + virtual QIcon getIcon() throw(); + + virtual sptr< WordSearchRequest > prefixMatch( wstring const & /*word*/, + unsigned long /*maxResults*/ ) throw( std::exception ) + { + sptr< WordSearchRequestInstant > sr = new WordSearchRequestInstant; + + sr->setUncertain( true ); + + return sr; + } + + virtual sptr< DataRequest > getArticle( wstring const &, vector< wstring > const & alts, + wstring const & ) + throw( std::exception ); +}; + +sptr< DataRequest > ProgramsDictionary::getArticle( wstring const & word, + vector< wstring > const &, + wstring const & ) + throw( std::exception ) +{ + if ( prg.type == Config::Program::Audio ) + { + // Audio results are instantaneous + string result; + + string wordUtf8( Utf8::encode( word ) ); + + result += ""; + + QUrl url; + url.setScheme( "gdprg" ); + url.setHost( QString::fromUtf8( getId().c_str() ) ); + url.setPath( QString::fromUtf8( wordUtf8.c_str() ) ); + + string ref = string( "\"" ) + url.toEncoded().data() + "\""; + + result += addAudioLink( ref, getId() ); + + result += ""; + result += ""; + result += "
\"Play\"/" + + Html::escape( wordUtf8 ) + "
"; + + sptr< Dictionary::DataRequestInstant > ret = + new Dictionary::DataRequestInstant( true ); + + ret->getData().resize( result.size() ); + + memcpy( &(ret->getData().front()), result.data(), result.size() ); + return ret; + } + else + return new ArticleRequest( gd::toQString( word ), prg ); +} + +QIcon ProgramsDictionary::getIcon() throw() +{ + return QIcon( ":/icons/programs.png" ); +} + +} + +ArticleRequest::ArticleRequest( QString const & word, + Config::Program const & prg_ ): + prg( prg_ ), process( this ) +{ + QStringList args = prg.commandLine.split( ' ', QString::SkipEmptyParts ); + + if ( !args.empty() ) + { + QString programName = args.first(); + args.pop_front(); + + for( int x = 0; x < args.size(); ++x ) + args[ x ].replace( "%GDWORD%", word ); + + connect( this, SIGNAL(processFinished()), this, + SLOT(handleProcessFinished()), Qt::QueuedConnection ); + connect( &process, SIGNAL(finished(int)), this, SIGNAL(processFinished())); + connect( &process, SIGNAL(error(QProcess::ProcessError)), this, + SIGNAL(processFinished()) ); + + process.start( programName, args ); + process.write( word.toLocal8Bit() ); + process.closeWriteChannel(); + } + else + { + setErrorString( tr( "No program name was given." ) ); + finish(); + } +} + +void ArticleRequest::handleProcessFinished() +{ + if ( !isFinished() ) + { + // It seems that sometimes the process isn't finished yet despite being + // signalled as such. So we wait for it here, which should hopefully be + // nearly instant. + process.waitForFinished(); + + QByteArray output = process.readAllStandardOutput(); + + if ( !output.isEmpty() ) + { + string result = "
"; + result += Html::preformat( QString::fromLocal8Bit( output ).toUtf8().data() ); + break; + default: + result += "html'>"; + // We assume html data is in utf8 encoding already. + result += output.data(); + } + + result += "
"; + + data.resize( result.size() ); + memcpy( data.data(), result.data(), data.size() ); + hasAnyData = true; + } + + QString error; + if ( process.exitStatus() != QProcess::NormalExit ) + error = tr( "The program has crashed." ); + else + if ( int code = process.exitCode() ) + error = tr( "The program has returned exit code %1." ).arg( code ); + + if ( !error.isEmpty() ) + { + QByteArray err = process.readAllStandardError(); + + if ( !err.isEmpty() ) + error += "\n\n" + QString::fromLocal8Bit( err ); + + setErrorString( error ); + } + + finish(); + } +} + +void ArticleRequest::cancel() +{ + finish(); +} + + +vector< sptr< Dictionary::Class > > makeDictionaries( + Config::Programs const & programs ) + throw( std::exception ) +{ + vector< sptr< Dictionary::Class > > result; + + for( Config::Programs::const_iterator i = programs.begin(); + i != programs.end(); ++i ) + result.push_back( new ProgramsDictionary( *i ) ); + + return result; +} + +} diff --git a/programs.hh b/programs.hh new file mode 100644 index 00000000..3e1d70d8 --- /dev/null +++ b/programs.hh @@ -0,0 +1,43 @@ +/* This file is (c) 2008-2011 Konstantin Isakov + * Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */ + +#ifndef __PROGRAMS_HH_INCLUDED__ +#define __PROGRAMS_HH_INCLUDED__ + +#include +#include "dictionary.hh" +#include "config.hh" +#include "wstring.hh" + +/// Support for arbitrary programs. +namespace Programs { + +using std::vector; +using std::string; +using gd::wstring; + +vector< sptr< Dictionary::Class > > makeDictionaries( Config::Programs const & ) + throw( std::exception ); + +class ArticleRequest: public Dictionary::DataRequest +{ + Q_OBJECT + Config::Program prg; + QProcess process; + +public: + + ArticleRequest( QString const & word, Config::Program const & ); + + virtual void cancel(); + +signals: + void processFinished(); +private slots: + + void handleProcessFinished(); +}; + +} + +#endif