![]() |
TinkerCell Core 1.0
TinkerCell's Core library providing all basic functionalities
|
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 }