diff options
-rw-r--r-- | src/virtualkeyboard/t9writeinputmethod.cpp | 311 | ||||
-rw-r--r-- | src/virtualkeyboard/t9writeinputmethod.h | 4 | ||||
-rw-r--r-- | src/virtualkeyboard/t9writeworker.cpp | 66 | ||||
-rw-r--r-- | src/virtualkeyboard/t9writeworker.h | 15 |
4 files changed, 252 insertions, 144 deletions
diff --git a/src/virtualkeyboard/t9writeinputmethod.cpp b/src/virtualkeyboard/t9writeinputmethod.cpp index 332a94c8..329bdbd3 100644 --- a/src/virtualkeyboard/t9writeinputmethod.cpp +++ b/src/virtualkeyboard/t9writeinputmethod.cpp @@ -130,6 +130,7 @@ public: attachedDictionary(0), traceListHardLimit(32), resultId(0), + lastResultId(0), resultTimer(0), decumaSession(0), activeWordIndex(-1), @@ -230,7 +231,6 @@ public: languageCategories.append(DECUMA_LANG_EN); sessionSettings.recognitionMode = mcrMode; - sessionSettings.bMinimizeAddArcPreProcessing = 1; sessionSettings.writingDirection = unknownWriting; sessionSettings.charSet.pSymbolCategories = symbolCategories.data(); sessionSettings.charSet.nSymbolCategories = symbolCategories.size(); @@ -255,6 +255,9 @@ public: worker.reset(new T9WriteWorker(decumaSession, cjk)); worker->start(); + Q_Q(T9WriteInputMethod); + processResultConnection = QObject::connect(q, &T9WriteInputMethod::resultListChanged, q, &T9WriteInputMethod::processResult, Qt::QueuedConnection); + return true; } @@ -262,6 +265,9 @@ public: { VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::exitEngine()"; + if (processResultConnection) + QObject::disconnect(processResultConnection); + worker.reset(); if (sessionSettings.pStaticDB) { @@ -683,6 +689,7 @@ public: InputEngine::InputMode inputMode) { Q_Q(T9WriteInputMethod); + Q_UNUSED(language) Q_UNUSED(locale) // Select recognition mode @@ -992,9 +999,10 @@ public: void setContext(InputEngine::PatternRecognitionMode patternRecognitionMode, const QVariantMap &traceCaptureDeviceInfo, - const QVariantMap &traceScreenInfo) + const QVariantMap &traceScreenInfo, + const QByteArray &context) { - QByteArray context = getContext(patternRecognitionMode, traceCaptureDeviceInfo, traceScreenInfo); + Q_UNUSED(patternRecognitionMode) if (context == currentContext) return; currentContext = context; @@ -1050,6 +1058,10 @@ public: if (!worker) return 0; + // The result id follows the trace id so that the (previous) + // results completed during the handwriting can be rejected. + resultId = traceId; + stopResultTimer(); // Dictionary must be completed before the arc addition can begin @@ -1060,10 +1072,9 @@ public: // Cancel the current recognition task worker->removeAllTasks<T9WriteRecognitionResultsTask>(); + worker->removeAllTasks<T9WriteRecognitionTask>(); if (recognitionTask) { recognitionTask->cancelRecognition(); - recognitionTask->wait(); - worker->removeTask(recognitionTask); recognitionTask.reset(); } @@ -1072,25 +1083,21 @@ public: unipenTrace.reset(new UnipenTrace(traceCaptureDeviceInfo, traceScreenInfo)); #endif - setContext(patternRecognitionMode, traceCaptureDeviceInfo, traceScreenInfo); + QByteArray context = getContext(patternRecognitionMode, traceCaptureDeviceInfo, traceScreenInfo); + if (context != currentContext) { + worker->waitForAllTasks(); + setContext(patternRecognitionMode, traceCaptureDeviceInfo, traceScreenInfo, context); + } DECUMA_STATUS status; if (!arcAdditionStarted) { + worker->waitForAllTasks(); status = DECUMA_API(BeginArcAddition)(decumaSession); Q_ASSERT(status == decumaNoError); arcAdditionStarted = true; } - DECUMA_UINT32 arcID = (DECUMA_UINT32)traceId; - status = DECUMA_API(StartNewArc)(decumaSession, arcID); - Q_ASSERT(status == decumaNoError); - if (status != decumaNoError) { - DECUMA_API(EndArcAddition)(decumaSession); - arcAdditionStarted = false; - return NULL; - } - Trace *trace = new Trace(); #ifdef QT_VIRTUALKEYBOARD_RECORD_TRACE_INPUT trace->setChannels(QStringList("t")); @@ -1103,25 +1110,21 @@ public: void traceEnd(Trace *trace) { if (trace->isCanceled()) { - DECUMA_API(CancelArc)(decumaSession, trace->traceId()); traceList.removeOne(trace); delete trace; } else { - addPointsToTraceGroup(trace); + if (cjk && countActiveTraces() == 0) { + // For some reason gestures don't seem to work in CJK mode + // Using our own gesture recognizer as fallback + if (handleGesture()) + return; + } + worker->addTask(QSharedPointer<T9WriteAddArcTask>(new T9WriteAddArcTask(trace))); } if (!traceList.isEmpty()) { Q_ASSERT(arcAdditionStarted); - if (countActiveTraces() == 0) { + if (countActiveTraces() == 0) restartRecognition(); - if (cjk) { - // For some reason gestures don't seem to work in CJK mode - // Using our own gesture recognizer as fallback - handleGesture(); - } - } - } else if (arcAdditionStarted) { - DECUMA_API(EndArcAddition)(decumaSession); - arcAdditionStarted = false; } } @@ -1137,37 +1140,11 @@ public: void clearTraces() { + worker->waitForAllTasks(); qDeleteAll(traceList); traceList.clear(); } - void addPointsToTraceGroup(Trace *trace) - { - Q_ASSERT(decumaSession != 0); - - const QVariantList points = trace->points(); - Q_ASSERT(!points.isEmpty()); - DECUMA_UINT32 arcID = (DECUMA_UINT32)trace->traceId(); - DECUMA_STATUS status; - - for (const QVariant &p : points) { - const QPoint pt(p.toPointF().toPoint()); - status = DECUMA_API(AddPoint)(decumaSession, (DECUMA_COORD)pt.x(),(DECUMA_COORD)pt.y(), arcID); - if (status != decumaNoError) { - VIRTUALKEYBOARD_DEBUG() << "decumaAddPoint failed" << status; - finishRecognition(); - return; - } - } - - status = DECUMA_API(CommitArc)(decumaSession, arcID); - if (status != decumaNoError) { - VIRTUALKEYBOARD_DEBUG() << "decumaCommitArc failed" << status; - finishRecognition(); - return; - } - } - void noteSelected(int index) { if (wordCandidatesHwrResultIndex.isEmpty()) @@ -1187,6 +1164,12 @@ public: Q_Q(T9WriteInputMethod); + worker->removeAllTasks<T9WriteRecognitionResultsTask>(); + if (recognitionTask) { + recognitionTask->cancelRecognition(); + recognitionTask.reset(); + } + // Boost dictionary words by default BOOST_LEVEL boostLevel = attachedDictionary ? boostDictWords : noBoost; @@ -1196,7 +1179,7 @@ public: if (sessionSettings.recognitionMode == ucrMode && (inputMethodHints & (Qt::ImhUrlCharactersOnly | Qt::ImhEmailCharactersOnly))) boostLevel = noBoost; - QSharedPointer<T9WriteRecognitionResult> recognitionResult(new T9WriteRecognitionResult(++resultId, 9, 64)); + QSharedPointer<T9WriteRecognitionResult> recognitionResult(new T9WriteRecognitionResult(resultId, 9, 64)); recognitionTask.reset(new T9WriteRecognitionTask(recognitionResult, instantGestureSettings, boostLevel, stringStart)); worker->addTask(recognitionTask); @@ -1208,6 +1191,16 @@ public: resetResultTimer(); } + void waitForRecognitionResults() + { + if (!worker) + return; + + VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::waitForRecognitionResults()"; + worker->waitForAllTasks(); + processResult(); + } + bool finishRecognition(bool emitSelectionListChanged = true) { VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::finishRecognition()"; @@ -1220,17 +1213,16 @@ public: stopResultTimer(); - clearTraces(); - + worker->removeAllTasks<T9WriteAddArcTask>(); worker->removeAllTasks<T9WriteRecognitionResultsTask>(); if (recognitionTask) { recognitionTask->cancelRecognition(); - recognitionTask->wait(); - worker->removeTask(recognitionTask); recognitionTask.reset(); result = true; } + clearTraces(); + if (arcAdditionStarted) { DECUMA_API(EndArcAddition)(decumaSession); arcAdditionStarted = false; @@ -1314,12 +1306,12 @@ public: return true; } - void resetResultTimer() + void resetResultTimer(int interval = 500) { - VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::resetResultTimer()"; + VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::resetResultTimer():" << interval; Q_Q(T9WriteInputMethod); stopResultTimer(); - resultTimer = q->startTimer(500); + resultTimer = q->startTimer(interval); } void stopResultTimer() @@ -1332,24 +1324,9 @@ public: } } - void resultsAvailable(const QVariantList &resultList) + void processResult() { - if (!resultList.isEmpty()) { - if (recognitionTask && recognitionTask->resultId() == resultList.first().toMap()["resultId"].toInt()) - processResult(resultList); - } - } - - void processResult(const QVariantList &resultList) - { - if (resultList.isEmpty()) - return; - - if (resultList.first().toMap()["resultId"] != resultId) - return; - VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::processResult()"; - Q_Q(T9WriteInputMethod); InputContext *ic = q->inputContext(); if (!ic) @@ -1360,80 +1337,100 @@ public: QString resultString; QString gesture; QVariantList symbolStrokes; - for (int i = 0; i < resultList.size(); i++) { - QVariantMap result = resultList.at(i).toMap(); - QString resultChars = result["chars"].toString(); - if (i == 0) { - if (ic->shift()) { - caseFormatter.ensureLength(1, textCase); - caseFormatter.ensureLength(resultChars.length(), InputEngine::Lower); - } else { - caseFormatter.ensureLength(resultChars.length(), textCase); - } + { + QMutexLocker resultListGuard(&resultListLock); + if (resultList.isEmpty()) + return; + + if (resultList.first().toMap()["resultId"] != resultId) { + VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::processResult(): resultId mismatch" << resultList.first().toMap()["resultId"] << "(" << resultId << ")"; + resultList.clear(); + return; } - if (!resultChars.isEmpty()) { - resultChars = caseFormatter.formatString(resultChars); - if (sessionSettings.recognitionMode != scrMode) { - newWordCandidates.append(resultChars); - newWordCandidatesHwrResultIndex.append(i); + lastResultId = resultId; + + for (int i = 0; i < resultList.size(); i++) { + QVariantMap result = resultList.at(i).toMap(); + QString resultChars = result["chars"].toString(); + if (i == 0) { + if (ic->shift()) { + caseFormatter.ensureLength(1, textCase); + caseFormatter.ensureLength(resultChars.length(), InputEngine::Lower); + } else { + caseFormatter.ensureLength(resultChars.length(), textCase); + } } - } - if (i == 0) { - resultString = resultChars; - if (result.contains("gesture")) - gesture = result["gesture"].toString(); - if (sessionSettings.recognitionMode != scrMode && result.contains("symbolStrokes")) - symbolStrokes = result["symbolStrokes"].toList(); - if (sessionSettings.recognitionMode == scrMode) - break; - } else { - // Add a gesture symbol to the secondary candidate - if (sessionSettings.recognitionMode != scrMode && result.contains("gesture")) { - QString gesture2 = result["gesture"].toString(); - if (gesture2.length() == 1) { - QChar symbol = T9WriteInputMethodPrivate::mapGestureToSymbol(gesture2.at(0).unicode()); - if (!symbol.isNull()) { - // Check for duplicates - bool duplicateFound = false; - for (const QString &wordCandidate : newWordCandidates) { - duplicateFound = wordCandidate.size() == 1 && wordCandidate.at(0) == symbol; - if (duplicateFound) - break; - } - if (!duplicateFound) { - if (!resultChars.isEmpty()) { - newWordCandidates.last().append(symbol); - } else { - newWordCandidates.append(symbol); - newWordCandidatesHwrResultIndex.append(i); + if (!resultChars.isEmpty()) { + resultChars = caseFormatter.formatString(resultChars); + if (sessionSettings.recognitionMode != scrMode) { + newWordCandidates.append(resultChars); + newWordCandidatesHwrResultIndex.append(i); + } + } + if (i == 0) { + resultString = resultChars; + if (result.contains("gesture")) + gesture = result["gesture"].toString(); + if (sessionSettings.recognitionMode != scrMode && result.contains("symbolStrokes")) + symbolStrokes = result["symbolStrokes"].toList(); + if (sessionSettings.recognitionMode == scrMode) + break; + } else { + // Add a gesture symbol to the secondary candidate + if (sessionSettings.recognitionMode != scrMode && result.contains("gesture")) { + QString gesture2 = result["gesture"].toString(); + if (gesture2.length() == 1) { + QChar symbol = T9WriteInputMethodPrivate::mapGestureToSymbol(gesture2.at(0).unicode()); + if (!symbol.isNull()) { + // Check for duplicates + bool duplicateFound = false; + for (const QString &wordCandidate : newWordCandidates) { + duplicateFound = wordCandidate.size() == 1 && wordCandidate.at(0) == symbol; + if (duplicateFound) + break; + } + if (!duplicateFound) { + if (!resultChars.isEmpty()) { + newWordCandidates.last().append(symbol); + } else { + newWordCandidates.append(symbol); + newWordCandidatesHwrResultIndex.append(i); + } } } } } } } + + resultList.clear(); } bool wordCandidatesChanged = wordCandidates != newWordCandidates; #ifndef QT_VIRTUALKEYBOARD_RECORD_TRACE_INPUT // Delete trace history - const InputEngine::InputMode inputMode = q->inputEngine()->inputMode(); - if (sessionSettings.recognitionMode == mcrMode && !symbolStrokes.isEmpty() && - inputMode != InputEngine::ChineseHandwriting && - inputMode != InputEngine::JapaneseHandwriting && - inputMode != InputEngine::KoreanHandwriting) { - int activeTraces = symbolStrokes.at(symbolStrokes.count() - 1).toInt(); - if (symbolStrokes.count() > 1) - activeTraces += symbolStrokes.at(symbolStrokes.count() - 2).toInt(); - while (activeTraces < traceList.count()) - delete traceList.takeFirst(); - } + // Note: We have to be sure there are no background tasks + // running since the Trace objects consumed there. + if (worker->numberOfPendingTasks() == 0) { - // Enforce hard limit for number of traces - if (traceList.count() >= traceListHardLimit) { - VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::processResult(): Clearing traces (hard limit):" << traceList.count(); - clearTraces(); + const InputEngine::InputMode inputMode = q->inputEngine()->inputMode(); + if (sessionSettings.recognitionMode == mcrMode && !symbolStrokes.isEmpty() && + inputMode != InputEngine::ChineseHandwriting && + inputMode != InputEngine::JapaneseHandwriting && + inputMode != InputEngine::KoreanHandwriting) { + int activeTraces = symbolStrokes.at(symbolStrokes.count() - 1).toInt(); + if (symbolStrokes.count() > 1) + activeTraces += symbolStrokes.at(symbolStrokes.count() - 2).toInt(); + while (activeTraces < traceList.count()) + delete traceList.takeFirst(); + } + + // Enforce hard limit for number of traces + if (traceList.count() >= traceListHardLimit) { + VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethodPrivate::processResult(): Clearing traces (hard limit):" << traceList.count(); + clearTraces(); + } } #endif @@ -1454,10 +1451,7 @@ public: ic->setPreeditText(resultString); ignoreUpdate = false; } else { - if (resultTimer == 0 && !resultString.isEmpty()) - ic->inputEngine()->virtualKeyClick((Qt::Key)resultString.at(0).unicode(), resultString, Qt::NoModifier); - else - scrResult = resultString; + scrResult = resultString; } if (wordCandidatesChanged) { @@ -1467,6 +1461,11 @@ public: emit q->selectionListChanged(SelectionListModel::WordCandidateList); emit q->selectionListActiveItemChanged(SelectionListModel::WordCandidateList, activeWordIndex); } + + if (arcAdditionStarted && traceList.isEmpty() && worker->numberOfPendingTasks() == 0) { + DECUMA_API(EndArcAddition)(decumaSession); + arcAdditionStarted = false; + } } static QChar mapGestureToSymbol(const QChar &gesture) @@ -1637,8 +1636,12 @@ public: QSharedPointer<T9WriteDictionary> attachedDictionary; QSharedPointer<T9WriteDictionaryTask> dictionaryTask; QSharedPointer<T9WriteRecognitionTask> recognitionTask; + QMutex resultListLock; + QVariantList resultList; int resultId; + int lastResultId; int resultTimer; + QMetaObject::Connection processResultConnection; QByteArray session; DECUMA_SESSION *decumaSession; QStringList wordCandidates; @@ -1801,6 +1804,7 @@ bool T9WriteInputMethod::keyEvent(Qt::Key key, const QString &text, Qt::Keyboard // WA: T9Write CJK may crash in some cases with long stringStart. // Therefore we commit the current input and finish the recognition. if (d->cjk) { + d->waitForRecognitionResults(); ic->commit(); d->finishRecognition(); return true; @@ -1829,6 +1833,7 @@ bool T9WriteInputMethod::keyEvent(Qt::Key key, const QString &text, Qt::Keyboard default: if (d->sessionSettings.recognitionMode != scrMode && text.length() > 0) { + d->waitForRecognitionResults(); InputContext *ic = inputContext(); QString preeditText = ic->preeditText(); QChar c = text.at(0); @@ -2020,6 +2025,13 @@ void T9WriteInputMethod::timerEvent(QTimerEvent *timerEvent) VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethod::timerEvent():" << timerId; if (timerId == d->resultTimer) { d->stopResultTimer(); + + // Ignore if the result is not yet available + if (d->resultId != d->lastResultId) { + VIRTUALKEYBOARD_DEBUG() << "T9WriteInputMethod::timerEvent(): Result not yet available"; + return; + } + if (d->sessionSettings.recognitionMode != scrMode) { #ifndef QT_VIRTUALKEYBOARD_RECORD_TRACE_INPUT // Don't clear traces in UCR mode if dictionary is loaded. @@ -2090,7 +2102,22 @@ void T9WriteInputMethod::resultsAvailable(const QVariantList &resultList) } #endif Q_D(T9WriteInputMethod); - d->resultsAvailable(resultList); + QMutexLocker resultListGuard(&d->resultListLock); + d->resultList = resultList; + emit resultListChanged(); +} + +void T9WriteInputMethod::processResult() +{ + Q_D(T9WriteInputMethod); + bool resultTimerWasRunning = d->resultTimer != 0; + + d->processResult(); + + // Restart the result timer now if it stopped before the results were completed + if (!resultTimerWasRunning && (!d->scrResult.isEmpty() || !d->wordCandidates.isEmpty())) + d->resetResultTimer(0); + } void T9WriteInputMethod::recognitionError(int status) diff --git a/src/virtualkeyboard/t9writeinputmethod.h b/src/virtualkeyboard/t9writeinputmethod.h index 173abd99..9d922537 100644 --- a/src/virtualkeyboard/t9writeinputmethod.h +++ b/src/virtualkeyboard/t9writeinputmethod.h @@ -68,12 +68,16 @@ public: bool reselect(int cursorPosition, const InputEngine::ReselectFlags &reselectFlags); +signals: + void resultListChanged(); + protected: void timerEvent(QTimerEvent *timerEvent); protected slots: void dictionaryLoadCompleted(QSharedPointer<T9WriteDictionary> dictionary); void resultsAvailable(const QVariantList &resultList); + void processResult(); void recognitionError(int status); }; diff --git a/src/virtualkeyboard/t9writeworker.cpp b/src/virtualkeyboard/t9writeworker.cpp index 45608f77..cc4564dd 100644 --- a/src/virtualkeyboard/t9writeworker.cpp +++ b/src/virtualkeyboard/t9writeworker.cpp @@ -93,6 +93,47 @@ void T9WriteDictionaryTask::run() emit completed(dictionary); } +T9WriteAddArcTask::T9WriteAddArcTask(Trace *trace) : + trace(trace) +{ +} + +void T9WriteAddArcTask::run() +{ +#ifdef QT_VIRTUALKEYBOARD_DEBUG + QTime perf; + perf.start(); +#endif + DECUMA_UINT32 arcID = (DECUMA_UINT32)trace->traceId(); + DECUMA_STATUS status = DECUMA_API(StartNewArc)(decumaSession, arcID); + Q_ASSERT(status == decumaNoError); + if (status != decumaNoError) { + qWarning() << "T9WriteAddArcTask::run(): Failed to start new arc, status:" << status; + return; + } + + const QVariantList points = trace->points(); + Q_ASSERT(!points.isEmpty()); + + for (const QVariant &p : points) { + const QPoint pt(p.toPointF().toPoint()); + status = DECUMA_API(AddPoint)(decumaSession, (DECUMA_COORD)pt.x(),(DECUMA_COORD)pt.y(), arcID); + if (status != decumaNoError) { + qWarning() << "T9WriteAddArcTask::run(): Failed to add point, status:" << status; + DECUMA_API(CancelArc)(decumaSession, arcID); + return; + } + } + + status = DECUMA_API(CommitArc)(decumaSession, arcID); + if (status != decumaNoError) + qWarning() << "T9WriteAddArcTask::run(): Failed to commit arc, status:" << status; +#ifdef QT_VIRTUALKEYBOARD_DEBUG + else + VIRTUALKEYBOARD_DEBUG() << "T9WriteAddArcTask::run(): time:" << perf.elapsed() << "ms"; +#endif +} + /*! \class QtVirtualKeyboard::T9WriteRecognitionResult \internal @@ -142,8 +183,6 @@ T9WriteRecognitionTask::T9WriteRecognitionTask(QSharedPointer<T9WriteRecognition void T9WriteRecognitionTask::run() { - VIRTUALKEYBOARD_DEBUG() << "T9WriteRecognitionTask::run()"; - if (!decumaSession) return; @@ -176,6 +215,8 @@ void T9WriteRecognitionTask::run() DECUMA_INTERRUPT_FUNCTIONS *pInterruptFunctions = NULL; #endif result->status = DECUMA_API(Recognize)(decumaSession, result->results.data(), result->results.size(), &result->numResults, result->maxCharsPerWord, &recSettings, pInterruptFunctions); + if (result->status != decumaNoError) + qWarning() << "T9WriteRecognitionTask::run(): Recognition failed, status:" << result->status; #ifdef QT_VIRTUALKEYBOARD_DEBUG int perfElapsed = perf.elapsed(); @@ -326,12 +367,33 @@ int T9WriteWorker::removeAllTasks() return count; } +void T9WriteWorker::waitForAllTasks() +{ + while (isRunning()) { + idleSema.acquire(); + QMutexLocker guard(&taskLock); + if (taskList.isEmpty()) { + idleSema.release(); + break; + } + idleSema.release(); + } +} + +int T9WriteWorker::numberOfPendingTasks() +{ + QMutexLocker guard(&taskLock); + return taskList.count() + !idleSema.available() ? 1 : 0; +} + void T9WriteWorker::run() { while (!abort) { + idleSema.release(); taskSema.acquire(); if (abort) break; + idleSema.acquire(); QSharedPointer<T9WriteTask> currentTask; { QMutexLocker guard(&taskLock); diff --git a/src/virtualkeyboard/t9writeworker.h b/src/virtualkeyboard/t9writeworker.h index 437a84f5..f34eef67 100644 --- a/src/virtualkeyboard/t9writeworker.h +++ b/src/virtualkeyboard/t9writeworker.h @@ -86,6 +86,18 @@ signals: void completed(QSharedPointer<T9WriteDictionary> dictionary); }; +class T9WriteAddArcTask : public T9WriteTask +{ + Q_OBJECT +public: + explicit T9WriteAddArcTask(Trace *trace); + + void run(); + +private: + Trace *trace; +}; + class T9WriteRecognitionResult { Q_DISABLE_COPY(T9WriteRecognitionResult) @@ -159,6 +171,8 @@ public: void addTask(QSharedPointer<T9WriteTask> task); int removeTask(QSharedPointer<T9WriteTask> task); int removeAllTasks(); + void waitForAllTasks(); + int numberOfPendingTasks(); template <class X> int removeAllTasks() { @@ -181,6 +195,7 @@ protected: private: QList<QSharedPointer<T9WriteTask> > taskList; + QSemaphore idleSema; QSemaphore taskSema; QMutex taskLock; DECUMA_SESSION *decumaSession; |