diff --git a/articleview.cc b/articleview.cc
index 95399a44..6bf106e0 100644
--- a/articleview.cc
+++ b/articleview.cc
@@ -721,15 +721,22 @@ void ArticleView::openLink( QUrl const & url, QUrl const & ref,
if ( i->id == id )
{
// Found the corresponding program.
- Programs::ArticleRequest * req = new Programs::ArticleRequest(
- url.path().mid( 1 ), *i );
+ Programs::RunInstance * req = new Programs::RunInstance;
- connect( req, SIGNAL( finished() ), req, SLOT( deleteLater() ) );
+ connect( req, SIGNAL(finished(QByteArray,QString)),
+ req, SLOT( deleteLater() ) );
- // Delete the request if it has finished already
- if ( req->isFinished() )
+ QString error;
+
+ // Delete the request if it fails to start
+ if ( !req->start( *i, url.path().mid( 1 ), error ) )
+ {
delete req;
+ QMessageBox::critical( this, tr( "GoldenDict" ),
+ error );
+ }
+
return;
}
}
diff --git a/config.hh b/config.hh
index 0ddaead6..9480ef26 100644
--- a/config.hh
+++ b/config.hh
@@ -312,6 +312,7 @@ struct Program
Audio,
PlainText,
Html,
+ PrefixMatch,
MaxTypeValue
} type;
QString id, name, commandLine;
diff --git a/programs.cc b/programs.cc
index 97762405..408eacdf 100644
--- a/programs.cc
+++ b/programs.cc
@@ -40,8 +40,23 @@ public:
virtual QIcon getIcon() throw();
- virtual sptr< WordSearchRequest > prefixMatch( wstring const & /*word*/,
- unsigned long /*maxResults*/ ) throw( std::exception )
+ virtual sptr< WordSearchRequest > prefixMatch( wstring const & word,
+ unsigned long maxResults )
+ throw( std::exception );
+
+ virtual sptr< DataRequest > getArticle( wstring const &,
+ vector< wstring > const & alts,
+ wstring const & )
+ throw( std::exception );
+};
+
+sptr< WordSearchRequest > ProgramsDictionary::prefixMatch( wstring const & word,
+ unsigned long /*maxResults*/ )
+ throw( std::exception )
+{
+ if ( prg.type == Config::Program::PrefixMatch )
+ return new ProgramWordSearchRequest( gd::toQString( word ), prg );
+ else
{
sptr< WordSearchRequestInstant > sr = new WordSearchRequestInstant;
@@ -49,50 +64,52 @@ public:
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 & )
+sptr< Dictionary::DataRequest > ProgramsDictionary::getArticle(
+ wstring const & word, vector< wstring > const &, wstring const & )
throw( std::exception )
{
- if ( prg.type == Config::Program::Audio )
+ switch( prg.type )
{
- // Audio results are instantaneous
- string result;
+ case Config::Program::Audio:
+ {
+ // Audio results are instantaneous
+ string result;
- string wordUtf8( Utf8::encode( word ) );
+ string wordUtf8( Utf8::encode( word ) );
- result += "
";
+ result += "";
- QUrl url;
- url.setScheme( "gdprg" );
- url.setHost( QString::fromUtf8( getId().c_str() ) );
- url.setPath( QString::fromUtf8( wordUtf8.c_str() ) );
+ 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() + "\"";
+ string ref = string( "\"" ) + url.toEncoded().data() + "\"";
- result += addAudioLink( ref, getId() );
+ result += addAudioLink( ref, getId() );
- result += " | ";
- result += "" +
- Html::escape( wordUtf8 ) + " | ";
- result += "
";
+ result += " | ";
+ result += "" +
+ Html::escape( wordUtf8 ) + " | ";
+ result += "
";
- sptr< Dictionary::DataRequestInstant > ret =
- new Dictionary::DataRequestInstant( true );
+ sptr< DataRequestInstant > ret = new DataRequestInstant( true );
- ret->getData().resize( result.size() );
+ ret->getData().resize( result.size() );
- memcpy( &(ret->getData().front()), result.data(), result.size() );
- return ret;
+ memcpy( &(ret->getData().front()), result.data(), result.size() );
+ return ret;
+ }
+
+ case Config::Program::Html:
+ case Config::Program::PlainText:
+ return new ProgramDataRequest( gd::toQString( word ), prg );
+
+ default:
+ return new DataRequestInstant( false );
}
- else
- return new ArticleRequest( gd::toQString( word ), prg );
}
QIcon ProgramsDictionary::getIcon() throw()
@@ -102,9 +119,17 @@ QIcon ProgramsDictionary::getIcon() throw()
}
-ArticleRequest::ArticleRequest( QString const & word,
- Config::Program const & prg_ ):
- prg( prg_ ), process( this )
+RunInstance::RunInstance(): process( this )
+{
+ 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()) );
+}
+
+bool RunInstance::start( Config::Program const & prg, QString const & word,
+ QString & error )
{
QStringList args = parseCommandLine( prg.commandLine );
@@ -116,34 +141,65 @@ ArticleRequest::ArticleRequest( QString const & word,
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();
+
+ return true;
}
else
{
- setErrorString( tr( "No program name was given." ) );
+ error = tr( "No program name was given." );
+ return false;
+ }
+}
+
+void RunInstance::handleProcessFinished()
+{
+ // 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();
+
+ 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 );
+ }
+
+ emit finished( output, error );
+}
+
+ProgramDataRequest::ProgramDataRequest( QString const & word,
+ Config::Program const & prg_ ):
+ prg( prg_ )
+{
+ connect( &instance, SIGNAL(finished(QByteArray,QString)),
+ this, SLOT(instanceFinished(QByteArray,QString)) );
+
+ QString error;
+ if ( !instance.start( prg, word, error ) )
+ {
+ setErrorString( error );
finish();
}
}
-void ArticleRequest::handleProcessFinished()
+void ProgramDataRequest::instanceFinished( QByteArray output, QString error )
{
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 = "setColumnWidth( 1,
QFontMetrics( QFont() ).width(
- ProgramTypeEditor::getNameForType( Config::Program::PlainText ) ) + 16 );
+ ProgramTypeEditor::getNameForType( Config::Program::PrefixMatch ) ) + 16 );
ui.programs->resizeColumnToContents( 2 );
ui.programs->resizeColumnToContents( 3 );
ui.programs->setItemDelegate( itemDelegate );
@@ -773,6 +773,8 @@ QString ProgramTypeEditor::getNameForType( int v )
return tr( "Plain Text" );
case Config::Program::Html:
return tr( "Html" );
+ case Config::Program::PrefixMatch:
+ return tr( "Prefix Match" );
default:
return tr( "Unknown" );
}