add generic helper class for calling functions in gui thread

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@35735 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Peter Kümmel 2010-10-20 23:50:49 +00:00
parent e35f55975e
commit c259957b69
5 changed files with 331 additions and 6 deletions

View File

@ -14,7 +14,6 @@
#include "alert.h"
#include "frontends/Application.h"
#include "qt_helpers.h"
@ -25,6 +24,7 @@
#include "support/docstring.h"
#include "support/lstrings.h"
#include "support/ProgressInterface.h"
#include "support/InGuiThread.h"
#include <QApplication>
#include <QCheckBox>
@ -37,6 +37,11 @@
#include <iomanip>
#include <iostream>
// sync with GuiView.cpp
#define EXPORT_in_THREAD 0
using namespace std;
using namespace lyx::support;
@ -124,7 +129,8 @@ void noAppDialog(QString const & title, QString const & msg, QMessageBox::Icon m
namespace Alert {
int prompt(docstring const & title0, docstring const & question,
int doPrompt(docstring const & title0, docstring const & question,
int default_button, int cancel_button,
docstring const & b1, docstring const & b2,
docstring const & b3, docstring const & b4)
@ -178,8 +184,21 @@ int prompt(docstring const & title0, docstring const & question,
return res;
}
int prompt(docstring const & title0, docstring const & question,
int default_button, int cancel_button,
docstring const & b1, docstring const & b2,
docstring const & b3, docstring const & b4)
{
#ifdef EXPORT_in_THREAD
return InGuiThread<int>().call(&doPrompt,
#else
return doPrompt(
#endif
title0, question, default_button,
cancel_button, b1, b2, b3, b4);
}
void warning(docstring const & title0, docstring const & message,
void doWarning(docstring const & title0, docstring const & message,
bool const & askshowagain)
{
lyxerr << "Warning: " << title0 << '\n'
@ -213,8 +232,18 @@ void warning(docstring const & title0, docstring const & message,
qApp->restoreOverrideCursor();
}
void warning(docstring const & title0, docstring const & message,
bool const & askshowagain)
{
#ifdef EXPORT_in_THREAD
InGuiThread<void>().call(&doWarning,
#else
doWarning(
#endif
title0, message, askshowagain);
}
void error(docstring const & title0, docstring const & message)
void doError(docstring const & title0, docstring const & message)
{
lyxerr << "Error: " << title0 << '\n'
<< "----------------------------------------\n"
@ -240,8 +269,17 @@ void error(docstring const & title0, docstring const & message)
qApp->restoreOverrideCursor();
}
void error(docstring const & title0, docstring const & message)
{
#ifdef EXPORT_in_THREAD
InGuiThread<void>().call(&doError,
#else
doError(
#endif
title0, message);
}
void information(docstring const & title0, docstring const & message)
void doInformation(docstring const & title0, docstring const & message)
{
if (!use_gui || lyxerr.debugging())
lyxerr << title0 << '\n'
@ -268,8 +306,17 @@ void information(docstring const & title0, docstring const & message)
qApp->restoreOverrideCursor();
}
void information(docstring const & title0, docstring const & message)
{
#ifdef EXPORT_in_THREAD
InGuiThread<void>().call(&doInformation,
#else
doInformation(
#endif
title0, message);
}
bool askForText(docstring & response, docstring const & msg,
bool doAskForText(docstring & response, docstring const & msg,
docstring const & dflt)
{
if (!use_gui || lyxerr.debugging()) {
@ -300,6 +347,16 @@ bool askForText(docstring & response, docstring const & msg,
return false;
}
bool askForText(docstring & response, docstring const & msg,
docstring const & dflt)
{
#ifdef EXPORT_in_THREAD
return InGuiThread<bool>().call(&doAskForText,
#else
return doAskGForText(
#endif
response, msg, dflt);
}
} // namespace Alert
} // namespace frontend

View File

@ -0,0 +1,52 @@
/**
* \file InGuiThread.cpp
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Peter Kümmel
*
* Full author contact details are available in file CREDITS.
*/
#include "InGuiThread.h"
#include <QThread>
#include <QEventLoop>
#include <QApplication>
namespace lyx {
namespace frontend {
IntoGuiThreadMover::IntoGuiThreadMover()
{
moveToThread(QApplication::instance()->thread());
connect(this, SIGNAL(triggerCall()), this, SLOT(doFunctionCall()),
Qt::QueuedConnection);
}
void IntoGuiThreadMover::callInGuiThread()
{
if (QThread::currentThread() == QApplication::instance()->thread()) {
synchronousFunctionCall();
} else {
QEventLoop loop;
connect(this, SIGNAL(called()), &loop, SLOT(quit()));
Q_EMIT triggerCall();
loop.exec();
}
}
void IntoGuiThreadMover::doFunctionCall()
{
synchronousFunctionCall();
Q_EMIT called();
}
} // namespace frontend
} // namespace lyx

172
src/support/InGuiThread.h Normal file
View File

@ -0,0 +1,172 @@
// -*- C++ -*-
/**
* \file InGuiThread.h
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Peter Kümmel
*
* Full author contact details are available in file CREDITS.
*/
#ifndef INGUITHREAD_H
#define INGUITHREAD_H
#include <QObject>
#include "support/bind.h"
#include "support/functional.h"
namespace lyx {
namespace frontend {
class IntoGuiThreadMover : public QObject
{
Q_OBJECT
protected:
IntoGuiThreadMover();
void callInGuiThread();
Q_SIGNALS:
void triggerCall();
void called();
private Q_SLOTS:
void doFunctionCall();
private:
virtual void synchronousFunctionCall() = 0;
};
template<class R>
class InGuiThread : private IntoGuiThreadMover
{
public:
InGuiThread() {}
template<class F>
R call(F f)
{
func_ = f;
callInGuiThread();
return return_value_;
}
template<class F, class P1>
R call(F f, P1 p1)
{
return call(bind(f, p1));
}
template<class F, class P1, class P2>
R call(F f, P1 p1, P2 p2)
{
return call(bind(f, p1, p2));
}
template<class F, class P1, class P2, class P3>
R call(F f, P1 p1, P2 p2, P3 p3)
{
return call(bind(f, p1, p2, p3));
}
template<class F, class P1, class P2, class P3, class P4>
R call(F f, P1 p1, P2 p2, P3 p3, P4 p4)
{
return call(bind(f, p1, p2, p3, p4));
}
/*
...
*/
template<class F, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
R call(F f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8)
{
return call(bind(f, p1, p2, p3, p4, p5, p6, p7, p8));
}
private:
void synchronousFunctionCall()
{
return_value_ = func_();
}
private:
R return_value_;
function<R()> func_;
};
// void specialisation
template<>
class InGuiThread<void> : private IntoGuiThreadMover
{
public:
InGuiThread() {}
template<class F>
void call(F f)
{
func_ = f;
callInGuiThread();
}
template<class F, class P1>
void call(F f, P1 p1)
{
call(bind(f, p1));
}
template<class F, class P1, class P2>
void call(F f, P1 p1, P2 p2)
{
call(bind(f, p1, p2));
}
template<class F, class P1, class P2, class P3>
void call(F f, P1 p1, P2 p2, P3 p3)
{
call(bind(f, p1, p2, p3));
}
template<class F, class P1, class P2, class P3, class P4>
void call(F f, P1 p1, P2 p2, P3 p3, P4 p4)
{
call(bind(f, p1, p2, p3, p4));
}
/*
...
*/
template<class F, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
void call(F f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8)
{
call(bind(f, p1, p2, p3, p4, p5, p6, p7, p8));
}
private:
void synchronousFunctionCall()
{
func_();
}
private:
function<void()> func_;
};
} // namespace frontend
} // namespace lyx
#endif // GUIABOUT_H

View File

@ -56,10 +56,13 @@ liblyxsupport_a_SOURCES = \
foreach.h \
ForkedCalls.cpp \
ForkedCalls.h \
functional.h \
gettext.cpp \
gettext.h \
gzstream.cpp \
gzstream.h \
InGuiThread.h \
InGuiThread.cpp \
kill.cpp \
lassert.h \
lassert.cpp \

41
src/support/functional.h Normal file
View File

@ -0,0 +1,41 @@
// -*- C++ -*-
/**
* \file functional.h
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Peter Kümmel
*
* Full author contact details are available in file CREDITS.
*/
#ifndef LYX_FUNCTIONAL_H
#define LYX_FUNCTIONAL_H
#ifdef LYX_USE_TR1
#include <functional>
#ifdef __GNUC__
#include <tr1/functional>
#endif
namespace lyx
{
using std::tr1::function;
}
#else
#include <boost/function.hpp>
#include <boost/functional.hpp>
namespace lyx
{
using boost::function;
}
#endif
#endif