FIND_PACKAGE(Boost)
FIND_PACKAGE(PythonLibs)
+SET(USE_PYTHON 1)
+
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH}
${QT_INCLUDES}
${BOOST_INCLUDE_DIR} )
SET(PYTHON_CFLAGS "-DUSE_PYTHON")
TARGET_LINK_LIBRARIES(mussagl
mussa_py
+ ${QT_LIBRARIES}
+ mussa_qui_py
${BOOST_PYTHON_LIBRARY}
${PYTHON_LIBRARIES}
${PYTHON_LINK_LIBRARIES})
: color_mapper(new AnnotationColors)
{
clear();
- connect(&the_paths, SIGNAL(progress(const std::string&, int, int)),
- this, SIGNAL(progress(const std::string&, int, int)));
+ connect(&the_paths, SIGNAL(progress(const QString&, int, int)),
+ this, SIGNAL(progress(const QString&, int, int)));
}
Mussa::Mussa(const Mussa& m)
analysis_path(m.analysis_path),
dirty(m.dirty)
{
- connect(&the_paths, SIGNAL(progress(const std::string&, int, int)),
- this, SIGNAL(progress(const std::string&, int, int)));
+ connect(&the_paths, SIGNAL(progress(const QString&, int, int)),
+ this, SIGNAL(progress(const QString&, int, int)));
+}
+
+MussaRef Mussa::init()
+{
+ boost::shared_ptr<Mussa> m(new Mussa());
+ return m;
}
boost::filesystem::path Mussa::get_analysis_path() const
// ----------------------------------------
// ---------- mussa_class.hh -----------
// ----------------------------------------
-#include <QObject>
+#include <QObject>
+#include <QString>
#include <boost/filesystem/path.hpp>
#include <boost/shared_ptr.hpp>
std::string int_to_str(int an_int);
+class Mussa;
+//! provide a simple name to point to our Mussa shared_ptr
+typedef boost::shared_ptr<Mussa> MussaRef;
+
class Mussa : public QObject
{
Q_OBJECT
signals:
//! call whatever signaling system we want
- void progress(const std::string& description, int cur, int max);
+ void progress(const QString& description, int cur, int max);
//! triggered when our state changes between unsaved(true) and saved(false)
void isModified(bool);
Mussa();
Mussa(const Mussa &);
+ //! dynamically construct a new Mussa object and return a reference to it
+ static MussaRef init();
+
//! save all of mussa
void save(boost::filesystem::path save_path="");
//! save the nway comparison
void seqcomp();
};
-//! provide a simple name to point to our Mussa shared_ptr
-typedef boost::shared_ptr<Mussa> MussaRef;
#endif
soft_thres = sft_thres;
}
+int NwayPaths::get_soft_threshold() const
+{
+ return soft_thres;
+}
+
int NwayPaths::get_threshold() const
{
return threshold;
// ---------- mussa_nway.hh -----------
// ----------------------------------------
#include <QObject>
+#include <QString>
#include <boost/filesystem/path.hpp>
signals:
//! emit to indicate how much progress we've made
- void progress(const std::string& description, int cur, int max);
+ void progress(const QString& description, int cur, int max);
public:
+ typedef std::list<ConservedPath> ConservedPaths;
+
NwayPaths();
NwayPaths(const NwayPaths&);
void setup_ent(double new_entropy_thres, std::vector<Sequence> some_Seqs);
//! clear out our path
void clear();
+ //! get the "soft" threshold (between the hard threshold and window size)
+ int get_soft_threshold() const;
//! set the score that a match must exceed inorder to be recorded as a path
void set_soft_threshold(int soft_thres);
//! return minimum threshold for this analysis
// The following iterator functions are mostly for the python interface
// they'll have problems when being called from within a const object
- std::list<ConservedPath>::iterator pbegin() { return pathz.begin() ; }
- std::list<ConservedPath>::iterator pend() { return pathz.end() ; }
+ ConservedPaths::iterator pbegin() { return pathz.begin() ; }
+ ConservedPaths::iterator pend() { return pathz.end() ; }
size_t path_size() const { return refined_pathz.size(); }
- std::list<ConservedPath>::iterator rpbegin() { return refined_pathz.begin() ; }
- std::list<ConservedPath>::iterator rpend() { return refined_pathz.end() ; }
+ ConservedPaths::iterator rpbegin() { return refined_pathz.begin() ; }
+ ConservedPaths::iterator rpend() { return refined_pathz.end() ; }
size_t refined_path_size() const { return refined_pathz.size(); }
// these probably shouldn't be public, but lets start
// simple
- std::list<ConservedPath> pathz;
- std::list<ConservedPath > refined_pathz;
+ ConservedPaths pathz;
+ ConservedPaths refined_pathz;
protected:
int threshold;
return;
}
- MussaRef new_mussa(new Mussa);
- opts.analysis = new_mussa;
+ opts.analysis = Mussa::init();
// currently we can only have one analysis loaded, so
// running trumps viewing.
nway_paths.cpp
sequence.cpp
)
-
+ SET(QUI_SOURCES
+ module_qui.cpp
+ MussaWindow.cpp
+ )
ADD_LIBRARY(mussa MODULE ${SOURCES})
ADD_LIBRARY(mussa_py STATIC ${SOURCES})
+ ADD_LIBRARY(mussa_qui_py STATIC ${QUI_SOURCES})
# Any suggestions for a more elegant solution to this? -diane
IF(WIN32)
ADD_CUSTOM_TARGET(mussa.dll ALL
COMPILE_FLAGS "${PY_CFLAGS}"
)
SET_TARGET_PROPERTIES(
- mussa mussa_py PROPERTIES
+ mussa mussa_py mussa_qui_py PROPERTIES
COMPILE_FLAGS "${PY_CFLAGS}"
LINK_FLAGS "${PY_LDFLAGS}"
)
-
#include <boost/python.hpp>
-#include <QApplication>
-#include <QPushButton>
-#include "alg/mussa.hpp"
-#include "qui/MussaWindow.hpp"
-
-struct gui {
- QApplication *app;
- QPushButton *b;
- MussaWindow *mw;
-
- gui() : b(0), mw(0) {
- char *argv[] = {"mussagl"};
- int argc = 1;
- app = new QApplication(argc, (char **)argv);
- Q_INIT_RESOURCE(icons);
- }
-
- void button() {
- b = new QPushButton("hi");
- b->show();
- }
-
- void mussa() {
- Mussa *analysis = new Mussa();
- mw = new MussaWindow(analysis);
- mw->show();
- }
+#include "qui/threading/GuiProxy.hpp"
- int run() {
- return app->exec();
- }
-};
+using namespace boost::python;
-void export_mussa_window()
+void export_gui_proxy()
{
- /*
- class_<MussaWindow>("MussaWindow", init<Mussa *, QObject *>)
- .def("show", &MussaWindow::show)
- ;
- */
- boost::python::class_<gui>("gui")
- .def("button", &gui::button)
- .def("mussa", &gui::mussa)
- .def("run", &gui::run)
- ;
+ def("MussaWindow", &MussaWindowProxy,
+ "Create mussa window, DO NOT access the mussa analysis after passing it to this function "
+ "the mussa analysis object is NOT thread safe.");
}
--- /dev/null
+#include <boost/python.hpp>
+using namespace boost::python;
+
+void export_gui_proxy();
+
+BOOST_PYTHON_MODULE(mussaqui)
+{
+ export_gui_proxy();
+}
.def("__delitem__", &std_item<Mussa::vector_sequence_type>::del)
;
- py::class_<Mussa>("Mussa")
+ py::class_<Mussa>("_Mussa", py::no_init)
.def("save", &Mussa::save)
.def("load", &Mussa::load, "Load previous run analysis")
.def("load_mupa", load_mupa_string, "Load mussa parameter file")
.def("clear", &Mussa::clear, "Clear the current analysis")
- .add_property("name", &Mussa::get_name, &Mussa::set_name)
- .def("size", &Mussa::size, "Number of sequences to be used "
- "in this analysis")
+ .add_property("name", &Mussa::get_name, &Mussa::set_name, "Set the name of the analysis")
+ .def("size", &Mussa::size, "Number of sequences attached to "
+ "this analysis")
.add_property("window", &Mussa::get_window, &Mussa::set_window,
"the number of base pairs in the sliding window")
.add_property("threshold", &Mussa::get_threshold, &Mussa::set_threshold,
&Mussa::set_analysis_mode)
.add_property("analysisModeName", &Mussa::get_analysis_mode_name)
.def("analyze", &Mussa::analyze, "Run the analysis")
- .def("paths", &Mussa::paths, py::return_internal_reference<>())
- .def("sequences", &Mussa::sequences, py::return_internal_reference<>())
- .def("add_sequence", append_sequence_ref)
+ .def("paths", &Mussa::paths, py::return_internal_reference<>(), "return list of paths")
+ .def("sequences", &Mussa::sequences, py::return_internal_reference<>(), "return list of sequences")
+ .def("add_sequence", append_sequence_ref, "attach a sequence to the analysis")
;
-
+ py::def("Mussa", &Mussa::init, "Construct a new Mussa object");
+ py::register_ptr_to_python< boost::shared_ptr<Mussa> >();
+
py::enum_<Mussa::analysis_modes>("analysis_modes")
.value("TransitiveNway", Mussa::TransitiveNway )
.value("RadialNway", Mussa::RadialNway )
void export_nway_paths()
{
- py::class_<NwayPaths>("NwayPaths")
+ /*py::class_<NwayPaths::ConservedPaths>("ConservedPaths")
+ .def("__len__", &NwayPaths::ConservedPaths::size, "return length of paths")
+ .def("__contains__", &std_item<NwayPaths::ConservedPaths>::in)
+ .def("__iter__", py::iterator<NwayPaths::ConservedPaths>())
+ .def("clear", &NwayPaths::ConservedPaths::clear, "remove all the paths")
+ .def("append", &std_item<NwayPaths::ConservedPaths>::add,
+ py::with_custodian_and_ward<1,2>()) // to let container keep value
+ .def("__getitem__", &std_item<NwayPaths::ConservedPaths>::get,
+ py::return_value_policy<py::copy_non_const_reference>())
+ .def("__setitem__", &std_item<NwayPaths::ConservedPaths>::set,
+ py::with_custodian_and_ward<1,2>()) // to let container keep value
+ .def("__delitem__", &std_item<NwayPaths::ConservedPaths>::del)
+ ;*/
+
+ py::class_<NwayPaths>("NwayPaths")
+ .def("__len__", &NwayPaths::sequence_count)
+ .def("clear", &NwayPaths::clear, "remove all paths")
+ .add_property("threshold", &NwayPaths::get_threshold, "Get hard threshold")
+ .add_property("soft_threshold", &NwayPaths::get_soft_threshold, &NwayPaths::set_soft_threshold)
+ .add_property("window_size", &NwayPaths::get_window)
.add_property("pathz", py::range(&NwayPaths::pbegin, &NwayPaths::pend))
- .add_property("refinedPathz", py::range(&NwayPaths::rpbegin, &NwayPaths::rpend)) ;
+ .add_property("refinedPathz", py::range(&NwayPaths::rpbegin, &NwayPaths::rpend))
+ ;
}
try {
// add our mussa module to our environment
PyImport_AppendInittab("mussa", &initmussa);
+ PyImport_AppendInittab("mussaqui", &initmussaqui);
// go ahead and finish initalizing python
Py_Initialize();
// get reference to the global namespace
// FIXME: this really should be a configuration file?
run("import __main__\n"
"import mussa\n"
- "import webbrowser\n");
+ "import mussaqui");
} catch (py::error_already_set e) {
PyErr_Print();
}
}
-void MussaPython::interpreter(FILE *fp)
+void MussaPython::interpreter()
+{
+ try {
+ run("import sys\n"
+ "sys.argv = ['Mussa']\n"
+ "banner='Welcome to Mussa'\n"
+ "try:\n"
+ " from IPython.Shell import IPShellEmbed\n"
+ " ipshell = IPShellEmbed(banner=banner)\n"
+ " ipshell()\n"
+ "except ImportError, e:\n"
+ " import code\n"
+ " code.interact(banner, local=globals())\n"
+ "print 'exiting interpreter'\n"
+ );
+ } catch (py::error_already_set e) {
+ PyErr_Print();
+ }
+}
+void MussaPython::simple_interpreter(FILE *fp)
{
try {
PyRun_InteractiveLoop(fp, "mussa");
//! return a reference to a single mussa python interpreter
MussaPython& get_py()
{
- static MussaPython py;
- return py;
+ static MussaPython *py;
+ if (!py) {
+ py = new MussaPython;
+ }
+ return *py;
}
\ No newline at end of file
#include <string>
extern "C" void initmussa();
+extern "C" void initmussaqui();
//! Create a singleton class to manage our reference to the python interpreter
class MussaPython {
void run(std::string);
//! pass single expression to the python interpreter and return the result
boost::python::object eval(std::string);
- //! launch read-eval-print loop tied to the provided FILE pointer
- void interpreter(FILE *fp=stdin);
+ //! use InteractiveConsole for readloop
+ void interpreter();
+ //! launch fgets based read-eval-print loop tied to the provided FILE pointer
+ void simple_interpreter(FILE *fp=stdin);
//! return an object in the python namespace
boost::python::object operator[](std::string);
mussa_py
mussa_core
${QT_QTCORE_LIBRARY}
+ mussa_qui_py
${OPENGL_gl_LIBRARY}
${BOOST_PROGRAM_OPTIONS_LIBRARY}
${BOOST_FILESYSTEM_LIBRARY}
m.add_sequence(s2)
m.add_sequence(s3)
m.analyze()
- print m.paths()
+ # this could probably be a more thorough test
+ self.failUnless( len(m.paths()), 3 )
def suite():
return unittest.makeSuite(TestMussa, 'test')
seqbrowser/seqproperties/PropertiesWindow.hpp
subanalysis/SequenceLocationModel.hpp
subanalysis/SubanalysisWindow.hpp
+ threading/GuiProxy.hpp
+ threading/InterpreterThread.hpp
)
SET(GUI_SOURCES
ImageSaveDialog.cpp
seqbrowser/seqproperties/PropertiesWindow.cpp
subanalysis/SequenceLocationModel.cpp
subanalysis/SubanalysisWindow.cpp
+ threading/GuiProxy.cpp
+ threading/InterpreterThread.cpp
+ threading/ThreadManager.cpp
)
SET(PY_SOURCES ../py/python.cpp)
SET(RCCS ../icons.qrc)
statusBar()->showMessage("Welcome to mussa", 2000);
// FIXME: we should start refactoring the connect call to updateAnalysis or something
if (analysis) {
- connect(analysis.get(), SIGNAL(progress(const std::string&, int, int)),
- this, SLOT(updateProgress(const std::string&, int, int)));
+ connect(analysis.get(), SIGNAL(progress(const QString&, int, int)),
+ this, SLOT(updateProgress(const QString&, int, int)));
connect(analysis.get(), SIGNAL(isModified(bool)),
this, SLOT(updateAnalysisModified(bool)));
}
// but this should work for the moment.
if (not isClearingAnalysisSafe()) return;
- MussaRef m(new Mussa);
+ MussaRef m = Mussa::init();
fs::path converted_path(mupa_path.toStdString(), fs::native);
- connect(m.get(), SIGNAL(progress(const std::string&, int, int)),
- this, SLOT(updateProgress(const std::string&, int, int)));
+ connect(m.get(), SIGNAL(progress(const QString&, int, int)),
+ this, SLOT(updateProgress(const QString&, int, int)));
m->load_mupa_file(converted_path);
m->analyze();
setAnalysis(m);
// but this should work for the moment.
if (not isClearingAnalysisSafe()) return;
- MussaRef m(new Mussa);
+ MussaRef m = Mussa::init();
fs::path converted_path(muway_dir.toStdString(), fs::native);
- connect(m.get(), SIGNAL(progress(const std::string&, int, int)),
- this, SLOT(updateProgress(const std::string&, int, int)));
+ connect(m.get(), SIGNAL(progress(const QString&, int, int)),
+ this, SLOT(updateProgress(const QString&, int, int)));
m->load(converted_path);
// only switch mussas if we loaded without error
if (analysis->empty()) {
void MussaWindow::newMussaWindow()
{
- MussaRef a(new Mussa);
- MussaWindow *win = new MussaWindow(a);
+ MussaWindow *win = new MussaWindow(Mussa::init());
win->default_dir = default_dir;
win->show();
}
}
void
-MussaWindow::updateProgress(const string& description, int current, int max)
+MussaWindow::updateProgress(const QString& description, int current, int max)
{
// if we're done
if (current == max) {
} else {
// if we're starting, create the dialog
if (progress_dialog == 0) {
- QString desc(description.c_str());
QString cancel("Cancel");
- progress_dialog = new QProgressDialog(desc, cancel, current, max, this);
+ progress_dialog = new QProgressDialog(description, cancel, current, max, this);
progress_dialog->show();
} else {
// just update the dialog
class QStringList;
class Mussa;
class QAssistantClient;
+class MussaWindow;
+
+typedef boost::shared_ptr<MussaWindow> MussaWindowRef;
class MussaWindow : public QMainWindow
{
public:
MussaWindow(MussaRef analysis, QWidget *parent=0);
+public:
//! reset any attached window
void clear();
//! set the soft threshold used by the Nway_Path algorithm
void setSoftThreshold(int thres);
//! update progress bar
- void updateProgress(const std::string& description, int cur, int max);
+ void updateProgress(const QString& description, int cur, int max);
//! open a new mussa window so one can compare analyses
void newMussaWindow();
//! update annotations?
void updateAnnotations();
};
+
#endif
MussaRef MussaSetupWidget::getMussaObject()
{
- MussaRef mussa(new Mussa);
+ MussaRef mussa = Mussa::init();
int fastaIndex;
int start;
#endif
#include "qui/MussaWindow.hpp"
+#include "qui/threading/ThreadManager.hpp"
+#include "qui/threading/InterpreterThread.hpp"
#include "alg/parse_options.hpp"
#include "mussa_exceptions.hpp"
return 1;
}
+ ThreadManager &thread = ThreadManagerFactory();
try {
#ifdef USE_PYTHON
if (opts.runAsPythonInterpeter) {
- get_py().interpreter();
+ // allow the user to keep the interpreter open even after
+ // closing all the windows
+ app.setQuitOnLastWindowClosed(false);
+ const InterpreterThread *interp = thread.create_interpreter();
+ // quit when the interpreter exits
+ QObject::connect(interp, SIGNAL(finished()),
+ &app, SLOT(quit()));
+ app.exec();
} else
#endif /* USE_PYTHON */
if (opts.useGUI) {
SubanalysisWindow::SubanalysisWindow(MussaRef m, QWidget *parent)
: QWidget(parent),
analysis(m),
+ parameterLayout(0),
+ thresholdLabel(0),
+ windowLabel(0),
window(0),
threshold(0),
table(0),
ok(0),
cancel(0)
{
- QGridLayout *parameterLayout = new QGridLayout;
+ parameterLayout = new QGridLayout;
- QLabel *thresholdLabel = new QLabel(tr("threshold (bp)"));
+ thresholdLabel = new QLabel(tr("threshold (bp)"));
parameterLayout->addWidget(thresholdLabel, 0, 0);
threshold = new QSpinBox(this);
threshold->setValue(8);
parameterLayout->addWidget(threshold, 1, 0);
- QLabel *windowLabel = new QLabel(tr("window (bp)"));
+ windowLabel = new QLabel(tr("window (bp)"));
parameterLayout->addWidget(windowLabel, 0, 1);
window = new QSpinBox(this);
window->setValue(10);
#include <boost/shared_ptr.hpp>
-#include <QTableView>
+#include <QGridLayout>
+#include <QLabel>
#include <QPushButton>
#include <QSpinBox>
#include <QStringList>
+#include <QTableView>
#include <QWidget>
#include "qui/subanalysis/SequenceLocationModel.hpp"
private:
//! keep track of what analysis we're attached to
MussaRef analysis;
+ QGridLayout *parameterLayout;
+ QLabel *thresholdLabel;
QSpinBox *window;
QSpinBox *threshold;
+ QLabel *windowLabel;
QTableView *table;
QPushButton *ok;
QPushButton *cancel;
--- /dev/null
+#include <QThreadStorage>
+
+#include "qui/threading/GuiProxy.hpp"
+#include "qui/threading/ThreadManager.hpp"
+#include <iostream>
+GuiProxy::GuiProxy() :
+ master(this)
+{
+}
+
+GuiProxy::GuiProxy(GuiProxy *master_) :
+ master(master_)
+{
+ connect(this, SIGNAL(create_mussa_window_signal(GuiProxy *)),
+ master, SLOT(create_mussa_window(GuiProxy *)),
+ Qt::QueuedConnection);
+}
+
+void GuiProxy::create_mussa_window(MussaRef m)
+{
+ if (this == master) {
+ MussaWindow *mw(new MussaWindow(m));
+ mw->show();
+ windows.push_back(mw);
+ } else {
+ if (!analysis) {
+ analysis = m;
+ emit create_mussa_window_signal(this);
+ }
+ }
+}
+
+void GuiProxy::create_mussa_window(GuiProxy *proxy) {
+ create_mussa_window(proxy->analysis);
+ proxy->analysis.reset();
+}
+
+void MussaWindowProxy(MussaRef m) {
+ GuiProxy *proxy = ThreadManager::get_gui_proxy();
+ if (proxy) {
+ proxy->create_mussa_window(m);
+ } else {
+ std::cout << "no local proxy" << std::endl;
+ }
+}
+
\ No newline at end of file
--- /dev/null
+#ifndef GUIPROXY_HPP_
+#define GUIPROXY_HPP_
+
+#include "alg/mussa.hpp"
+#include "qui/MussaWindow.hpp"
+
+#include <list>
+
+class GuiProxy;
+typedef boost::shared_ptr<GuiProxy> GuiProxyRef;
+class GuiProxy : public QObject {
+ Q_OBJECT
+
+public:
+ //! default
+ GuiProxy();
+ //! initialize from master
+ GuiProxy(GuiProxy *);
+ GuiProxy(const GuiProxy &o);
+
+signals:
+ void create_mussa_window_signal(GuiProxy *);
+
+public slots:
+ void create_mussa_window(MussaRef m);
+ void create_mussa_window(GuiProxy *);
+private:
+ GuiProxy *master;
+ MussaRef analysis;
+ std::list<MussaWindow *> windows;
+};
+
+void MussaWindowProxy(MussaRef);
+#endif /*GUIPROXY_HPP_*/
--- /dev/null
+#include "py/python.hpp"
+#include "qui/threading/InterpreterThread.hpp"
+#include "qui/threading/ThreadManager.hpp"
+
+void InterpreterThread::run()
+{
+ get_py().interpreter();
+}
+
+InterpreterThread::InterpreterThread()
+{
+}
--- /dev/null
+#ifndef INTERPRETERTHREAD_HPP_
+#define INTERPRETERTHREAD_HPP_
+
+#include <QThread>
+
+class InterpreterThread : public QThread {
+ Q_OBJECT
+public:
+ void run();
+private:
+ //! only let ThreadManager create this object.
+ InterpreterThread();
+ friend class ThreadManager;
+};
+#endif /*INTERPRETERTHREAD_HPP_*/
--- /dev/null
+#include "qui/threading/ThreadManager.hpp"
+#include "qui/threading/InterpreterThread.hpp"
+#include <QMessageBox>
+#include <QMutex>
+#include <QThreadStorage>
+
+ThreadManager& ThreadManagerFactory() {
+ static ThreadManager *mgr;
+ if (!mgr) {
+ mgr = new ThreadManager;
+ }
+ return *mgr;
+}
+
+ThreadManager::ThreadManager()
+{
+ // initialize thread variable
+ get_gui_proxy();
+}
+
+const InterpreterThread *ThreadManager::create_interpreter() {
+
+ static QMutex interpreter_lock;
+ static InterpreterThread *interpreter_thread;
+ if (interpreter_lock.tryLock()) {
+ // we're the first thread
+ interpreter_thread = new InterpreterThread();
+ interpreter_thread->start();
+ }
+ return interpreter_thread;
+ // someone already started a copy of the interpreter
+}
+
+GuiProxy *ThreadManager::get_gui_proxy()
+{
+ static GuiProxy *master;
+ static QThreadStorage <GuiProxy *> storage;
+ if (!master) {
+ // we don't have a master object so we probably should make one
+ assert (storage.hasLocalData() == false);
+ master = new GuiProxy;
+ if (!master) {
+ QMessageBox::critical(0, "Memory error", "Out of memory");
+ }
+ storage.setLocalData(master);
+ return master;
+ } else if (storage.hasLocalData()) {
+ // we've been initialized properly
+ return storage.localData();
+ } else {
+ // we have a master, but not a local proxy,
+ GuiProxy *client = new GuiProxy(master);
+ if (!client) {
+ QMessageBox::critical(0, "Memory error", "Out of memory");
+ }
+ storage.setLocalData(client);
+ return client;
+ }
+}
\ No newline at end of file
--- /dev/null
+#ifndef THREADMANAGER_HPP_
+#define THREADMANAGER_HPP_
+
+#include "qui/threading/GuiProxy.hpp"
+
+#include <QThread>
+
+class InterpreterThread;
+class ThreadManager
+{
+public:
+ //! make a python interpreter
+ const InterpreterThread *create_interpreter();
+ static GuiProxy *get_gui_proxy();
+private:
+ ThreadManager();
+ friend ThreadManager& ThreadManagerFactory();
+};
+
+ThreadManager& ThreadManagerFactory();
+#endif /*THREADMANAGER_HPP_*/