SpikeStream Application Library  0.2
NetworksWidget.cpp
Go to the documentation of this file.
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 
 All Classes Files Functions Variables Typedefs Friends Defines