TinkerCell Core 1.0
TinkerCell's Core library providing all basic functionalities
CThread.cpp
Go to the documentation of this file.
00001 /****************************************************************************
00002 
00003 Copyright (c) 2008 Deepak Chandran
00004 Contact: Deepak Chandran (dchandran1@gmail.com)
00005 See COPYRIGHT.TXT
00006 
00007 This file defines the class that is used to create new threads in the 
00008 Tinkercell main window. The threads can be associated with a dialog that provides
00009 users with the option to terminate the thread.
00010 
00011 ****************************************************************************/
00012 
00013 #include "GraphicsScene.h"
00014 #include "MainWindow.h"
00015 #include "NodeGraphicsItem.h"
00016 #include "ConnectionGraphicsItem.h"
00017 #include "TextGraphicsItem.h"
00018 #include "CThread.h"
00019 #include "ConsoleWindow.h"
00020 #include <QVBoxLayout>
00021 #include <QDockWidget>
00022 #include <QDir>
00023 #include <QSemaphore>
00024 #include <QCoreApplication>
00025 #include <QtDebug>
00026 #include "GlobalSettings.h"
00027 
00028 namespace Tinkercell
00029 {
00030         /******************
00031         LIBRARY THREAD
00032         *******************/
00033         typedef void (*TinkercellCEntryFunction)();
00034         
00035         void CThread::createProgressBarDialog()
00036         {
00037                 QDialog * dialog = new QDialog(mainWindow);
00038                 QHBoxLayout * layout = new QHBoxLayout;
00039                 QLabel * label = new QLabel();
00040                 QProgressBar * progressbar = new QProgressBar;
00041                 layout->addWidget(label);
00042                 layout->addWidget(progressbar);
00043                 progressbar->setRange(0,100);
00044                 dialog->setLayout(layout);
00045                 dialog->hide();
00046                 
00047                 /*signals to control progress bar dialog*/
00048                 connect(this,SIGNAL(setProgress(int)),progressbar,SLOT(setValue(int)));
00049                 connect(this,SIGNAL(setTitle(const QString&)),label,SLOT(setText(const QString&)));
00050                 connect(this,SIGNAL(showProgressBar()),dialog,SLOT(show()));
00051                 connect(this,SIGNAL(hideProgressBar()),dialog,SLOT(hide()));
00052         }
00053         
00054         CThread::CThread(MainWindow * main, QLibrary * libPtr, bool autoUnload)
00055                 : QThread(main), mainWindow(main), autoUnloadLibrary(autoUnload)
00056         {
00057                 f1 = 0;
00058                 f2 = 0;
00059                 f3 = 0;
00060                 f4 = 0;
00061                 callbackPtr = 0;
00062                 callWhenExitPtr = 0;
00063                 setLibrary(libPtr);
00064 
00065                 connect(this,SIGNAL(terminated()),this,SLOT(cleanupAfterTerminated()));
00066                 
00067                 cthreads << this;
00068                 
00069                 createProgressBarDialog();
00070                 
00071                 call_tc_main();
00072         }
00073 
00074         CThread::CThread(MainWindow * main, const QString & libName, bool autoUnload)
00075                 : QThread(main), mainWindow(main), autoUnloadLibrary(autoUnload)
00076         {
00077                 f1 = 0;
00078                 f2 = 0;
00079                 f3 = 0;
00080                 f4 = 0;
00081                 callbackPtr = 0;
00082                 callWhenExitPtr = 0;
00083                 this->lib = 0;
00084                 setLibrary(libName);
00085                 connect(this,SIGNAL(terminated()),this,SLOT(cleanupAfterTerminated()));
00086 
00087                 cthreads << this;
00088                 
00089                 createProgressBarDialog();
00090                 
00091                 call_tc_main();
00092         }
00093         
00094         void CThread::call_tc_main()
00095         {
00096                 if (!lib) return;
00097                 
00098                 TinkercellCEntryFunction f = (TinkercellCEntryFunction)lib->resolve(GlobalSettings::C_ENTRY_FUNCTION.toAscii().data());
00099                 if (f)
00100                         f();    
00101         }
00102 
00103         CThread::~CThread()
00104         {
00105                 cthreads.removeAll(this);
00106         }
00107 
00108         typedef void (*VoidFunction)();
00109 
00110         typedef void (*IntFunction)(int);
00111 
00112         typedef void (*DoubleFunction)(double);
00113 
00114         typedef void (*CharFunction)(const char*);
00115 
00116         typedef void (*MatrixFunction)(tc_matrix);
00117 
00118         void CThread::setFunction( void (*f)(void) , QSemaphore * sem)
00119         {
00120                 f1 = f;
00121                 if (sem)
00122                         sem->release();
00123         }
00124 
00125         void CThread::setVoidFunction( const char* f, QSemaphore * sem)
00126         {
00127                 if (!lib) return;
00128                 f1 = (VoidFunction)lib->resolve(f);
00129                 if (sem)
00130                         sem->release();
00131         }
00132 
00133         void CThread::setFunction( void (*f)(double) , QSemaphore * sem)
00134         {
00135                 f2 = f;
00136                 if (sem)
00137                         sem->release();
00138         }
00139 
00140         void CThread::setDoubleFunction(const char* f, QSemaphore * sem)
00141         {
00142                 if (!lib) return;
00143                 f2 = (DoubleFunction)lib->resolve(f);
00144                 if (sem)
00145                         sem->release();
00146         }
00147 
00148         void CThread::setFunction( void (*f)(const char*) , QSemaphore * sem)
00149         {
00150                 f3 = f;
00151                 if (sem)
00152                         sem->release();
00153         }
00154 
00155         void CThread::setCharFunction( const char* f , QSemaphore * sem)
00156         {
00157                 if (!lib) return;
00158                 f3 = (CharFunction)lib->resolve(f);
00159                 if (sem)
00160                         sem->release();
00161         }
00162 
00163         void CThread::setFunction( void (*f)(tc_matrix) , QSemaphore * sem)
00164         {
00165                 f4 = f;
00166                 if (sem)
00167                         sem->release();
00168         }
00169 
00170         void CThread::setMatrixFunction( const char* f , QSemaphore * sem)
00171         {
00172                 if (!lib) return;
00173                 f4 = (MatrixFunction)lib->resolve(f);
00174                 if (sem)
00175                         sem->release();
00176         }
00177 
00178         typedef void (*cthread_api_initialize)(
00179                 long cthread,
00180                 void (*callback)(long, void (*f)(void)),
00181                 void (*callWhenExiting)(long, void (*f)(void)),
00182                 void (*showProgress)(long , const char *, int) );
00183                 
00184         void CThread::setupCFunctionPointers(QLibrary * lib)
00185         {
00186                 if (lib == 0)
00187                         lib = this->lib;
00188                 if (lib)
00189                 {
00190                         cthread_api_initialize f0 = (cthread_api_initialize)lib->resolve("tc_CThread_api_initialize");
00191                         void * p = (void*)this;
00192                         if (f0)
00193                         {
00194                                 f0( 
00195                                         (long)(p),
00196                                         &(_setCallback),
00197                                         &(_setCallWhenExiting),
00198                                         &(_setProgress)
00199                                 );
00200                         }
00201                 }
00202         }
00203         
00204         void CThread::setLibrary(QLibrary * lib)
00205         {
00206                 this->lib = lib;
00207                 if (mainWindow && lib)
00208                 {
00209                         QSemaphore * s = new QSemaphore(1);
00210                         s->acquire();
00211                         mainWindow->setupNewThread(s,lib);
00212                         s->acquire();
00213                         s->release();
00214                 }
00215                 
00216                 setupCFunctionPointers();
00217         }
00218 
00219         void CThread::setLibrary(const QString& libname)
00220         {
00221                 lib = loadLibrary(libname,this);
00222                 
00223                 bool loaded = lib && lib->isLoaded();
00224                 
00225                 if (mainWindow && loaded)
00226                 {
00227                         setLibrary(lib);
00228                 }
00229         }
00230 
00231         QLibrary * CThread::library()
00232         {
00233                 return lib;
00234         }
00235 
00236         void CThread::setAutoUnload(bool b)
00237         {
00238                 autoUnloadLibrary = b;
00239         }
00240 
00241         bool CThread::autoUnload()
00242         {
00243                 return autoUnloadLibrary;
00244         }
00245 
00246         void CThread::run()
00247         {
00248                 QString current = QDir::currentPath();
00249                 QDir::setCurrent(GlobalSettings::tempDir());
00250 
00251                 if (f1)
00252                         f1();
00253                 else
00254                         if (f2)
00255                                 f2(argDouble);
00256                         else
00257                                 if (f3)
00258                                         f3(ConvertValue(argString));
00259                                 else
00260                                         if (f4)
00261                                                 f4(ConvertValue(argMatrix));
00262 
00263                 QDir::setCurrent(current);
00264 
00265                 if (lib && autoUnloadLibrary)
00266                 {
00267                         unload();
00268                 }
00269         }
00270 
00271         void CThread::setArg(double d, QSemaphore * sem)
00272         {
00273                 argDouble = d;
00274                 if (sem)
00275                         sem->release();
00276         }
00277 
00278         void CThread::setArg(const QString& s, QSemaphore * sem)
00279         {
00280                 argString = s;
00281                 if (sem)
00282                         sem->release();
00283         }
00284 
00285         void CThread::setArg(const DataTable<qreal>& dat, QSemaphore * sem)
00286         {
00287                 argMatrix = dat;
00288                 if (sem)
00289                         sem->release();
00290         }
00291 
00292         void CThread::cleanupAfterTerminated()
00293         {
00294                 if (autoUnloadLibrary)
00295                         unload();
00296         }
00297         
00298         void CThread::update()
00299         {
00300                 if (callbackPtr)
00301                         callbackPtr();
00302         }
00303         
00304         void CThread::unload()
00305         {
00306                 if (lib && lib->isLoaded())
00307                 {
00308                         if (callWhenExitPtr)
00309                                 callWhenExitPtr();
00310                         lib->unload();
00311                         lib = 0;
00312                 }
00313         }
00314 
00315         /*
00316         QString CThread::style = QString("background-color: qlineargradient(x1: 0, y1: 1, x2: 0, y2: 0, stop: 1.0 #585858, stop: 0.5 #0E0E0E, stop: 0.5 #9A9A9A, stop: 1.0 #E2E2E2);");
00317 
00318         QWidget * CThread::dialog(CThread * newThread, const QString& title, const QIcon& icon, bool progressBar)
00319         {
00320                 if (!newThread || !newThread->mainWindow) return 0;
00321 
00322                 QWidget * dialog = new QWidget(newThread->mainWindow);
00323                 dialog->setStyleSheet(CThread::style);
00324 
00325                 dialog->move(newThread->mainWindow->pos() + QPoint(10,10));
00326                 dialog->setWindowIcon(icon);
00327 
00328                 QHBoxLayout * layout = new QHBoxLayout;
00329                 QPushButton * killButton = new QPushButton("Terminate Program",dialog);
00330                 killButton->setShortcut(QKeySequence(Qt::Key_Escape));
00331 
00332                 dialog->setWindowFlags(Qt::Dialog);
00333                 dialog->setAttribute(Qt::WA_DeleteOnClose,true);
00334 
00335                 QLabel * label1 = new QLabel(title);
00336                 layout->addWidget(label1);
00337 
00338                 if (progressBar)
00339                 {
00340                         QProgressBar * progressbar = new QProgressBar;
00341                         layout->addWidget(progressbar);
00342                         progressbar->setRange(0,100);
00343                         connect(newThread,SIGNAL(progress(int)),progressbar,SLOT(setValue(int)));
00344                         connect(newThread,SIGNAL(title(const QString&)),label1,SLOT(setText(const QString&)));
00345                 }
00346 
00347                 layout->addWidget(killButton);
00348                 dialog->setWindowTitle(title);
00349 
00350                 dialog->setLayout(layout);
00351 
00352                 connect(killButton,SIGNAL(released()),newThread,SLOT(terminate()));
00353                 connect(newThread,SIGNAL(finished()),dialog,SLOT(hide()));
00354                 connect(newThread,SIGNAL(terminated()),dialog,SLOT(hide()));
00355                 connect(newThread,SIGNAL(started()),dialog,SLOT(show()));
00356                 newThread->hasDialog = true;
00357                 
00358                 return dialog;
00359         }*/
00360 
00361         QList<CThread*> CThread::cthreads;
00362 
00363         void CThread::_setCallback(long address,  void (*f)(void) )
00364         {
00365                 void * ptr = (void*)address;
00366                 CThread * thread = static_cast<CThread*>(ptr);
00367                 if (cthreads.contains(thread))
00368                 {
00369                         thread->callbackPtr = f;
00370                         connect(thread->mainWindow,SIGNAL(historyChanged(int)),thread,SLOT(update()));
00371                 }
00372         }
00373 
00374         void CThread::_setCallWhenExiting(long address,  void (*f)(void) )
00375         {
00376                 void * ptr = (void*)address;
00377                 CThread * thread = static_cast<CThread*>(ptr);
00378                 if (cthreads.contains(thread))
00379                         thread->callWhenExitPtr = f;
00380         }
00381 
00382         void CThread::_setProgress(long address, const char * title, int progress)
00383         {
00384                 void * ptr = (void*)address;
00385                 CThread * thread = static_cast<CThread*>(ptr);
00386                 if (cthreads.contains(thread))
00387                 {
00388                         thread->showProgress(QString(title), progress);
00389                 }
00390         }
00391         
00392         void CThread::showProgress(const QString & title, int progress)
00393         {
00394                 if (progress > 99)
00395                 {
00396                         emit hideProgressBar();
00397                         return;
00398                 }
00399                 
00400                 if (progress < 2)
00401                         emit showProgressBar();
00402                 
00403                 if (title != _prevProgressBarTitle)
00404                 {
00405                         _prevProgressBarTitle = title;
00406                         emit setTitle(title);
00407                 }
00408                 
00409                 if (progress != _prevProgress)
00410                 {
00411                         _prevProgress = progress;
00412                         emit setProgress(progress);
00413                 }
00414         }
00415 
00416         QLibrary * CThread::loadLibrary(const QString& libname, QObject * parent)
00417         {
00418                 QString  home = GlobalSettings::homeDir(),
00419                         temp = GlobalSettings::tempDir(),
00420                         current = QDir::currentPath(),
00421                         appDir = QCoreApplication::applicationDirPath();
00422 
00423                 QString name[] = {  
00424                         libname,
00425                         temp + QObject::tr("/") + libname,
00426                         home + QObject::tr("/") + libname,
00427                         current + QObject::tr("/") + libname,
00428                         appDir + QObject::tr("/") + libname,
00429                         };
00430 
00431                 QLibrary * lib = new QLibrary(parent);
00432 
00433                 bool loaded = false;
00434                 for (int i=0; i < 5; ++i) //try different possibilities
00435                 {
00436                         lib->setFileName(name[i]);
00437                         loaded = lib->load();
00438                         if (loaded)
00439                                 break;
00440                 }
00441 
00442                 if (!loaded)
00443                 {
00444                         if (!lib->parent())
00445                         {
00446                                 delete lib;
00447                                 lib = 0;
00448                         }
00449                 }
00450                 
00451                 return lib;
00452         }
00453 
00454         /******************
00455         PROCESS THREAD
00456         *******************/
00457 
00458         QWidget * ProcessThread::dialog(MainWindow * mainWindow, ProcessThread * newThread, const QString& text, QIcon icon)
00459         {
00460                 QWidget * dialog = new QDialog(mainWindow);
00461                 
00462                 dialog->hide();
00463 
00464                 dialog->move(newThread->mainWindow->pos() + QPoint(10,10));
00465                 dialog->setWindowIcon(icon);
00466 
00467                 QHBoxLayout * layout = new QHBoxLayout;
00468                 QPushButton * killButton = new QPushButton("Terminate Program");
00469                 connect(killButton,SIGNAL(released()),dialog,SLOT(accept()));
00470                 QLabel * label = new QLabel(text + tr(" is Running..."));
00471 
00472                 layout->addWidget(label);
00473                 layout->addWidget(killButton);
00474                 dialog->setWindowTitle(tr("Program Running"));
00475 
00476                 dialog->setLayout(layout);
00477                 dialog->setWindowFlags(Qt::Dialog);
00478                 dialog->setAttribute(Qt::WA_DeleteOnClose,true);
00479 
00480                 connect(killButton,SIGNAL(released()),newThread,SLOT(terminate()));
00481                 connect(newThread,SIGNAL(finished()),dialog,SLOT(close()));
00482                 connect(newThread,SIGNAL(started()),dialog,SLOT(show()));
00483 
00484                 return dialog;
00485         }
00486 
00487         ProcessThread::ProcessThread(const QString& exe, const QString& args,MainWindow* main)
00488                 : QThread(main)
00489         {
00490                 this->args = args;
00491                 this->exe = exe;
00492                 mainWindow = main;
00493 
00494                 connect(this,SIGNAL(terminated()),this,SLOT(stopProcess()));
00495                 connect(this,SIGNAL(finished()),this,SLOT(stopProcess()));
00496         }
00497 
00498         void ProcessThread::run()
00499         {
00500                 if (mainWindow && !exe.isEmpty())
00501                 {
00502                         QString current = QDir::currentPath();
00503                         QDir::setCurrent(GlobalSettings::tempDir());
00504 
00505                         //setPriority(QThread::LowestPriority);
00506                         connect(this,SIGNAL(terminated()),&process,SLOT(kill()));
00507                         process.start(exe,QStringList() << args);
00508                         process.waitForFinished();
00509                         errStream = process.readAllStandardError();
00510                         outputStream = process.readAllStandardOutput();
00511                         //ConsoleWindow::error(errors);
00512 
00513                         QDir::setCurrent(current);
00514                 }
00515         }
00516 
00517         void ProcessThread::stopProcess()
00518         {
00519                 if (process.state() != QProcess::NotRunning)
00520                         process.close();
00521         }
00522 
00523         ProcessThread::~ProcessThread()
00524         {
00525                 stopProcess();
00526         }
00527         
00528         QString ProcessThread::output() const
00529         {
00530                 return outputStream;
00531         }
00532         
00533         QString ProcessThread::errors() const
00534         {
00535                 return errStream;
00536         }
00537 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines