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

ArchiveWidget.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 "ArchiveWidget.h"
00025 #include "Debug.h"
00026 #include "GlobalVariables.h"
00027 #include "Utilities.h"
00028 #include "LoadArchiveDialog.h"
00029 #include "NetworkModelXmlHandler.h"
00030 #include "SpikeStreamMainWindow.h"
00031 #include "ArchiveStatisticsDialog.h"
00032 
00033 //Qt includes
00034 #include <qlayout.h>
00035 #include <qfile.h>
00036 #include <qpixmap.h>
00037 #include <qlabel.h>
00038 #include <qstring.h>
00039 #include <qgroupbox.h>
00040 #include <qxml.h>
00041 #include <qapplication.h>
00042 #include <qmessagebox.h>
00043 
00044 //Other includes
00045 #include <iostream>
00046 using namespace std;
00047 using namespace mysqlpp;
00048 
00049 
00050 /*! Constructor. */
00051 ArchiveWidget::ArchiveWidget(QWidget *parent, DBInterface *archDBInter) : QWidget(parent, "Archive Widget"){
00052         //Store references
00053         archiveDBInterface = archDBInter;
00054         spikeStrApp = SpikeStreamMainWindow::spikeStreamApplication;//Set up a short version of this reference
00055 
00056         //Initialise variables
00057         ignoreButton = false;
00058         archiveStatisticsIDCount = 0;
00059 
00060         //Set up pixmap that user clicks on to edit statistics
00061         editPixmap = new QPixmap(SpikeStreamMainWindow::workingDirectory + "/images/edit_parameters.xpm");
00062 
00063         //Set up pixmaps to control play and stop
00064         QPixmap playPixmap(SpikeStreamMainWindow::workingDirectory + "/images/play.xpm");
00065         QPixmap stepPixmap(SpikeStreamMainWindow::workingDirectory + "/images/step.xpm");
00066         QPixmap stopPixmap(SpikeStreamMainWindow::workingDirectory + "/images/stop.xpm");
00067         QPixmap rewindPixmap(SpikeStreamMainWindow::workingDirectory + "/images/rewind.xpm");
00068         QPixmap fastForwardPixmap(SpikeStreamMainWindow::workingDirectory + "/images/fast_forward.xpm");
00069 
00070         //Create archive manager to read from database and play back patterns
00071         archiveManager = new ArchiveManager(archiveDBInterface, this);
00072         connect (archiveManager, SIGNAL(stopped()), this, SLOT(archiveStopped()));
00073         connect (archiveManager, SIGNAL(archiveError(const QString&)), this, SLOT(showArchiveError(const QString&)));
00074 
00075         //Create vertical layout to organise widget
00076         QVBoxLayout *mainVerticalBox = new QVBoxLayout(this, 5, 10, "vertical1");
00077 
00078 
00079         //--------------------- ARCHIVE CONTROLS ---------------------------
00080         //Create group box for the simulation controls
00081         QGroupBox *archiveGrpBox = new QGroupBox("Controls", this);
00082 
00083         //Create a vertical box to organise layout in group box
00084         QVBoxLayout *archVerticalBox = new QVBoxLayout(archiveGrpBox, 5, 10, "vertical3");
00085         archVerticalBox->addSpacing(20);
00086 
00087         //Set up load section
00088         QHBoxLayout *archLoadBox = new QHBoxLayout();
00089         loadButton = new QPushButton("Load", archiveGrpBox);
00090         loadButton->setBaseSize(120, 30);
00091         loadButton->setMaximumSize(120, 30);
00092         loadButton->setMinimumSize(120, 30);
00093         connect (loadButton, SIGNAL(clicked()), this, SLOT(loadButtonPressed()));
00094         archLoadBox->addSpacing(10);
00095         archLoadBox->addWidget(loadButton);
00096 
00097         unloadButton = new QPushButton("Unload", archiveGrpBox);
00098         unloadButton->setBaseSize(120, 30);
00099         unloadButton->setMaximumSize(120, 30);
00100         unloadButton->setMinimumSize(120, 30);
00101         connect (unloadButton, SIGNAL(clicked()), this, SLOT(unloadArchive()));
00102         archLoadBox->addStretch(5);
00103         archLoadBox->addWidget(unloadButton);
00104         archLoadBox->addSpacing(10);
00105 
00106         archVerticalBox->addLayout(archLoadBox);
00107 
00108         //Set up display for name and date of the archive
00109         QHBoxLayout *archInfoBox = new QHBoxLayout();
00110         archInfoText = new QLineEdit("", archiveGrpBox);
00111         archInfoText->setReadOnly(true);
00112         archInfoText->setEnabled(false);
00113         archInfoBox->addSpacing(10);
00114         archInfoBox->addWidget(archInfoText);
00115         archInfoBox->addSpacing(10);
00116 
00117         archVerticalBox->addLayout(archInfoBox);
00118         archVerticalBox->addSpacing(5);
00119 
00120         //Set up transport buttons
00121         QHBoxLayout *archTransportButtonBox = new QHBoxLayout();
00122         rewindButton = new QPushButton(QIconSet(rewindPixmap), "", archiveGrpBox);
00123         rewindButton->setEnabled(false);
00124         rewindButton->setBaseSize(30, 30);
00125         rewindButton->setMaximumSize(30, 30);
00126         rewindButton->setMinimumSize(30, 30);
00127         connect (rewindButton, SIGNAL(clicked()), this, SLOT(rewindButtonPressed()));
00128         archTransportButtonBox->addSpacing(10);
00129         archTransportButtonBox->addWidget(rewindButton);
00130 
00131         playButton = new QPushButton(QIconSet(playPixmap), "", archiveGrpBox);
00132         playButton->setToggleButton(true);
00133         playButton->setEnabled(false);
00134         playButton->setBaseSize(100, 30);
00135         playButton->setMaximumSize(100, 30);
00136         playButton->setMinimumSize(100, 30);
00137         connect (playButton, SIGNAL(toggled(bool)), this, SLOT(playButtonToggled(bool)));
00138         archTransportButtonBox->addWidget(playButton);
00139 
00140         stepButton = new QPushButton(QIconSet(stepPixmap), "", archiveGrpBox);
00141         stepButton->setEnabled(false);
00142         stepButton->setBaseSize(50, 30);
00143         stepButton->setMaximumSize(50, 30);
00144         stepButton->setMinimumSize(50, 30);
00145         connect (stepButton, SIGNAL(clicked()), this, SLOT(stepButtonPressed()));
00146         archTransportButtonBox->addWidget(stepButton);
00147 
00148         fastForwardButton = new QPushButton(QIconSet(fastForwardPixmap), "", archiveGrpBox);
00149         fastForwardButton->setToggleButton(true);
00150         fastForwardButton->setEnabled(false);
00151         fastForwardButton->setBaseSize(30, 30);
00152         fastForwardButton->setMaximumSize(30, 30);
00153         fastForwardButton->setMinimumSize(30, 30);
00154         connect (fastForwardButton, SIGNAL(toggled(bool)), this, SLOT(fastForwardButtonToggled(bool)));
00155         archTransportButtonBox->addWidget(fastForwardButton);
00156         archTransportButtonBox->addStretch(5);
00157 
00158         stopButton = new QPushButton(QIconSet(stopPixmap), "", archiveGrpBox);
00159         stopButton->setEnabled(false);
00160         stopButton->setBaseSize(50, 30);
00161         stopButton->setMaximumSize(50, 30);
00162         stopButton->setMinimumSize(50, 30);
00163         connect (stopButton, SIGNAL(clicked()), this, SLOT(stopButtonPressed()));
00164         archTransportButtonBox->addWidget(stopButton);
00165         archTransportButtonBox->addSpacing(10);
00166 
00167         archVerticalBox->addLayout(archTransportButtonBox);
00168         archVerticalBox->addSpacing(5);
00169 
00170         QHBoxLayout *archFrameRateBox = new QHBoxLayout();
00171         archFrameRateBox->addSpacing(10);
00172         frameRateLabel = new QLabel("Frames per second", archiveGrpBox);
00173         frameRateLabel->setEnabled(false);
00174         archFrameRateBox->addWidget(frameRateLabel);
00175         frameRateCombo = new QComboBox(archiveGrpBox);
00176         frameRateCombo->setEnabled(false);
00177         frameRateCombo->insertItem("1");        
00178         frameRateCombo->insertItem("5");
00179         frameRateCombo->insertItem("10");
00180         frameRateCombo->insertItem("15");
00181         frameRateCombo->insertItem("20");
00182         frameRateCombo->insertItem("25");
00183         connect(frameRateCombo, SIGNAL(activated(int)), this, SLOT(frameRateComboChanged(int)));
00184         archFrameRateBox->addWidget(frameRateCombo);
00185         archFrameRateBox->addStretch(5);
00186 
00187         archVerticalBox->addLayout(archFrameRateBox);
00188         archVerticalBox->addSpacing(20);
00189 
00190         //Add Archive box to layout. Need an extra box to make it fit nicely
00191         QHBoxLayout *archHBox = new QHBoxLayout();
00192         archHBox->addWidget(archiveGrpBox);
00193         archHBox->addStretch(5);
00194         mainVerticalBox->addLayout(archHBox);
00195         mainVerticalBox->addSpacing(5);
00196 
00197         //----------------------- ARCHIVE STATISTICS -----------------------------
00198         //Create group box for the simulation controls
00199         statsGrpBox = new QGroupBox("Statistics", this);
00200 
00201         //Create a vertical box to organise layout in group box
00202         QVBoxLayout *statsVerticalBox = new QVBoxLayout(statsGrpBox, 5, 10, "vertical3");
00203         statsVerticalBox->addSpacing(20);
00204 
00205         //Add button for creating a statistical monitor
00206         QHBoxLayout* statsButtBox = new QHBoxLayout();
00207         QPushButton *addStatsButton = new QPushButton("Add Statistics Monitor", statsGrpBox);
00208         addStatsButton->setBaseSize(170, 30);
00209         addStatsButton->setMaximumSize(170, 30);
00210         addStatsButton->setMinimumSize(170, 30);
00211         connect(addStatsButton, SIGNAL(clicked()), this, SLOT(addStatsButtonClicked()));
00212         statsButtBox->addSpacing(10);
00213         statsButtBox->addWidget(addStatsButton);
00214 
00215         //Add button for deleting statistical monitor(s)
00216         deleteStatsButton = new QPushButton("Delete Statistics Monitor", statsGrpBox);
00217         deleteStatsButton->setBaseSize(170, 30);
00218         deleteStatsButton->setMaximumSize(170, 30);
00219         deleteStatsButton->setMinimumSize(170, 30);
00220         connect(deleteStatsButton, SIGNAL(clicked()), this, SLOT(deleteStatsButtonClicked()));
00221         statsButtBox->addWidget(deleteStatsButton);
00222 
00223         QPushButton* viewModelButton = new QPushButton("View Network Model", statsGrpBox);
00224         viewModelButton->setBaseSize(170, 30);
00225         viewModelButton->setMaximumSize(170, 30);
00226         viewModelButton->setMinimumSize(170, 30);
00227         connect(viewModelButton, SIGNAL(clicked()), this, SLOT(viewModelButtonClicked()));
00228         statsButtBox->addWidget(viewModelButton);
00229 
00230         statsButtBox->addStretch(5);
00231         statsVerticalBox->addLayout(statsButtBox);
00232 
00233         //Set up table
00234         QHBoxLayout* statsTableBox = new QHBoxLayout();
00235         statsTableBox->addSpacing(10);
00236         statsTable = new QTable(0, 6, statsGrpBox);
00237         statsTable->setShowGrid(false);
00238         statsTable->setSorting(false);
00239         statsTable->setSelectionMode(QTable::NoSelection);
00240         statsTable->verticalHeader()->hide();
00241         statsTable->setLeftMargin(0);
00242         QHeader* statsTableHeader = statsTable->horizontalHeader();
00243         checkBxCol = 0;
00244         statsTableHeader->setLabel( checkBxCol, "" );
00245         statsTable->setColumnWidth( checkBxCol, 20);
00246         editCol = 1;
00247         statsTableHeader->setLabel( editCol, "Edit" );
00248         statsTable->setColumnWidth( editCol, 30);
00249         descCol = 2;
00250         statsTableHeader->setLabel( descCol, "Description");
00251         statsTable->setColumnWidth( descCol, 150);
00252         neursPerTimeStepCol = 3;
00253         statsTableHeader->setLabel( neursPerTimeStepCol, "Neurons Firing Per Time Step");
00254         statsTable->setColumnWidth( neursPerTimeStepCol, 200);
00255         totalNeursCol = 4;
00256         statsTableHeader->setLabel( totalNeursCol, "Neurons Fired Total");
00257         statsTable->setColumnWidth( totalNeursCol, 130);
00258         idCol = 5;
00259         statsTableHeader->setLabel( idCol, "ID");
00260         statsTable->setColumnWidth( idCol, 20);
00261         statsTable->setMinimumSize(600, 200);
00262         statsTableBox->addWidget(statsTable);
00263         statsTableBox->addSpacing(10);
00264         statsTableBox->addStretch(5);
00265         statsVerticalBox->addLayout(statsTableBox);
00266 
00267         //Listen for clicks on the edit pixmap
00268         connect (statsTable, SIGNAL(clicked(int, int, int, const QPoint &)), this, SLOT(statsTableClicked(int, int, int, const QPoint &)));
00269 
00270         //Add number of spikes/ neurons information
00271         QHBoxLayout *spikeNeurCountLayout = new QHBoxLayout();
00272         spikeNeurCountLayout->addSpacing(10);
00273         spikeNeurCountLabel_1 = new QLabel("Number of firing neurons ", statsGrpBox);
00274         spikeNeurCountLayout->addWidget(spikeNeurCountLabel_1);
00275         spikeNeurCountLabel_2 = new QLabel("", statsGrpBox);
00276         spikeNeurCountLayout->addWidget(spikeNeurCountLabel_2);
00277         spikeNeurCountLayout->addStretch(5);
00278         statsVerticalBox->addLayout(spikeNeurCountLayout);
00279 
00280         //Add total number of spikes information
00281         QHBoxLayout *spikeNeurTotalLayout = new QHBoxLayout();
00282         spikeNeurTotalLayout->addSpacing(10);
00283         spikeNeurTotalLabel_1 = new QLabel("Total firing neuron count ", statsGrpBox);
00284         spikeNeurTotalLayout->addWidget(spikeNeurTotalLabel_1);
00285         spikeNeurTotalLabel_2 = new QLabel("", statsGrpBox);
00286         spikeNeurTotalLayout->addWidget(spikeNeurTotalLabel_2);
00287         spikeNeurTotalLayout->addStretch(5);
00288         statsVerticalBox->addLayout(spikeNeurTotalLayout);
00289         statsVerticalBox->addSpacing(10);
00290 
00291         statsVerticalBox->addStretch(5);
00292 
00293         //Add Statistics box to layout. Need an extra box to make it fit nicely
00294         statsGrpBox->setEnabled(false);
00295         QHBoxLayout *statsHBox = new QHBoxLayout();
00296         statsHBox->addWidget(statsGrpBox);
00297         statsHBox->addStretch(5);
00298         mainVerticalBox->addLayout(statsHBox);
00299         mainVerticalBox->addStretch(5);
00300 
00301         //Set up a dialog to view the model
00302         viewModelDialog = new ViewModelDialog(this, &networkModelString);
00303 
00304 
00305         //----------------------- DOCK BUTTONS ------------------------------------
00306         QHBoxLayout *dockButtonBox = new QHBoxLayout();
00307         dockAllButton = new QPushButton("Dock All", this);
00308         dockAllButton->setEnabled(false);
00309         connect(dockAllButton, SIGNAL(clicked()), this, SLOT(dockAllButtonClicked()));
00310         dockButtonBox->addWidget(dockAllButton);
00311         undockAllButton = new QPushButton("Undock All", this);
00312         undockAllButton->setEnabled(false);
00313         connect(undockAllButton, SIGNAL(clicked()), this, SLOT(undockAllButtonClicked()));
00314         dockButtonBox->addWidget(undockAllButton);
00315         dockButtonBox->addStretch(5);
00316 
00317         mainVerticalBox->addLayout(dockButtonBox);
00318 }
00319 
00320 
00321 /*! Destructor. */
00322 ArchiveWidget::~ArchiveWidget(){
00323         #ifdef MEMORY_DEBUG
00324                 cout<<"DESTROYING ARCHIVE WIDGET"<<endl;
00325         #endif//MEMORY_DEBUG
00326         
00327         //Clean up any memory on the heap if we have an archive loaded.
00328         if(archiveManager->archiveIsLoaded())
00329                 for(vector<NeuronGroup*>::iterator iter = neuronGrpVector.begin(); iter != neuronGrpVector.end(); ++iter){
00330                         delete *iter;
00331         }
00332         delete archiveManager;
00333 }
00334 
00335 
00336 //-----------------------------------------------------------------------------
00337 //------------------------- PUBLIC METHODS ------------------------------------
00338 //-----------------------------------------------------------------------------
00339 
00340 /*! Called to set controls appropriately when the archive has stopped playing. */
00341 void ArchiveWidget::archiveStopped(){
00342         if(playButton->isOn())
00343                 playButton->toggle();
00344         if(fastForwardButton->isOn())
00345                 fastForwardButton->toggle();
00346 }
00347 
00348 
00349 /*! Used when deleting an archive. This interferes with the resUse of the
00350         archiveManager, which has to be deleted and reinitialised after the deletion
00351         of the archive is complete. */
00352 void ArchiveWidget::freezeArchive(){
00353         archiveManager->freezeArchive();
00354 }
00355 
00356 
00357 /*! Returns a reference to the archive manager that handles the archive data. */
00358 ArchiveManager* ArchiveWidget::getArchiveManager(){
00359         return archiveManager;
00360 }
00361 
00362 
00363 /*! Hides the windows that are currently visible.
00364 FIXME NEED TO TRACK WHICH ARE CURRENTLY OPEN. */
00365 void ArchiveWidget::hideOpenWindows(){
00366         monitorArea->dockMonitorWindows();
00367         viewModelDialog->hide();
00368 }
00369 
00370 
00371 /*! Passes a reference to the monitor area used to display archive. */
00372 void ArchiveWidget::setMonitorArea(MonitorArea* monArea){
00373         monitorArea = monArea;
00374 }
00375 
00376 /*! Shows the windows that are currently visible.
00377 FIXME NEED TO TRACK WHICH ARE CURRENTLY OPEN. */
00378 void ArchiveWidget::showOpenWindows(){
00379 
00380 }
00381 
00382 
00383 /*! Used for displaying statistics about archive as it plays back. */
00384 void ArchiveWidget::setSpikeCount(unsigned int spikeCount){
00385         spikeStrApp->lock();
00386         spikeNeurCountLabel_2->setText(QString::number(spikeCount));
00387         spikeStrApp->unlock();
00388 }
00389 
00390 
00391 /*! Used for displaying statistics about archive as it is played back. */
00392 void ArchiveWidget::setSpikeTotal(unsigned int spikeTotal){
00393         spikeStrApp->lock();
00394         spikeNeurTotalLabel_2->setText(QString::number(spikeTotal));
00395         spikeStrApp->unlock();
00396 }
00397 
00398 
00399 /*! Re-initialises the archive from the values stored in the archive manager. 
00400         Only does this if the archive has not been deleted, otherwise the archive
00401         is unloaded. */
00402 void ArchiveWidget::unfreezeArchive(){
00403         //If an archive has been loaded check to see if it still exists
00404         if(archiveManager->archiveIsLoaded()){
00405                 try{
00406                         Query query = archiveDBInterface->getQuery();
00407                         query.reset();
00408                         query<<"SELECT * FROM NetworkModels WHERE StartTime = UNIX_TIMESTAMP(\'"<<archiveManager->getSimulationStartDateTime()<<"\')";
00409                         Result results = query.store();
00410                         if(results.size() != 1){//Current archive has been deleted
00411                                 //Unload archive
00412                                 unloadArchive();
00413                         }
00414                         else{//Current archive still exists, so unfreeze archive
00415                                 archiveManager->unfreezeArchive();
00416                         }
00417                 }
00418                 catch (const BadQuery& er) {// Handle any query errors
00419                         cerr<<"ArchiveWidget: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
00420                         QString errorString = "Bad query when unfreezing archive: \"";
00421                         errorString += er.what();
00422                         errorString += "\"";
00423                         QMessageBox::critical( 0, "Archive Error", errorString);
00424                         return;
00425                 }
00426                 catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00427                         cerr<<"ArchiveWidget: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
00428                         QString errorString = "Exception thrown when unfreezing archive: \"";
00429                         errorString += er.what();
00430                         errorString += "\"";
00431                         QMessageBox::critical( 0, "Archive Error", errorString);
00432                         return;
00433         }
00434         }
00435 }
00436 
00437 
00438 /*! Unloads the current archive. */
00439 void ArchiveWidget::unloadArchive(){
00440         if(archiveManager->isRunning()){
00441                 QMessageBox::critical( 0, "Archive Error", "Archive cannot be unloaded whilst it is being played back.");
00442                 return;
00443         }
00444 
00445         //Instruct archive manager to unload the archive
00446         archiveManager->unloadArchive();
00447 
00448         //Reset monitor area
00449         monitorArea->resetMonitorWindows();
00450 
00451         //Disable the transport controls
00452         enableArchiveControls(false);
00453 
00454         //Reset statistics
00455         spikeNeurCountLabel_2->setText("0");
00456         spikeNeurTotalLabel_2->setText("0");
00457         statsTable->setNumRows(0);
00458         archiveStatisticsVector.clear();
00459 
00460         //Reset and hide the view model dialog
00461         networkModelString = "";
00462         viewModelDialog->reloadText();
00463         viewModelDialog->hide();
00464 
00465         //Set the text descrbing the archive
00466         archInfoText->setText("");
00467 
00468         //Delete neuron groups stored in neuron group vector
00469         for(vector<NeuronGroup*>::iterator iter = neuronGrpVector.begin(); iter != neuronGrpVector.end(); ++iter){
00470                 delete *iter;
00471         }
00472         neuronGrpVector.clear();
00473 }
00474 
00475 
00476 //-----------------------------------------------------------------------------
00477 //---------------------------- SLOTS ------------------------------------------
00478 //-----------------------------------------------------------------------------
00479 
00480 /*! Adds a statistical monitor to the statistics table. */
00481 void ArchiveWidget::addStatsButtonClicked(){
00482         if(!archiveManager->archiveIsLoaded()){//Double check that the neuron group vector has sensible values
00483                 cerr<<"ArchiveWidget: NO ARCHIVE LOADED"<<endl;
00484                 return;
00485         }
00486 
00487         //Use archive statistics dialog to get information about the statistics
00488         ArchiveStatisticsDialog statsMonDlg(this, neuronGrpVector);
00489         if(statsMonDlg.exec() == QDialog::Accepted){
00490                 //Extract the information about the statistical properties to be monitored
00491                 ArchiveStatisticsHolder* archStatHolder = statsMonDlg.getArchiveStatistics();
00492                 addArchiveStatistics(archStatHolder);
00493         }
00494 }
00495 
00496 
00497 /*! Called when an  archive name is changed.
00498         If the currently loaded archive's name has been changed, it is updated. */
00499 void ArchiveWidget::archiveNameChanged(QString timeStamp, QString newName){
00500         cout<<"time stamp = \""<<timeStamp<<"\" new name = "<<newName<<" get date stuff \""<<getDate(archInfoText->text())<<"\""<<endl;
00501         if(archiveManager->archiveIsLoaded()){
00502                 if(getDate(archInfoText->text()) == timeStamp)
00503                         archInfoText->setText(newName + " [ " + timeStamp + " ]");
00504         }
00505 }
00506 
00507 
00508 /*! Removes statistical monitor(s) from the statistics table. */
00509 void ArchiveWidget::deleteStatsButtonClicked(){
00510         //Keep a record of whether we have deleted any
00511         bool archStatDeleted = false;
00512 
00513         //Work through table
00514         for(int i=0; i<statsTable->numRows(); ++i){
00515                 QCheckTableItem * item = (QCheckTableItem*)statsTable->item(i, checkBxCol);
00516                         if(item->isChecked()){
00517                                 //Get the ID of the selected statistic
00518                                 unsigned int archStatID;
00519                                 try{
00520                                         archStatID = Utilities::getUInt(statsTable->item(i, idCol)->text().ascii());
00521                                 }
00522                                 catch(std::exception& er){// Catch-all for all std exceptions
00523                                         cerr<<"ArchiveWidget: STD EXCEPTION \""<<er.what()<<"\""<<endl;
00524                                         QString errorString = "Exception thrown getting neuron group id: \"";
00525                                         errorString += er.what();
00526                                         errorString += "\"";
00527                                         QMessageBox::critical( 0, "NeuronGrpID Error", errorString);
00528                                         return;
00529                                 }
00530                                 
00531                                 //Delete the archive statistics
00532                                 deleteArchiveStatistics(archStatID);
00533                                 archStatDeleted = true;
00534                         }
00535         }
00536 
00537         //Reload the archive statistics table if we have deleted anything
00538         if(archStatDeleted)
00539                 loadStatisticsTable();
00540 }
00541 
00542 
00543 /*! Docks all monitor windows into the Monitor Area. */
00544 void ArchiveWidget::dockAllButtonClicked(){
00545         monitorArea->dockMonitorWindows();
00546 }
00547 
00548 
00549 /*! Sets fast forwarding on or off. */
00550 void ArchiveWidget::fastForwardButtonToggled(bool on){
00551         if(ignoreButton){
00552                 ignoreButton = false;
00553                 return;
00554         }
00555         if(on){
00556                 if(playButton->isOn()){
00557                         ignoreButton = true;
00558                         playButton->toggle();
00559                 }
00560                 loadButton->setEnabled(false);
00561                 deleteStatsButton->setEnabled(false);//Not a good idea to delete statistics whilst it is playing
00562                 unloadButton->setEnabled(false);
00563                 archiveManager->fastForwardArchive();
00564         }
00565         else{
00566                 archiveManager->stopArchive();
00567                 loadButton->setEnabled(true);
00568                 deleteStatsButton->setEnabled(true);
00569                 unloadButton->setEnabled(true);
00570         }
00571 }
00572 
00573 
00574 /*! Changes the frame rate at which the archive is played back. */
00575 void ArchiveWidget::frameRateComboChanged(int){
00576         try{
00577                 unsigned int frameRate = Utilities::getUInt(frameRateCombo->currentText().ascii());
00578                 archiveManager->setFrameRate(frameRate);
00579         }
00580         catch(std::exception& er){// Catch-all for any other exceptions
00581                 cerr<<"ArchiveWidget: STD EXCEPTION \""<<er.what()<<"\""<<endl;
00582                 QString errorString = "Exception thrown setting frame rate: \"";
00583                 errorString += er.what();
00584                 errorString += "\"";
00585                 QMessageBox::critical( 0, "Frame Rate Error", errorString);
00586         }
00587 }
00588 
00589 
00590 /*! Displays load archive dialog. */
00591 void ArchiveWidget::loadButtonPressed(){
00592         //Create load archive dialog
00593         LoadArchiveDialog *loadArchiveDialog = new LoadArchiveDialog(this, archiveDBInterface);
00594         connect (loadArchiveDialog, SIGNAL (deleteArchiveStarted()), this, SLOT (freezeArchive()));
00595         connect (loadArchiveDialog, SIGNAL (deleteArchiveFinished()), this, SLOT (unfreezeArchive()));
00596         connect (loadArchiveDialog, SIGNAL (archiveNameChanged(QString, QString)), this, SLOT (archiveNameChanged(QString, QString)));
00597 
00598         //Show load archive dialog
00599         if (loadArchiveDialog->exec() == QDialog::Accepted ) {//Load the archive
00600                 QString archiveString = loadArchiveDialog->getArchiveString();
00601                 
00602                 if(archiveString != ""){//Check to see something has been selected
00603                         /* Load up archive into monitor area, which 
00604                                 passes the necessary classes and data to the archive manager*/
00605                         loadArchive(archiveString);
00606                 }
00607         }
00608         //Free memory
00609         delete loadArchiveDialog;
00610 }
00611 
00612 
00613 /*! Plays or stops archive. */
00614 void ArchiveWidget::playButtonToggled(bool on){
00615         if(ignoreButton){
00616                 ignoreButton = false;
00617                 return;
00618         }
00619         if(on){
00620                 archiveManager->playArchive();
00621                 loadButton->setEnabled(false);//To prevent conflict with load dialog
00622                 deleteStatsButton->setEnabled(false);//Not a good idea to delete statistics whilst it is playing
00623                 unloadButton->setEnabled(false);
00624                 if(fastForwardButton->isOn()){
00625                         ignoreButton = true;
00626                         fastForwardButton->toggle();
00627                 }
00628         }
00629         else{
00630                 archiveManager->stopArchive();
00631                 loadButton->setEnabled(true);
00632                 deleteStatsButton->setEnabled(true);
00633                 unloadButton->setEnabled(true);
00634         }
00635 }
00636 
00637 
00638 /*! Rewinds archive back to beginning. */
00639 void ArchiveWidget::rewindButtonPressed(){
00640         try{
00641                 //Rewind archive manager
00642                 archiveManager->rewindArchive();
00643 
00644                 //Rewind network monitors
00645                 monitorArea->rewindNetworkMonitors();
00646 
00647                 //Reload statistics table
00648                 updateStatisticsTable();
00649 
00650                 //Reset statistics totals
00651                 spikeNeurCountLabel_2->setText("0");
00652                 spikeNeurTotalLabel_2->setText("0");
00653         }
00654     catch (const BadQuery& er) {// Handle any query errors
00655                 cerr<<"ArchiveWidget: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
00656                 QString errorString = "Bad query when rewinding archive: \"";
00657                 errorString += er.what();
00658                 errorString += "\"";
00659                 QMessageBox::critical( 0, "Archive Error", errorString);
00660                 return;
00661     }
00662     catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00663         cerr<<"ArchiveWidget: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
00664                 QString errorString = "Exception thrown when rewinding archive: \"";
00665                 errorString += er.what();
00666                 errorString += "\"";
00667                 QMessageBox::critical( 0, "Archive Error", errorString);
00668                 return;
00669     }
00670         if(playButton->isOn())
00671                 playButton->toggle();
00672 }
00673 
00674 
00675 /*! Steps the archive forward one time step. */
00676 void ArchiveWidget::stepButtonPressed(){
00677         if(playButton->isOn()){
00678                 ignoreButton = true;
00679                 playButton->toggle();
00680                 loadButton->setEnabled(true);
00681                 unloadButton->setEnabled(true);
00682         }
00683         if(fastForwardButton->isOn()){
00684                 fastForwardButton->toggle();
00685         }
00686         archiveManager->stepArchive();
00687 }
00688 
00689 
00690 /*! Displays an error generated by the archive manager and stops playback. */
00691 void ArchiveWidget::showArchiveError(const QString& message){
00692         archiveStopped();
00693         QMessageBox::critical( 0, "Archive Error", message);
00694 }
00695 
00696 
00697 void ArchiveWidget::statsTableClicked(int row, int col, int, const QPoint &){
00698         if(col == editCol){
00699                 //Get the id of this statistic. The rows match the positions in the vector
00700                 unsigned int archStatID = archiveStatisticsVector[row]->ID;
00701 
00702                 //Launch a dialog with the information from this archive statistic
00703                 ArchiveStatisticsDialog statsMonDlg(this, neuronGrpVector, archiveStatisticsVector[row]);
00704 
00705                 /* If the dialog is accepted delete the old archive statistics and create
00706                         a new one with the same id. */
00707                 if(statsMonDlg.exec() == QDialog::Accepted){
00708                         //Extract the information about the statistical properties to be monitored
00709                         ArchiveStatisticsHolder* archStatHolder = statsMonDlg.getArchiveStatistics();
00710 
00711                         //Delete the old archive statistics with this id
00712                         deleteArchiveStatistics(archStatID);
00713 
00714                         //Add the new one with the same id as before
00715                         addArchiveStatistics(archStatHolder, archStatID);
00716                 }
00717         }
00718 }
00719 
00720 /*! Stops the archive if it is running. */
00721 void ArchiveWidget::stopButtonPressed(){
00722         archiveManager->stopArchive();
00723         loadButton->setEnabled(true);
00724         unloadButton->setEnabled(true);
00725         if(playButton->isOn()){
00726                 playButton->toggle();
00727         }
00728         if(fastForwardButton->isOn()){
00729                 fastForwardButton->toggle();
00730         }
00731 }
00732 
00733 
00734 /*! Undocks all monitor windows. */
00735 void ArchiveWidget::undockAllButtonClicked(){
00736         monitorArea->undockMonitorWindows();
00737 }
00738 
00739 
00740 /*! Called when the archive statistics counts have been changed. */
00741 void ArchiveWidget::updateStatisticsTable(){
00742         //Reload the firing neuron count and firing neuron total for each statistic
00743         int rowCount = 0;
00744         for(vector<ArchiveStatisticsHolder*>::iterator iter = archiveStatisticsVector.begin(); iter != archiveStatisticsVector.end(); ++iter){
00745                 statsTable->setItem(rowCount, neursPerTimeStepCol, new QTableItem(statsTable, QTableItem::Never, QString::number((*iter)->firingNeuronCount)));
00746                 statsTable->setItem(rowCount, totalNeursCol, new QTableItem(statsTable, QTableItem::Never, QString::number((*iter)->firingNeuronTotal)));
00747                 ++rowCount;
00748         }
00749 }
00750 
00751 
00752 /*! Called when the view model button is clicked and displays a non-modal dialog
00753         containing the view model. */
00754 void ArchiveWidget::viewModelButtonClicked(){
00755         viewModelDialog->show();
00756 }
00757 
00758 
00759 //----------------------------------------------------------------------
00760 //----------------------- PRIVATE METHODS ------------------------------
00761 //----------------------------------------------------------------------
00762 
00763 /*! Adds archive statistics to this widget and elsewhere. */
00764 void ArchiveWidget::addArchiveStatistics(ArchiveStatisticsHolder* archStatHolder){
00765         /* Give each archive statistic and the archive statistics holder a unique 
00766                 id to make it easier to delete. The archive statistics are stored as 
00767                 a group in an archive statistics holder, so give the same id
00768                 to each archive statistic in the group. */
00769         archStatHolder->ID = archiveStatisticsIDCount;
00770         for(vector<ArchiveStatistic*>::iterator iter = archStatHolder->archStatVector.begin(); iter != archStatHolder->archStatVector.end(); ++iter){
00771                 (*iter)->setID(archiveStatisticsIDCount);
00772         }
00773 
00774         //Increase the id that will be allocated to the next group
00775         ++archiveStatisticsIDCount;
00776 
00777         //Store the archStatHolder
00778         archiveStatisticsVector.push_back(archStatHolder);
00779         archiveManager->addArchiveStatistics(archStatHolder);
00780 
00781         //Reload the table
00782         loadStatisticsTable();
00783 }
00784 
00785 
00786 /*! Adds archive statistics to this widget and elsewhere using the supplied id. */
00787 void ArchiveWidget::addArchiveStatistics(ArchiveStatisticsHolder* archStatHolder, unsigned int archStatID){
00788         /* Give each archive statistic and the archive statistics holder a unique 
00789                 id to make it easier to delete. The archive statistics are stored as 
00790                 a group in an archive statistics holder, so give the same id
00791                 to each archive statistic in the group. */
00792         archStatHolder->ID = archStatID;
00793         for(vector<ArchiveStatistic*>::iterator iter = archStatHolder->archStatVector.begin(); iter != archStatHolder->archStatVector.end(); ++iter){
00794                 (*iter)->setID(archStatID);
00795         }
00796 
00797         //Store the archStatHolder
00798         archiveStatisticsVector.push_back(archStatHolder);
00799         archiveManager->addArchiveStatistics(archStatHolder);
00800 
00801         //Reload the table
00802         loadStatisticsTable();
00803 }
00804 
00805 
00806 /*! Adds archive statistics to this widget and elsewhere. */
00807 void ArchiveWidget::deleteArchiveStatistics(unsigned int archStatID){
00808         //Remove the reference to this ArchiveStatistic from the other classes
00809         archiveManager->deleteArchiveStatistics(archStatID);
00810 
00811         //Work through the vector and delete the ArchiveStatistic with this ID
00812         for(vector<ArchiveStatisticsHolder*>::iterator iter = archiveStatisticsVector.begin(); iter != archiveStatisticsVector.end(); ++iter){
00813                 if((*iter)->ID == archStatID){
00814                         iter = archiveStatisticsVector.erase(iter);//iter now points to the element after the erased element
00815                         if(iter == archiveStatisticsVector.end())//Don't want to increase iter again if we are at the end of the vector.
00816                                 break;
00817                 }
00818         }
00819 }
00820 
00821 
00822 /*! Enables or disables the archive controls. */
00823 void ArchiveWidget::enableArchiveControls(bool enable){
00824         if(enable){
00825                 archInfoText->setEnabled(true);
00826                 rewindButton->setEnabled(true);
00827                 playButton->setEnabled(true);
00828                 stepButton->setEnabled(true);
00829                 fastForwardButton->setEnabled(true);
00830                 stopButton->setEnabled(true);
00831                 frameRateLabel->setEnabled(true);
00832                 frameRateCombo->setEnabled(true);
00833                 dockAllButton->setEnabled(true);
00834                 undockAllButton->setEnabled(true);
00835                 statsGrpBox->setEnabled(true);
00836         }
00837         else{
00838                 archInfoText->setEnabled(false);
00839                 rewindButton->setEnabled(false);
00840                 playButton->setEnabled(false);
00841                 stepButton->setEnabled(false);
00842                 fastForwardButton->setEnabled(false);
00843                 stopButton->setEnabled(false);
00844                 frameRateLabel->setEnabled(false);
00845                 frameRateCombo->setEnabled(false);
00846                 dockAllButton->setEnabled(false);
00847                 undockAllButton->setEnabled(false);
00848                 statsGrpBox->setEnabled(false);
00849         }
00850 }
00851 
00852 
00853 /*! Extracts the date of the archive from the string. */
00854 QString ArchiveWidget::getDate(QString archiveString){
00855         archiveString = archiveString.section('[', 1, 1, QString::SectionSkipEmpty);
00856         archiveString = archiveString.section(']', 0, 0, QString::SectionSkipEmpty);
00857         return archiveString.stripWhiteSpace();
00858 }
00859 
00860 
00861 /*! Sets up the GUI to play back an archive. */
00862 void ArchiveWidget::loadArchive(QString archiveString){
00863         try{
00864                 //Set up the archive manager
00865                 archiveManager->loadArchive(getDate(archiveString));
00866                 archiveManager->setFrameRate(Utilities::getDouble(frameRateCombo->currentText().ascii()));
00867         
00868                 //Reset monitor area
00869                 monitorArea->resetMonitorWindows();
00870         
00871                 //Get XML string from database with appropriate parameters
00872                 Query archiveQuery = archiveDBInterface->getQuery();
00873                 archiveQuery.reset();
00874                 archiveQuery<<"SELECT NeuronGroups, ArchiveType FROM NetworkModels WHERE StartTime = UNIX_TIMESTAMP(\""<<getDate(archiveString)<<"\")";
00875                 Result results = archiveQuery.store();
00876                 Row row(*results.begin());//Should only be one row
00877 
00878                 //Set up labels for count and total spikes
00879                 unsigned int archiveType = Utilities::getUInt((std::string)row["ArchiveType"]);
00880                 if(archiveType == FIRING_NEURON_ARCHIVE){
00881                         spikeNeurCountLabel_1->setText("Number of firing neurons ");
00882                         spikeNeurTotalLabel_1->setText("Total firing neuron count ");
00883                 }
00884                 else if(archiveType == SPIKE_ARCHIVE){
00885                         spikeNeurCountLabel_1->setText("Number of spikes ");
00886                         spikeNeurTotalLabel_1->setText("Total spike count ");
00887                 }
00888                 else{
00889                         cerr<<"ArchiveWidget: ARCHIVE TYPE NOT RECOGNIZED!"<<endl;
00890                         QMessageBox::critical( 0, "Archive Error", "Archive type not recognized");
00891                         archiveManager->unloadArchive();
00892                         monitorArea->resetMonitorWindows();
00893                         return;
00894                 }
00895         
00896                 //Process XML
00897                 QString tmpNwModelStr((std::string)row["NeuronGroups"]);
00898         
00899                 /* Parse XML file. 
00900                         The nwModelXmlHandler will receive events from the parsing and use 
00901                         the information to set up the monitor area */
00902                 QXmlInputSource xmlInput;
00903                 xmlInput.setData(tmpNwModelStr);
00904                 NetworkModelXmlHandler nwModelXmlHandler(monitorArea);
00905                 QXmlSimpleReader reader;
00906                 reader.setContentHandler(&nwModelXmlHandler);
00907                 reader.setErrorHandler(&nwModelXmlHandler);
00908                 reader.parse(xmlInput);
00909                 if(nwModelXmlHandler.getParseError()){
00910                         cerr<<"ArchiveWidget: ERROR OCCURRED DURING PARSING \""<<nwModelXmlHandler.getParseErrorString()<<"\""<<endl;
00911                         QString errorString = "Error encountered whilst parsing XML Network Model: \"";
00912                         errorString += nwModelXmlHandler.getParseErrorString();
00913                         errorString += "\"";
00914                         QMessageBox::critical( 0, "Archive Error", errorString);
00915                         archiveManager->unloadArchive();
00916                         monitorArea->resetMonitorWindows();
00917                         return;
00918                 }
00919 
00920                 /* Store the neuron groups in the model. The neuron groups are created on the heap so this
00921                         operation should copy across the addresses. We will have to delete these when the archive
00922                         is unloaded.*/
00923                 neuronGrpVector = nwModelXmlHandler.getNeuronGrpVector();
00924 
00925                 /* Extract the formatted XML string of the network model and reload this into 
00926                         the view model dialog. */
00927                 networkModelString = nwModelXmlHandler.getNetworkModelString();
00928                 viewModelDialog->reloadText();
00929         
00930                 /* Connect the network monitors that have been created with the
00931                         archive manager and networkDataXmlHandler that are going to 
00932                         update them */
00933                 monitorArea->connectToManager();
00934         
00935                 /* Undock the monitor windows. */
00936                 monitorArea->undockMonitorWindows();
00937         
00938                 // Enable the transport controls
00939                 enableArchiveControls(true);
00940         
00941                 //Reset statistics
00942                 spikeNeurCountLabel_2->setText("0");
00943                 spikeNeurTotalLabel_2->setText("0");
00944                 statsTable->setNumRows(0);
00945         
00946                 //Set the text descrbing the archive
00947                 archInfoText->setText(archiveString);
00948         }
00949     catch (const BadQuery& er) {// Handle any query errors
00950                 cerr<<"ArchiveWidget: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
00951                 QString errorString = "Bad query when loading archive: \"";
00952                 errorString += er.what();
00953                 errorString += "\"";
00954                 QMessageBox::critical( 0, "Archive Error", errorString);
00955                 archiveManager->unloadArchive();
00956                 monitorArea->resetMonitorWindows();
00957     }
00958     catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00959         cerr<<"ArchiveWidget: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
00960                 QString errorString = "Exception thrown when loading archive: \"";
00961                 errorString += er.what();
00962                 errorString += "\"";
00963                 QMessageBox::critical( 0, "Archive Error", errorString);
00964                 archiveManager->unloadArchive();
00965                 monitorArea->resetMonitorWindows();
00966     }
00967     catch (const std::exception& er) {// Catch-all for any std exceptions
00968         cerr<<"ArchiveWidget: EXCEPTION \""<<er.what()<<"\""<<endl;
00969                 QString errorString = "Exception thrown when loading archive: \"";
00970                 errorString += er.what();
00971                 errorString += "\"";
00972                 QMessageBox::critical( 0, "Archive Error", errorString);
00973                 archiveManager->unloadArchive();
00974                 monitorArea->resetMonitorWindows();
00975     }
00976 }
00977 
00978 
00979 /*! Loads up the statistics table from the archiveStatisticsVector. */
00980 void ArchiveWidget::loadStatisticsTable(){
00981         //Reset the table
00982         statsTable->setNumRows(0);
00983         int currentRowNumber = 0;
00984 
00985         //Load up the archive statistics
00986         for(vector<ArchiveStatisticsHolder*>::iterator iter = archiveStatisticsVector.begin(); iter != archiveStatisticsVector.end(); ++iter){
00987                 statsTable->insertRows(currentRowNumber, 1);
00988                 statsTable->setItem(currentRowNumber, checkBxCol, new QCheckTableItem( statsTable, QString("")));
00989                 statsTable->setPixmap(currentRowNumber, editCol, *editPixmap);
00990                 statsTable->setItem(currentRowNumber, descCol, new QTableItem(statsTable, QTableItem::Never, (*iter)->description));
00991                 statsTable->setItem(currentRowNumber, neursPerTimeStepCol, new QTableItem(statsTable, QTableItem::Never, QString::number((*iter)->firingNeuronCount)));
00992                 statsTable->setItem(currentRowNumber, totalNeursCol, new QTableItem(statsTable, QTableItem::Never, QString::number((*iter)->firingNeuronTotal)));
00993                 statsTable->setItem(currentRowNumber, idCol, new QTableItem(statsTable, QTableItem::Never, QString::number((*iter)->ID)));
00994                 ++currentRowNumber;
00995         }
00996 }

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