SpikeStream Application Library
0.2
|
00001 //SpikeStream includes 00002 #include "Globals.h" 00003 #include "NetworkDao.h" 00004 #include "NetworkDialog.h" 00005 #include "NetworksWidget.h" 00006 #include "PluginsDialog.h" 00007 #include "SpikeStreamException.h" 00008 #include "Util.h" 00009 using namespace spikestream; 00010 00011 //Qt includes 00012 #include <QDebug> 00013 #include <QLabel> 00014 #include <QMessageBox> 00015 #include <QPushButton> 00016 #include <QTimer> 00017 00018 //Other includes 00019 #include <iostream> 00020 using namespace std; 00021 00022 //Enable to show debugging information 00023 //#define DEBUG 00024 00025 00027 NetworksWidget::NetworksWidget(QWidget* parent) : QWidget(parent){ 00028 //this->setStyleSheet("* { background-color: white; }"); 00029 00030 QVBoxLayout* verticalBox = new QVBoxLayout(this); 00031 00032 //Add button to add a new empty network to the database 00033 QHBoxLayout* buttonBox = new QHBoxLayout(); 00034 QPushButton* newNetworkButton = new QPushButton("New Network"); 00035 newNetworkButton->setMaximumSize(120, 30); 00036 connect (newNetworkButton, SIGNAL(clicked()), this, SLOT(addNewNetwork())); 00037 buttonBox->addWidget(newNetworkButton); 00038 00039 //Add button to launch networks dialog 00040 QPushButton* addNetworksButton = new QPushButton("Add Networks"); 00041 addNetworksButton->setMaximumSize(120, 30); 00042 connect (addNetworksButton, SIGNAL(clicked()), this, SLOT(addNetworks())); 00043 buttonBox->addWidget(addNetworksButton); 00044 buttonBox->addStretch(10); 00045 verticalBox->addLayout(buttonBox); 00046 00047 //Add grid holding networks 00048 gridLayout = new QGridLayout(); 00049 gridLayout->setColumnMinimumWidth(idCol, 50);//ID 00050 gridLayout->setColumnMinimumWidth(nameCol, 120);//Name 00051 gridLayout->setColumnMinimumWidth(spacer1Col, 50);//Spacer 00052 gridLayout->setColumnMinimumWidth(descCol, 250);//Description 00053 00054 QHBoxLayout* gridLayoutHolder = new QHBoxLayout(); 00055 gridLayoutHolder->addLayout(gridLayout); 00056 gridLayoutHolder->addStretch(5); 00057 verticalBox->addLayout(gridLayoutHolder); 00058 00059 //Load the network into the grid layout 00060 loadNetworkList(); 00061 verticalBox->addStretch(10); 00062 00063 //Create thread-based class for heavy operations 00064 networkManager = new NetworkManager(); 00065 connect(networkManager, SIGNAL(progress(int, int, QString, bool)), this, SLOT(updateProgress(int, int, QString, bool)), Qt::QueuedConnection); 00066 connect(networkManager, SIGNAL(finished()), this, SLOT(networkManagerFinished())); 00067 progressDialog = new QProgressDialog(this, Qt::CustomizeWindowHint); 00068 progressDialog->setAutoClose(false); 00069 progressDialog->setAutoReset(false); 00070 progressDialog->setModal(true); 00071 progressDialog->setMinimumDuration(0); 00072 00073 //Connect to global reload signal 00074 connect(Globals::getEventRouter(), SIGNAL(reloadSignal()), this, SLOT(loadNetworkList()), Qt::QueuedConnection); 00075 connect(Globals::getEventRouter(), SIGNAL(networkChangedSignal()), this, SLOT(loadNetworkList()), Qt::QueuedConnection); 00076 connect(Globals::getEventRouter(), SIGNAL(networkListChangedSignal()), this, SLOT(loadNetworkList()), Qt::QueuedConnection); 00077 connect(this, SIGNAL(networkChanged()), Globals::getEventRouter(), SLOT(networkChangedSlot()), Qt::QueuedConnection); 00078 } 00079 00080 00082 NetworksWidget::~NetworksWidget(){ 00083 delete networkManager; 00084 } 00085 00086 00087 /*----------------------------------------------------------*/ 00088 /*----- PRIVATE SLOTS -----*/ 00089 /*----------------------------------------------------------*/ 00090 00092 void NetworksWidget::addNetworks(){ 00093 try{ 00094 PluginsDialog* pluginsDialog = new PluginsDialog(this, "/plugins/networks", "Add Network"); 00095 pluginsDialog->exec(); 00096 delete pluginsDialog; 00097 } 00098 catch(SpikeStreamException& ex){ 00099 qCritical()<<ex.getMessage(); 00100 } 00101 } 00102 00103 00105 void NetworksWidget::addNewNetwork(){ 00106 try{ 00107 NetworkDialog* networkDialog = new NetworkDialog(this); 00108 if(networkDialog->exec() == QDialog::Accepted) 00109 loadNetworkList(); 00110 delete networkDialog; 00111 } 00112 catch(SpikeStreamException& ex){ 00113 qCritical()<<ex.getMessage(); 00114 } 00115 } 00116 00117 00119 void NetworksWidget::deleteNetwork(){ 00120 //Get the ID of the network to be deleted 00121 deleteNetworkID = Util::getUInt(sender()->objectName()); 00122 if(!networkInfoMap.contains(deleteNetworkID)){ 00123 qCritical()<<"Network with ID "<<deleteNetworkID<<" cannot be found."; 00124 return; 00125 } 00126 00127 //Run checks if we are deleting the current network 00128 if(Globals::networkLoaded() && Globals::getNetwork()->getID() == deleteNetworkID){ 00129 if(!Globals::networkChangeOk()) 00130 return; 00131 } 00132 00133 //Confirm that user wants to take this action. 00134 QMessageBox msgBox; 00135 msgBox.setText("Deleting Network"); 00136 msgBox.setInformativeText("Are you sure that you want to delete network with ID " + QString::number(deleteNetworkID) + "? This step cannot be undone."); 00137 msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); 00138 msgBox.setDefaultButton(QMessageBox::Cancel); 00139 int ret = msgBox.exec(); 00140 if(ret != QMessageBox::Ok) 00141 return; 00142 00143 //Delete the network from the database 00144 try{ 00145 //Start network manager to load network in a separate thread. 00146 networkManager->startDeleteNetwork(deleteNetworkID); 00147 progressDialog->reset(); 00148 progressDialog->setLabelText("Starting network delete."); 00149 progressDialog->setCancelButton(0);//Cancel not implemented at this stage 00150 cancelButtonVisible = false; 00151 progressDialog->show(); 00152 } 00153 catch(SpikeStreamException& ex){ 00154 qCritical()<<"Exception thrown when deleting network: "<<ex.getMessage(); 00155 } 00156 } 00157 00158 00160 void NetworksWidget::loadNetwork(){ 00161 unsigned int networkID = sender()->objectName().toUInt(); 00162 if(!networkInfoMap.contains(networkID)){ 00163 qCritical()<<"Network with ID "<<networkID<<" cannot be found."; 00164 return; 00165 } 00166 00167 //Run checks to make sure that we want to change network 00168 if(!Globals::networkChangeOk()) 00169 return; 00170 if(Globals::networkLoaded() && !Globals::getNetwork()->isSaved()){ 00171 QMessageBox msgBox(QMessageBox::Warning, "Changing network", "Network is loaded in prototype mode and has not been saved.\nThis will discard all of your changes to the network.\nDo you want to continue?", QMessageBox::Ok | QMessageBox::Cancel, this); 00172 if(msgBox.exec() != QMessageBox::Ok) 00173 return; 00174 } 00175 00176 //load the network 00177 loadNetwork(networkInfoMap[networkID]); 00178 } 00179 00180 00182 void NetworksWidget::loadNetworkList(){ 00183 //Reset widget 00184 reset(); 00185 00186 //Get a list of the networks in the database 00187 NetworkDao* networkDao = Globals::getNetworkDao(); 00188 QList<NetworkInfo> networkInfoList; 00189 try{ 00190 networkInfoList = networkDao->getNetworksInfo(); 00191 } 00192 catch(SpikeStreamException& ex){ 00193 qCritical()<<ex.getMessage(); 00194 return; 00195 } 00196 00197 //Show "no network" message if list is empty 00198 if(networkInfoList.size() == 0){ 00199 gridLayout->addWidget(new QLabel("No networks in database"), 0, 0); 00200 if(Globals::networkLoaded()){ 00201 Globals::setNetwork(0); 00202 emit networkChanged(); 00203 } 00204 return; 00205 } 00206 00207 //Copy network infos into map 00208 for(int i=0; i<networkInfoList.size(); ++i){ 00209 networkInfoMap[networkInfoList[i].getID()] = networkInfoList[i]; 00210 } 00211 00212 /* If the current network is in the network list, then set this as the one loaded 00213 Otherwise currentNetworkID is set to zero and the user has to choose the loaded network */ 00214 unsigned int currentNetworkID = 0; 00215 if(Globals::networkLoaded() && networkInfoMap.contains(Globals::getNetwork()->getID())){ 00216 currentNetworkID = Globals::getNetwork()->getID(); 00217 } 00218 00219 //Display the list in the widget 00220 for(int i=0; i<networkInfoList.size(); ++i){ 00221 //Property button 00222 QPushButton* propButton = new QPushButton("P"); 00223 propButton->setMaximumWidth(20); 00224 propButton->setObjectName(QString::number(networkInfoList[i].getID())); 00225 connect ( propButton, SIGNAL(clicked()), this, SLOT( setNetworkProperties() ) ); 00226 gridLayout->addWidget(propButton, i, propCol); 00227 00228 //Create labels 00229 QLabel* idLabel = new QLabel(QString::number(networkInfoList[i].getID())); 00230 gridLayout->addWidget(idLabel, i, idCol); 00231 QLabel* nameLabel = new QLabel(networkInfoList[i].getName()); 00232 gridLayout->addWidget(nameLabel, i, nameCol); 00233 QLabel* descriptionLabel = new QLabel(networkInfoList[i].getDescription()); 00234 gridLayout->addWidget(descriptionLabel, i, descCol); 00235 00236 //Create the load button and name it with the object id so we can tell which button was invoked 00237 QPushButton* loadButton = new QPushButton("Load"); 00238 loadButton->setObjectName(QString::number(networkInfoList[i].getID())); 00239 connect ( loadButton, SIGNAL(clicked()), this, SLOT( loadNetwork() ) ); 00240 gridLayout->addWidget(loadButton, i, loadCol); 00241 00242 //Create the prototype button and name it with the object id so we can tell which button was invoked 00243 QPushButton* prototypeButton = new QPushButton("Prototype"); 00244 prototypeButton->setObjectName(QString::number(networkInfoList[i].getID())); 00245 connect ( prototypeButton, SIGNAL(clicked()), this, SLOT( prototypeNetwork() ) ); 00246 gridLayout->addWidget(prototypeButton, i, protoCol); 00247 00248 //Create the delete button and name it with the object id so we can tell which button was invoked 00249 QPushButton* deleteButton = new QPushButton(QIcon(Globals::getSpikeStreamRoot() + "/images/trash_can.png"), ""); 00250 deleteButton->setObjectName(QString::number(networkInfoList[i].getID())); 00251 connect ( deleteButton, SIGNAL(clicked()), this, SLOT( deleteNetwork() ) ); 00252 gridLayout->addWidget(deleteButton, i, delCol); 00253 00254 //Set labels and buttons depending on whether it is the current network 00255 if(currentNetworkID == networkInfoList[i].getID()){ 00256 if(Globals::getNetwork()->isPrototypeMode() && !Globals::getNetwork()->isSaved()){ 00257 QPushButton* saveButton = new QPushButton(QIcon(Globals::getSpikeStreamRoot() + "/images/save.png"), ""); 00258 saveButton->setObjectName(QString::number(networkInfoList[i].getID())); 00259 connect ( saveButton, SIGNAL(clicked()), this, SLOT( saveNetwork() ) ); 00260 gridLayout->addWidget(saveButton, i, saveCol); 00261 } 00262 00263 if(Globals::getArchiveDao()->networkHasArchives(currentNetworkID)){ 00264 idLabel->setStyleSheet( "QLabel { color: #F08080; font-weight: bold; font-style: italic; }"); 00265 nameLabel->setStyleSheet( "QLabel { color: #F08080; font-weight: bold; font-style: italic; }"); 00266 descriptionLabel->setStyleSheet( "QLabel { color: #F08080; font-weight: bold; font-style: italic; }"); 00267 } 00268 else{ 00269 idLabel->setStyleSheet( "QLabel { color: #008000; font-weight: bold; }"); 00270 nameLabel->setStyleSheet( "QLabel { color: #008000; font-weight: bold; }"); 00271 descriptionLabel->setStyleSheet( "QLabel { color: #008000; font-weight: bold; }"); 00272 } 00273 00274 //Disable load or prototype button 00275 if(Globals::getNetwork()->isPrototypeMode()) 00276 prototypeButton->setEnabled(false); 00277 else 00278 loadButton->setEnabled(false); 00279 } 00280 else if (Globals::getArchiveDao()->networkHasArchives(currentNetworkID)) { 00281 idLabel->setStyleSheet( "QLabel { color: #777777; font-style: italic; }"); 00282 nameLabel->setStyleSheet( "QLabel { color: #777777; font-style: italic; }"); 00283 descriptionLabel->setStyleSheet( "QLabel { color: #777777; font-style: italic; }"); 00284 } 00285 else{ 00286 idLabel->setStyleSheet( "QLabel { color: #777777; }"); 00287 nameLabel->setStyleSheet( "QLabel { color: #777777; }"); 00288 descriptionLabel->setStyleSheet( "QLabel { color: #777777; }"); 00289 } 00290 } 00291 00292 //FIXME: HACK TO GET IT TO DISPLAY PROPERLY 00293 this->setMinimumHeight(networkInfoList.size() * 100); 00294 } 00295 00296 00298 void NetworksWidget::networkManagerFinished(){ 00299 //If we have reached this point, loading is complete 00300 progressDialog->hide(); 00301 00302 //Check for errors 00303 if(networkManager->isError()){ 00304 qCritical()<<"Error occurred saving network: '"<<networkManager->getErrorMessage()<<"'."; 00305 } 00306 00307 //Handle task specific stuff 00308 switch(networkManager->getCurrentTask()){ 00309 case NetworkManager::LOAD_NETWORK_TASK: 00310 if(networkManager->isError() || progressDialog->wasCanceled()){ 00311 delete newNetwork; 00312 } 00313 else{ 00314 //Store network in global scope 00315 Globals::setNetwork(newNetwork); 00316 00317 //Use event router to inform other classes that the network has changed. 00318 emit networkChanged(); 00319 } 00320 break; 00321 case NetworkManager::SAVE_NETWORK_TASK: 00322 //Refresh network list 00323 emit networkChanged(); 00324 break; 00325 case NetworkManager::DELETE_NETWORK_TASK: 00326 // If we have deleted the current network, use event router to inform other classes that the network has changed. 00327 if(Globals::networkLoaded() && Globals::getNetwork()->getID() == deleteNetworkID){ 00328 Globals::setNetwork(NULL); 00329 emit networkChanged(); 00330 } 00331 00332 //Reload the network list 00333 loadNetworkList(); 00334 break; 00335 default: 00336 qCritical()<<"Network manager task not recognized: "<<networkManager->getCurrentTask(); 00337 } 00338 } 00339 00340 00342 void NetworksWidget::prototypeNetwork(){ 00343 unsigned int networkID = sender()->objectName().toUInt(); 00344 if(!networkInfoMap.contains(networkID)){ 00345 qCritical()<<"Network with ID "<<networkID<<" cannot be found."; 00346 return; 00347 } 00348 00349 //Run checks to make sure that we want to change network 00350 if(!Globals::networkChangeOk()) 00351 return; 00352 if(Globals::networkLoaded() && !Globals::getNetwork()->isSaved()){ 00353 QMessageBox msgBox(QMessageBox::Warning, "Changing network", "Network is loaded in prototype mode and has not been saved.\nThis will discard all of your changes to the network.\nDo you want to continue?", QMessageBox::Ok | QMessageBox::Cancel, this); 00354 if(msgBox.exec() != QMessageBox::Ok) 00355 return; 00356 } 00357 if(Globals::getArchiveDao()->networkHasArchives(networkID)){ 00358 QMessageBox msgBox(QMessageBox::Warning, "Prototype Mode", "This network has archives associated with it.\nIf you change this network in prototype mode, your changes cannot be saved until the archives have been deleted.\nWould you like to continue?", QMessageBox::Ok | QMessageBox::Cancel, this); 00359 if(msgBox.exec() != QMessageBox::Ok) 00360 return; 00361 } 00362 //Set prototype mode and load the network 00363 loadNetwork(networkInfoMap[networkID], true); 00364 } 00365 00366 00368 void NetworksWidget::saveNetwork(){ 00369 //Run some internal checks 00370 if(!Globals::networkLoaded()){ 00371 qCritical()<<"SpikeStream internal error. Should not be able to save network when no network is loaded"; 00372 return; 00373 } 00374 unsigned int networkID = sender()->objectName().toUInt(); 00375 if(!networkInfoMap.contains(networkID)){ 00376 qCritical()<<"Network with ID "<<networkID<<" cannot be found."; 00377 return; 00378 } 00379 if(!Globals::getNetwork()->isPrototypeMode()){ 00380 qCritical()<<"SpikeStream internal error. Should not be able to save a network that is not in prototype mode."; 00381 } 00382 if(Globals::getArchiveDao()->networkHasArchives(networkID)){ 00383 qCritical()<<"Network has archives.\nYour prototype mode changes cannot be saved until these archives have been deleted."; 00384 return; 00385 } 00386 00387 //Save network 00388 try{ 00389 //Start network manager to load network in a separate thread. 00390 networkManager->startSaveNetwork(Globals::getNetwork()); 00391 progressDialog->reset(); 00392 progressDialog->setLabelText("Starting save network."); 00393 progressDialog->setCancelButton(0);//Cancel not implemented at this stage 00394 cancelButtonVisible = false; 00395 progressDialog->show(); 00396 } 00397 catch(SpikeStreamException& ex){ 00398 qCritical()<<ex.getMessage(); 00399 } 00400 } 00401 00402 00404 void NetworksWidget::setNetworkProperties(){ 00405 unsigned int networkID = sender()->objectName().toUInt(); 00406 if(!networkInfoMap.contains(networkID)){ 00407 qCritical()<<"Network with ID "<<networkID<<" cannot be found."; 00408 return; 00409 } 00410 try{ 00411 NetworkDialog* networkDialog = new NetworkDialog(networkInfoMap[networkID].getName(), networkInfoMap[networkID].getDescription(), this); 00412 if(networkDialog->exec() == QDialog::Accepted){ 00413 Globals::getNetworkDao()->setNetworkProperties(networkID, networkDialog->getName(), networkDialog->getDescription()); 00414 loadNetworkList(); 00415 } 00416 delete networkDialog; 00417 } 00418 catch(SpikeStreamException& ex){ 00419 qCritical()<<ex.getMessage(); 00420 } 00421 } 00422 00423 00425 void NetworksWidget::updateProgress(int stepsCompleted, int totalSteps, QString message, bool showCancelButton){ 00426 #ifdef DEBUG 00427 qDebug()<<"steps completed: "<<stepsCompleted<<"; totalSteps: "<<totalSteps<<"; message: |"<<message<<"|"; 00428 #endif//DEBUG 00429 00430 //Avoid multiple calls to graphics 00431 if(progressUpdating) 00432 return; 00433 progressUpdating = true; 00434 00435 //Add or remove cancel button depending on the current task that is being done 00436 if(cancelButtonVisible != showCancelButton){ 00437 if(showCancelButton) 00438 progressDialog->setCancelButton(new QPushButton("Cancel")); 00439 else 00440 progressDialog->setCancelButton(0); 00441 cancelButtonVisible = showCancelButton; 00442 } 00443 00444 //Check for cancellation - stop timer and abort operation 00445 if(progressDialog->wasCanceled()){ 00446 networkManager->cancel(); 00447 progressDialog->show(); 00448 } 00449 00450 if(networkManager->isRunning() && progressDialog->isVisible()){ 00451 progressDialog->setMaximum(totalSteps); 00452 progressDialog->setValue(stepsCompleted); 00453 progressDialog->setLabelText(message); 00454 } 00455 00456 progressUpdating = false; 00457 } 00458 00459 00460 /*----------------------------------------------------------*/ 00461 /*----- PRIVATE METHODS -----*/ 00462 /*----------------------------------------------------------*/ 00463 00465 void NetworksWidget::loadNetwork(NetworkInfo& netInfo, bool prototypeMode){ 00466 if(!networkInfoMap.contains(netInfo.getID())){ 00467 qCritical()<<"Network with ID "<<netInfo.getID()<<" cannot be found."; 00468 return; 00469 } 00470 00471 //Check to see if the network is already loaded and matches the database 00472 if(Globals::networkLoaded() && Globals::getNetwork()->getID() == netInfo.getID()){ 00473 //Change from saved prototype to loaded mode 00474 if(Globals::getNetwork()->isPrototypeMode() && Globals::getNetwork()->isSaved()){ 00475 //Change status of network and refresh list 00476 Globals::getNetwork()->setPrototypeMode(false); 00477 loadNetworkList(); 00478 return; 00479 } 00480 //Change from loaded to prototype 00481 if(!Globals::getNetwork()->isPrototypeMode() && prototypeMode){ 00482 //Change status of network and refresh list 00483 Globals::getNetwork()->setPrototypeMode(true); 00484 loadNetworkList(); 00485 return; 00486 } 00487 } 00488 00489 //Load the network 00490 progressUpdating = false; 00491 try{ 00492 /* Create new network and store it in global scope. 00493 Network is set to null because if an exception is thrown during construction 00494 then we need to know if the object was created */ 00495 newNetwork = NULL; 00496 newNetwork = new Network(netInfo, Globals::getNetworkDao()->getDBInfo(), Globals::getArchiveDao()->getDBInfo()); 00497 00498 //Set prototype mode 00499 newNetwork->setPrototypeMode(prototypeMode); 00500 00501 //Start network manager to load network in a separate thread. 00502 networkManager->startLoadNetwork(newNetwork); 00503 progressDialog->reset(); 00504 progressDialog->setLabelText("Starting load network."); 00505 progressDialog->setCancelButton(0); 00506 cancelButtonVisible = false; 00507 progressDialog->show(); 00508 } 00509 catch (SpikeStreamException& ex){ 00510 qCritical()<<ex.getMessage(); 00511 if(newNetwork != NULL){ 00512 delete newNetwork; 00513 } 00514 progressDialog->hide(); 00515 return; 00516 } 00517 } 00518 00519 00522 void NetworksWidget::reset(){ 00523 //Clean up widgets that were scheduled to be deleted during the previous event cycle 00524 foreach(QWidget* widget , cleanUpList) 00525 widget->deleteLater(); 00526 cleanUpList.clear(); 00527 00528 //Remove no networks label if it exists 00529 if(networkInfoMap.size() == 0){ 00530 QLayoutItem* item = gridLayout->itemAtPosition(0, 0); 00531 if(item != 0){ 00532 delete item->widget(); 00533 } 00534 return; 00535 } 00536 00537 //Remove list of networks 00538 for(int rowIndx=0; rowIndx<networkInfoMap.size(); ++rowIndx){ 00539 for(int colIndx = 0; colIndx < numCols; ++colIndx){ 00540 QLayoutItem* item = gridLayout->itemAtPosition(rowIndx, colIndx); 00541 if(item != 0){ 00542 QWidget* tmpWidget = item->widget(); 00543 tmpWidget->setVisible(false); 00544 gridLayout->removeWidget(tmpWidget); 00545 cleanUpList.append(tmpWidget); 00546 } 00547 } 00548 } 00549 networkInfoMap.clear(); 00550 } 00551 00552