mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-23 20:14:05 +00:00
Implement asyncronous word finding.
This commit is contained in:
parent
17b90a3cca
commit
faeacaff3e
|
@ -5,6 +5,7 @@
|
|||
#include "config.hh"
|
||||
#include "htmlescape.hh"
|
||||
#include "utf8.hh"
|
||||
#include "dictlock.hh"
|
||||
#include <QFile>
|
||||
#include <set>
|
||||
|
||||
|
@ -68,6 +69,8 @@ string ArticleMaker::makeDefinitionFor( QString const & inWord,
|
|||
|
||||
result += "</head><body>";
|
||||
|
||||
DictLock _;
|
||||
|
||||
// Accumulate main forms
|
||||
|
||||
vector< wstring > alts;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
||||
|
||||
#include "article_netmgr.hh"
|
||||
#include "dictlock.hh"
|
||||
|
||||
using std::string;
|
||||
|
||||
|
@ -68,6 +69,8 @@ bool ArticleNetworkAccessManager::getResource( QUrl const & url,
|
|||
|
||||
bool search = ( id == "search" );
|
||||
|
||||
DictLock _;
|
||||
|
||||
for( unsigned x = 0; x < dictionaries.size(); ++x )
|
||||
{
|
||||
if ( search || dictionaries[ x ]->getId() == id )
|
||||
|
|
25
src/dictlock.cc
Normal file
25
src/dictlock.cc
Normal file
|
@ -0,0 +1,25 @@
|
|||
/* This file is (c) 2008-2009 Konstantin Isakov <ikm@users.sf.net>
|
||||
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
||||
|
||||
#include "dictlock.hh"
|
||||
#include <QMutex>
|
||||
|
||||
namespace
|
||||
{
|
||||
QMutex & mutexInstance()
|
||||
{
|
||||
static QMutex mutex;
|
||||
|
||||
return mutex;
|
||||
}
|
||||
}
|
||||
|
||||
DictLock::DictLock()
|
||||
{
|
||||
mutexInstance().lock();
|
||||
}
|
||||
|
||||
DictLock::~DictLock()
|
||||
{
|
||||
mutexInstance().unlock();
|
||||
}
|
24
src/dictlock.hh
Normal file
24
src/dictlock.hh
Normal file
|
@ -0,0 +1,24 @@
|
|||
/* This file is (c) 2008-2009 Konstantin Isakov <ikm@users.sf.net>
|
||||
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
||||
|
||||
#ifndef __DICTLOCK_HH_INCLUDED__
|
||||
#define __DICTLOCK_HH_INCLUDED__
|
||||
|
||||
/// This is a one large coarse-grained lock class used to lock all the
|
||||
/// dictionaries and all their shared containers (usually vectors) in order
|
||||
/// to work with them concurrently in different threads. Since we do matching
|
||||
/// in a different thread, we need this, and since matching doesn't happen
|
||||
/// too much and doesn't typically take a lot of time, there's no need for any
|
||||
/// more fine-grained locking approaches.
|
||||
/// Create this object before working with any dictionary objects or their
|
||||
/// containers which are known to be shared with the other objects. Destory
|
||||
/// this object when you're done (i.e,, leave the scope where it was declared).
|
||||
class DictLock
|
||||
{
|
||||
public:
|
||||
|
||||
DictLock();
|
||||
~DictLock();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -53,7 +53,9 @@ HEADERS += folding.hh \
|
|||
article_maker.hh \
|
||||
scanpopup.hh \
|
||||
articleview.hh \
|
||||
externalviewer.hh
|
||||
externalviewer.hh \
|
||||
dictlock.hh \
|
||||
wordfinder.hh
|
||||
|
||||
|
||||
FORMS += groups.ui dictgroupwidget.ui mainwindow.ui sources.ui initializing.ui\
|
||||
|
@ -65,6 +67,6 @@ SOURCES += folding.cc main.cc dictionary.cc md5.c config.cc sources.cc \
|
|||
chunkedstorage.cc xdxf2html.cc iconv.cc lsa.cc htmlescape.cc \
|
||||
dsl.cc dsl_details.cc filetype.cc fsencoding.cc groups.cc \
|
||||
groups_widgets.cc instances.cc article_maker.cc scanpopup.cc \
|
||||
articleview.cc externalviewer.cc
|
||||
articleview.cc externalviewer.cc dictlock.cc wordfinder.cc
|
||||
|
||||
RESOURCES += resources.qrc flags.qrc
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "stardict.hh"
|
||||
#include "lsa.hh"
|
||||
#include "dsl.hh"
|
||||
#include "dictlock.hh"
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
#include <QIcon>
|
||||
|
@ -25,8 +26,8 @@ MainWindow::MainWindow():
|
|||
cfg( Config::load() ),
|
||||
articleMaker( dictionaries, groupInstances ),
|
||||
articleNetMgr( this, dictionaries, articleMaker ),
|
||||
wordFinder( this ),
|
||||
scanPopup( 0, articleNetMgr ),
|
||||
startLookupTimeout( this ),
|
||||
initializing( 0 )
|
||||
{
|
||||
ui.setupUi( this );
|
||||
|
@ -58,8 +59,6 @@ MainWindow::MainWindow():
|
|||
connect( ui.tabWidget, SIGNAL( tabCloseRequested( int ) ),
|
||||
this, SLOT( tabCloseRequested( int ) ) );
|
||||
|
||||
startLookupTimeout.setSingleShot( true );
|
||||
|
||||
ui.tabWidget->setTabsClosable( true );
|
||||
|
||||
connect( ui.sources, SIGNAL( activated() ),
|
||||
|
@ -71,15 +70,17 @@ MainWindow::MainWindow():
|
|||
connect( ui.translateLine, SIGNAL( textChanged( QString const & ) ),
|
||||
this, SLOT( translateInputChanged( QString const & ) ) );
|
||||
|
||||
connect( &startLookupTimeout, SIGNAL( timeout() ),
|
||||
this, SLOT( startLookup() ) );
|
||||
|
||||
connect( ui.wordList, SIGNAL( itemActivated( QListWidgetItem * ) ),
|
||||
this, SLOT( wordListItemActivated( QListWidgetItem * ) ) );
|
||||
|
||||
connect( wordFinder.qobject(), SIGNAL( prefixMatchComplete( WordFinderResults ) ),
|
||||
this, SLOT( prefixMatchComplete( WordFinderResults ) ) );
|
||||
|
||||
makeDictionaries();
|
||||
|
||||
addNewTab();
|
||||
|
||||
ui.translateLine->setFocus();
|
||||
}
|
||||
|
||||
LoadDictionaries::LoadDictionaries( vector< string > const & allFiles_ ):
|
||||
|
@ -133,7 +134,10 @@ void LoadDictionaries::indexingDictionary( string const & dictionaryName ) throw
|
|||
|
||||
void MainWindow::makeDictionaries()
|
||||
{
|
||||
dictionaries.clear();
|
||||
{
|
||||
DictLock _;
|
||||
dictionaries.clear();
|
||||
}
|
||||
|
||||
::Initializing init( this );
|
||||
|
||||
|
@ -175,7 +179,11 @@ void MainWindow::makeDictionaries()
|
|||
|
||||
loadDicts.wait();
|
||||
|
||||
dictionaries = loadDicts.getDictionaries();
|
||||
{
|
||||
DictLock _;
|
||||
|
||||
dictionaries = loadDicts.getDictionaries();
|
||||
}
|
||||
|
||||
initializing = 0;
|
||||
|
||||
|
@ -235,6 +243,8 @@ void MainWindow::updateGroupList()
|
|||
|
||||
groupInstances.clear();
|
||||
|
||||
DictLock _;
|
||||
|
||||
for( unsigned x = 0; x < cfg.groups.size(); ++x )
|
||||
{
|
||||
groupInstances.push_back( Instances::Group( cfg.groups[ x ], dictionaries ) );
|
||||
|
@ -347,119 +357,83 @@ void MainWindow::editSources()
|
|||
|
||||
void MainWindow::editGroups()
|
||||
{
|
||||
Groups groups( this, dictionaries, cfg.groups );
|
||||
|
||||
groups.show();
|
||||
|
||||
if ( groups.exec() == QDialog::Accepted )
|
||||
{
|
||||
cfg.groups = groups.getGroups();
|
||||
// We lock all dictionaries during the entire group editing process, since
|
||||
// the dictionaries might get queried for various infos there
|
||||
DictLock _;
|
||||
|
||||
Groups groups( this, dictionaries, cfg.groups );
|
||||
|
||||
groups.show();
|
||||
|
||||
Config::save( cfg );
|
||||
if ( groups.exec() == QDialog::Accepted )
|
||||
{
|
||||
cfg.groups = groups.getGroups();
|
||||
|
||||
updateGroupList();
|
||||
Config::save( cfg );
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
updateGroupList();
|
||||
}
|
||||
|
||||
void MainWindow::translateInputChanged( QString const & )
|
||||
void MainWindow::translateInputChanged( QString const & newValue )
|
||||
{
|
||||
startLookup();
|
||||
//startLookupTimeout.start( 0 );
|
||||
}
|
||||
QString req = newValue.trimmed();
|
||||
|
||||
void MainWindow::startLookup()
|
||||
{
|
||||
QString word = ui.translateLine->text();
|
||||
if ( !req.size() )
|
||||
{
|
||||
// An empty request always results in an empty result
|
||||
prefixMatchComplete( WordFinderResults( req, &getActiveDicts() ) );
|
||||
|
||||
ui.wordList->clear();
|
||||
|
||||
wstring wordW = word.trimmed().toStdWString();
|
||||
|
||||
if ( wordW.empty() )
|
||||
return;
|
||||
|
||||
// Maps lowercased string to the original one. This catches all duplicates
|
||||
// without case sensitivity
|
||||
map< wstring, wstring > exactResults, prefixResults;
|
||||
|
||||
// Where to look?
|
||||
|
||||
vector< sptr< Dictionary::Class > > const & activeDicts = getActiveDicts();
|
||||
|
||||
for( unsigned x = 0; x < activeDicts.size(); ++x )
|
||||
{
|
||||
vector< wstring > exactMatches, prefixMatches;
|
||||
|
||||
activeDicts[ x ]->findExact( wordW, exactMatches, prefixMatches, 200 );
|
||||
|
||||
for( unsigned y = 0; y < exactMatches.size(); ++y )
|
||||
{
|
||||
wstring lowerCased = Folding::applySimpleCaseOnly( exactMatches[ y ] );
|
||||
|
||||
pair< map< wstring, wstring >::iterator, bool > insertResult =
|
||||
exactResults.insert( pair< wstring, wstring >( lowerCased, exactMatches[ y ] ) );
|
||||
|
||||
if ( !insertResult.second )
|
||||
{
|
||||
// Wasn't inserted since there was already an item -- check the case
|
||||
if ( insertResult.first->second != exactMatches[ y ] )
|
||||
{
|
||||
// The case is different -- agree on a lowercase version
|
||||
insertResult.first->second = lowerCased;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for( unsigned y = 0; y < prefixMatches.size(); ++y )
|
||||
{
|
||||
wstring lowerCased = Folding::applySimpleCaseOnly( prefixMatches[ y ] );
|
||||
|
||||
pair< map< wstring, wstring >::iterator, bool > insertResult =
|
||||
prefixResults.insert( pair< wstring, wstring >( lowerCased, prefixMatches[ y ] ) );
|
||||
|
||||
if ( !insertResult.second )
|
||||
{
|
||||
// Wasn't inserted since there was already an item -- check the case
|
||||
if ( insertResult.first->second != prefixMatches[ y ] )
|
||||
{
|
||||
// The case is different -- agree on a lowercase version
|
||||
insertResult.first->second = lowerCased;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do any sort of collation here in the future. For now we just put the
|
||||
// strings sorted by the map.
|
||||
ui.wordList->setCursor( Qt::WaitCursor );
|
||||
|
||||
for( map< wstring, wstring >::const_iterator i = exactResults.begin();
|
||||
i != exactResults.end(); ++i )
|
||||
wordFinder.prefixMatch( req, &getActiveDicts() );
|
||||
}
|
||||
|
||||
void MainWindow::prefixMatchComplete( WordFinderResults r )
|
||||
{
|
||||
if ( r.requestStr != ui.translateLine->text().trimmed() ||
|
||||
r.requestDicts != &getActiveDicts() )
|
||||
{
|
||||
ui.wordList->addItem( QString::fromStdWString( i->second ) );
|
||||
|
||||
QListWidgetItem * item = ui.wordList->item( ui.wordList->count() - 1 );
|
||||
|
||||
QFont font = item->font();
|
||||
//font.setWeight( QFont::Bold );
|
||||
|
||||
item->setFont( font );
|
||||
// Those results are already irrelevant, ignore the result
|
||||
return;
|
||||
}
|
||||
|
||||
if ( prefixResults.size() )
|
||||
ui.wordList->setUpdatesEnabled( false );
|
||||
|
||||
for( unsigned x = 0; x < r.results.size(); ++x )
|
||||
{
|
||||
for( map< wstring, wstring >::const_iterator i = prefixResults.begin();
|
||||
i != prefixResults.end(); ++i )
|
||||
{
|
||||
ui.wordList->addItem( QString::fromStdWString( i->second ) );
|
||||
QListWidgetItem * i = ui.wordList->item( x );
|
||||
|
||||
QListWidgetItem * item = ui.wordList->item( ui.wordList->count() - 1 );
|
||||
|
||||
QFont font = item->font();
|
||||
//font.setStyle( QFont::StyleOblique );
|
||||
|
||||
item->setFont( font );
|
||||
}
|
||||
if ( !i )
|
||||
ui.wordList->addItem( r.results[ x ] );
|
||||
else
|
||||
if ( i->text() != r.results[ x ] )
|
||||
i->setText( r.results[ x ] );
|
||||
}
|
||||
|
||||
while ( ui.wordList->count() > (int) r.results.size() )
|
||||
{
|
||||
// Chop off any extra items that were there
|
||||
QListWidgetItem * i = ui.wordList->takeItem( ui.wordList->count() - 1 );
|
||||
|
||||
if ( i )
|
||||
delete i;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ui.wordList->count() )
|
||||
ui.wordList->scrollToItem( ui.wordList->item( 0 ), QAbstractItemView::PositionAtTop );
|
||||
|
||||
ui.wordList->setUpdatesEnabled( true );
|
||||
ui.wordList->unsetCursor();
|
||||
}
|
||||
|
||||
void MainWindow::wordListItemActivated( QListWidgetItem * item )
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "article_maker.hh"
|
||||
#include "scanpopup.hh"
|
||||
#include "articleview.hh"
|
||||
#include "wordfinder.hh"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -67,9 +68,9 @@ private:
|
|||
ArticleMaker articleMaker;
|
||||
ArticleNetworkAccessManager articleNetMgr;
|
||||
|
||||
ScanPopup scanPopup;
|
||||
WordFinder wordFinder;
|
||||
|
||||
QTimer startLookupTimeout;
|
||||
ScanPopup scanPopup;
|
||||
|
||||
::Initializing * initializing;
|
||||
|
||||
|
@ -102,7 +103,7 @@ private slots:
|
|||
void indexingDictionary( QString dictionaryName );
|
||||
|
||||
void translateInputChanged( QString const & );
|
||||
void startLookup();
|
||||
void prefixMatchComplete( WordFinderResults );
|
||||
void wordListItemActivated( QListWidgetItem * );
|
||||
|
||||
void showTranslationFor( QString const & );
|
||||
|
|
186
src/wordfinder.cc
Normal file
186
src/wordfinder.cc
Normal file
|
@ -0,0 +1,186 @@
|
|||
/* This file is (c) 2008-2009 Konstantin Isakov <ikm@users.sf.net>
|
||||
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
||||
|
||||
#include "wordfinder.hh"
|
||||
#include "dictlock.hh"
|
||||
#include "folding.hh"
|
||||
#include <QMetaType>
|
||||
#include <map>
|
||||
|
||||
using std::vector;
|
||||
using std::wstring;
|
||||
using std::map;
|
||||
using std::pair;
|
||||
|
||||
namespace
|
||||
{
|
||||
struct MetaTypeRegister
|
||||
{
|
||||
MetaTypeRegister()
|
||||
{
|
||||
qRegisterMetaType< WordFinderResults >( "WordFinderResults" );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
WordFinder::WordFinder( QObject * parent ): QThread( parent ), op( NoOp )
|
||||
{
|
||||
static MetaTypeRegister _;
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
WordFinder::~WordFinder()
|
||||
{
|
||||
// Request termination and wait for it to happen
|
||||
opMutex.lock();
|
||||
|
||||
op = QuitOp;
|
||||
|
||||
opCondition.wakeOne();
|
||||
|
||||
opMutex.unlock();
|
||||
|
||||
wait();
|
||||
}
|
||||
|
||||
void WordFinder::prefixMatch( QString const & str,
|
||||
std::vector< sptr< Dictionary::Class > > const * dicts )
|
||||
{
|
||||
opMutex.lock();
|
||||
|
||||
op = DoPrefixMatch;
|
||||
prefixMatchString = str;
|
||||
prefixMatchDicts = dicts;
|
||||
|
||||
opCondition.wakeOne();
|
||||
|
||||
opMutex.unlock();
|
||||
}
|
||||
|
||||
void WordFinder::run()
|
||||
{
|
||||
opMutex.lock();
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
// Check the operation requested
|
||||
|
||||
if ( op == NoOp )
|
||||
{
|
||||
opCondition.wait( &opMutex );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( op == QuitOp )
|
||||
break;
|
||||
|
||||
// The only one op value left is DoPrefixMatch
|
||||
|
||||
Q_ASSERT( op == DoPrefixMatch );
|
||||
|
||||
QString prefixMatchReq = prefixMatchString;
|
||||
vector< sptr< Dictionary::Class > > const & activeDicts = *prefixMatchDicts;
|
||||
|
||||
op = NoOp;
|
||||
|
||||
opMutex.unlock();
|
||||
|
||||
map< wstring, wstring > exactResults, prefixResults;
|
||||
|
||||
{
|
||||
wstring word = prefixMatchReq.toStdWString();
|
||||
|
||||
DictLock _;
|
||||
|
||||
// Maps lowercased string to the original one. This catches all duplicates
|
||||
// without case sensitivity
|
||||
|
||||
bool cancel = false;
|
||||
|
||||
for( unsigned x = 0; x < activeDicts.size(); ++x )
|
||||
{
|
||||
vector< wstring > exactMatches, prefixMatches;
|
||||
|
||||
activeDicts[ x ]->findExact( word, exactMatches, prefixMatches, 40 );
|
||||
|
||||
for( unsigned y = 0; y < exactMatches.size(); ++y )
|
||||
{
|
||||
wstring lowerCased = Folding::applySimpleCaseOnly( exactMatches[ y ] );
|
||||
|
||||
pair< map< wstring, wstring >::iterator, bool > insertResult =
|
||||
exactResults.insert( pair< wstring, wstring >( lowerCased,
|
||||
exactMatches[ y ] ) );
|
||||
|
||||
if ( !insertResult.second )
|
||||
{
|
||||
// Wasn't inserted since there was already an item -- check the case
|
||||
if ( insertResult.first->second != exactMatches[ y ] )
|
||||
{
|
||||
// The case is different -- agree on a lowercase version
|
||||
insertResult.first->second = lowerCased;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for( unsigned y = 0; y < prefixMatches.size(); ++y )
|
||||
{
|
||||
wstring lowerCased = Folding::applySimpleCaseOnly( prefixMatches[ y ] );
|
||||
|
||||
pair< map< wstring, wstring >::iterator, bool > insertResult =
|
||||
prefixResults.insert( pair< wstring, wstring >( lowerCased,
|
||||
prefixMatches[ y ] ) );
|
||||
|
||||
if ( !insertResult.second )
|
||||
{
|
||||
// Wasn't inserted since there was already an item -- check the case
|
||||
if ( insertResult.first->second != prefixMatches[ y ] )
|
||||
{
|
||||
// The case is different -- agree on a lowercase version
|
||||
insertResult.first->second = lowerCased;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we've got an op request -- abort the query then
|
||||
|
||||
opMutex.lock();
|
||||
|
||||
if ( op != NoOp )
|
||||
{
|
||||
cancel = true;
|
||||
break;
|
||||
}
|
||||
|
||||
opMutex.unlock();
|
||||
}
|
||||
|
||||
if ( cancel )
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do any sort of collation here in the future. For now we just put the
|
||||
// strings sorted by the map.
|
||||
|
||||
WordFinderResults r( prefixMatchReq, &activeDicts );
|
||||
|
||||
r.results.reserve( exactResults.size() + prefixResults.size() );
|
||||
|
||||
for( map< wstring, wstring >::const_iterator i = exactResults.begin();
|
||||
i != exactResults.end(); ++i )
|
||||
r.results.push_back( QString::fromStdWString( i->second ) );
|
||||
|
||||
for( map< wstring, wstring >::const_iterator i = prefixResults.begin();
|
||||
i != prefixResults.end(); ++i )
|
||||
r.results.push_back( QString::fromStdWString( i->second ) );
|
||||
|
||||
emit prefixMatchComplete( r );
|
||||
|
||||
// Continue serving op requests
|
||||
|
||||
opMutex.lock();
|
||||
}
|
||||
|
||||
opMutex.unlock();
|
||||
}
|
||||
|
92
src/wordfinder.hh
Normal file
92
src/wordfinder.hh
Normal file
|
@ -0,0 +1,92 @@
|
|||
/* This file is (c) 2008-2009 Konstantin Isakov <ikm@users.sf.net>
|
||||
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
||||
|
||||
#ifndef __WORDFINDER_HH_INCLUDED__
|
||||
#define __WORDFINDER_HH_INCLUDED__
|
||||
|
||||
#include <QThread>
|
||||
#include <QMutex>
|
||||
#include <QWaitCondition>
|
||||
#include "dictionary.hh"
|
||||
|
||||
|
||||
/// This struct represents results of a WordFinder match operation.
|
||||
/// We need to separate this since it's needed to register is as a metatype
|
||||
/// for the signal-slot connections to be able to pass it in queued mode.
|
||||
struct WordFinderResults
|
||||
{
|
||||
/// The initial request parameters. They are passed back so that it'd be
|
||||
/// possible to tell the results apart from any previously cancelled
|
||||
/// operations.
|
||||
QString requestStr;
|
||||
std::vector< sptr< Dictionary::Class > > const * requestDicts;
|
||||
|
||||
/// The results themselves
|
||||
std::vector< QString > results;
|
||||
|
||||
WordFinderResults()
|
||||
{}
|
||||
|
||||
WordFinderResults( QString const & requestStr_,
|
||||
std::vector< sptr< Dictionary::Class > > const * requestDicts_ ):
|
||||
requestStr( requestStr_ ), requestDicts( requestDicts_ )
|
||||
{}
|
||||
};
|
||||
|
||||
/// This component takes care of finding words in dictionaries asyncronously,
|
||||
/// in another thread. This means the GUI doesn't get blocked during the
|
||||
/// sometimes lenghtly process of finding words.
|
||||
class WordFinder: QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
WordFinder( QObject * parent );
|
||||
~WordFinder();
|
||||
|
||||
/// Allows accessing the otherwise inaccessible QObject indirect base,
|
||||
/// which is QThread's base. This is needed to connect signals of the object.
|
||||
QObject * qobject()
|
||||
{ return this; }
|
||||
|
||||
/// Do the standard prefix-match search in the given list of dictionaries.
|
||||
/// Some dictionaries might only support exact matches -- for them, only
|
||||
/// the exact matches would be found. All search results are put into a single
|
||||
/// list containing the exact matches first, then the prefix ones. Duplicate
|
||||
/// matches from different dictionaries are merged together.
|
||||
/// If there already was a prefixMatch operation underway, it gets cancelled
|
||||
/// and the new one replaces it.
|
||||
/// The dictionaries and the containing vector get locked during the search
|
||||
/// using the DictLock object. Be sure you do that too in case you'd want
|
||||
/// to work with them during the search underway.
|
||||
void prefixMatch( QString const &,
|
||||
std::vector< sptr< Dictionary::Class > > const * );
|
||||
|
||||
signals:
|
||||
|
||||
/// This singal gets emitted from another thread and indicates that the
|
||||
/// previously requested prefixMatch() operation was finished. See the
|
||||
/// WordFinderResults structure description for further details.
|
||||
void prefixMatchComplete( WordFinderResults );
|
||||
|
||||
private:
|
||||
|
||||
QMutex opMutex;
|
||||
QWaitCondition opCondition;
|
||||
|
||||
enum Op
|
||||
{
|
||||
NoOp,
|
||||
QuitOp,
|
||||
DoPrefixMatch
|
||||
} op;
|
||||
|
||||
QString prefixMatchString;
|
||||
std::vector< sptr< Dictionary::Class > > const * prefixMatchDicts;
|
||||
|
||||
virtual void run();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in a new issue