00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <QImage>
00025 #include <QThread>
00026 #include <QMutex>
00027 #include <QWaitCondition>
00028 #include <QQueue>
00029
00030 #include <klfbackend.h>
00031
00032 #include "klflatexpreviewthread.h"
00033 #include "klflatexpreviewthread_p.h"
00034
00035
00036
00037 KLFLatexPreviewHandler::KLFLatexPreviewHandler(QObject * parent)
00038 : QObject(parent)
00039 {
00040 }
00041 KLFLatexPreviewHandler::~KLFLatexPreviewHandler()
00042 {
00043 }
00044
00045 void KLFLatexPreviewHandler::latexPreviewReset()
00046 {
00047 }
00048 void KLFLatexPreviewHandler::latexOutputAvailable(const KLFBackend::klfOutput& output)
00049 {
00050 Q_UNUSED(output);
00051 }
00052 void KLFLatexPreviewHandler::latexPreviewAvailable(const QImage& preview, const QImage& largePreview,
00053 const QImage& fullPreview)
00054 {
00055 Q_UNUSED(preview); Q_UNUSED(largePreview); Q_UNUSED(fullPreview);
00056 }
00057 void KLFLatexPreviewHandler::latexPreviewImageAvailable(const QImage& preview)
00058 {
00059 Q_UNUSED(preview);
00060 }
00061 void KLFLatexPreviewHandler::latexPreviewLargeImageAvailable(const QImage& largePreview)
00062 {
00063 Q_UNUSED(largePreview);
00064 }
00065 void KLFLatexPreviewHandler::latexPreviewFullImageAvailable(const QImage& fullPreview)
00066 {
00067 Q_UNUSED(fullPreview);
00068 }
00069 void KLFLatexPreviewHandler::latexPreviewError(const QString& errorString, int errorCode)
00070 {
00071 Q_UNUSED(errorString); Q_UNUSED(errorCode);
00072 }
00073
00074
00075
00076
00077
00078
00079 KLFLatexPreviewThread::KLFLatexPreviewThread(QObject * parent)
00080 : QThread(parent)
00081 {
00082 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00083
00084 KLF_INIT_PRIVATE( KLFLatexPreviewThread ) ;
00085
00086
00087
00088 if (QMetaType::type("KLFBackend::klfOutput") == 0) {
00089 qRegisterMetaType<KLFBackend::klfOutput>("KLFBackend::klfOutput") ;
00090 }
00091 if (QMetaType::type("KLFBackend::klfInput") == 0) {
00092 qRegisterMetaType<KLFBackend::klfInput>("KLFBackend::klfInput") ;
00093 }
00094 if (QMetaType::type("KLFBackend::klfSettings") == 0) {
00095 qRegisterMetaType<KLFBackend::klfSettings>("KLFBackend::klfSettings") ;
00096 }
00097 if (QMetaType::type("KLFLatexPreviewThreadWorker::Task") == 0) {
00098 qRegisterMetaType<KLFLatexPreviewThreadWorker::Task>("KLFLatexPreviewThreadWorker::Task") ;
00099 }
00100 if (QMetaType::type("KLFLatexPreviewThread::TaskId") == 0) {
00101 qRegisterMetaType<KLFLatexPreviewThread::TaskId>("KLFLatexPreviewThread::TaskId") ;
00102 }
00103
00104
00105
00106
00107
00108
00109 d->worker = new KLFLatexPreviewThreadWorker;
00110 d->worker->moveToThread(this);
00111
00112
00113 connect(d, SIGNAL(internalRequestAbort()), d->worker, SLOT(abort()), Qt::DirectConnection);
00114
00115
00116 connect(d, SIGNAL(internalRequestSubmitNewTask(KLFLatexPreviewThreadWorker::Task, bool,
00117 KLFLatexPreviewThread::TaskId)),
00118 d->worker, SLOT(threadSubmitTask(KLFLatexPreviewThreadWorker::Task, bool,
00119 KLFLatexPreviewThread::TaskId)),
00120 Qt::QueuedConnection);
00121
00122 connect(d, SIGNAL(internalRequestClearPendingTasks()), d->worker, SLOT(threadClearPendingTasks()),
00123 Qt::QueuedConnection);
00124
00125 connect(d, SIGNAL(internalRequestCancelTask(KLFLatexPreviewThread::TaskId)),
00126 d->worker, SLOT(threadCancelTask(KLFLatexPreviewThread::TaskId)),
00127 Qt::QueuedConnection);
00128 }
00129
00130 KLFLatexPreviewThread::~KLFLatexPreviewThread()
00131 {
00132 stop();
00133
00134 if (d->worker) {
00135 delete d->worker;
00136 }
00137
00138 KLF_DELETE_PRIVATE ;
00139 }
00140
00141
00142 QSize KLFLatexPreviewThread::previewSize() const
00143 { return d->previewSize; }
00144 QSize KLFLatexPreviewThread::largePreviewSize() const
00145 { return d->largePreviewSize; }
00146
00147 void KLFLatexPreviewThread::setPreviewSize(const QSize& previewSize)
00148 { d->previewSize = previewSize; }
00149 void KLFLatexPreviewThread::setLargePreviewSize(const QSize& largePreviewSize)
00150 { d->largePreviewSize = largePreviewSize; }
00151
00152
00153 void KLFLatexPreviewThread::start(Priority priority)
00154 {
00155 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00156
00157
00158 QThread::start(priority);
00159 }
00160
00161 void KLFLatexPreviewThread::stop()
00162 {
00163
00164 emit d->internalRequestAbort();
00165 quit();
00166 wait();
00167 }
00168
00169
00170 void KLFLatexPreviewThread::run()
00171 {
00172 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00173
00174
00175 QThread::run();
00176 }
00177
00178 KLFLatexPreviewThread::TaskId
00179 KLFLatexPreviewThread::submitPreviewTask(const KLFBackend::klfInput& input,
00180 const KLFBackend::klfSettings& settings,
00181 KLFLatexPreviewHandler * outputhandler,
00182 const QSize& previewSize,
00183 const QSize& largePreviewSize)
00184 {
00185 KLFLatexPreviewThreadWorker::Task t;
00186 t.input = input;
00187 t.settings = settings;
00188 t.handler = outputhandler;
00189 t.previewSize = previewSize;
00190 t.largePreviewSize = largePreviewSize;
00191
00192 return d->submitTask(t, false, -1);
00193 }
00194
00195 KLFLatexPreviewThread::TaskId
00196 KLFLatexPreviewThread::submitPreviewTask(const KLFBackend::klfInput& input,
00197 const KLFBackend::klfSettings& settings,
00198 KLFLatexPreviewHandler * outputhandler)
00199 {
00200 KLFLatexPreviewThreadWorker::Task t;
00201 t.input = input;
00202 t.settings = settings;
00203 t.handler = outputhandler;
00204 t.previewSize = d->previewSize;
00205 t.largePreviewSize = d->largePreviewSize;
00206
00207 return d->submitTask(t, false, -1);
00208 }
00209
00210 KLFLatexPreviewThread::TaskId
00211 KLFLatexPreviewThread::clearAndSubmitPreviewTask(const KLFBackend::klfInput& input,
00212 const KLFBackend::klfSettings& settings,
00213 KLFLatexPreviewHandler * outputhandler,
00214 const QSize& previewSize,
00215 const QSize& largePreviewSize)
00216 {
00217 KLFLatexPreviewThreadWorker::Task t;
00218 t.input = input;
00219 t.settings = settings;
00220 t.handler = outputhandler;
00221 t.previewSize = previewSize;
00222 t.largePreviewSize = largePreviewSize;
00223
00224 return d->submitTask(t, true, -1);
00225 }
00226
00227 KLFLatexPreviewThread::TaskId
00228 KLFLatexPreviewThread::clearAndSubmitPreviewTask(const KLFBackend::klfInput& input,
00229 const KLFBackend::klfSettings& settings,
00230 KLFLatexPreviewHandler * outputhandler)
00231 {
00232 KLFLatexPreviewThreadWorker::Task t;
00233 t.input = input;
00234 t.settings = settings;
00235 t.handler = outputhandler;
00236 t.previewSize = d->previewSize;
00237 t.largePreviewSize = d->largePreviewSize;
00238
00239 return d->submitTask(t, true, -1);
00240 }
00241
00242 KLFLatexPreviewThread::TaskId
00243 KLFLatexPreviewThread::replaceSubmitPreviewTask(KLFLatexPreviewThread::TaskId replaceId,
00244 const KLFBackend::klfInput& input,
00245 const KLFBackend::klfSettings& settings,
00246 KLFLatexPreviewHandler * outputhandler,
00247 const QSize& previewSize,
00248 const QSize& largePreviewSize)
00249 {
00250 KLFLatexPreviewThreadWorker::Task t;
00251 t.input = input;
00252 t.settings = settings;
00253 t.handler = outputhandler;
00254 t.previewSize = previewSize;
00255 t.largePreviewSize = largePreviewSize;
00256
00257 return d->submitTask(t, false, replaceId);
00258 }
00259
00260 KLFLatexPreviewThread::TaskId
00261 KLFLatexPreviewThread::replaceSubmitPreviewTask(KLFLatexPreviewThread::TaskId replaceId,
00262 const KLFBackend::klfInput& input,
00263 const KLFBackend::klfSettings& settings,
00264 KLFLatexPreviewHandler * outputhandler)
00265 {
00266 KLFLatexPreviewThreadWorker::Task t;
00267 t.input = input;
00268 t.settings = settings;
00269 t.handler = outputhandler;
00270 t.previewSize = d->previewSize;
00271 t.largePreviewSize = d->largePreviewSize;
00272
00273 return d->submitTask(t, false, replaceId);
00274 }
00275
00276
00277
00278 void KLFLatexPreviewThread::cancelTask(TaskId task)
00279 {
00280 emit d->internalRequestCancelTask(task);
00281 }
00282 void KLFLatexPreviewThread::clearPendingTasks()
00283 {
00284 emit d->internalRequestClearPendingTasks();
00285 }
00286
00287
00288
00289
00290
00291
00292
00293
00294 void KLFLatexPreviewThreadWorker::threadSubmitTask(Task task, bool clearOtherJobs, TaskId replaceTaskId)
00295 {
00296 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00297
00298 if (clearOtherJobs) {
00299 threadClearPendingTasks();
00300 }
00301 if (replaceTaskId) {
00302 threadCancelTask(replaceTaskId);
00303 }
00304
00305
00306 newTasks.enqueue(task);
00307
00308 klfDbg("enqueued task id="<<task.taskid) ;
00309
00310
00311 QMetaObject::invokeMethod(this, "threadProcessJobs", Qt::QueuedConnection);
00312 }
00313
00314 bool KLFLatexPreviewThreadWorker::threadCancelTask(TaskId taskid)
00315 {
00316 int k;
00317 for (k = 0; k < newTasks.size(); ++k) {
00318 if (newTasks.at(k).taskid == taskid) {
00319 newTasks.removeAt(k);
00320 return true;
00321 }
00322 }
00323
00324
00325
00326 klfDbg("No such task ID: "<<taskid) ;
00327 return false;
00328 }
00329
00330 void KLFLatexPreviewThreadWorker::threadClearPendingTasks()
00331 {
00332 newTasks.clear();
00333 }
00334
00335 void KLFLatexPreviewThreadWorker::threadProcessJobs()
00336 {
00337 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
00338
00339 Task task;
00340 KLFBackend::klfOutput ouroutput;
00341
00342 if (!newTasks.size()) {
00343 return;
00344 }
00345
00346 if (_abort) {
00347 return;
00348 }
00349
00350
00351 task = newTasks.dequeue();
00352
00353 klfDbg("processing job ID="<<task.taskid) ;
00354
00355 QImage img, prev, lprev;
00356 if ( task.input.latex.trimmed().isEmpty() ) {
00357 QMetaObject::invokeMethod(task.handler, "latexPreviewReset", Qt::QueuedConnection);
00358 } else {
00359
00360 klfDbg("worker: running KLFBackend::getLatexFormula()") ;
00361 ouroutput = KLFBackend::getLatexFormula(task.input, task.settings, false);
00362 img = ouroutput.result;
00363
00364 klfDbg("got result: status="<<ouroutput.status) ;
00365
00366 if (ouroutput.status != 0) {
00367
00368 QMetaObject::invokeMethod(task.handler, "latexPreviewError", Qt::QueuedConnection,
00369 Q_ARG(QString, ouroutput.errorstr),
00370 Q_ARG(int, ouroutput.status));
00371 } else {
00372
00373 QMetaObject::invokeMethod(task.handler, "latexOutputAvailable", Qt::QueuedConnection,
00374 Q_ARG(KLFBackend::klfOutput, ouroutput));
00375 if (task.previewSize.isValid()) {
00376 prev = img;
00377 if (prev.width() > task.previewSize.width() || prev.height() > task.previewSize.height()) {
00378 prev = img.scaled(task.previewSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
00379 }
00380 }
00381 if (task.largePreviewSize.isValid()) {
00382 lprev = img;
00383 if (lprev.width() > task.largePreviewSize.width() || lprev.height() > task.largePreviewSize.height()) {
00384 lprev = img.scaled(task.largePreviewSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
00385 }
00386 }
00387
00388 QMetaObject::invokeMethod(task.handler, "latexPreviewAvailable", Qt::QueuedConnection,
00389 Q_ARG(QImage, prev),
00390 Q_ARG(QImage, lprev),
00391 Q_ARG(QImage, img));
00392 if (task.previewSize.isValid()) {
00393 QMetaObject::invokeMethod(task.handler, "latexPreviewImageAvailable", Qt::QueuedConnection,
00394 Q_ARG(QImage, prev));
00395 }
00396 if (task.largePreviewSize.isValid()) {
00397 QMetaObject::invokeMethod(task.handler, "latexPreviewLargeImageAvailable", Qt::QueuedConnection,
00398 Q_ARG(QImage, lprev));
00399 }
00400 QMetaObject::invokeMethod(task.handler, "latexPreviewFullImageAvailable", Qt::QueuedConnection,
00401 Q_ARG(QImage, img));
00402 }
00403 }
00404
00405 klfDbg("about to invoke delayed threadProcessJobs.") ;
00406
00407
00408 QMetaObject::invokeMethod(this, "threadProcessJobs", Qt::QueuedConnection);
00409
00410 klfDbg("threadProcessJobs: end") ;
00411 }
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422 KLFContLatexPreview::KLFContLatexPreview(KLFLatexPreviewThread *thread)
00423 : QObject(thread)
00424 {
00425 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00426
00427 KLF_INIT_PRIVATE( KLFContLatexPreview ) ;
00428
00429 setThread(thread);
00430 }
00431
00432 KLFContLatexPreview::~KLFContLatexPreview()
00433 {
00434 KLF_DELETE_PRIVATE ;
00435 }
00436
00437 KLF_DEFINE_PROPERTY_GET(KLFContLatexPreview, QSize, previewSize) ;
00438
00439 KLF_DEFINE_PROPERTY_GET(KLFContLatexPreview, QSize, largePreviewSize) ;
00440
00441
00442
00443 bool KLFContLatexPreview::enabled() const
00444 {
00445 return d->enabled;
00446 }
00447
00448 void KLFContLatexPreview::setEnabled(bool enabled)
00449 {
00450 d->enabled = enabled;
00451 }
00452
00453
00454 void KLFContLatexPreview::setThread(KLFLatexPreviewThread * thread)
00455 {
00456 d->thread = thread;
00457 }
00458
00459 bool KLFContLatexPreview::setInput(const KLFBackend::klfInput& input)
00460 {
00461 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00462
00463 if (d->input == input)
00464 return false;
00465
00466 d->input = input;
00467 d->refreshPreview();
00468 return true;
00469 }
00470 bool KLFContLatexPreview::setSettings(const KLFBackend::klfSettings& settings, bool disableExtraFormats)
00471 {
00472 KLFBackend::klfSettings s = settings;
00473 if (disableExtraFormats) {
00474 s.wantRaw = false;
00475 s.wantPDF = false;
00476 s.wantSVG = false;
00477 }
00478
00479 if (d->settings == s)
00480 return false;
00481
00482 d->settings = s;
00483 d->refreshPreview();
00484 return true;
00485 }
00486
00487 bool KLFContLatexPreview::setPreviewSize(const QSize& previewSize)
00488 {
00489 if (d->previewSize == previewSize)
00490 return false;
00491 d->previewSize = previewSize;
00492 d->refreshPreview();
00493 return true;
00494 }
00495 bool KLFContLatexPreview::setLargePreviewSize(const QSize& largePreviewSize)
00496 {
00497 if (d->largePreviewSize == largePreviewSize)
00498 return false;
00499 d->largePreviewSize = largePreviewSize;
00500 d->refreshPreview();
00501 return true;
00502 }
00503
00504
00505