• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

C:/CVUT/diplomka/Automata_editor/sources/automataWorkSimulator.cpp

Go to the documentation of this file.
00001 #include "constants.h"
00002 
00003 #include "automataWorkSimulator.h"
00004 #include "editor.h"
00005 #include "stringProcessor.h"
00006 #include "utils.h"
00007 #include "scopedsetter.h" // utility
00008 
00009 #include <QRubberBand>
00010 #include <QPainterPath>
00011 #include <QLabel>
00012 #include <QLineEdit>
00013 #include <QPushButton>
00014 #include <QTableWidget>
00015 #include <QGridLayout>
00016 #include <QList>
00017 #include <QVector>
00018 #include <QTextEdit>
00019 #include <QCheckBox>
00020 #include <QDoubleSpinBox>
00021 #include <QMessageBox>
00022 #include <QTimer>
00023 #include <QCoreApplication>
00024 #include <QUndoStack>
00025 #include <QFileDialog>
00026 
00027 #ifdef TESTING_ANIMATIONS
00028 #   define DBGLOG_ANIM(x) DBGLOG_("ANIMATIONS", x)
00029 #else
00030 #   define DBGLOG_ANIM(x)
00031 #endif
00032 
00033 //<-- SimulationMarker ----------------------------------------------------
00034 
00035 // TODO: marker doesn't seem much well, maybe implement it rather using QGraphicsItem
00036 /*!
00037  * Marks active states during simulation process. One marker for each active state.
00038  */
00039 class SimulationMarker : public QRubberBand        
00040 {
00041 public:
00042     SimulationMarker(const QPainterPath &path, Shape s, QWidget *p = 0)
00043     : QRubberBand(s, p), m_pos(0.0f), m_path(path), m_moveStep(0.05f)
00044     {
00045         updatePosition();
00046     }
00047     
00048     void setPos(float pos)
00049     {
00050         m_pos = pos;
00051         updatePosition();
00052     }
00053     
00054     float pos()
00055     {
00056         return m_pos;
00057     }
00058     
00059     void setMoveStep(float step)
00060     {
00061         m_moveStep = step;
00062     }
00063     
00064     bool moveByStep()
00065     {
00066         m_pos += m_moveStep;
00067         if (m_pos >= 1.0f)
00068             return false;
00069         
00070         updatePosition();
00071         return true;
00072     }
00073     
00074     void setPath(const QPainterPath &path)
00075     {
00076         m_path = path;
00077         // updatePosition(); // should be neccesary maybe when dynamic paths will be used ;-)
00078     }
00079     
00080 public:
00081     static const float  width;
00082     static const float  height;    
00083     
00084 protected:
00085     void updatePosition()
00086     {
00087         QPointF point = m_path.pointAtPercent(m_pos);
00088         setGeometry(point.x()-width/2, point.y()-height/2, width, height);
00089     }
00090 
00091     void paintEvent(QPaintEvent * /*event*/)
00092     {
00093         // TODO: implement better for OpenGL usage!!! - currently problem with drawing
00094         QPainter painter(this);        
00095         painter.setPen(Qt::NoPen);
00096 
00097 #ifndef DONT_USE_OPENGL_RENDERING // hack due to rendering problems - now seems better
00098         painter.fillRect(QRectF(0, 0, width, height), QColor(255, 255, 255, 255));
00099 #endif
00100 
00101         painter.setBrush(QColor(50, 50, 200, 80));
00102         painter.drawEllipse(QRectF(0, 0, width, height));
00103     }
00104     
00105     QPointF         m_center;
00106     float           m_pos;
00107     QPainterPath    m_path;
00108     float           m_moveStep;
00109 };
00110 
00111 const float SimulationMarker::width      = 10.0f;
00112 const float SimulationMarker::height     = 10.0f;
00113 
00114 //---------------------------------------------------- SimulationMarker -->
00115 
00116 
00117 
00118 //<-- AutomataWorkSimulator -----------------------------------------------
00119 
00120 AutomataWorkSimulator::AutomataWorkSimulator(Editor *editor, QUndoStack &undoStack,
00121                                              const QSharedPointer<AutomatonImpl> &automaton)
00122 :   m_editor(editor), m_undoStack(undoStack), m_undoStackStartIdx(undoStack.index()),
00123     m_automaton(automaton), m_status(Configuration::eNoStatus),
00124     m_inputIndex(0), m_dialog(new SimulationDialog(editor, this)),
00125     m_activeStatesAreMarked(false), m_simulationTimer(new QTimer(this)), 
00126     m_playing(false), m_animationTimer(new QTimer(this)),
00127     m_useAnimations(USE_ANIMS_BY_DEFAULT), m_animationSpeed(ANIM_SPEED_DEFAULT)
00128 {    
00129     DBGLOG(DBGPAR(m_undoStackStartIdx));
00130 
00131     m_simulationTimer->setInterval(SIMULATION_STEP_DEFAULT * 1000);
00132     connect(m_simulationTimer.data(), SIGNAL(timeout()), this, SLOT(processStep()));
00133     
00134     m_animationTimer->setInterval(ANIMATION_FRAME_TIME);
00135     connect(m_animationTimer.data(), SIGNAL(timeout()), this, SLOT(animate()));
00136     
00137     connect(m_dialog.data(), SIGNAL(closed()), this, SLOT(dialogClosed()));
00138     connect(m_dialog.data(), SIGNAL(useAnimChanged(int)), this, SLOT(useAnimChanged(int)));
00139     connect(m_dialog.data(), SIGNAL(animSpeedChanged(double)), this, SLOT(animSpeedChanged(double)));
00140     connect(m_dialog.data(), SIGNAL(stepSpeedChanged(double)), this, SLOT(stepSpeedChanged(double)));
00141 }
00142 
00143 AutomataWorkSimulator::~AutomataWorkSimulator()
00144 {
00145     DBGLOG("called");
00146     foreach(SimulationMarker *sm, m_markers)
00147     {
00148         delete sm;
00149     }
00150     
00151     m_markers.clear();
00152 }
00153 
00154 bool AutomataWorkSimulator::hasStateBefore() const
00155 {
00156     return (m_inputIndex > 0);
00157 }
00158 
00159 bool AutomataWorkSimulator::hasStateAfter() const
00160 {
00161     // m_inputIndex is increased after process input, so value
00162     // equals to next processing character's index
00163     return (m_inputIndex < m_inputList.count() &&            
00164             !(m_status == Configuration::eError && m_backSteps == 0)); // error aplied only if not replayed
00165 }
00166 
00167 bool AutomataWorkSimulator::isPlaying() const
00168 {
00169     Q_ASSERT(m_simulationTimer->isActive() == m_playing);
00170     return m_playing;
00171 }
00172 
00173 bool AutomataWorkSimulator::isSet() const
00174 {
00175     return !m_inputList.empty();
00176 }
00177 
00178 int AutomataWorkSimulator::getPos() const
00179 {
00180     if (m_inputList.isEmpty()) return 0;
00181     if (m_inputIndex == m_inputList.size()) return m_dialog->getInputLength();
00182     
00183     int result = m_inputList[m_inputIndex].textIdx;
00184     return result;
00185 }
00186 
00187 AutomataWorkSimulator::TConfigurationList AutomataWorkSimulator::getConfigurations() const
00188 {
00189     return m_configurationList.mid(0, m_inputIndex + 1);
00190 }
00191 
00192 void AutomataWorkSimulator::run()
00193 {    
00194     m_dialog->show();
00195     reset();
00196 }
00197 
00198 bool AutomataWorkSimulator::setInput(const QString &text)
00199 {
00200     ITransition::TCharSet alphabet = m_automaton->getAlphabet();
00201     
00202     m_inputList = StringProcessor::computeCharacterList(text);
00203     Q_ASSERT(!(text != "" && m_inputList.empty()));
00204         
00205     foreach(const StringProcessor::CharacterInfo &c, m_inputList)
00206     {
00207         if (!alphabet.contains(c.character))
00208         {
00209             m_inputList.clear();
00210             return false;
00211         }
00212     }
00213 
00214     Q_ASSERT(!m_automaton->getActiveStates().isEmpty());    
00215     m_configurationList << Configuration(m_automaton->getActiveStatesNames(),
00216                                          QStringList(AutomataCreator::defaultEpsilonSymbList[0]),
00217                                          StringProcessor::parseSymbols(m_inputList),
00218                                          m_automaton->isConfigurationAccepted() ? Configuration::eAccepted : Configuration::eNoStatus);
00219     
00220     m_dialog->updateState();
00221     
00222     return true;
00223 }
00224 
00225 void AutomataWorkSimulator::stepForward()
00226 {
00227     if (isPlaying())
00228         pause();
00229         
00230     Q_ASSERT(!m_animationTimer->isActive());
00231 
00232     processStep();
00233 }
00234 
00235 void AutomataWorkSimulator::stepBackward()
00236 {
00237     if (isPlaying())
00238         pause();
00239 
00240     Q_ASSERT(!m_animationTimer->isActive());
00241 
00242     Q_ASSERT(m_inputIndex > 0);
00243     if (m_inputIndex == 0) return;
00244     
00245     m_backSteps++;
00246     m_inputIndex--;
00247     
00248     m_editor->undo(); // unmark states
00249     
00250     if (m_useAnimations) // if statement due to revertPaths calling
00251         doAnimation(revertPaths(m_animationPathMemory[m_animationPathMemory.count()-m_backSteps]));
00252     
00253     m_editor->undo(); // mark states
00254     
00255     m_activeStates = m_activeStatesMemory[m_activeStatesMemory.count()-m_backSteps];
00256     
00257     m_dialog->updateState();
00258 }
00259 
00260 void AutomataWorkSimulator::play()
00261 {
00262     Q_ASSERT(!m_animationTimer->isActive());
00263     
00264     // keep timer start calling before processStep because of logic in processStep!!!
00265     m_simulationTimer->start();
00266     m_playing = true;
00267     
00268     m_dialog->updateState();
00269     
00270     processStep(); // first step procces right now
00271 }
00272 
00273 void AutomataWorkSimulator::pause()
00274 {
00275     if (m_playing)
00276     {
00277         m_playing = false;
00278         m_simulationTimer->stop();
00279     }
00280 
00281     m_dialog->updateState();
00282 }
00283 
00284 void AutomataWorkSimulator::reset()
00285 {
00286     Q_ASSERT(!m_animationTimer->isActive());
00287     
00288     m_playing = false;
00289     m_simulationTimer->stop();
00290 
00291 #ifdef RESET_UNDO_STACK_AFTER_SIMULATION
00292     m_undoStack.setIndex(m_undoStackStartIdx);
00293     m_activeStatesAreMarked = false;
00294 #else
00295     setActiveStatesMarked(false);
00296 #endif
00297 
00298     m_status = Configuration::eNoStatus;
00299     m_inputIndex = 0;
00300     m_inputList.clear();
00301     m_backSteps = 0;
00302     m_animationPathMemory.clear();
00303     m_configurationList.clear();
00304 
00305     m_automaton->reset();
00306         
00307     m_activeStates = m_automaton->getPrivateActiveStates();
00308     setActiveStatesMarked(true);
00309 
00310     m_activeStatesMemory.clear();
00311 
00312     m_dialog->updateState();
00313 }
00314 
00315 void AutomataWorkSimulator::doAnimation(const QList<QPainterPath> &paths)
00316 {
00317     if (m_useAnimations)
00318     {        
00319         m_pathCount = paths.count();
00320         for (int i = 0; i < m_pathCount; ++i) // create enough of markers when required
00321         {
00322             if (i < m_markers.count())
00323             {
00324                 m_markers[i]->setPath(paths[i]);
00325                 m_markers[i]->setPos(0.0f);
00326             }
00327             else
00328             {
00329                 m_markers << new SimulationMarker(paths[i], QRubberBand::Line, m_editor);
00330             }
00331             
00332             m_markers[i]->setMoveStep(ANIMATION_FRAME_TIME / m_animationSpeed);
00333             m_markers[i]->show();
00334         }
00335     
00336         m_animationState = eMoving;
00337         m_animationTimer->start();
00338         animate();
00339         
00340         // wait until animation is finished ( process only timer event! )
00341         while (m_animationTimer->isActive()) { QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } 
00342 
00343         for (int i = 0; i < paths.count(); ++i)
00344         {
00345             m_markers[i]->hide();
00346         }        
00347     }
00348 }
00349 
00350 void AutomataWorkSimulator::animate()
00351 {
00352     DBGLOG_ANIM("called");
00353     switch(m_animationState)
00354     {    
00355     case eMoving:
00356         if (!animateMove())
00357             m_animationState = eStopped;
00358         break;
00359     case eStopped:
00360         m_animationTimer->stop();
00361         break;
00362     }
00363     
00364     m_editor->update();
00365 }
00366 
00367 bool AutomataWorkSimulator::animateMove()
00368 {
00369     bool resume = false;
00370     Q_ASSERT(m_pathCount <= m_markers.count());
00371     for(int i=0; i < m_pathCount; ++i)
00372     {
00373         resume |= m_markers[i]->moveByStep();
00374     }    
00375     
00376     DBGLOG_ANIM(DBGPAR(resume));
00377     return resume;
00378 }
00379 
00380 void AutomataWorkSimulator::refreshPlayingStatus()
00381 {
00382     if (!m_playing) return;
00383      
00384     if (m_inputIndex != m_inputList.count())    // don't run again if processing is finished
00385         m_simulationTimer->start();
00386     else
00387         m_playing = false;                      // playing not possible - stop
00388 }
00389 
00390 void AutomataWorkSimulator::processStep()
00391 {    
00392     m_simulationTimer->stop(); // ever stop! - due to bug when processing is longer than timer interval!
00393     
00394     if (m_backSteps > 0)
00395     {
00396         m_editor->redo(); // unmark states
00397                 
00398         doAnimation(m_animationPathMemory[m_animationPathMemory.count()-m_backSteps]);
00399         
00400         m_editor->redo(); // mark states
00401         m_backSteps--;
00402         m_inputIndex++;
00403        
00404         m_activeStates = m_activeStatesMemory[m_activeStatesMemory.count()-1-m_backSteps];
00405        
00406         refreshPlayingStatus();
00407         
00408         m_dialog->updateState();
00409         return;
00410     }
00411 
00412     Q_ASSERT(m_inputIndex < m_inputList.count());
00413     QString currentCharacter = m_inputList[m_inputIndex].character;
00414         
00415     QList<QPainterPath>                 animationPaths;
00416     IState::TIStateNameSet              newActiveStatesNames = 
00417         m_automaton->processCharacterWithInfo(currentCharacter, animationPaths);
00418     StateImpl::TStateList               newActiveStates =
00419         m_automaton->getPrivateActiveStates();
00420     
00421     setActiveStatesMarked(false); // unmark states
00422     
00423     for(int i=0; i<animationPaths.count(); ++i)
00424     {
00425         animationPaths[i] = m_editor->mapFromScene(animationPaths[i]);
00426     }    
00427     doAnimation(animationPaths); // blocking method waiting until animation is done
00428     
00429     m_activeStates = newActiveStates;
00430     setActiveStatesMarked(true); // makr states
00431 
00432     m_inputIndex++;    
00433     
00434     if (m_activeStates.empty()) // no more states available, not possible processing input
00435     {
00436         m_status = Configuration::eError;
00437     }
00438     else if(m_automaton->isConfigurationAccepted())
00439     {
00440         m_status = Configuration::eAccepted;
00441     }
00442     else
00443     {
00444         m_status = Configuration::eNoStatus;
00445     }
00446     
00447     QStringList remainingString(m_inputIndex == m_inputList.count() ?
00448                                 QStringList(AutomataCreator::defaultEpsilonSymbList[0]) :
00449                                 StringProcessor::parseSymbols((m_inputList.mid(m_inputIndex))));
00450     m_configurationList << Configuration(m_automaton->getActiveStatesNames(),
00451                                          m_automaton->getProcessedString(),
00452                                          remainingString,
00453                                          m_status);
00454     
00455     m_activeStatesMemory << m_activeStates; // TODO: is this array necessary?
00456     
00457     // store for enabling animations when using undo/redo    
00458     m_animationPathMemory << animationPaths;
00459     
00460     refreshPlayingStatus();
00461     
00462     m_dialog->updateState();
00463 }
00464 
00465 void AutomataWorkSimulator::setActiveStatesMarked(bool marked)
00466 {
00467     if (m_activeStatesAreMarked == marked) return;
00468     
00469     QList<State*> statesToBeMarked;
00470     foreach(const QSharedPointer<StateImpl> &state, m_activeStates)
00471     {
00472         State *graphicsState = state->getGraphicsState();
00473         Q_ASSERT(graphicsState);
00474         statesToBeMarked << graphicsState;
00475     }
00476     
00477     emit setStatesMarked(statesToBeMarked, marked);
00478     
00479     m_activeStatesAreMarked = marked;
00480     m_editor->update();
00481 }
00482 
00483 void AutomataWorkSimulator::stepSpeedChanged(double val)
00484 {
00485     m_simulationTimer->setInterval(val * 1000);
00486 }
00487 
00488 void AutomataWorkSimulator::animSpeedChanged(double val)
00489 {
00490     m_animationSpeed = val;    
00491 }
00492 
00493 void AutomataWorkSimulator::useAnimChanged(int state)
00494 {
00495     m_useAnimations = (state == Qt::Checked);
00496 }
00497 
00498 void AutomataWorkSimulator::dialogClosed()
00499 {   
00500 #ifdef RESET_UNDO_STACK 
00501     m_undoStack.setIndex(m_undoStackStartIdx);
00502     m_activeStatesAreMarked = false;
00503 #else
00504     setActiveStatesMarked(false);
00505 #endif
00506     emit finished();
00507 }
00508 
00509 QList<QPainterPath> AutomataWorkSimulator::revertPaths(const QList<QPainterPath> &paths) const
00510 {
00511     QList<QPainterPath> result;    
00512     
00513     foreach(const QPainterPath &path, paths)
00514     {
00515         result << path.toReversed();
00516     }
00517     
00518     return result;
00519 }
00520 
00521 bool AutomataWorkSimulator::getFileName(QString &fileName, bool &latexHeader)
00522 {
00523     fileName = "";
00524     latexHeader = false;
00525     
00526     QStringList formats;
00527     formats << tr("LaTeX file (*.tex)")
00528             << tr("LaTeX file w/o head and tail (*.tex)")
00529             << tr("VauCanSon-G (*.vcg)");
00530     
00531     QString filter;
00532     fileName = QFileDialog::getSaveFileName(m_dialog.data(), "Save file", "slideshow",
00533         formats.join(";;"), &filter);
00534     
00535     if (fileName == "") return false;
00536     
00537     if (filter == formats[0] || filter == formats[1])
00538     {
00539         appendFilenameSuffix(fileName, "tex");
00540         if (filter == formats[0]) latexHeader = true;
00541     }    
00542     else if (filter == formats[2])
00543     {
00544         appendFilenameSuffix(fileName, "vcg");
00545     }
00546     else
00547     {
00548         RELLOG("Incorrect filter, please report bug to developer");
00549         Q_ASSERT(0);
00550         return false;
00551     }
00552         
00553     return true;
00554 }
00555 
00556 void AutomataWorkSimulator::generateSlideshow()
00557 {
00558     // TODO: implement configuratin exporting too!
00559     DBGLOG("Slideshow generating ...");
00560 
00561     ScopedSetter<bool> scopedSetter(m_useAnimations, false); // turn off animations for this scope
00562     
00563     reset();
00564     if (!setInput(m_dialog->getInput()))
00565     {
00566         SimulationDialog::showMessageSetInputFailed(m_dialog.data());
00567         return;
00568     }
00569     
00570     QString fileName;
00571     bool latexHeader;
00572     if (!getFileName(fileName, latexHeader)) return;
00573     
00574     QFile file(fileName);
00575     if (!file.open(QIODevice::WriteOnly))
00576     {
00577         RELLOG("Unable to save file " << fileName << ".");
00578         return;
00579     }
00580     QTextStream out(&file);        
00581     
00582     if (latexHeader)
00583         m_editor->saveLaTeXHeader(out);
00584     
00585     out << "% Global slideshow settings" << endl;
00586     m_editor->saveVCSettings(out);
00587     out << endl;
00588     
00589     int frameNum = 0;
00590     out << "% FRAME NUMBER " << ++frameNum << endl;
00591     // current state
00592     m_editor->saveHeader(out);
00593     saveInputState(out);
00594     m_editor->saveGraph(out);
00595     m_editor->saveFooter(out);
00596     
00597     while (hasStateAfter())
00598     {
00599         processStep();
00600         out << endl;
00601         out << "% FRAME NUMBER " << ++frameNum << endl;
00602         m_editor->saveHeader(out);
00603         saveInputState(out);
00604         m_editor->saveGraph(out);
00605         m_editor->saveFooter(out);
00606     }        
00607     
00608     if (latexHeader)
00609         m_editor->saveLaTeXFooter(out);
00610     
00611     out.setDevice(0);
00612     file.close();
00613     
00614     DBGLOG("Slideshow generated sucessfully");
00615 }
00616 
00617 void AutomataWorkSimulator::saveInputState(QTextStream &out)
00618 {
00619     const int x_pos = m_editor->getGridRect().x() + 1;
00620     const int y_pos = m_editor->getGridRect().y() + m_editor->getGridRect().height() + 1;
00621 
00622     out << "\\VCPut{(" << x_pos << "," << y_pos << ")}" << "{";
00623 
00624     DBGLOG(DBGPAR(m_inputIndex));
00625 
00626     if (m_inputIndex > 0)
00627         out << "\\textbf{";
00628     int i = 0;
00629     for (; i < m_inputIndex; ++i)
00630     {
00631         Q_ASSERT(i < m_inputList.count());
00632         StringProcessor::CharacterInfo ci = m_inputList[i];
00633         QString symb = StringProcessor::isSpecialSymbol(ci.character) ? "$%1$" : "%1";
00634         out << symb.arg(ci.character);
00635     }
00636     if (m_inputIndex > 0)
00637         out << "}";
00638     for (; i < m_inputList.count(); ++i)
00639     {
00640         StringProcessor::CharacterInfo ci = m_inputList[i];
00641         QString symb = StringProcessor::isSpecialSymbol(ci.character) ? "$%1$" : "%1";
00642         out << symb.arg(ci.character);
00643     }
00644 
00645     out << "}" << endl;
00646 }
00647 
00648 //----------------------------------------------- AutomataWorkSimulator -->
00649 
00650 
00651 
00652 //<-- SimulationDialog ----------------------------------------------------
00653 
00654 SimulationDialog::SimulationDialog(Editor *editor, AutomataWorkSimulator *simulator)
00655 : QDialog(editor), m_editor(editor), m_simulator(simulator), m_bUsePrettyPrint(true)
00656 {
00657     m_edtInput = new QLineEdit(this);
00658     m_edtInput->setReadOnly(false);
00659     const QString inputTip = "Input syntax: '[character][character]...' (e.g.: 'abc')\n"
00660                              "Note that special symbols is connected as in LaTeX (e.g. '\\alpha\\beta{}c')";
00661     m_edtInput->setToolTip(inputTip);
00662     m_edtInput->setWhatsThis(inputTip);
00663     
00664     m_btnStepBack = new QPushButton(QIcon(":images/stepBack.png"), "", this);
00665     m_btnStepBack->setToolTip(tr("Step backward"));
00666     m_btnStepBack->setEnabled(false);
00667     connect(m_btnStepBack, SIGNAL(clicked()), simulator, SLOT(stepBackward()));
00668     
00669     m_btnStepFwd = new QPushButton(QIcon(":images/stepFwd.png"), "", this);
00670     m_btnStepFwd->setToolTip(tr("Step forward"));
00671     connect(m_btnStepFwd, SIGNAL(clicked()), this, SLOT(stepForward()));
00672     
00673     m_btnPlay = new QPushButton(QIcon(":images/play.png"), "", this);
00674     m_btnPlay->setToolTip(tr("Simulate"));
00675     connect(m_btnPlay, SIGNAL(clicked()), this, SLOT(play()));
00676     
00677     m_btnPause = new QPushButton(QIcon(":images/pause.png"), "", this);
00678     m_btnPause->setToolTip(tr("Pause"));
00679     m_btnPause->setEnabled(false);
00680     connect(m_btnPause, SIGNAL(clicked()), simulator, SLOT(pause()));
00681     
00682     m_btnReset = new QPushButton(QIcon(":images/stop.png"), "", this);
00683     m_btnReset->setToolTip(tr("Reset"));
00684     m_btnReset->setEnabled(false);
00685     connect(m_btnReset, SIGNAL(clicked()), simulator, SLOT(reset()));
00686     
00687     m_textSimulation = new QTextEdit(this);
00688     m_textSimulation->setReadOnly(true);
00689     
00690     QLabel *lblStepSpeed = new QLabel("Step speed:", this);
00691     m_stepSpeed = new QDoubleSpinBox(this);
00692     m_stepSpeed->setRange(SIMULATION_STEP_MIN, SIMULATION_STEP_MAX);
00693     m_stepSpeed->setValue(SIMULATION_STEP_DEFAULT);
00694     m_stepSpeed->setSingleStep(0.1);
00695     m_stepSpeed->setDecimals(1);
00696     m_stepSpeed->setSuffix(" s");
00697     connect(m_stepSpeed, SIGNAL(valueChanged(double)), this, SIGNAL(stepSpeedChanged(double)));
00698     
00699     QLabel *lblAnimSpeed = new QLabel("Animation speed:", this);
00700     m_animSpeed = new QDoubleSpinBox(this);
00701     m_animSpeed->setRange(ANIM_SPEED_MIN, ANIM_SPEED_MAX);
00702     m_animSpeed->setValue(ANIM_SPEED_DEFAULT);
00703     m_animSpeed->setSingleStep(50);
00704     m_animSpeed->setDecimals(0);
00705     m_animSpeed->setSuffix(" ms");
00706     connect(m_animSpeed, SIGNAL(valueChanged(double)), this, SIGNAL(animSpeedChanged(double)));
00707     
00708     m_checkUseAnim = new QCheckBox("Use animations", this);
00709     m_checkUseAnim->setChecked(true);
00710     connect(m_checkUseAnim, SIGNAL(stateChanged(int)), this, SIGNAL(useAnimChanged(int)));
00711     
00712     m_checkPrettyPrint = new QCheckBox("Pretty printing", this);
00713     m_checkPrettyPrint->setChecked(true);
00714     connect(m_checkPrettyPrint, SIGNAL(stateChanged(int)), this, SLOT(prettyPrintChanged(int)));
00715     
00716     m_btnGenerate = new QPushButton("&Generate slideshow", this);
00717     connect(m_btnGenerate, SIGNAL(clicked()), m_simulator, SLOT(generateSlideshow()));    
00718     
00719     QPushButton *closeButton = new QPushButton("&Close", this);
00720     connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
00721     
00722     connect(this, SIGNAL(accepted()), this, SIGNAL(closed()));
00723     connect(this, SIGNAL(rejected()), this, SIGNAL(closed()));
00724         
00725     QGridLayout *layout = new QGridLayout(this);
00726     int i = 0;
00727     layout->addWidget(m_edtInput, i++, 0, 1, 5);                    // \n
00728     layout->addWidget(m_btnStepBack, i, 0);
00729     layout->addWidget(m_btnStepFwd, i, 1);
00730     layout->addWidget(m_btnPlay, i, 2);
00731     layout->addWidget(m_btnPause, i, 3);
00732     layout->addWidget(m_btnReset, i++, 4);                          // \n
00733     layout->addWidget(m_textSimulation, i++, 0, 1, 5);              // \n
00734     layout->addWidget(lblAnimSpeed, i, 0);
00735     layout->addWidget(m_animSpeed, i, 1);
00736     layout->addWidget(m_checkUseAnim, i, 2);                      
00737     layout->addWidget(m_btnGenerate, i++, 3, 1, 2, Qt::AlignRight);// \n
00738     layout->addWidget(lblStepSpeed, i, 0);
00739     layout->addWidget(m_stepSpeed, i, 1); 
00740     layout->addWidget(m_checkPrettyPrint, i, 2);
00741     layout->addWidget(closeButton, i++, 3, 1, 2, Qt::AlignRight);   // \n
00742     
00743     setWindowTitle(tr("Simulation dialog"));
00744     setWindowIcon(QIcon(":images/simulating.png"));
00745 }
00746 
00747 SimulationDialog::~SimulationDialog()
00748 {
00749     DBGLOG("called");
00750 }
00751 
00752 int SimulationDialog::getInputLength() const
00753 {
00754     return m_edtInput->text().length();
00755 }
00756 
00757 QString SimulationDialog::getInput() const
00758 {
00759     return m_edtInput->text();
00760 }
00761 
00762 void SimulationDialog::updateState()
00763 {
00764     m_edtInput->setReadOnly(m_simulator->isSet());
00765     m_btnReset->setEnabled(m_simulator->isSet());
00766     
00767     m_btnPause->setEnabled(m_simulator->isPlaying());
00768     
00769     m_btnStepBack->setEnabled(m_simulator->hasStateBefore());
00770     m_btnStepFwd->setEnabled(!m_simulator->isSet() || m_simulator->hasStateAfter());
00771     m_btnPlay->setEnabled(!m_simulator->isSet() || (m_simulator->hasStateAfter() && !m_simulator->isPlaying()));
00772     
00773     int pos = m_simulator->getPos();
00774     m_edtInput->setSelection(0, pos);
00775     
00776     m_textSimulation->clear();
00777     AutomataWorkSimulator::TConfigurationList info = m_simulator->getConfigurations();
00778     for(AutomataWorkSimulator::TConfigurationList::ConstIterator confIt = info.begin();
00779         confIt != info.end();
00780         ++confIt)
00781     {
00782         const AutomataWorkSimulator::Configuration &conf = *confIt;
00783 
00784         appendSymbol("(");
00785         
00786         QStringList symbols = conf.activeStates;
00787         if (symbols.count() > 1) appendSymbol("{");
00788         bool forFirst = true;
00789         foreach(const QString &symb, symbols)
00790         {
00791             if (!forFirst) appendSymbol(",");
00792             else forFirst = false;
00793             appendSymbol(symb);
00794         }
00795         if (symbols.count() > 1) appendSymbol("}");
00796         
00797         appendSymbol(",");
00798         
00799         symbols = conf.processed;
00800         foreach(const QString &symb, symbols)
00801         {
00802             appendSymbol(symb);
00803         }
00804         
00805         appendSymbol(",");
00806         
00807         symbols = conf.input;
00808         foreach(const QString &symb, symbols)
00809         {
00810             appendSymbol(symb);
00811         }
00812         
00813         appendSymbol(")");
00814         if ((confIt+1 != info.end()) || m_simulator->hasStateAfter())
00815         {
00816             appendSymbol(" ");
00817             appendSymbol("\\vdash");
00818         }
00819         
00820         switch(conf.status)
00821         {
00822         case AutomataWorkSimulator::Configuration::eAccepted:
00823             appendSymbol(" ACCEPT");
00824             break;
00825         case AutomataWorkSimulator::Configuration::eError:
00826             appendSymbol(" ERROR");
00827             break;
00828         default:
00829             break;
00830         }
00831         appendSymbol("\n");
00832     }
00833 }
00834 
00835 void SimulationDialog::appendSymbol(const QString &symb)
00836 {
00837     if (!m_bUsePrettyPrint)
00838     {        
00839         m_textSimulation->textCursor().insertText(symb);
00840         if (StringProcessor::isSpecialSymbol(symb))
00841             m_textSimulation->textCursor().insertText("{}");
00842         return;
00843     }
00844     
00845     QString curFamily;
00846     QString symbol;
00847     const QString prevFamily = m_textSimulation->fontFamily();
00848     
00849     symbol = StringProcessor::getSymbolPrintInfo(symb, curFamily);
00850     
00851     m_textSimulation->setFontFamily(curFamily);
00852     m_textSimulation->textCursor().insertText(symbol);
00853     
00854     m_textSimulation->setFontFamily(prevFamily);
00855 }
00856 
00857 void SimulationDialog::prettyPrintChanged(int status)
00858 {
00859     m_bUsePrettyPrint = (status == Qt::Checked);
00860     updateState(); // TODO: create method only for configuration field updating
00861 }
00862 
00863 void SimulationDialog::stepForward()
00864 {
00865     set();
00866     
00867     if (!m_simulator->isSet()) return;
00868 
00869     m_simulator->stepForward();
00870 }
00871 
00872 void SimulationDialog::play()
00873 {   
00874     set();
00875         
00876     if (!m_simulator->isSet()) return;
00877         
00878     m_simulator->play();
00879 }
00880 
00881 void SimulationDialog::set()
00882 {
00883     if (m_simulator->isSet()) return;
00884     
00885     if (!setInput())
00886     {
00887         showMessageSetInputFailed(this);
00888         return;
00889     }
00890 }
00891 
00892 bool SimulationDialog::setInput()
00893 {
00894     if (m_edtInput->text() == "")
00895         return false;
00896     
00897     return m_simulator->setInput(m_edtInput->text());    
00898 }
00899 
00900 void SimulationDialog::showMessageSetInputFailed(QWidget *parent)
00901 {
00902     QMessageBox::information(parent, "Incorrect input",
00903                              "Please set correct input before running,\n"
00904                              "Be sure to use only characters in alphabet!",
00905                              QMessageBox::Ok);
00906 }
00907 
00908 //---------------------------------------------------- SimulationDialog -->

Generated on Tue Jan 4 2011 03:03:22 for Autoamata editor by  doxygen 1.7.0