Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Class Members | File Members

ProbeDialog.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   SpikeStream Application                                               *
00003  *   Copyright (C) 2007 by David Gamez                                     *
00004  *   david@davidgamez.eu                                                   *
00005  *   Version 0.1                                                           *
00006  *                                                                         *
00007  *   This program is free software; you can redistribute it and/or modify  *
00008  *   it under the terms of the GNU General Public License as published by  *
00009  *   the Free Software Foundation; either version 2 of the License, or     *
00010  *   (at your option) any later version.                                   *
00011  *                                                                         *
00012  *   This program is distributed in the hope that it will be useful,       *
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00015  *   GNU General Public License for more details.                          *
00016  *                                                                         *
00017  *   You should have received a copy of the GNU General Public License     *
00018  *   along with this program; if not, write to the                         *
00019  *   Free Software Foundation, Inc.,                                       *
00020  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00021  ***************************************************************************/
00022 
00023 //SpikeStream includes
00024 #include "ProbeDialog.h"
00025 #include "NeuronGroupType.h"
00026 #include "Utilities.h"
00027 #include "Debug.h"
00028 
00029 //Qt includes
00030 #include <qlayout.h>
00031 #include <qlabel.h>
00032 #include <qpushbutton.h>
00033 #include <qvalidator.h>
00034 #include <qstring.h>
00035 #include <qregexp.h>
00036 #include <qmessagebox.h>
00037 
00038 //Other includes
00039 #include <iostream>
00040 #include "mysql++.h"
00041 using namespace std;
00042 using namespace mysqlpp;
00043 
00044 
00045 /*! Constructor */
00046 ProbeDialog::ProbeDialog(QWidget* parent, DBInterface* netDBInter) : QDialog(parent){
00047         //Store references to database
00048         networkDBInterface = netDBInter;
00049 
00050         //Create boxes to organise layout of dialog
00051         QVBoxLayout *vBox = new QVBoxLayout(this, 5, 5, "Main vertical Box");
00052 
00053         //Create validator for name field
00054         QRegExp regExp( "([0-9]|[A-Z]|[a-z]|_|\\s){1,50}" );
00055     QValidator* nameValidator = new QRegExpValidator(regExp, this);
00056 
00057         //Add field, combo and button to add new probes
00058         QHBoxLayout *newProbeBox = new QHBoxLayout();
00059         newProbeBox->addWidget(new QLabel("Name:", this));
00060         nameText = new QLineEdit("Untitled", this);
00061         nameText->setValidator(nameValidator);
00062         nameText->setMaximumSize(200,30);
00063         newProbeBox->addWidget(nameText);
00064         probeTypeCombo = new QComboBox(this, "Probe Type");
00065         probeTypeCombo->setMinimumSize(250,30);
00066         fillProbeTypeCombo();
00067         newProbeBox->addWidget(new QLabel("Type:", this));
00068         newProbeBox->addWidget(probeTypeCombo);
00069         QPushButton* addProbeButt = new QPushButton("Add Probe", this, "AddProbe");
00070         addProbeButt->setBaseSize(130, 30);
00071         addProbeButt->setMaximumSize(130,30);
00072         addProbeButt->setMinimumSize(130,30);
00073         addProbeButt->setAccel(QKeySequence(CTRL + Key_A));
00074         connect (addProbeButt, SIGNAL(clicked()), this, SLOT(addProbe()));
00075         newProbeBox->addWidget(addProbeButt);
00076 
00077         vBox->addLayout(newProbeBox);
00078         vBox->addSpacing(10);
00079 
00080         //Add delete button
00081         QHBoxLayout *buttonBox = new QHBoxLayout();
00082         QPushButton* deleteProbeButt = new QPushButton("Delete Probe(s)", this, "DeleteProbe");
00083         deleteProbeButt->setBaseSize(130, 30);
00084         deleteProbeButt->setMaximumSize(130,30);
00085         deleteProbeButt->setMinimumSize(130,30);
00086         deleteProbeButt->setAccel(QKeySequence(Key_Delete));
00087         connect (deleteProbeButt, SIGNAL(clicked()), this, SLOT(deleteProbes()));
00088         buttonBox->addWidget(deleteProbeButt);
00089         buttonBox->addStretch(5);
00090         
00091         vBox->addLayout(buttonBox);
00092         vBox->addSpacing(10);
00093 
00094         //Set up table to hold pattern information
00095         probeTable = new QTable(0, 5, this);
00096         probeTable->setShowGrid(false);
00097         probeTable->setSorting(false);
00098         probeTable->setSelectionMode(QTable::NoSelection);
00099         probeTable->verticalHeader()->hide();
00100         probeTable->setLeftMargin(0);
00101         QHeader * probeTableHeader = probeTable->horizontalHeader();
00102 
00103         selectionCol = 0;//Remember to update this when changing the table
00104         probeTableHeader->setLabel(selectionCol, "");
00105         probeTable->setColumnWidth(selectionCol, 20);
00106 
00107         probeIDCol = 1;//Remember to update this when changing the table
00108         probeTableHeader->setLabel(probeIDCol, "ID");
00109         probeTable->setColumnWidth(probeIDCol, 50);
00110         
00111         nameCol = 2;
00112         probeTableHeader->setLabel(nameCol, "Name");
00113         probeTable->setColumnWidth(nameCol, 280);
00114 
00115         typeDescCol = 3;
00116         probeTableHeader->setLabel(typeDescCol, "Type");
00117         probeTable->setColumnWidth(typeDescCol, 280);
00118 
00119         typeCol = 4;
00120         probeTableHeader->setLabel(typeCol, "TypeID");
00121         probeTable->setColumnWidth(typeCol, 50);
00122 
00123         //Connect layer table header clicked() slot to select all
00124         connect (probeTableHeader, SIGNAL(clicked(int)), this, SLOT(probeTableHeaderClicked(int)));
00125 
00126         //Fill probe table with information about current probes.
00127         loadProbeTable();
00128 
00129         vBox->addWidget(probeTable);
00130 
00131         //Set up ok and cancel buttons
00132         QHBoxLayout *okCancelBox = new QHBoxLayout();
00133         QPushButton *okPushButton = new QPushButton("Ok", this, "okButton");
00134         QPushButton *cancelPushButton = new QPushButton("Cancel", this, "cancelButton");        
00135         okCancelBox->addWidget(okPushButton);
00136         okCancelBox->addWidget(cancelPushButton);
00137         vBox->addLayout(okCancelBox);
00138         
00139         connect (okPushButton, SIGNAL(clicked()), this, SLOT(accept()));
00140         connect (cancelPushButton, SIGNAL(clicked()), this, SLOT(reject()));
00141 
00142         this->setMinimumSize(700, 500);
00143 
00144 }
00145 
00146 
00147 //!Destructor
00148 ProbeDialog::~ProbeDialog(){
00149         #ifdef MEMORY_DEBUG
00150                 cout<<"DELETING PROBE DIALOG"<<endl;
00151         #endif//MEMORY_DEBUG
00152 }
00153 
00154 
00155 //---------------------------------------------------------------------
00156 //-----------------          PRIVATE SLOTS           ------------------
00157 //---------------------------------------------------------------------
00158 
00159 /*! Adds a new probe to the neuron groups database and hides the dialog */
00160 void ProbeDialog::addProbe(){
00161         //Sort out probe name
00162         QString probeName = nameText->text();
00163         if(probeName == "")
00164                 probeName = "Untitled";
00165 
00166         //Extract probe type
00167         unsigned int probeType;
00168         int comboIndex = probeTypeCombo->currentItem();
00169         if(comboIndex > 0)
00170                 probeType =  typePositionMap[comboIndex];
00171         else{
00172                 cout<<"ProbeDialog: No probes currently available."<<endl;
00173                 return;
00174         }
00175 
00176         //Add a new probe of this type to the database
00177         try{
00178                 Query query = networkDBInterface->getQuery();
00179                 query.reset();
00180         
00181                 /* Add to NeuronGroups
00182                         For most purposes, a probe acts as another neuron group that sends 
00183                         and receives messages. */
00184                 query.reset();
00185                 query<<"INSERT INTO Probes (Name, Type) VALUES (\""<<probeName<<"\", "<<probeType<<")";
00186                 query.execute();
00187                 
00188                 //Now need to get the automatically generated NeuronGrpID so that it can be added to the neurons in the new layers
00189                 query.reset();
00190                 query<<"SELECT MAX(ProbeID) from Probes";
00191                 Result probeIDResult = query.store();
00192                 Row row(*(probeIDResult.begin()));
00193                 unsigned int probeID = Utilities::getUInt((std::string)row["MAX(ProbeID)"]);
00194         
00195                 //Get the name of the parameter table for this probe from the database
00196                 query.reset();
00197                 query<<"SELECT ParameterTableName FROM ProbeTypes WHERE TypeID = "<<probeType;
00198                 Result tableNameRes = query.store();
00199                 Row tableNameRow (*tableNameRes.begin());//Should only be 1 row
00200         
00201                 //Add a row to this table for this probe
00202                 query.reset();
00203                 query<<"INSERT INTO "<<(std::string)tableNameRow["ParameterTableName"]<<" (ProbeID) VALUES ("<<probeID<<")";
00204                 query.execute();
00205         }
00206         catch (const BadQuery& er) {// Handle any query errors
00207                 cerr<<"ProbeDialog: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
00208                 QString errorString = "Bad query when adding probe: \"";
00209                 errorString += er.what();
00210                 errorString += "\"";
00211                 QMessageBox::critical( 0, "Probe Error", errorString);
00212         }
00213         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00214                 cerr<<"ProbeDialog: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
00215                 QString errorString = "Exception thrown adding probe: \"";
00216                 errorString += er.what();
00217                 errorString += "\"";
00218                 QMessageBox::critical( 0, "Probe Error", errorString);
00219         }
00220         catch(std::exception& er){// Catch-all for any other exceptions
00221                 cerr<<"ProbeDialog: STD EXCEPTION \""<<er.what()<<"\""<<endl;
00222                 QString errorString = "Exception thrown adding probe: \"";
00223                 errorString += er.what();
00224                 errorString += "\"";
00225                 QMessageBox::critical( 0, "Probe Error", errorString);
00226         }
00227 
00228         //Reload probe table
00229         loadProbeTable();
00230 }
00231 
00232 
00233 /*! Deletes the selected probes from the database */
00234 void ProbeDialog::deleteProbes(){
00235         QString confirmDeleteStr = "Do you want to delete the following probe(s)?\n";
00236         map<unsigned int, unsigned int> deleteProbesMap;
00237 
00238         //Get the probe id(s) for the probe(s) to be deleted
00239         for(int i=0; i<probeTable->numRows(); i++){
00240                 QCheckTableItem * item = (QCheckTableItem*)probeTable->item(i, selectionCol);
00241                 if(item->isChecked()){
00242                         unsigned int pID = probeTable->item(i, probeIDCol)->text().toUInt();    
00243                         unsigned int pType = probeTable->item(i, typeCol)->text().toUInt();     
00244                         deleteProbesMap[pID] = pType;
00245                         confirmDeleteStr += "   ";
00246                         confirmDeleteStr += probeTable->item(i, nameCol)->text()+= " (ID: ";
00247                         confirmDeleteStr += probeTable->item(i, probeIDCol)->text() += ")\n";
00248                 }
00249         }
00250 
00251         //Check that user really wants to delete these layers
00252         if(deleteProbesMap.size() > 0){
00253                 if(!( QMessageBox::warning( this, "Confirm Delete of Probe(s)", confirmDeleteStr, "Yes", "No", 0, 0, 1 ))) {
00254                         //Delete probes from database and table
00255                         for(map<unsigned int, unsigned int>::iterator iter = deleteProbesMap.begin(); iter != deleteProbesMap.end(); ++iter){
00256                                 try{
00257                                         //Delete from Probes database
00258                                         Query query = networkDBInterface->getQuery();
00259                                         query.reset();
00260                                         query<<"DELETE FROM Probes WHERE ProbeID = "<<iter->first;
00261                                         query.execute();
00262         
00263                                         //Delete from probes parameter database
00264                                         //Get the name of the parameter table for this probe from the database
00265                                         query.reset();
00266                                         query<<"SELECT ParameterTableName FROM ProbeTypes WHERE TypeID = "<<iter->second;
00267                                         Result tableNameRes = query.store();
00268         
00269                                         //Check we have found this type
00270                                         if(tableNameRes.size() != 1){
00271                                                 QString errStr =  "Missing probe type: ";
00272                                                 errStr += QString::number(iter->second);
00273                                                 QMessageBox::critical( 0, "Probe Manager", errStr);
00274                                                 return;
00275                                         }
00276                 
00277                                         Row tableNameRow (*tableNameRes.begin());//Should only be 1 row
00278         
00279                                         //Delete this probe from its parameter table
00280                                         query.reset();
00281                                         query<<"DELETE FROM "<<(std::string)tableNameRow["ParameterTableName"]<<" WHERE ProbeID = "<<iter->first;
00282                                         query.execute();
00283                                 }
00284                                 catch (const BadQuery& er) {// Handle any query errors
00285                                         cerr<<"ProbeDialog: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
00286                                         QString errorString = "Bad query when deleting probe: \"";
00287                                         errorString += er.what();
00288                                         errorString += "\"";
00289                                         QMessageBox::critical( 0, "Delete Probe Error", errorString);
00290                                 }
00291                                 catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00292                                         cerr<<"ProbeDialog: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
00293                                         QString errorString = "Exception thrown deleting probe: \"";
00294                                         errorString += er.what();
00295                                         errorString += "\"";
00296                                         QMessageBox::critical( 0, "Delete Probe Error", errorString);
00297                                 }
00298 
00299                                 //Remove entry from probe table
00300                                 removeProbeFromTable(iter->first);
00301                         }
00302                 }
00303         }
00304 }
00305 
00306 
00307 /*! Selects or deselects all of the check boxes */
00308 void ProbeDialog::probeTableHeaderClicked(int colNumber){
00309         if(colNumber == selectionCol){//Header above check boxes has been clicked
00310                 //First count the number of selected rows
00311                 int selectedRowCount = 0;
00312                 for(int i=0; i<probeTable->numRows(); i++){
00313                         QCheckTableItem * item = (QCheckTableItem*)probeTable->item(i, selectionCol);
00314                         if(item->isChecked())
00315                                 selectedRowCount++;
00316                 }
00317                 //If all rows are selected want to deselect rows
00318                 if(selectedRowCount == probeTable->numRows()){
00319                         for(int i=0; i<probeTable->numRows(); i++){//Deselect all rows
00320                                 QCheckTableItem * item = (QCheckTableItem*)probeTable->item(i, selectionCol);
00321                                 item->setChecked(false);
00322                         }
00323                 }
00324                 else{//Select all rows
00325                         for(int i=0; i<probeTable->numRows(); i++){
00326                                 QCheckTableItem * item = (QCheckTableItem*)probeTable->item(i, selectionCol);
00327                                 item->setChecked(true);
00328                         }
00329                 }
00330         }
00331 }
00332 
00333 
00334 //---------------------------------------------------------------------
00335 //-----------------         PRIVATE METHODS          ------------------
00336 //---------------------------------------------------------------------
00337 
00338 /*! Fills the probe type combo box with a list of probe types from the 
00339         ProbeTypes table in the NeuralNetwork database. */
00340 void ProbeDialog::fillProbeTypeCombo(){
00341         try{
00342                 Query query = networkDBInterface->getQuery();
00343                 query.reset();
00344                 query<<"SELECT TypeID, Description FROM ProbeTypes";
00345                 Result typeResult = query.store();
00346                 int counter = 0;
00347                 for(Result::iterator iter = typeResult.begin(); iter != typeResult.end(); ++iter){
00348                         Row typeRow(*iter);
00349                         unsigned short typeID = Utilities::getUShort((std::string) typeRow["TypeID"]);
00350         
00351                         //Store link between neuron type and combo index
00352                         typePositionMap[counter] = typeID;
00353         
00354                         //Add to combo box
00355                         QString typeDescription = (std::string) typeRow["Description"];
00356                         typeDescription += " [" + (std::string) typeRow["TypeID"] + "]";
00357                         probeTypeCombo->insertItem(typeDescription);
00358         
00359                         //Increase counter
00360                         ++counter;
00361                 }
00362         }
00363         catch (const BadQuery& er) {// Handle any query errors
00364                 cerr<<"ProbeDialog: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
00365                 QString errorString = "Bad query when getting probe types: \"";
00366                 errorString += er.what();
00367                 errorString += "\"";
00368                 QMessageBox::critical( 0, "Probe Type Error", errorString);
00369         }
00370         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00371                 cerr<<"ProbeDialog: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
00372                 QString errorString = "Exception thrown getting probe types: \"";
00373                 errorString += er.what();
00374                 errorString += "\"";
00375                 QMessageBox::critical( 0, "Probe Type Error", errorString);
00376         }
00377         catch(std::exception& er){// Catch-all for any other exceptions
00378                 cerr<<"ProbeDialog: STD EXCEPTION \""<<er.what()<<"\""<<endl;
00379                 QString errorString = "Exception thrown getting probe types: \"";
00380                 errorString += er.what();
00381                 errorString += "\"";
00382                 QMessageBox::critical( 0, "Probe Type Error", errorString);
00383         }
00384 }
00385 
00386 
00387 /*! Gets the description corresponding to a particular probe type. */
00388 string ProbeDialog::getDescription(unsigned int pType){
00389         try{
00390                 Query query = networkDBInterface->getQuery();
00391                 query.reset();
00392                 query<<"SELECT Description FROM ProbeTypes WHERE TypeID = "<<pType;
00393                 Result result = query.store();
00394                 
00395                 //Should be just one row for each type id
00396                 Row row(*result.begin());
00397                 return (std::string)row["Description"];
00398         }
00399         catch (const BadQuery& er) {// Handle any query errors
00400                 cerr<<"ProbeDialog: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
00401                 QString errorString = "Bad query when getting probe description: \"";
00402                 errorString += er.what();
00403                 errorString += "\"";
00404                 QMessageBox::critical( 0, "Probe Error", errorString);
00405                 return string("Unknown");
00406         }
00407         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00408                 cerr<<"ProbeDialog: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
00409                 QString errorString = "Exception thrown getting probe description: \"";
00410                 errorString += er.what();
00411                 errorString += "\"";
00412                 QMessageBox::critical( 0, "Probe Error", errorString);
00413                 return string("Unknown");
00414         }
00415 }
00416 
00417 
00418 /*! Loads a table with all the available patterns. 
00419         Enables a pattern to be assigned to a suitable neuron group before 
00420         the simulation starts*/
00421 void ProbeDialog::loadProbeTable(){
00422         //Empty table
00423         probeTable->setNumRows(0);
00424         
00425         //Load up a row for each pattern in the database
00426         try{
00427                 Query probeQuery = networkDBInterface->getQuery();
00428                 probeQuery.reset();
00429                 probeQuery<<"SELECT ProbeID, Name, Type FROM Probes";
00430                 Result result = probeQuery.store();
00431                 for(Result::iterator iter = result.begin(); iter != result.end(); ++iter){
00432                         Row row(*iter);
00433         
00434                         //Add new row to the table
00435                         int currentRow = probeTable->numRows();
00436                         probeTable->insertRows(currentRow, 1);
00437                 
00438                         //Populate row with pattern information
00439                         QCheckTableItem *checkTableItem = new QCheckTableItem( probeTable, "");
00440                         probeTable->setItem( currentRow, selectionCol, checkTableItem);
00441         
00442                         probeTable->setItem(currentRow, probeIDCol,
00443                                 new QTableItem(probeTable, QTableItem::Never, (std::string)row["ProbeID"]));//ProbeID
00444         
00445                         probeTable->setItem(currentRow, nameCol,
00446                                 new QTableItem(probeTable, QTableItem::Never, (std::string)row["Name"]));//Description
00447                 
00448                         unsigned int probeType = Utilities::getUInt((std::string)row["Type"]);
00449                         probeTable->setItem(currentRow, typeDescCol,
00450                                 new QTableItem(probeTable, QTableItem::Never, getDescription(probeType)));//Type description
00451         
00452                         probeTable->setItem(currentRow, typeCol,
00453                                 new QTableItem(probeTable, QTableItem::Never, QString::number(probeType)));//Type ID
00454                 }
00455         }
00456         catch (const EndOfResults& er) {//EndOfResults exception thrown when fetch row no longer returns anything
00457                 cout<<"ProbeDialog: No probes found"<<endl;
00458         }
00459         catch (const BadQuery& er) {// Handle any query errors
00460                 cerr<<"ProbeDialog: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
00461                 QString errorString = "Bad query when loading probes: \"";
00462                 errorString += er.what();
00463                 errorString += "\"";
00464                 QMessageBox::critical( 0, "Probe Error", errorString);
00465         }
00466         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00467                 cerr<<"ProbeDialog: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
00468                 QString errorString = "Exception thrown loading probes: \"";
00469                 errorString += er.what();
00470                 errorString += "\"";
00471                 QMessageBox::critical( 0, "Probe Error", errorString);
00472         }
00473 }
00474 
00475 
00476 /*! Removes the indicated probe from the table. */
00477 void ProbeDialog::removeProbeFromTable(unsigned int probeID){
00478         for(int i=0; i<probeTable->numRows(); i++){
00479                 unsigned int tempID = probeTable->item(i, probeIDCol)->text().toUInt();
00480                 if(tempID == probeID){
00481                         probeTable->removeRow(i);
00482                         break;
00483                 }
00484         }
00485 }
00486 
00487 
00488 

Generated on Mon Sep 3 22:29:04 2007 for SpikeStream Application by  doxygen 1.4.4