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

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

Go to the documentation of this file.
00001 #include "constants.h"
00002 
00003 #include "editor.h"
00004 #include "transforms.h"
00005 #include "mainwindow.h"
00006 #include "parser.h"
00007 #include "commands.h"
00008 #include "state.h"
00009 #include "stateDialogs.h"
00010 #include "stateManager.h"
00011 #include "transition.h"
00012 #include "transitionDialogs.h"
00013 #include "transitionManager.h"
00014 #include "oneStateTransition.h"
00015 #include "twoStatesTransition.h"
00016 #include "dialogs.h"
00017 #include "label.h"
00018 #include "serializers.h" // objects for serializing items to QDataStream e.g. for clipboard, QVariant, ...
00019 #include "automataWorkSimulator.h"
00020 #include "drawAlgorithm.h"
00021 #include "automataCreator.h"
00022 #include "utils.h"
00023 #include "dbglog.h"
00024 
00025 #include "ialgorithm.h"
00026 #include "istate.h"
00027 #include "itransition.h"
00028 #include "iautomaton.h"
00029 
00030 #include "igraphviz.h"
00031 
00032 #include <QGraphicsScene>
00033 #include <QGraphicsView>
00034 #include <QGraphicsItem>
00035 #include <QGraphicsLineItem>
00036 #include <QGraphicsSimpleTextItem>
00037 #include <QMessageBox>
00038 #include <QMenu>
00039 #include <QResizeEvent>
00040 #include <QGraphicsSceneMouseEvent>
00041 #include <QFontMetrics>
00042 #include <QMouseEvent>
00043 #include <QScrollBar>
00044 #include <QRubberBand>
00045 #include <QList>
00046 #include <QQueue>
00047 #include <QCursor>
00048 #include <QRectF>
00049 #include <QSharedPointer>
00050 
00051 #ifndef DONT_USE_SVG_MODULE
00052 #   include <QSvgGenerator>
00053 #endif
00054 
00055 #ifndef DONT_USE_OPENGL_RENDERING
00056 #   include <QGLWidget>
00057 #endif
00058 
00059 // export
00060 #include <QFile>
00061 #include <QTextStream>
00062 #include <QPixmap>
00063 #include <QPrinter>
00064 #include <QImage>
00065 #include <QDate>
00066 
00067 // import
00068 #include <QRegExpValidator>
00069 #include <QRegExp>
00070 
00071 #include <QUndoStack>
00072 #include <QDir>
00073 #include <QShortcut>
00074 
00075 
00076 #include <math.h>
00077 
00078 // copy/paste
00079 #include <QApplication>
00080 #include <QMimeData>
00081 #include <QDataStream>
00082 #include <QClipboard>
00083 
00084 #ifdef PERFORMANCE_MEASUREMENT
00085 #   include <QTime>
00086 #endif
00087 
00088 #include <QObject>
00089 
00090 
00091 /*!
00092  * Reimplementation of painting QRubberBand to give only dashed line around selection rect.
00093  */
00094 class DashedRubberBand : public QRubberBand
00095 {
00096 public:
00097     DashedRubberBand(Shape s, QWidget *p = 0)
00098     : QRubberBand(s, p)
00099     {
00100     }
00101 
00102 protected:
00103     void paintEvent(QPaintEvent *event)
00104     {
00105         QPainter painter(this);
00106         
00107         painter.setPen(QPen(
00108             QColor(SelectedColor::r, SelectedColor::g,
00109                    SelectedColor::b, SelectedColor::a),
00110             2, Qt::DashLine));
00111                 
00112         painter.setBrush(Qt::NoBrush);
00113         painter.drawRect(event->rect());
00114     }
00115 
00116     friend class Editor;
00117 };
00118 
00119 
00120 
00121 //<-- Editor -----------------------------------------------------------------
00122 
00123 Editor::Editor(MainWindow *parent)
00124 :   QGraphicsView((QWidget*) parent), mw(parent), sceneBorder(SCENE_BORDER),
00125     startState(NULL), selectedState(NULL), selectedTransition(NULL),
00126     snapToGrid(SNAP_TO_GRID), showGrid(SHOW_GRID), showFrame(SHOW_FRAME),
00127     antial(INIT_ANTIALIASING), saved(false), addition(false), //changed(false),
00128     m_stateIsMoving(false), m_simulationIsRun(false)
00129 {
00130     // 120.0 is delta for most mice, ZOOM_DIVIDER should be in multiples of 120.0
00131     m_zoomInFactor = pow(2.0, 120.0 / ZOOM_DIVIDER);
00132 
00133     // state parameters adjustable
00134     stateLineStyle = DEF_LINE_STYLE;
00135     stateLineWidth = DEF_STATE_LINE_WIDTH;
00136     stateLineColor = DEF_COLOR;
00137     stateLabelColor = DEF_COLOR;
00138     stateLabelScale = DEF_LABEL_SCALE;
00139     stateFillStatus = DEF_FILL_STATUS;
00140     stateFillColor = DEF_FILL_COLOR;
00141     // state parameters preset
00142     dimStateLineStyle = DEF_DIM_LINE_STYLE;
00143     dimStateLineColor = DEF_DIM_COLOR;
00144     dimStateLineCoef = DEF_DIM_STATE_LINE_COEF;
00145     dimStateLabelColor = DEF_DIM_COLOR;
00146     dimStateFillColor = DEF_DIM_FILL_COLOR;
00147     // state parameters double
00148     stateLineDoubleCoef = DEF_STATE_LINE_DBL_COEF;
00149     stateLineDoubleSep = DEF_STATE_LINE_DBL_SEP;
00150 
00151     // edge parameters adjustable
00152     edgeLineStyle = DEF_LINE_STYLE;
00153     edgeLineWidth = DEF_EDGE_LINE_WIDTH;
00154     edgeLineColor = DEF_COLOR;
00155     edgeLabelColor = DEF_COLOR;
00156     edgeLabelScale = DEF_LABEL_SCALE;
00157     edgeLineDblStatus = DEF_EDGE_LINE_DBL_STATUS;
00158     // transition parameters dimmed
00159     dimEdgeLineStyle = DEF_DIM_LINE_STYLE;
00160     dimEdgeLineColor = DEF_DIM_COLOR;
00161     dimEdgeLineCoef = DEF_DIM_EDGE_LINE_COEF;
00162     dimEdgeLabelColor = DEF_DIM_COLOR; 
00163     // transition parameters border
00164     edgeLineBorderCoef = DEF_EDGE_LINE_BORDER_COEF;
00165     edgeLineBorderColor = DEF_EDGE_LINE_BORDER_COLOR;
00166     // transition parameters double
00167     edgeLineDblCoef = DEF_EDGE_LINE_DBL_COEF;
00168     edgeLineDblSep = DEF_EDGE_LINE_DBL_SEP;
00169     
00170     setScene(new QGraphicsScene(this));
00171 
00172     m_undoStack = new QUndoStack();
00173     m_undoStack->setUndoLimit(UNDO_LIMIT);
00174     connect(m_undoStack, SIGNAL(canUndoChanged(bool)), this, SLOT(canUndoChangedSlot(bool)));
00175     connect(m_undoStack, SIGNAL(canRedoChanged(bool)), this, SLOT(canRedoChangedSlot(bool)));
00176     connect(m_undoStack, SIGNAL(cleanChanged(bool)), this, SLOT(setClean(bool)));
00177 
00178     createUndoView();
00179     connect(m_undoView, SIGNAL(closed()), this, SIGNAL(undoViewClosed()));
00180 
00181     connect(scene(), SIGNAL(changed(const QList<QRectF> &)), this, SLOT(sceneChanged(const QList<QRectF> &)));
00182     
00183     if (!antial)
00184         setRenderHint(QPainter::SmoothPixmapTransform); // nicier lines and still good performance
00185     else
00186         setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
00187 
00188     setCacheMode(QGraphicsView::CacheNone);
00189 
00190     newStateNumber = 0; // first state is Q0
00191 
00192     // popup menus
00193     popup = new QMenu(this);
00194     popup->addAction(QString("Edit state style parameters"), this, SLOT(editStateStyleParams()));
00195     popup->addAction(QString("Edit transition style parameters"), this, SLOT(editTransitionStyleParams()));
00196     popup->addAction(QString("Set grid rect"), this, SLOT(showGridRectDialog()));
00197     popup->addSeparator();
00198     popupPasteHere = popup->addAction(tr("Paste here"), this, SLOT(pasteOnPos()));
00199 
00200     popupSelection = new QMenu(this);
00201     popupSelection->addAction(tr("Cut"), this, SLOT(cutSelection()));
00202     popupSelection->addAction(tr("Copy"), this, SLOT(copySelection()));
00203     popupSelection->addAction(tr("Remove"), this, SLOT(removeSelection()));
00204     
00205     popupState = new QMenu(this);
00206     popupStateLabel = new QAction("State", this);
00207     popupState->addAction(popupStateLabel);
00208     popupState->addSeparator();
00209     popupState->addAction(QString("Edit"),this,SLOT(editState()));
00210     popupState->addAction(QString("Edit extended"), this, SLOT(editStateParams()));
00211     popupState->addAction(QString("Move"), this, SLOT(moveState()));
00212     popupState->addSeparator();
00213     popupState->addAction(QString("Cut"), this, SLOT(cutState()));
00214     popupState->addAction(QString("Copy"), this, SLOT(copyState()));
00215     popupState->addSeparator();
00216     popupState->addAction(QString("Remove"),this,SLOT(removeState()));
00217 
00218     //! right action will be selected when used according to transition type
00219     popupTransitionLabel = new QAction("Transition", this);
00220     popupOneStateTransitionEdit = new QAction("Edit", this);
00221     connect(popupOneStateTransitionEdit, SIGNAL(triggered()), this, SLOT(editOneStateTransition()));
00222     popupTwoStatesTransitionEdit = new QAction("Edit", this);
00223     connect(popupTwoStatesTransitionEdit, SIGNAL(triggered()), this, SLOT(editTwoStatesTransition()));
00224     
00225     popupTransition = new QMenu(this);
00226     popupTransition->addAction(popupTransitionLabel);
00227     popupTransition->addSeparator();
00228     popupTransition->addAction(popupOneStateTransitionEdit);
00229     popupTransitionEdit = popupOneStateTransitionEdit;
00230     popupTransition->addAction(QString("Edit next labels"), this, SLOT(editNextLabels()));
00231     popupTransition->addAction(QString("Edit extended"), this, SLOT(editTransitionParams()));
00232     popupTransition->addSeparator();
00233     popupTransition->addAction(QString("Remove"),this,SLOT(removeTransition()));
00234 
00235     setGridRect(QRect(LLX, LLY, URX - LLX, URY - LLY));
00236 
00237     fileName = QString(NEW_FILENAME); // new file
00238 
00239     QFont::insertSubstitution("Arial", "Helvetica");
00240 
00241     //! needed because editor propagates mouse click to main window
00242     setAttribute(Qt::WA_NoMousePropagation);
00243 
00244     // TODO: how to grap bitmap when OpenGL is enabled? .. this has no effect :(
00245     DBGLOG(DBGPAR(testAttribute(Qt::WA_NoBackground)));
00246     DBGLOG(DBGPAR(testAttribute(Qt::WA_NoSystemBackground)));
00247     DBGLOG(DBGPAR(testAttribute(Qt::WA_OpaquePaintEvent)));
00248     DBGLOG(DBGPAR(testAttribute(Qt::WA_TranslucentBackground)));
00249     setAttribute(Qt::WA_NoBackground, false);
00250     setAttribute(Qt::WA_NoSystemBackground, true);
00251     setAttribute(Qt::WA_OpaquePaintEvent, false);
00252     setAttribute(Qt::WA_TranslucentBackground, false);
00253 
00254     setTransformationAnchor(QGraphicsView::AnchorUnderMouse);    
00255     setOptimizationFlags(QGraphicsView::DontSavePainterState);
00256 
00257 #ifndef DONT_USE_OPENGL_RENDERING
00258     setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));    
00259 #endif
00260     
00261     // TODO: try to set QGraphicsView::SmartViewportUpdate, currently redrawing
00262     //       is incorrect when SmartViewportUpdate is set
00263     setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
00264     
00265     // required Rectangle due to OpenGL!!! (other rubber band is opaque) // TODO: not functional on Windows Qt 4.6.2
00266     m_rubberBand = new DashedRubberBand(QRubberBand::Rectangle, this); // implemented here in Editor.cpp (on top)
00267     setRubberBandSelectionMode(Qt::IntersectsItemShape);
00268 
00269     m_drawAlgorithmList << QSharedPointer<IDrawAlgorithm>(new NaiveDrawAlgorithm());
00270     m_drawAlgorithmList << QSharedPointer<IDrawAlgorithm>(new FarthestFinalDrawAlgorithm());
00271     m_currentDrawAlgorithm = m_drawAlgorithmList.count()-1;
00272 
00273     qRegisterMetaTypeStreamOperators<StateSerializer>("StateSerializer");
00274     qRegisterMetaTypeStreamOperators<SelectionSerializer>("SelectionSerializer");
00275     qRegisterMetaTypeStreamOperators<TransitionSerializer>("TransitionSerializer");
00276 
00277 #ifdef STRING_PROCESSOR_TEST
00278     StringProcessor::runTest();
00279 #endif
00280 }
00281 
00282 Editor::~Editor()
00283 { // probably scene do this, but rather ...
00284     m_undoStack->clear();
00285     delete m_undoStack;
00286     
00287     QList<State*> stateList = getStateList();
00288   
00289     while ( !stateList.isEmpty() )
00290         delete stateList.takeFirst(); // transitions are deleted in state's destructor
00291 
00292     Q_ASSERT(StateManager::getInstance());
00293     Q_ASSERT(TransitionManager::getInstance());
00294     delete StateManager::getInstance();
00295     delete TransitionManager::getInstance();    
00296 
00297     DBGLOG("deleted");
00298 }
00299 
00300 void Editor::createUndoView()
00301 {
00302     m_undoView = new UndoView(m_undoStack, this);
00303     m_undoView->setWindowTitle(tr("Undo stack"));
00304     m_undoView->setAttribute(Qt::WA_QuitOnClose, false);
00305     m_undoView->setWindowFlags(Qt::Tool);
00306 } 
00307 
00308 void Editor::setGridRect(QRect gridRect)
00309 {
00310     int dllx,dury;
00311     dllx = this->gridRect.x();
00312     dury = this->gridRect.y() + this->gridRect.height();
00313   
00314     if (!(gridRect.width() > 0 && gridRect.height() > 0))
00315     {
00316         QMessageBox::warning(this,
00317                 tr("Bad coordinate?"),
00318                 tr("GridRect will not be changed!"),tr("&Ok"));
00319         return;
00320     }
00321   
00322     this->gridRect = gridRect;
00323     br = QPoint(gridRect.width() * GRID_STEP + GRID_STEP/2 + 2,
00324                 gridRect.height() * GRID_STEP + GRID_STEP/2 + 2);
00325   
00326     scene()->setSceneRect(0,0,br.x(),br.y());
00327     setSceneRect(-sceneBorder, -sceneBorder, br.x() + sceneBorder*2, br.y() + sceneBorder*2);
00328     centerOn(scene()->width() / 2,scene()->height() / 2);
00329   
00330     dllx = gridRect.x() - dllx;
00331     dury = gridRect.y() + gridRect.height() - dury;
00332   
00333     // if scene is changed, change positions of states too
00334     if (dllx != 0 || dury != 0)
00335     {
00336         QList<State*> stateList = getStateList();
00337         foreach (State *state, stateList)
00338         {
00339             state->setPos(state->x() - dllx * GRID_STEP, state->y() + dury * GRID_STEP);
00340         }
00341     }
00342 }
00343 
00344 QRect Editor::getGridRect()
00345 {
00346     return gridRect;
00347 }
00348 
00349 void Editor::setAction(EAction action)
00350 {
00351     m_selectedAction = action;
00352 
00353     setActionCursor(action);
00354 
00355     if (action != eSelection)
00356         scene()->clearSelection();
00357 
00358     if (startState)
00359     {
00360         startState->setChecked(false);
00361         startState = NULL;
00362     }
00363     selectedState = NULL;
00364 }
00365 
00366 void Editor::setActionCursor(EAction action)
00367 {
00368     switch(action)
00369     {
00370     case eSelection:
00371         DBGLOG_ME("cursor=ArrowCursor");
00372         setCursor(Qt::ArrowCursor);
00373         break;
00374     case eInsertState:
00375         DBGLOG_ME("cursor=CrossCursor");
00376         setCursor(Qt::CrossCursor);
00377         break;
00378     case eInsertTransition:
00379         DBGLOG_ME("cursor=UpArrowCursor");
00380         setCursor(Qt::UpArrowCursor);
00381         break;
00382     default:
00383         Q_ASSERT(0 && "Unexpected state");
00384     }
00385 }
00386 
00387 void Editor::setActionInternal(EAction action)
00388 {
00389     setAction(action);
00390     emit actionChanged(action); // mainwindow changes it's tools toolbar menu
00391 }
00392 
00393 void Editor::setSelectedState(State *state)
00394 {
00395     if (state) selectedState = state;
00396     else selectedState = NULL;
00397 }
00398 
00399 void Editor::update()
00400 {
00401     QGraphicsView::update();
00402 }
00403 
00404 void Editor::canUndoChangedSlot(bool can)
00405 {
00406     if (m_simulationIsRun) return;
00407     emit canUndoChanged(can);
00408 }
00409 
00410 void Editor::canRedoChangedSlot(bool can)
00411 {
00412     if (m_simulationIsRun) return;
00413     emit canRedoChanged(can);
00414 }
00415 
00416 void Editor::slotSnapToGrid()
00417 {
00418     QString s;
00419   
00420     if (snapToGrid == true)
00421     {
00422         snapToGrid = false;
00423         s = "Snap to grid set off";
00424     }
00425     else
00426     {
00427         snapToGrid = true;
00428         s = "Snap to grid set on";
00429     }
00430 
00431     mw->setStatusBar(s);
00432 }
00433 
00434 void Editor::slotAlignToGrid()
00435 {
00436     QList<State*> stateList = getStateList();
00437     QVector<QPointF> origPositions(stateList.size());    
00438 
00439     int i = 0;    
00440     foreach(QGraphicsItem *item, stateList)
00441     {
00442         origPositions[i] = item->pos();
00443         ++i;
00444     }
00445     
00446     if (itemsAlignToGrid(stateList))
00447     {
00448         m_undoStack->push
00449         (
00450             createMoveItemsCommand(stateList, origPositions)
00451         );
00452         
00453         mw->setStatusBar( QString("States aligned to grid") );
00454     }
00455     else
00456     {
00457         DBGLOG("nothing to be aligned");
00458     }
00459 }
00460 
00461 void Editor::setShowGridFrame(bool grid, bool frame)
00462 {
00463     resetCachedContent();
00464     scene()->update();
00465 
00466     showGrid = grid;
00467     showFrame = frame;
00468 
00469     emit showChanged(showGrid, showFrame);
00470 }
00471 
00472 void Editor::slotShowGrid(bool show)
00473 {
00474     m_undoStack->push(
00475         new ShowGridFrameCommand(this, showGrid, show, showFrame, showFrame)
00476     );
00477 
00478     QString s("Grid set ");
00479     s += (showGrid) ? "on" : "off";
00480     mw->setStatusBar(s);
00481 }
00482 
00483 void Editor::slotShowFrame(bool show)
00484 {
00485     m_undoStack->push(
00486         new ShowGridFrameCommand(this, showGrid, showGrid, showFrame, show)
00487     );
00488 
00489     QString s("Frame set ");
00490     s += (showFrame) ? "on" : "off";
00491     mw->setStatusBar(s);
00492 }
00493 
00494 bool Editor::testStateName(const QString &s)
00495 {
00496     return testStateName(s, m_stateMap);
00497 }
00498 
00499 bool Editor::testStateName(const QString &s, const TStateMap &stateMap)
00500 {
00501     return stateMap.contains(s);
00502 }
00503 
00504 bool Editor::isChanged() const
00505 {
00506     return !m_undoStack->isClean();
00507 }
00508 
00509 void Editor::setClean(bool clean)
00510 {
00511     QString file = fileName.right(fileName.length() - fileName.lastIndexOf('/') - 1);
00512     if (clean)
00513         mw->setWindowTitle(QString("%1 - %2").arg(PROGRAM_NAME).arg(file));
00514     else
00515         mw->setWindowTitle(QString("%1 - %2*").arg(PROGRAM_NAME).arg(file));
00516 
00517     if (!saved && clean && m_undoStack->index() == 0)
00518     {
00519         emit isChanged(true);
00520         return;
00521     }
00522 
00523     emit isChanged(!clean);
00524 }
00525 
00526 void Editor::newFile()
00527 {
00528     m_undoStack->clear();
00529 
00530     QList<State*> stateList = getStateList();
00531     while ( !stateList.isEmpty() )
00532         delete stateList.takeFirst();
00533     
00534     m_stateMap.clear();
00535     
00536     // deleted from state, here only removed from editor's list
00537     m_transitionList.clear();
00538 
00539     scene()->update();
00540     setFileName(NEW_FILENAME);
00541     
00542     saved = false;
00543     setClean(true);
00544 
00545     newStateNumber = 0; // first added state will be Q0 again
00546 }
00547 
00548 void Editor::openFile(const QString& fn)
00549 {
00550     DBGLOG("opening" << fn);
00551 
00552     newFile();
00553     
00554     QList<State *>  parsedStates;
00555     QRect           newGridRect;
00556     
00557     bool wasFrame = showFrame;
00558     bool wasGrid = showGrid;
00559 
00560     Parser p(this, true);
00561 #ifdef MEASURE_PARSER_RUN
00562     QTime timer;
00563     timer.start();
00564 #endif
00565     bool ret = p.run(fn, parsedStates, newGridRect);
00566 #ifdef MEASURE_PARSER_RUN
00567     RELLOG("Parsing have taken " << timer.elapsed() << "ms");
00568 #endif
00569     if (ret || !parsedStates.empty())
00570     {
00571         ItemsAddCommand command(this, parsedStates, newGridRect);
00572         command.redo();
00573         
00574         QMessageBox::information(this, "Loading report", p.getReport() , QMessageBox::Ok);
00575         mw->setStatusBar(QString("File %1 was loaded sucessfully!").arg(fn));
00576 
00577         if (!ret)
00578         {
00579             ReportDialog prd(p.getReport(), this);
00580             prd.exec();
00581 
00582             mw->setStatusBar(QString("Loading file %1 wasn't totally successfull! See report!").arg(fn));
00583         }
00584 
00585         update();
00586 
00587         setFileName(fn);
00588         saved = true;
00589         setClean(true);
00590     }
00591     else
00592     {
00593         showFrame = wasFrame;
00594         showGrid = wasGrid;
00595 
00596         ReportDialog prd(p.getReport(), this);
00597         prd.exec();
00598         
00599         mw->setStatusBar(QString("Loading file %1 was totally unsuccessfull! See report!").arg(fn));
00600     }
00601 }
00602 
00603 QPointF Editor::mapToGrid(const QPointF& scenePos)
00604 {
00605     return QPointF((float)(scenePos.x() - GRID_STEP/2) / GRID_STEP + gridRect.x(),
00606                    gridRect.height()-((float)(scenePos.y() - GRID_STEP/2) / GRID_STEP - gridRect.y()));
00607 }
00608 
00609 void Editor::setStatePrevParamsDef(StatePrevParams &prevParams)
00610 {
00611     prevParams.stateLineStyle = stateLineStyle; // default is editor
00612     prevParams.stateLineWidth = 1;
00613     prevParams.stateLineColor = stateLineColor;
00614     prevParams.stateLabelColor = stateLabelColor;
00615     prevParams.stateLabelScale = 1;
00616     prevParams.stateFillStatus = stateFillStatus;
00617     prevParams.stateFillColor = stateFillColor;
00618 }
00619 
00620 void Editor::setTrPrevParamsDef(EdgePrevParams &prevTrParams)
00621 {
00622     prevTrParams.edgeLineStyle = edgeLineStyle; // default is editor
00623     prevTrParams.edgeLineWidth = 1;
00624     prevTrParams.edgeLineColor = edgeLineColor;
00625     prevTrParams.edgeLabelColor = edgeLabelColor;
00626     prevTrParams.edgeLabelScale = 1;
00627     prevTrParams.edgeLineDblStatus = edgeLineDblStatus;
00628 }
00629 
00630 void Editor::setFileName(const QString &fn)
00631 {
00632     QString file = fn.right(fn.length() - fn.lastIndexOf(QRegExp("[/\\\\]")) - 1);
00633     fileName = fn;
00634     DBGLOG(DBGPAR(fileName));
00635     mw->setWindowTitle(QString("%1 - %2")
00636         .arg(PROGRAM_NAME)
00637         .arg(file));
00638 }
00639 
00640 void Editor::exportToVaucanson(const QString& fn, bool additionals)
00641 {   // TODO: remove exportToVaucanson -> replace by saveToFile only
00642     saveToFile(fn, additionals);
00643 }
00644 
00645 void Editor::saveLaTeXHeader(QTextStream &out)
00646 {
00647     // LaTeX header
00648     out << "\\documentclass[11pt]{article}" << endl;
00649     out << "\\usepackage{vaucanson-g}" << endl;
00650     out << "\\begin{document}" << endl;   
00651 }
00652 
00653 void Editor::saveLaTeXFooter(QTextStream &out)
00654 {
00655     out << "\\end{document}" << endl;
00656 }
00657 
00658 void Editor::saveHeader(QTextStream &out)
00659 {
00660     if (showGrid) out << "\\ShowGrid" << endl;
00661     if (showFrame) out << "\\ShowFrame" << endl;
00662   
00663     // VCPicture with gridRect size
00664     out << "\\begin{VCPicture}"
00665         << "{(" 
00666         << gridRect.x() << "," << gridRect.y()
00667         << ")("
00668         << gridRect.x() + gridRect.width() << "," << gridRect.y() + gridRect.height()
00669         << ")}"
00670         << endl;
00671 }
00672 
00673 void Editor::saveVCSettings(QTextStream &out)
00674 {
00675     if(stateLineStyle != DEF_LINE_STYLE)
00676         out << "\\SetStateLineStyle{" << trLineStyle(stateLineStyle) << "}" << endl;
00677     if(stateLineWidth != (float) DEF_STATE_LINE_WIDTH)
00678         out << "\\SetStateLineWidth{" << stateLineWidth << "pt}" << endl;
00679     if(stateLineColor != DEF_COLOR)
00680         out << "\\SetStateLineColor{" << stateLineColor << "}" << endl;
00681     if(stateLabelScale != (float) DEF_LABEL_SCALE)
00682         out << "\\SetStateLabelScale{" << stateLabelScale << "}" << endl;
00683     if(stateFillStatus != DEF_FILL_STATUS)
00684         out << "\\SetStateFillStatus{" << trFillStatus(stateFillStatus) << "}" << endl;
00685     if(stateFillColor != DEF_FILL_COLOR)
00686         out << "\\SetStateFillColor{" << stateFillColor << "}" << endl;
00687     
00688     if(edgeLineStyle != DEF_LINE_STYLE)
00689         out << "\\SetEdgeLineStyle{" << trLineStyle(edgeLineStyle) << "}" << endl;
00690     if(edgeLineWidth != (float) DEF_EDGE_LINE_WIDTH)
00691         out << "\\SetEdgeLineWidth{" << edgeLineWidth << "pt}" << endl;
00692     if(edgeLineColor != DEF_COLOR)
00693         out << "\\SetEdgeLineColor{" << edgeLineColor << "}" << endl;
00694     if(edgeLabelColor != DEF_COLOR)
00695         out << "\\SetEdgeLabelColor{" << edgeLabelColor << "}" << endl;
00696     if(edgeLabelScale != (float) DEF_LABEL_SCALE)
00697         out << "\\SetEdgeLabelScale{" << edgeLabelScale << "}" << endl;
00698     if(edgeLineDblStatus != DEF_EDGE_LINE_DBL_STATUS)
00699         out << "\\EdgeLineDouble" << endl;
00700 }
00701 
00702 void Editor::saveFooter(QTextStream &out)
00703 {
00704     out << "\\end{VCPicture}" << endl;
00705 }
00706 
00707 void Editor::saveGraph(QTextStream &out)
00708 {
00709     out << "%" << m_stateMap.count() << " states";
00710     bool first = true;
00711   
00712     // TODO: implement memory optimalization -> group states with same switches
00713     int sbs = 0; // how many states is written side-by-side
00714     bool prevDimmed = false;
00715   
00716     StatePrevParams prevParams;
00717     prevParams.stateLineStyle = stateLineStyle;
00718     prevParams.stateLineWidth = 1;
00719     prevParams.stateLineColor = stateLineColor;
00720     prevParams.stateLabelColor = stateLabelColor;
00721     prevParams.stateLabelScale = 1;
00722     prevParams.stateFillStatus = stateFillStatus;
00723     prevParams.stateFillColor = stateFillColor;
00724     prevParams.stateLineDoubleCoef = DEF_STATE_LINE_DBL_COEF;
00725     prevParams.stateLineDoubleSep = DEF_STATE_LINE_DBL_SEP;
00726     prevParams.dimStateLineStyle = DEF_DIM_LINE_STYLE;
00727     prevParams.dimStateLineColor = DEF_DIM_COLOR;
00728     prevParams.dimStateLineCoef = DEF_DIM_STATE_LINE_COEF;
00729     prevParams.dimStateLabelColor = DEF_DIM_COLOR;
00730     prevParams.dimStateFillColor = DEF_DIM_FILL_COLOR;
00731   
00732     QPointF s_pos;
00733     QList<State*> stateList = getStateList();
00734     foreach(State *state, stateList)
00735     {
00736         if (prevDimmed)
00737         {
00738             if (!state->isDimmed())
00739             {
00740                 out << " \\RstState";
00741                 setStatePrevParamsDef(prevParams);
00742                 sbs = 0;
00743                 prevDimmed = false;
00744                 first = false;
00745             }
00746             if(state->getVCParams(out, prevParams)) {sbs = SBS_STATES;}
00747             else if (first) sbs = 0; 
00748         }
00749         else
00750         {
00751             if(state->getVCParams(out, prevParams)) {sbs = SBS_STATES;}
00752             else if (first) sbs = 0;
00753             if (state->isDimmed())
00754             {
00755                 if (sbs != SBS_STATES || first)
00756                 {
00757                     out << endl;
00758                     sbs = SBS_STATES;
00759                 }
00760                 out << "\\DimState ";
00761                 prevDimmed = true;
00762                 first = false;
00763             }
00764         }
00765     
00766         if (!sbs || first) out << endl;
00767         sbs = sbs ? sbs : SBS_STATES;
00768         first = false; 
00769         if (sbs != SBS_STATES) out << " ";
00770         out << state->getVCCommand();
00771         sbs--;
00772     }
00773     out << endl;
00774   
00775     // trasition printout
00776     QList<Transition *> trList;
00777     QList<Transition *> trIFList; // initial -- final
00778       
00779     foreach(Transition *tr, m_transitionList)
00780     {
00781         // only due to convention that IF transitions are first
00782         if (tr->getTypeName() == "Initial" ||
00783             tr->getTypeName() == "Final")
00784         {
00785             trIFList << tr;
00786         }
00787         else
00788         {
00789             trList << tr;
00790         }
00791     }
00792   
00793     // default parameters
00794     EdgePrevParams prevTrParams;
00795     prevTrParams.edgeLineStyle = edgeLineStyle; // default is editor
00796     prevTrParams.edgeLineWidth = 1;
00797     prevTrParams.edgeLineColor = edgeLineColor;
00798     prevTrParams.edgeLabelColor = edgeLabelColor;
00799     prevTrParams.edgeLabelScale = 1;
00800     prevTrParams.edgeLineDblStatus = edgeLineDblStatus;
00801     prevTrParams.edgeLineBorderCoef = DEF_EDGE_LINE_BORDER_COEF;
00802     prevTrParams.edgeLineBorderColor = DEF_EDGE_LINE_BORDER_COLOR;
00803     prevTrParams.edgeLineDblCoef = DEF_EDGE_LINE_DBL_COEF;
00804     prevTrParams.edgeLineDblSep = DEF_EDGE_LINE_DBL_SEP;
00805     prevTrParams.dimEdgeLineStyle = DEF_DIM_LINE_STYLE;
00806     prevTrParams.dimEdgeLineColor = DEF_DIM_COLOR;
00807     prevTrParams.dimEdgeLineCoef = DEF_DIM_EDGE_LINE_COEF;
00808     prevTrParams.dimEdgeLabelColor = DEF_DIM_COLOR;
00809    
00810     out << "%" << trIFList.size() << " initial-final";
00811     first = true;
00812   
00813     sbs = SBS_IF;
00814     prevDimmed = false;
00815     foreach(Transition *tr, trIFList)
00816     {
00817         if (prevDimmed)
00818         {
00819             if (!tr->isDimmed())
00820             {
00821                 out << " \\RstEdge";
00822                 setTrPrevParamsDef(prevTrParams);
00823                 sbs = 0;
00824                 prevDimmed = false;
00825                 first = false;
00826             }
00827             if(tr->getVCParams(out, prevTrParams)) {sbs = SBS_IF;}
00828             else if (first) sbs = 0;
00829         }
00830         else
00831         {
00832             if(tr->getVCParams(out, prevTrParams)) {sbs = SBS_IF;}
00833             else if (first) sbs = 0;
00834             if (tr->isDimmed())
00835             {
00836                 if (sbs != SBS_IF || first)
00837                 {
00838                     out << endl;
00839                     sbs = SBS_IF;
00840                 }
00841                 out << "\\DimEdge ";
00842                 prevDimmed = true;
00843                 first = false;
00844             }
00845         }
00846     
00847         if (!sbs || first) out << endl;
00848         sbs = sbs ? sbs : SBS_IF;
00849         first = false; 
00850         if (sbs != SBS_IF) out << " ";
00851         out << tr->getVCCommand();
00852         sbs--;
00853     }
00854     // if (prevDimmed) out << " \\RstEdge"; - tohle ne, jsou to take Transitions!
00855     out << endl; 
00856     
00857     out << "%" << trList.size() << " transitions";
00858     first = true;
00859   
00860     sbs = SBS_TRAN;
00861     // prevDimmed = false; - tohle ne, Initial a Final jsou take Transitions!
00862     foreach(Transition *tr, trList)
00863     {
00864         if (prevDimmed)
00865         {
00866             if (!tr->isDimmed())
00867             {
00868                 if (!first) out << " ";
00869                 out << "\\RstEdge";
00870                 setTrPrevParamsDef(prevTrParams);
00871                 sbs = 0;
00872                 prevDimmed = false;
00873                 first = false;
00874             }
00875             if(tr->getVCParams(out, prevTrParams)) { sbs = SBS_TRAN; }
00876             else if (first) sbs = 0;
00877         }
00878         else
00879         {
00880             if(tr->getVCParams(out, prevTrParams)) { sbs = SBS_TRAN; }
00881             else if (first) sbs = 0;
00882             if (tr->isDimmed()) 
00883             {
00884                 if (sbs != SBS_TRAN || first) 
00885                 {
00886                     out << endl;
00887                     sbs = SBS_TRAN;
00888                 }   
00889                 out << "\\DimEdge ";
00890                 prevDimmed = true;
00891                 first = false;
00892             }
00893         }
00894                   
00895         if (!sbs || first) out << endl;
00896         sbs = sbs ? sbs : SBS_TRAN;
00897         first = false;  
00898         if (sbs != SBS_TRAN) out << " ";
00899         out << tr->getVCCommand();
00900         sbs--;
00901     }
00902 
00903     out << endl;
00904 }
00905 
00906 void Editor::saveToFile(const QString &filename, bool latexHeader)
00907 {    
00908     // only to keep consistency with exportTo*
00909     scene()->clearSelection();
00910 
00911     QFile file(filename);
00912     if (!file.open(QIODevice::WriteOnly))
00913     {
00914         QString s;
00915         s = "Filename " + filename + " cannot be saved!";
00916         mw->setStatusBar(s);
00917         
00918         RELLOG("Unable to save file " << filename << ".");
00919         return;
00920     }
00921     QTextStream out(&file);
00922     
00923        
00924     if (latexHeader) saveLaTeXHeader(out);
00925     
00926     saveHeader(out);
00927     saveVCSettings(out);
00928     saveGraph(out);
00929     saveFooter(out);
00930     
00931     if (latexHeader) saveLaTeXFooter(out);
00932     
00933     out.setDevice(0);
00934     file.close();
00935         
00936     addition = latexHeader; // for save
00937     saved = true;
00938     m_undoStack->setClean();
00939     
00940     QString s;
00941     s = "Filename " + filename + " saved as Vaucanson-G format";
00942     mw->setStatusBar(s);
00943 }
00944 
00945 void Editor::exportToGraphML(const QString& fn)
00946 {
00947     // only to keep consistency with exportTo*
00948     scene()->clearSelection();
00949 
00950     QFile file(fn);
00951     file.open(QIODevice::WriteOnly);
00952     QTextStream out(&file);
00953  
00954     out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
00955     out << "<graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\">" << endl;
00956     out << "  <key id=\"d000\" for=\"node\" attr.name=\"type\" attr.type=\"string\" />" << endl
00957         << "  <key id=\"d001\" for=\"node\" attr.name=\"label\" attr.type=\"string\" />" << endl
00958         << "  <key id=\"d010\" for=\"node\" attr.name=\"x-coordinate\" attr.type=\"float\" />" << endl
00959         << "  <key id=\"d011\" for=\"node\" attr.name=\"y-coordinate\" attr.type=\"float\" />" << endl        
00960         << "  <key id=\"d02\" for=\"node\" attr.name=\"final\" attr.type=\"boolean\" />" << endl
00961         << "  <key id=\"d03\" for=\"node\" attr.name=\"dimmed\" attr.type=\"boolean\" />" << endl
00962         << "  <key id=\"d040\" for=\"node\" attr.name=\"lineStyle\" attr.type=\"string\">" << endl
00963         << "    <default>" << trLineStyle(stateLineStyle) << "</default>" << endl
00964         << "  </key>" << endl
00965         << "  <key id=\"d041\" for=\"node\" attr.name=\"lineWidth\" attr.type=\"float\">" << endl
00966         << "    <default>" << stateLineWidth << "</default>" << endl
00967         << "  </key>" << endl
00968         << "  <key id=\"d042\" for=\"node\" attr.name=\"lineColor\" attr.type=\"string\">" << endl
00969         << "    <default>" << stateLineColor << "</default>" << endl
00970         << "  </key>" << endl
00971         << "  <key id=\"d043\" for=\"node\" attr.name=\"labelColor\" attr.type=\"string\">" << endl
00972         << "    <default>" << stateLabelColor << "</default>" << endl
00973         << "  </key>" << endl
00974         << "  <key id=\"d044\" for=\"node\" attr.name=\"labelScale\" attr.type=\"float\">" << endl
00975         << "    <default>" << stateLabelScale << "</default>" << endl
00976         << "  </key>" << endl
00977         << "  <key id=\"d045\" for=\"node\" attr.name=\"fillStatus\" attr.type=\"string\">" << endl
00978         << "    <default>" << trFillStatus(stateFillStatus) << "</default>" << endl
00979         << "  </key>" << endl
00980         << "  <key id=\"d046\" for=\"node\" attr.name=\"fillColor\" attr.type=\"string\">" << endl
00981         << "    <default>" << stateFillColor << "</default>" << endl
00982         << "  </key>" << endl
00983         << "  <key id=\"d050\" for=\"node\" attr.name=\"dimLineStyle\" attr.type=\"string\">" << endl
00984         << "    <default>" << dimStateLineStyle << "</default>" << endl
00985         << "  </key>" << endl
00986         << "  <key id=\"d051\" for=\"node\" attr.name=\"dimLineColor\" attr.type=\"string\">" << endl
00987         << "    <default>" << dimStateLineColor << "</default>" << endl
00988         << "  </key>" << endl
00989         << "  <key id=\"d052\" for=\"node\" attr.name=\"dimLineCoef\" attr.type=\"float\">" << endl
00990         << "    <default>" << dimStateLineCoef << "</default>" << endl
00991         << "  </key>" << endl
00992         << "  <key id=\"d053\" for=\"node\" attr.name=\"dimLabelColor\" attr.type=\"string\">" << endl
00993         << "    <default>" << dimStateLabelColor << "</default>" << endl
00994         << "  </key>" << endl
00995         << "  <key id=\"d054\" for=\"node\" attr.name=\"dimFillColor\" attr.type=\"string\">" << endl
00996         << "    <default>" << dimStateFillColor << "</default>" << endl
00997         << "  </key>" << endl
00998         << "  <key id=\"d060\" for=\"node\" attr.name=\"lineDoubleCoef\" attr.type=\"float\">" << endl
00999         << "    <default>" << stateLineDoubleCoef << "</default>" << endl
01000         << "  </key>" << endl
01001         << "  <key id=\"d061\" for=\"node\" attr.name=\"lineDoubleSep\" attr.type=\"float\">" << endl
01002         << "    <default>" << stateLineDoubleSep << "</default>" << endl
01003         << "  </key>" << endl
01004         << endl
01005         << "  <key id=\"d10\" for=\"edge\" attr.name=\"type\" attr.type=\"string\" />" << endl
01006         << "  <key id=\"d11\" for=\"edge\" attr.name=\"label\" attr.type=\"string\" />" << endl
01007         << "  <key id=\"d12\" for=\"edge\" attr.name=\"dimmed\" attr.type=\"boolean\" />" << endl
01008         << "  <key id=\"d130\" for=\"edge\" attr.name=\"angle\" attr.type=\"integer\">" << endl
01009         << "    <default>" << DEF_ARC_ANGLE << "</default>" << endl
01010         << "  </key>" << endl
01011         << "  <key id=\"d131\" for=\"edge\" attr.name=\"arcangleA\" attr.type=\"integer\">" << endl
01012         << "    <default>" << DEF_VCURV_ANGLE << "</default>" << endl
01013         << "  </key>" << endl
01014         << "  <key id=\"d132\" for=\"edge\" attr.name=\"arcangleB\" attr.type=\"integer\">" << endl
01015         << "    <default>" << DEF_VCURV_ANGLE_B << "</default>" << endl
01016         << "  </key>" << endl
01017         << "  <key id=\"d133\" for=\"edge\" attr.name=\"ncurv\" attr.type=\"float\">" << endl
01018         << "    <default>" << DEF_ARC_CURV << "</default>" << endl
01019         << "  </key>" << endl
01020         << "  <key id=\"d140\" for=\"edge\" attr.name=\"lineStyle\" attr.type=\"string\">" << endl
01021         << "    <default>" << edgeLineStyle << "</default>" << endl
01022         << "  </key>" << endl
01023         << "  <key id=\"d141\" for=\"edge\" attr.name=\"lineWidth\" attr.type=\"float\">" << endl
01024         << "    <default>" << edgeLineWidth << "</default>" << endl
01025         << "  </key>" << endl
01026         << "  <key id=\"d142\" for=\"edge\" attr.name=\"lineColor\" attr.type=\"string\">" << endl
01027         << "    <default>" << edgeLineColor << "</default>" << endl
01028         << "  </key>" << endl
01029         << "  <key id=\"d143\" for=\"edge\" attr.name=\"labelColor\" attr.type=\"string\">" << endl
01030         << "    <default>" << edgeLabelColor << "</default>" << endl
01031         << "  </key>" << endl
01032         << "  <key id=\"d144\" for=\"edge\" attr.name=\"labelScale\" attr.type=\"float\">" << endl
01033         << "    <default>" << edgeLabelScale << "</default>" << endl
01034         << "  </key>" << endl
01035         << "  <key id=\"d145\" for=\"edge\" attr.name=\"lineDblStatus\" attr.type=\"boolean\">" << endl
01036         << "    <default>" << trBool(edgeLineDblStatus) << "</default>" << endl
01037         << "  </key>" << endl
01038         << "  <key id=\"d150\" for=\"edge\" attr.name=\"dimLineStyle\" attr.type=\"string\">" << endl
01039         << "    <default>" << dimEdgeLineStyle << "</default>" << endl
01040         << "  </key>" << endl
01041         << "  <key id=\"d151\" for=\"edge\" attr.name=\"dimLineColor\" attr.type=\"string\">" << endl
01042         << "    <default>" << dimEdgeLineColor << "</default>" << endl
01043         << "  </key>" << endl
01044         << "  <key id=\"d152\" for=\"edge\" attr.name=\"dimLineCoef\" attr.type=\"float\">" << endl
01045         << "    <default>" << dimEdgeLineCoef << "</default>" << endl
01046         << "  </key>" << endl
01047         << "  <key id=\"d153\" for=\"edge\" attr.name=\"dimLabelColor\" attr.type=\"string\">" << endl
01048         << "    <default>" << dimEdgeLabelColor << "</default>" << endl
01049         << "  </key>" << endl
01050         << "  <key id=\"d160\" for=\"edge\" attr.name=\"lineBorderCoef\" attr.type=\"float\">" << endl
01051         << "    <default>" << edgeLineBorderCoef << "</default>" << endl
01052         << "  </key>" << endl
01053         << "  <key id=\"d161\" for=\"edge\" attr.name=\"lineBorderColor\" attr.type=\"string\">" << endl
01054         << "    <default>" << edgeLineBorderColor << "</default>" << endl
01055         << "  </key>" << endl
01056         << "  <key id=\"d170\" for=\"edge\" attr.name=\"lineDblCoef\" attr.type=\"float\">" << endl
01057         << "    <default>" << edgeLineDblCoef << "</default>" << endl
01058         << "  </key>" << endl
01059         << "  <key id=\"d171\" for=\"edge\" attr.name=\"lineDblSep\" attr.type=\"float\">" << endl
01060         << "    <default>" << edgeLineDblSep << "</default>" << endl
01061         << "  </key>" << endl
01062         << endl 
01063         << "  <graph id=\"G\" edgedefualt=\"directed\">" << endl;
01064     
01065     QPointF pos;
01066     QList<State*> stateList = getStateList();
01067     foreach (State *state, stateList)
01068     {
01069         out << "    <node id=\"n" << state->getName() << "\">" << endl;
01070       
01071         out << "    <data key=\"d000\">" << state->getTypeName() << "</data>" << endl;
01072 
01073         if (state->getLabel() != "")
01074         out << "      <data key=\"d001\">" << state->getLabel() << "</data>" << endl;
01075       
01076         pos = mapToGrid(state->pos());
01077         out << "      <data key=\"d010\">" << pos.x() << "</data>" << endl;
01078         out << "      <data key=\"d011\">" << pos.y() << "</data>" << endl;
01079       
01080         out << "      <data key=\"d02\">" << trBool(state->isDoubleBorder()) << "</data>" << endl;
01081       
01082         out << "      <data key=\"d03\">" << trBool(state->isDimmed()) << "</data>" << endl;
01083       
01084         if (state->stateLineStyle != stateLineStyle)
01085         out << "      <data key=\"d040\">" << trLineStyle(state->stateLineStyle) << "</data>" << endl;
01086         if (state->stateLineWidth != 1)
01087         out << "      <data key=\"d041\">" << state->stateLineWidth * stateLineWidth << "</data>" << endl;
01088         if (state->stateLineColor != stateLineColor)
01089         out << "      <data key=\"d042\">" << state->stateLineColor << "</data>" << endl;
01090         if (state->stateLabelColor != stateLabelColor)
01091         out << "      <data key=\"d043\">" << state->stateLabelColor << "</data>" << endl;
01092         if (state->stateLabelScale != 1)
01093         out << "      <data key=\"d044\">" << state->stateLabelScale * stateLabelScale << "</data>" << endl;
01094         if (state->stateFillStatus != stateFillStatus)
01095         out << "      <data key=\"d046\">" << trFillStatus(state->stateFillStatus) << "</data>" << endl;
01096         if (state->stateFillColor != stateFillColor)
01097         out << "      <data key=\"d047\">" << state->stateFillColor << "</data>" << endl;
01098     
01099         if (state->dimStateLineStyle != dimStateLineStyle)
01100         out << "      <data key=\"d050\">" << trLineStyle(state->dimStateLineStyle) << "</data>" << endl;
01101         if (state->dimStateLineColor != dimStateLineColor)
01102         out << "      <data key=\"d051\">" << state->dimStateLineColor << "</data>" << endl;
01103         if (state->dimStateLineCoef != dimStateLineCoef)
01104         out << "      <data key=\"d052\">" << state->dimStateLineCoef << "</data>" << endl;
01105         if (state->dimStateLabelColor != dimStateLabelColor)
01106         out << "      <data key=\"d053\">" << state->dimStateLabelColor << "</data>" << endl;
01107         if (state->dimStateFillColor != dimStateFillColor)
01108         out << "      <data key=\"d054\">" << state->dimStateFillColor << "</data>" << endl;
01109       
01110         if (state->stateLineDoubleCoef != stateLineDoubleCoef)
01111         out << "      <data key=\"d060\">" << state->stateLineDoubleCoef << "</data>" << endl;
01112         if (state->stateLineDoubleSep != stateLineDoubleSep)
01113         out << "      <data key=\"d061\">" << state->stateLineDoubleSep << "</data>" << endl;
01114       
01115         out << "    </node>" << endl;
01116     }
01117     out << endl;
01118     
01119     foreach (Transition *tr, m_transitionList)
01120     {
01121         out << "    <edge source=\"n" << tr->getStartState()->getName() << "\"";
01122         if (tr->hasEndState())
01123             out << " target=\"n" << tr->getEndState()->getName() << "\">" << endl;
01124         else
01125             out << ">" << endl;
01126       
01127         out << "      <data key=\"d10\">" << tr->getTypeName() << tr->getTypeNameSuffix() << "</data>" << endl;
01128         if (tr->getLabelText() != "")
01129         out << "      <data key=\"d11\">" << tr->getLabelText() << "</data>" << endl;
01130         out << "      <data key=\"d12\">" << trBool(tr->isDimmed()) << "</data>" << endl;
01131         
01132         out << tr->getGraphMLParams();
01133 
01134         /*if (tr->getType() == TR_VARC)
01135         {
01136             if (tr->getArcAngle() != DEF_ARC_ANGLE)
01137         out << "      <data key=\"d130\">" << tr->getArcAngle() << "</data>" << endl;
01138             if (tr->getNCurv() != DEF_ARC_CURV)
01139         out << "      <data key=\"d133\">" << tr->getNCurv() << "</data>" << endl;
01140         }
01141         else if(tr->getType() == TR_VCURVE)
01142         {
01143         out << "      <data key=\"d131\">" << tr->getArcAngle() << "</data>" << endl;
01144         out << "      <data key=\"d132\">" << tr->getArcAngle() << "</data>" << endl;
01145         out << "      <data key=\"d133\">" << tr->getNCurv() << "</data>" << endl;
01146         } // if*/
01147       
01148         if (tr->edgeLineStyle != edgeLineStyle)
01149         out << "      <data key=\"d140\">" << trLineStyle(tr->edgeLineStyle) << "</data>" << endl;
01150         if (tr->edgeLineWidth != 1)
01151         out << "      <data key=\"d141\">" << tr->edgeLineWidth * edgeLineWidth << "</data>" << endl;
01152         if (tr->edgeLineColor != edgeLineColor)
01153         out << "      <data key=\"d142\">" << tr->edgeLineColor << "</data>" << endl;
01154         if (tr->edgeLabelColor != edgeLabelColor)
01155         out << "      <data key=\"d143\">" << tr->edgeLabelColor << "</data>" << endl;
01156         if (tr->edgeLabelScale != 1)
01157         out << "      <data key=\"d144\">" << tr->edgeLabelScale * edgeLabelScale << "</data>" << endl;
01158         if (tr->edgeLineDblStatus != edgeLineDblStatus)
01159         out << "      <data key=\"d145\">" << trBool(tr->edgeLineDblStatus) << "</data>" << endl;
01160       
01161         if (tr->dimEdgeLineStyle != dimEdgeLineStyle)
01162         out << "      <data key=\"d150\">" << trLineStyle(tr->dimEdgeLineStyle) << "</data>" << endl;
01163         if (tr->dimEdgeLineColor != dimEdgeLineColor)
01164         out << "      <data key=\"d151\">" << tr->dimEdgeLineColor << "</data>" << endl;
01165         if (tr->dimEdgeLineCoef != dimEdgeLineCoef)
01166         out << "      <data key=\"d152\">" << tr->dimEdgeLineCoef << "</data>" << endl;
01167         if (tr->dimEdgeLabelColor != dimEdgeLabelColor)
01168         out << "      <data key=\"d153\">" << tr->dimEdgeLabelColor << "</data>" << endl;
01169       
01170         if (tr->edgeLineBorderCoef != edgeLineBorderCoef)
01171         out << "      <data key=\"d160\">" << tr->edgeLineBorderCoef << "</data>" << endl;
01172         if (tr->edgeLineBorderColor != edgeLineBorderColor)
01173         out << "      <data key=\"d161\">" << tr->edgeLineBorderColor << "</data>" << endl;
01174       
01175         if (tr->edgeLineDblCoef != edgeLineDblCoef)
01176         out << "      <data key=\"d170\">" << tr->edgeLineDblCoef << "</data>" << endl;
01177         if (tr->edgeLineDblSep != edgeLineDblSep)
01178         out << "      <data key=\"d171\">" << tr->edgeLineDblSep << "</data>" << endl;
01179       
01180         out << "    </edge>" << endl;
01181     }
01182     
01183     out << "  </graph>" << endl
01184         << "</graphml>" << endl;    
01185   
01186     out.setDevice(0);
01187     file.close();
01188   
01189     QString s;
01190     s = "Filename " + fn + " saved as GraphML format";
01191     mw->setStatusBar(s);
01192 }
01193 
01194 /*void Editor::exportToEPS(const QString& fn)
01195 {
01196   QFile file(fn);
01197   file.open(QIODevice::WriteOnly);
01198   QTextStream out(&file);
01199   
01200   QRectF boundingBox = scene()->itemsBoundingRect();  
01201   boundingBox = boundingBox.united(scene()->sceneRect());
01202   // in EPS 0,0 is left bottom corner but in editor it is left top corner
01203   int height = scene()->height() - boundingBox.top(); // top is negative number or 0
01204   int bottom = scene()->height() - boundingBox.height(); // should be 0 or negative number
01205 
01206   QDateTime dt = QDateTime().currentDateTime();
01207   out << "%!PS-Adobe-3.0 EPSF-3.0" << endl
01208         << "%%Creator: Automata editor by krizm7@fel.cvut.cz" << endl
01209         << "%%CreationDate: " << QDateTime().currentDateTime().toString("d.M.yyyy hh:mm:ss") << endl
01210         << "%%Title: " << fn << endl                
01211         << "%%BoundingBox: " << (int)boundingBox.left()   << " "
01212                              << (int)bottom               << " "
01213                              << (int)boundingBox.width()  << " "
01214                              << (int)height               << endl
01215         << "%%EndComments" << endl;
01216   out << endl
01217       << "/bdef { bind def } bind def" << endl
01218       << "%line types: " << endl
01219       << "/solid { [] 0 setdash } bdef" << endl
01220       << "/dashed { [6 2] 0 setdash } bdef" << endl
01221       << "/dotted { [1 2] 0 setdash } bdef" << endl
01222       << "/dotdashed { [1 2 6 2] 0 setdash } bdef" << endl
01223       << "/none { [0 20] 0 setdash } bdef" << endl // TODO: make "none" better
01224       << endl
01225       << "% x y radius width r g b x y radius r g b sCircle" << endl
01226          << "/sCircle {" << endl
01227       //<< "  gsave" << endl
01228       << "  setrgbcolor" << endl
01229       << "  newpath" << endl
01230       << "  0 360 arc" << endl
01231       << "  fill" << endl
01232       << "  setrgbcolor" << endl
01233       << "  setlinewidth" << endl
01234       << "  newpath" << endl
01235       << "  0 360 arc" << endl
01236       << "  stroke" << endl
01237       //<< "  grestore" << endl
01238       << "} def" << endl
01239       << endl
01240       << "% x y radius x y radius width r g b x y radius r g b sDbCircle" << endl
01241       << "/sDbCircle {" << endl
01242       << "  gsave" << endl
01243       << "  setrgbcolor" << endl
01244       << "  newpath" << endl
01245       << "  0 360 arc" << endl
01246       << "  fill" << endl
01247       << "  setrgbcolor" << endl
01248       << "  setlinewidth" << endl
01249       << "  newpath" << endl
01250       << "  0 360 arc" << endl
01251       << "  stroke" << endl
01252       << "  newpath" << endl
01253       << "  0 360 arc" << endl      
01254       << "  stroke" << endl
01255       << "  grestore" << endl
01256       << "} def" << endl
01257       << endl
01258       << "% x y width height radius linewidth r g b rfill gfill bfill sBubble" << endl
01259       << "% x,y is center of bubble" << endl
01260       << "/sBubble {" << endl
01261       << "  setrgbcolor" << endl
01262       << "  /bval exch def" << endl
01263       << "  /gval exch def" << endl
01264       << "  /rval exch def" << endl
01265       << "  setlinewidth" << endl
01266       << "  /radval exch def" << endl
01267       << "  2 div" << endl
01268       << "  /hval exch def" << endl
01269       << "  2 div" << endl
01270       << "  /wval exch def" << endl
01271       << "  /yval exch def" << endl
01272       << "  /xval exch def" << endl
01273       << "  newpath" << endl
01274       << "  % from top to left" << endl
01275       << "  xval yval hval add moveto" << endl
01276       << "  xval wval sub" << endl
01277       << "  yval hval add" << endl
01278       << "  xval wval sub" << endl
01279       << "  yval radval arct" << endl
01280       << "  xval wval sub yval lineto     % to half of bubble (according to arct reference)" << endl
01281       << "  % from left to bottom" << endl
01282       << "  % xval wval sub yval moveto" << endl
01283       << "  xval wval sub" << endl
01284       << "  yval hval sub" << endl
01285       << "  xval yval hval sub radval arct" << endl
01286       << "  xval yval hval sub lineto" << endl
01287       << "  % from bottom to right" << endl
01288       << "  % xval yval hval sub moveto" << endl
01289       << "  xval wval add" << endl
01290       << "  yval hval sub" << endl
01291       << "  xval wval add yval radval arct" << endl
01292       << "  xval wval add yval lineto" << endl
01293       << "  % from right to top" << endl
01294       << "  % xval wval add yval moveto" << endl
01295       << "  xval wval add" << endl
01296       << "  yval hval add" << endl
01297       << "  xval yval hval add radval arct" << endl
01298       << "  xval yval hval add lineto" << endl
01299       << "  gsave" << endl
01300       << "  fill" << endl      
01301       << "  grestore" << endl
01302       << "  rval gval bval setrgbcolor" << endl
01303       << "  stroke" << endl
01304       << "} def" << endl
01305       << endl      
01306       << "% r g b lx1 ly lx ly lx ly mx my trArrow" << endl
01307       << "/trArrow {" << endl
01308       << "  newpath" << endl
01309       << "  moveto" << endl
01310       << "  lineto" << endl
01311       << "  lineto" << endl
01312       << "  lineto" << endl
01313       << "  closepath" << endl
01314       << "  setrgbcolor" << endl
01315       << "  fill" << endl
01316       << "} def" << endl
01317       << endl
01318       << "% r g b width lx ly mx my trLine" << endl
01319       << "/trLine {" << endl
01320       << "  newpath" << endl
01321       << "  moveto" << endl
01322       << "  lineto" << endl
01323       << "  setlinewidth" << endl
01324       << "  setrgbcolor" << endl
01325       << "  stroke" << endl
01326       << "} def" << endl
01327       << endl
01328       << "% r g b width cx cy cx cy cx cy mx my trLoop" << endl
01329       << "/trLoop {" << endl
01330       << "  newpath" << endl
01331       << "  moveto" << endl
01332       << "  curveto" << endl
01333       << "  setlinewidth" << endl
01334       << "  setrgbcolor" << endl
01335       << "  stroke" << endl
01336       << "} def" << endl
01337       //<< endl
01338       //<< "% r g b width x y radius angle1 angle2 trArc" << endl
01339       //<< "/trArc {" << endl
01340       //<< "  newpath" << endl
01341       //<< "  arc" << endl
01342       //<< "  setlinewidth" << endl
01343       //<< "  setrgbcolor" << endl
01344       //<< "  stroke" << endl
01345       //<< "} def" << endl
01346       // now Arc has same style of painting as VArc
01347       << endl      
01348       << "% r g b width x0 y0 x1 y1 x2 y2 x y trArc" << endl
01349       << "/trArc {" << endl
01350       << "  newpath" << endl
01351       << "  moveto" << endl
01352       << "  curveto" << endl
01353       << "  setlinewidth" << endl
01354       << "  setrgbcolor" << endl
01355       << "  stroke" << endl
01356       << "} def" << endl
01357       << endl      
01358       << "% r g b width x0 y0 x1 y1 x2 y2 x y trVArc" << endl
01359       << "/trVArc {" << endl
01360       << "  newpath" << endl
01361       << "  moveto" << endl
01362       << "  curveto" << endl
01363       << "  setlinewidth" << endl
01364       << "  setrgbcolor" << endl
01365       << "  stroke" << endl
01366       << "} def" << endl
01367       << endl
01368       // VCurve has the same style of painting as VArc, VArc has both angles same
01369       << "% r g b width x0 y0 x1 y1 x2 y2 x y trVCurve" << endl
01370       << "/trVCurve {" << endl
01371       << "  newpath" << endl
01372       << "  moveto" << endl
01373       << "  curveto" << endl
01374       << "  setlinewidth" << endl
01375       << "  setrgbcolor" << endl
01376       << "  stroke" << endl
01377       << "} def" << endl
01378       << endl
01379       << "% (text) r g b x y iLabel" << endl
01380       << "/iLabel {" << endl
01381       << "  newpath" << endl
01382       << "  moveto" << endl
01383       << "  setrgbcolor" << endl
01384       << "  show" << endl
01385       << "} def" << endl            
01386       << endl
01387       << "% default font" << endl
01388       << "/Arial findfont 30 scalefont setfont" << endl
01389       << endl;
01390       
01391   
01392     out << "%transitions" << endl;
01393     foreach (Transition *tr, m_transitionList){
01394         out << tr->getEPS();
01395     }
01396 
01397     out << endl;
01398 
01399     out << "%states" << endl;
01400     QList<State*> stateList = getStateList();
01401     foreach (State *state, stateList){
01402         out << state->getEPS();
01403     }
01404 
01405     out.setDevice(0);
01406     file.close();
01407 
01408     QString s = "Filename " + fn + " saved as Encapsulated PostScript format";
01409     mw->setStatusBar(s);
01410 }*/
01411 
01412 QRectF Editor::getPrintRect()
01413 {
01414     QRectF boundingBox = scene()->itemsBoundingRect();
01415     // TODO: what if showFrame == fasle? .. too much space on top and on left sides
01416     const QRectF sceneRect = showFrame ? scene()->sceneRect().adjusted(0,0,2,4) // adjusted due to grid numbers
01417                                        : scene()->sceneRect();
01418     boundingBox = boundingBox.united(sceneRect);
01419     return boundingBox;
01420 }
01421 
01422 void Editor::exportToEPS(const QString& fn)
01423 {
01424     // selection area marker shouldn't be exported
01425     scene()->clearSelection();
01426     
01427     QRectF boundingBox = getPrintRect();
01428     
01429     QPrinter printer(QPrinter::PrinterResolution);
01430     printer.setOutputFileName(fn);
01431     printer.setOutputFormat(QPrinter::PostScriptFormat);        
01432     DBGLOG("Paper size: " << boundingBox.size().toSize());
01433     printer.setPaperSize(boundingBox.size().toSize(), QPrinter::Point);
01434 
01435     QPainter painter(&printer);
01436     render(&painter, QRectF(), mapFromScene(boundingBox).boundingRect());
01437     painter.end();
01438 
01439     QString s = "Filename " + fn + " saved as Encapsulated PostScript format";
01440     mw->setStatusBar(s);
01441 }
01442 
01443 #ifndef DONT_USE_SVG_MODULE
01444 void Editor::exportToSVG(const QString& fn)
01445 {
01446     // selection area marker shouldn't be exported
01447     scene()->clearSelection();
01448 
01449     QRectF boundingBox = getPrintRect();
01450     // needs to be from point 0,0 for generator, so translate to it
01451     QRectF translatedBB = QRectF(0, 0, boundingBox.width(), boundingBox.height());
01452 
01453     QSvgGenerator generator;
01454     generator.setFileName(fn);
01455     generator.setSize(boundingBox.size().toSize());
01456     generator.setViewBox(translatedBB);
01457     generator.setTitle(tr("AutomataEditor"));
01458     generator.setDescription(tr("SVG graph exported by AutomataEditor"));
01459 
01460     QPainter painter;
01461     painter.begin(&generator);
01462 
01463     // background HACK? - maybe could be used even for OpenGL rendering of pixmap (bug)?
01464     painter.setPen(Qt::NoPen);
01465     painter.setBrush(Qt::white);
01466     painter.drawRect(translatedBB);
01467 
01468     render(&painter, QRectF(), mapFromScene(boundingBox).boundingRect());
01469     painter.end();
01470 }
01471 #endif
01472 
01473 void Editor::exportToPixmap(const QString& fn, Format f)
01474 {
01475     // selection area marker shouldn't be exported
01476     scene()->clearSelection();
01477 
01478     QString format;
01479     
01480     switch (f) {
01481         case png : format = "PNG"; break;
01482         case bmp : format = "BMP"; break;
01483         case xpm : format = "XPM"; break;
01484         default : return; break;
01485     }
01486 
01487     if (QPixmap::grabWidget(this,
01488         mapFromScene(getPrintRect()).boundingRect())
01489         .save(fn, format.toAscii())){
01490         mw->setStatusBar( QString("Filename \'%1\' saved").arg(fn) );
01491     } else {
01492         mw->setStatusBar( QString("Failed to save filename \'%1\'").arg(fn) );
01493     }
01494 }
01495 
01496 void Editor::setRightSceneRect()
01497 {
01498     // This is quite alogical, this method pass to QGraphicView another sceneRect than it realy is (in QGraphicsScene).
01499     // One should pressupose that it only sets new sceneRect to scene (as scene()->setSceneRect()).
01500     // Therefore it is very useful if one want to set BORDER around real scene ;-).
01501     QRectF newRect(-sceneBorder, -sceneBorder, br.x() + sceneBorder*2, br.y() + sceneBorder*2);
01502     newRect |= scene()->itemsBoundingRect();
01503 
01504     setSceneRect(newRect);
01505 }
01506 
01507 void Editor::sceneChanged(const QList<QRectF> &)
01508 {
01509     m_sceneChanged = true;
01510 }
01511 
01512 void Editor::resizeEvent(QResizeEvent* )
01513 {  
01514     setRightSceneRect();
01515 }
01516 
01517 void Editor::wheelEvent(QWheelEvent *event)
01518 {
01519     if (event->modifiers() == Qt::CTRL)
01520     {
01521         scaleView(pow(2., event->delta() / ZOOM_DIVIDER));
01522         return;
01523     }
01524     QGraphicsView::wheelEvent(event); // original behavior
01525 }
01526 
01527 void Editor::scaleView(qreal scaleFactor)
01528 {
01529     // TODO: try to use setMatrix instead of scale! (maybe faster)
01530     qreal factor = matrix().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
01531     if (factor < 0.07)
01532     {
01533         emit canZoomOut(false);
01534         return;
01535     }
01536     else if(factor > 100)
01537     {
01538         emit canZoomIn(false);
01539         return;
01540     }
01541 
01542     emit canZoomIn(true);
01543     emit canZoomOut(true);
01544 
01545     scale(scaleFactor, scaleFactor);
01546 }
01547 
01548 void Editor::moveState()
01549 {
01550     m_stateIsMoving = true;
01551     m_itemsMoved = false;
01552 
01553     m_origPos = selectedState->pos();
01554     m_origPositions.resize(1);
01555     m_origPositions[0] = selectedState->pos();
01556     
01557     // TODO: why this is not fuctional under Ubutnu/Linux?
01558     QCursor::setPos(mapToGlobal(mapFromScene(m_origPos.toPoint())));
01559     
01560     DBGLOG_ME("cursor=ClosedHandCursor");
01561     setCursor(Qt::ClosedHandCursor);
01562 }
01563 
01564 void Editor::cutSelection()
01565 {
01566     copySelection();
01567     removeSelection();
01568 }
01569 
01570 void Editor::removeSelection()
01571 {
01572     QList<State *> selectedStates;
01573     
01574     QSet<Transition *> transitionSet;
01575     transitionSet.reserve(m_transitionList.count());
01576 
01577     QList<State*> stateList = getStateList();
01578     foreach(State *state, stateList)
01579     {
01580         if (state->isSelected())
01581         {
01582             selectedStates << state;
01583             foreach(Transition *tr, state->getTransitionList())
01584             {
01585                 transitionSet << tr;
01586             }
01587         }
01588     }
01589 
01590     foreach(Transition *tr, m_transitionList)
01591     {
01592         if (tr->isSelected())
01593         {
01594             transitionSet << tr;
01595         }
01596     }
01597 
01598     m_undoStack->push(
01599         new ItemsRemoveCommand(this, selectedStates, transitionSet.toList())
01600     );
01601 }
01602 
01603 bool Editor::isSomethingSelected()
01604 {
01605     return !(scene()->selectedItems().empty());
01606 }
01607 
01608 bool Editor::isPastePossible()
01609 {
01610     if (m_simulationIsRun) return false;
01611 
01612     DBGLOG(QApplication::clipboard()->mimeData()->formats());
01613     if (QApplication::clipboard()->mimeData()->hasFormat(CLIPBOARD_FORMAT_STATE) ||
01614         QApplication::clipboard()->mimeData()->hasFormat(CLIPBOARD_FORMAT))
01615     {
01616         return true;
01617     }
01618     return false;
01619 }
01620 
01621 void Editor::cutState()
01622 {
01623     copyState();
01624     removeState();
01625 }
01626 
01627 void Editor::copyState()
01628 {
01629     QByteArray itemData;
01630     QDataStream dataStream(&itemData, QIODevice::WriteOnly);
01631     
01632     Q_ASSERT(selectedState != NULL && 
01633         "Pointer is NULL but should be filled in Editor::popupState!");
01634 
01635     dataStream << StateSerializer(*selectedState);
01636 
01637     QMimeData *mimeData = new QMimeData();
01638     mimeData->setData(CLIPBOARD_FORMAT_STATE, itemData);
01639 
01640     QApplication::clipboard()->setMimeData(mimeData);
01641 }
01642 
01643 void Editor::copySelection()
01644 {
01645     // TODO: make selection copyable only when some state is selected!
01646     //       or think up some way how to add copyied transiton -> 
01647     //       e.g. some dialog with existing state's selection
01648     
01649     QByteArray itemsData;
01650     QDataStream dataStream(&itemsData, QIODevice::WriteOnly);
01651 
01652     dataStream << SelectionSerializer(scene()->selectedItems());
01653 
01654     QMimeData *mimeData = new QMimeData();
01655     mimeData->setData(CLIPBOARD_FORMAT, itemsData);
01656 
01657     QApplication::clipboard()->setMimeData(mimeData);
01658 }
01659 
01660 void Editor::paste(const QPoint& insertPoint)
01661 {
01662     // TODO: paste data from clipboard with some offset (for each pasting other offset)
01663     try
01664     {
01665         QClipboard *clipboard = QApplication::clipboard();
01666         const QMimeData *mimeData = clipboard->mimeData();
01667 
01668         if (mimeData->hasFormat(CLIPBOARD_FORMAT_STATE)) // state is in clipboard
01669         {
01670             setActionInternal(eSelection);
01671 
01672             QByteArray itemData = mimeData->data(CLIPBOARD_FORMAT_STATE);
01673 
01674             QDataStream dataStream(&itemData, QIODevice::ReadOnly);
01675         
01676             StateSerializer stateSerializer;
01677             dataStream >> stateSerializer;
01678 
01679             DBGLOG_SER("stateSerializer ->" << stateSerializer.m_typeName);            
01680 
01681             State *state = stateSerializer.createState(this, insertPoint);
01682             state->setAutoNammed(true);
01683             m_undoStack->push(
01684                 new StateAddCommand(this, state)
01685             );
01686 
01687             scene()->clearSelection();
01688             state->setSelected(true);
01689         }
01690         else if (mimeData->hasFormat(CLIPBOARD_FORMAT)) // selection is in clipboard
01691         {
01692             setActionInternal(eSelection);
01693 
01694             QByteArray itemData = mimeData->data(CLIPBOARD_FORMAT);
01695 
01696             QDataStream dataStream(&itemData, QIODevice::ReadOnly);
01697 
01698             SelectionSerializer serializer;
01699             dataStream >> serializer;
01700 
01701             DBGLOG_SER("selectionSerializer ->" << "hotSpot=" << serializer.m_hotSpot << " "
01702                                                 << "state count=" << serializer.m_serializedStates.count());
01703 
01704             SelectionSerializer::TItemsPair items = serializer.createItems(this, insertPoint);
01705             QList<State*> states = items.first;
01706             QList<Transition*> transitions = items.second;
01707 
01708             m_undoStack->push(
01709                 new ItemsAddCommand(this, states, gridRect)
01710             );
01711 
01712             scene()->clearSelection();
01713 
01714             foreach(State* state, states)
01715             {
01716                 state->setSelected(true);
01717             }
01718             foreach(Transition *transition, transitions)
01719             {
01720                 transition->setSelected(true);
01721             }
01722         }
01723         else
01724         {
01725             Q_ASSERT(0 && "This shouldn't be possible call this method when incorrect data is in clipboard");
01726             RELLOG("Incorrect data in clipboard, but paste called!");
01727         }
01728     }
01729     catch(...)
01730     {
01731         QMessageBox::critical(this, PROGRAM_NAME,
01732             tr("Invalid clipboard! \n"
01733                "Data from clipboard couldn't be pasted!"), "OK");
01734     }
01735 }
01736 
01737 void Editor::paste()
01738 {
01739     paste(QPoint(scene()->width()/2, scene()->height()/2));
01740 }
01741 
01742 //! private only for pasting form popup
01743 void Editor::pasteOnPos()
01744 {
01745     paste(mapToScene(m_popupPoint).toPoint());
01746 }
01747 
01748 void Editor::itemsInvertSelection(QList<QGraphicsItem *> items)
01749 {
01750     foreach(QGraphicsItem *item, items)
01751     {
01752         item->setSelected(!item->isSelected());
01753     }
01754 }
01755 
01756 bool Editor::itemAlignToGrid(QGraphicsItem *item)
01757 {
01758     if (!(item->flags() & QGraphicsItem::ItemIsMovable))
01759     {
01760         return false;
01761     }
01762 
01763     QPoint pos(item->pos().toPoint());
01764     
01765     QPoint newPos;
01766     newPos.setX(pos.x() / GRID_STEP * GRID_STEP + (pos.x() > 0 ? GRID_STEP/2 : - GRID_STEP/2));
01767     newPos.setY(pos.y() / GRID_STEP * GRID_STEP + (pos.y() > 0 ? GRID_STEP/2 : - GRID_STEP/2));
01768 
01769     if (pos != newPos)
01770     {
01771         item->setPos(newPos.x(), newPos.y());
01772         return true;
01773     }
01774 
01775     return false;
01776 }
01777 
01778 void Editor::mousePressEvent(QMouseEvent *event)
01779 {
01780     DBGLOG_ME("accepted=" << event->isAccepted());
01781 
01782     if (m_simulationIsRun) return;
01783 
01784     if (m_stateIsMoving)
01785     {
01786         m_stateIsMoving = false;
01787         
01788         if (m_itemsMoved)
01789         {
01790             stateMoved(selectedState, m_origPositions[0]);
01791         }
01792 
01793         selectedState->setChecked(false);
01794         selectedState = NULL;
01795 
01796         return;
01797     }
01798 
01799     m_currentMouseAction = eNoMouseAction;
01800     QList<QGraphicsItem *> itemsOnPos(items(event->pos()));
01801 
01802     // remove nonselectable items due to controlling if clicked item is selected
01803     while(!itemsOnPos.isEmpty())
01804     {        
01805         if (itemsOnPos.first()->flags() & QGraphicsItem::ItemIsSelectable)
01806             break; // we need to be sure that first item in list selectable, no all of them
01807         else
01808             itemsOnPos.removeFirst();
01809     }
01810 
01811     if (m_selectedAction == eSelection)
01812     {
01813         switch (event->button())
01814         {
01815         case Qt::LeftButton:        
01816             if (event->modifiers() == Qt::ShiftModifier)
01817             {            
01818                 if (itemsOnPos.empty())
01819                 { // no item -> start rubberBand, don't clear previous selection
01820                     m_currentMouseAction = eSelectMultipleItems;
01821                     m_rubberBandOrigin = event->pos();
01822                     m_rubberBand->setGeometry(QRect(m_rubberBandOrigin, QSize()));
01823                     m_rubberBand->show();
01824                     return;
01825                 }
01826                 else
01827                 { // item (selected or not) -> invert
01828                     itemsInvertSelection(itemsOnPos);                
01829                 }
01830             }
01831             else // w/o SHIFT
01832             {                        
01833                 if (itemsOnPos.empty())
01834                 { // no item -> clear selection, start rubberBand                    
01835                     m_currentMouseAction = eSelectMultipleItems;
01836                     scene()->clearSelection();
01837                     m_rubberBandOrigin = event->pos();
01838                     m_rubberBand->setGeometry(QRect(m_rubberBandOrigin, QSize()));
01839                     m_rubberBand->show();
01840                     QGraphicsView::mousePressEvent(event);
01841                 }
01842                 else if (itemsOnPos[0]->isSelected() &&
01843                          scene()->selectedItems().count() > 1) // only when more items are selected
01844                 { // selected item -> move with selected items -> store original pos
01845                     // moving is possible only with movable items -> currently only on states
01846                     m_currentMouseAction = eMoveMultItem;                    
01847                     DBGLOG_ME("cursor=ClosedHandCursor");
01848                     setCursor(Qt::ClosedHandCursor); // TODO: why cursor isn't changed after popup menu is closed?                    
01849 
01850                     m_itemsMoved = false;
01851                     m_origPos = mapToScene(event->pos());
01852                     
01853                     m_origPositions.resize(scene()->selectedItems().size());
01854 
01855                     int i = 0;
01856                     foreach(QGraphicsItem *item, scene()->selectedItems())
01857                     {
01858                         m_origPositions[i] = item->pos();
01859                         ++i;
01860                     }
01861                 }
01862                 else
01863                 { // no selected item -> clear selection and propagate to item
01864                     m_currentMouseAction = eMoveItem;
01865                     scene()->clearSelection();                    
01866 
01867                     QGraphicsView::mousePressEvent(event);
01868                 }
01869             }
01870             break; // Qt::LeftButton
01871         case Qt::RightButton:
01872             if (itemsOnPos.empty())
01873             { // no item -> show popup (paste)
01874                 scene()->clearSelection();
01875                 m_currentMouseAction = eShowPopup;
01876             }
01877             else if (itemsOnPos[0]->isSelected() &&
01878                      scene()->selectedItems().count() > 1) // only when more items are selected
01879             { // selected item -> show popup (copy, remove)
01880                 m_currentMouseAction = eShowSelectionPopup;
01881             }
01882             else
01883             { // no selected item (or just one) -> propagate (item will invoke popup)
01884                 scene()->clearSelection();
01885                 QGraphicsView::mousePressEvent(event);
01886             }
01887             break; // Qt::RightButton
01888         case Qt::MidButton:
01889             scene()->clearSelection();
01890             QGraphicsView::mousePressEvent(event);
01891             break;
01892         default:;
01893         }
01894     } // if(m_selectedAction == eSelection)
01895     else if(m_selectedAction == eInsertState)
01896     {
01897         switch(event->button())
01898         {
01899         case Qt::LeftButton:
01900             m_currentMouseAction = eInsertItem;            
01901             break;
01902         case Qt::RightButton:            
01903             if (itemsOnPos.empty())
01904             { // no item -> show popup (insert state, paste)
01905                 m_currentMouseAction = eShowPopup;
01906             }
01907             else if (itemsOnPos[0]->isSelected())
01908             { // selected item -> show popup (cut, copy, remove
01909                 m_currentMouseAction = eShowSelectionPopup;
01910             }
01911             else
01912             { // item -> propagate (item will invoke popup)
01913                 QGraphicsView::mousePressEvent(event);
01914             }
01915             break;
01916         case Qt::MidButton:
01917             scene()->clearSelection();
01918             QGraphicsView::mousePressEvent(event);
01919             break;
01920         default:;
01921         }
01922     } // if(m_selectedAction == eInsertState)
01923     else if(m_selectedAction == eInsertTransition)
01924     {
01925         switch(event->button())
01926         {
01927         case Qt::LeftButton:
01928             m_currentMouseAction = eInsertItem;
01929             selectedState = NULL;
01930             QGraphicsView::mousePressEvent(event);
01931             break;
01932         case Qt::RightButton:
01933             if (itemsOnPos.empty())
01934             { // no item -> show popup (insert state, paste)
01935                 m_currentMouseAction = eShowPopup;         
01936             }            
01937             /*else if (itemsOnPos[0]->isSelected())
01938             { // selected item -> show popup (cut, copy, remove
01939                 m_currentMouseAction = eShowSelectionPopup;
01940             }*/
01941             else
01942             { // item -> propagate (item will invoke popup)                
01943                 QGraphicsView::mousePressEvent(event);
01944             }
01945             break;
01946         default:;
01947         }
01948     }
01949     else
01950     {
01951         RELLOG("Unexpected situation -> unknown editor action selected!!!");
01952         Q_ASSERT(0 && "Unexpected situation!");
01953     }
01954 
01955     DBGLOG_ME(trMouseAction(m_currentMouseAction));
01956 }
01957 
01958 void Editor::mouseMoveEvent(QMouseEvent *event)
01959 {
01960     // show cursor position in scene coordinates
01961     QPoint p = mapToScene(event->pos()).toPoint();
01962 
01963     if (snapToGrid)
01964     {
01965         mw->setStatusBar( QString("Cursor position: %1 , %2")
01966             .arg(p.x() / GRID_STEP + gridRect.x())
01967             .arg(gridRect.height()-(p.y() / GRID_STEP - gridRect.y())));
01968     }
01969     else 
01970     {
01971         QPointF ePoint = mapToGrid(mapToScene(event->pos()));
01972         mw->setStatusBar( QString("Cursor position: %1 , %2")
01973             .arg(ePoint.x())
01974             .arg(ePoint.y()));
01975     }
01976     
01977     if (m_stateIsMoving)
01978     {
01979         bool itemsMoved = false;
01980         QPointF movePoint(0,0);
01981         QPointF changePoint = mapToScene(event->pos()) - m_origPos;
01982 
01983         if (snapped())
01984         {
01985             itemsMoved |= itemAlignToGrid(selectedState);
01986             
01987             if (changePoint.x() > (GRID_STEP / 2))
01988             {
01989                 movePoint = QPoint(GRID_STEP, 0);
01990             } 
01991             else if (changePoint.x() < (-GRID_STEP / 2))
01992             {
01993                 movePoint = QPoint(-GRID_STEP, 0);
01994             }
01995             if(changePoint.y() > (GRID_STEP / 2))
01996             {
01997                 movePoint = QPoint(0, GRID_STEP);
01998             }
01999             else if(changePoint.y() < (-GRID_STEP / 2))
02000             {
02001                 movePoint = QPoint(0,-GRID_STEP);
02002             }
02003         }
02004         else
02005         {
02006             movePoint = changePoint;
02007         }
02008         
02009         if (movePoint != QPointF(0,0)) 
02010         {
02011             itemsMoved = true;
02012             selectedState->moveBy(movePoint.x(), movePoint.y());
02013         }
02014 
02015         if (itemsMoved)
02016         {
02017             m_origPos += movePoint;
02018         }
02019         
02020         m_itemsMoved |= itemsMoved;
02021 
02022         return;
02023     }
02024 
02025     if (m_rubberBand->isVisible())
02026         m_rubberBand->setGeometry(QRect(m_rubberBandOrigin, event->pos()).normalized());
02027 
02028     if (m_selectedAction == eSelection && m_currentMouseAction == eMoveMultItem)
02029     {
02030         bool itemsMoved = false;
02031         QPointF movePoint(0,0);
02032         QPointF changePoint = mapToScene(event->pos()) - m_origPos;        
02033 
02034         if (snapped())
02035         {
02036             m_itemsMoved |= itemsAlignToGrid(scene()->selectedItems());
02037             
02038             if (changePoint.x() > (GRID_STEP / 2))
02039             {
02040                 movePoint = QPoint(GRID_STEP, 0);
02041             } 
02042             else if (changePoint.x() < (-GRID_STEP / 2))
02043             {
02044                 movePoint = QPoint(-GRID_STEP, 0);
02045             }
02046             if(changePoint.y() > (GRID_STEP / 2))
02047             {
02048                 movePoint = QPoint(0, GRID_STEP);
02049             }
02050             else if(changePoint.y() < (-GRID_STEP / 2))
02051             {
02052                 movePoint = QPoint(0,-GRID_STEP);
02053             }
02054         }
02055         else
02056         {
02057             movePoint = changePoint;
02058         }
02059         
02060         foreach(QGraphicsItem *item, scene()->selectedItems())
02061         {
02062             if(item->flags() & QGraphicsItem::ItemIsMovable)
02063             {
02064                 if (movePoint != QPointF(0,0))
02065                 {
02066                     itemsMoved = true;
02067                     item->moveBy(movePoint.x(), movePoint.y());
02068                 }
02069             }
02070         }
02071 
02072         if (itemsMoved)
02073         {
02074             m_origPos += movePoint;
02075         }
02076 
02077         m_itemsMoved |= itemsMoved;
02078 
02079         return;
02080     }
02081 
02082     QGraphicsView::mouseMoveEvent(event); // opriginal implementation
02083 }
02084 
02085 void Editor::mouseReleaseEvent(QMouseEvent *event)
02086 {
02087     DBGLOG_ME("called");
02088     if (m_rubberBand->isVisible())
02089     {        
02090         itemsInvertSelection(items(m_rubberBand->geometry()));        
02091         m_rubberBand->hide();   
02092     }
02093 
02094     if ((m_selectedAction == eInsertState && m_currentMouseAction == eInsertItem) ||
02095         (m_selectedAction == eSelection && m_currentMouseAction == eInsertItem))
02096     {
02097         QPoint p = mapToScene(event->pos()).toPoint();
02098 
02099         if (snapped())
02100         { // if should be snapped, do it
02101             p.setX(p.x() / GRID_STEP * GRID_STEP + GRID_STEP/2);
02102             p.setY(p.y() / GRID_STEP * GRID_STEP + GRID_STEP/2);
02103         }
02104 
02105         insertState(p);
02106     }
02107     else if(m_selectedAction == eSelection && m_currentMouseAction == eMoveMultItem)
02108     {
02109         if (m_itemsMoved)
02110         {
02111             m_undoStack->push
02112             (
02113                 createMoveItemsCommand(scene()->selectedItems(), m_origPositions)
02114             );
02115 
02116             update();
02117         }
02118     }
02119     else if(m_currentMouseAction == eShowPopup)
02120     {
02121         popupPasteHere->setVisible(isPastePossible());
02122         m_popupPoint = event->pos();
02123         popup->exec(mapToGlobal(m_popupPoint));
02124     }
02125     else if(m_currentMouseAction == eShowSelectionPopup)
02126     {
02127         popupSelection->exec(mapToGlobal(event->pos()));
02128     }
02129     else
02130     {
02131         QGraphicsView::mouseReleaseEvent(event);
02132     }
02133 
02134     if (!m_stateIsMoving)
02135         setActionCursor(m_selectedAction);
02136 
02137     if (m_sceneChanged)
02138     {
02139         setRightSceneRect();
02140         m_sceneChanged = false;
02141     }
02142 
02143     m_currentMouseAction = eNoMouseAction;
02144 }
02145 
02146 void Editor::mouseDoubleClickEvent(QMouseEvent *event)
02147 {
02148     if (m_simulationIsRun) return;
02149 
02150     DBGLOG_ME("called");
02151     // double click on empty scene means state inserting
02152     if (event->button() == Qt::LeftButton)
02153     {
02154         QList<QGraphicsItem *> itemsOnPos(items(event->pos()));
02155 
02156         if (itemsOnPos.empty())
02157         {
02158             m_currentMouseAction = eInsertItem;
02159         }
02160         else
02161             QGraphicsView::mouseDoubleClickEvent(event); // orign behavior
02162     }
02163 }
02164 
02165 bool Editor::showPopup(State *state)
02166 {
02167     popupStateLabel->setText("State: \"" + state->getLabel() + "\" / " + state->getName());
02168     selectedState = state;
02169     if (startState != NULL)
02170     {
02171         startState->setChecked(false);
02172         startState = NULL;
02173     }
02174     // mapovani nejprve ze sceny - potom na globalni souradnice
02175     popupState->exec(mapToGlobal(mapFromScene(state->pos())));
02176     if (!selectedState) return false;
02177     if (!m_stateIsMoving)
02178     {   
02179         selectedState->setChecked(false);
02180         selectedState = NULL;
02181     }
02182     return  true;
02183 }
02184 
02185 void Editor::showPopup(OneStateTransition *transition,const QPointF &point)
02186 {
02187     popupTransitionLabel->setText(transition->getTypeName() + 
02188                                   transition->getTypeNameSuffix() +
02189                                   " \"" + transition->getLabelText() + "\"");    
02190     // switch Edit action if necessary -> handle diferent transtitions types
02191     if (popupTransitionEdit != popupOneStateTransitionEdit)
02192     {
02193         QList<QAction *> actions = popupTransition->actions();
02194         int i = actions.lastIndexOf(popupTransitionEdit);
02195         popupTransition->removeAction(popupTransitionEdit);
02196         popupTransition->insertAction(actions.value(i+1), popupOneStateTransitionEdit);
02197         popupTransitionEdit = popupOneStateTransitionEdit;
02198     }
02199 
02200     selectedTransition = transition;
02201 
02202     popupTransition->exec(mapToGlobal(mapFromScene(point.toPoint())));
02203     if(selectedTransition) // transition could be deleted
02204     {
02205         selectedTransition->setChecked(false);
02206         selectedTransition->update();
02207         selectedTransition = NULL;
02208     }    
02209 }
02210 
02211 void Editor::showPopup(TwoStatesTransition *transition, const QPointF &point)
02212 {
02213     popupTransitionLabel->setText(transition->getTypeName() + 
02214                                   transition->getTypeNameSuffix() +
02215                                   " \"" + transition->getLabelText() + "\"");    
02216     // switch Edit action if necessary -> handle diferent transtitions types
02217     if (popupTransitionEdit != popupTwoStatesTransitionEdit)
02218     {
02219         QList<QAction *> actions = popupTransition->actions();
02220         int i = actions.lastIndexOf(popupTransitionEdit);        
02221         popupTransition->removeAction(popupTransitionEdit);
02222         popupTransition->insertAction(actions.value(i+1), popupTwoStatesTransitionEdit);
02223         popupTransitionEdit = popupTwoStatesTransitionEdit;
02224     }
02225     
02226     selectedTransition = transition;
02227     popupTransition->exec(mapToGlobal(mapFromScene(point.toPoint())));
02228     if(selectedTransition) // transition could be deleted
02229     {
02230         selectedTransition->setChecked(false);
02231         selectedTransition->update();
02232         selectedTransition = NULL;
02233     }
02234 }
02235 
02236 // slots
02237 
02238 void Editor::editState()
02239 {
02240     StateManager *stateManager = StateManager::getInstance();
02241     StateDialog sd(this, stateManager->getTypeNameList(), StateDialog::eEdit, selectedState->isInitial(), this);
02242 
02243     sd.setLabel(selectedState->getLabel());
02244     sd.setName(selectedState->getName()); // i vygenerovane jmeno se zobrazi
02245     int typeID = stateManager->getTypeNameId(selectedState->getTypeName());
02246     sd.setType(typeID);
02247     sd.setDimmed(selectedState->isDimmed());
02248     sd.setAutoNammed(selectedState->isAutoNammed());
02249         
02250     int ret = sd.exec();
02251 
02252     selectedState->setChecked(false);
02253 
02254     if (ret == QDialog::Rejected)
02255     {
02256         return;
02257     }
02258         
02259     QUndoCommand *command = sd.quickInitial() ?
02260             new QUndoCommand(QString("Edit state (%1) + quick initial add").arg(selectedState->getName())) : NULL;
02261 
02262     QUndoCommand *tmpCommand = NULL;
02263     if (typeID == sd.getType())
02264     { // not changed
02265         tmpCommand =
02266                 new StateEditCommand(this, selectedState, sd.getLabel(), sd.getName(), (bool)(sd.getType() & 1),
02267                                      sd.isDimmed(), sd.isAutoNammed(), command);
02268     }
02269     else
02270     { // changed state Type        
02271         QPoint point = selectedState->pos().toPoint();        
02272         State *newState = stateManager->createState(this, point, sd);
02273 
02274         Q_ASSERT(newState != NULL);
02275 
02276         tmpCommand = new StateEditWithDelCommand(this, selectedState, newState, command);
02277         selectedState = newState;
02278     }
02279 
02280     Q_ASSERT(tmpCommand);
02281 
02282     if (sd.quickInitial()) // add initial transition quickly
02283     {
02284         Q_ASSERT(command && "shoul be parent command!");
02285         Transition *initial = TransitionManager::getInstance()->createOneStateTransition("Initial", this, selectedState, "", WEST, false);
02286         new TransitionAddCommand(this, initial, command);
02287     }
02288     else
02289     {
02290         Q_ASSERT(!command && "should be NULL!");
02291         command = tmpCommand;
02292     }
02293 
02294     m_undoStack->push(command);
02295 
02296     mw->setStatusBar("Selected state edited", 2000);
02297     update();
02298 }
02299 
02300 void Editor::editStateParams()
02301 {
02302     StateExtendedDialog sed(this);
02303   
02304     sed.setParams(selectedState);
02305     if (sed.exec() == QDialog::Rejected) return;
02306     
02307     m_undoStack->push(
02308         new StateEditExtendedCommand(selectedState, sed.getLineStyle(), sed.getLineWidth(),
02309             sed.getLineColor(), sed.getLabelColor(), sed.getLabelScale(), sed.getFillStatus(),
02310             sed.getFillColor(), sed.getDimLineStyle(), sed.getDimLineColor(),
02311             sed.getDimLineCoef(), sed.getDimLabelColor(), sed.getDimFillColor(), 
02312             sed.getLineDblCoef(), sed.getLineDblSep())
02313     );
02314   
02315     mw->setStatusBar("Selected state's parameters edited", 2000);
02316     update();
02317 }
02318 
02319 void Editor::editStateStyleParams()
02320 {
02321     StateStyleDialog ssd(this); // postara se o vsecho sam ...
02322     ssd.exec();
02323 }
02324 
02325 void Editor::editState(State *state)
02326 {
02327     selectedState = state;
02328     editState();    
02329 }
02330 
02331 void Editor::removeState()
02332 {   
02333     m_undoStack->push(
02334         new StateDeleteCommand(this, selectedState)
02335     );
02336 }
02337 
02338 void Editor::editOneStateTransition()
02339 {
02340     editTransition(static_cast<OneStateTransition *>(selectedTransition));
02341 }
02342 
02343 void Editor::editTwoStatesTransition()
02344 {
02345     editTransition(static_cast<TwoStatesTransition *>(selectedTransition));
02346 }
02347 
02348 void Editor::editTransition(OneStateTransition *selectedTr)
02349 {
02350     DBGLOG("ok" << selectedTr);
02351 
02352     TransitionManager *transitionManager = TransitionManager::getInstance();
02353 
02354     TransitionLoopSEDialog td(TransitionLoopSEDialog::eEdit, this);
02355     
02356     int typeId = transitionManager->getTypeNameId(selectedTr->getTypeName());
02357 
02358     td.setLabel(selectedTr->getLabelText());
02359     td.setLabelPos(selectedTr->getLabelPos());
02360     td.setDimmed(selectedTr->isDimmed());
02361     td.setType(typeId);
02362     td.setDirection(selectedTr->getDirection());
02363 
02364     int ret = td.exec();
02365  
02366     selectedTr->setChecked(false);
02367 
02368     if (ret == QDialog::Rejected)
02369     {
02370         return;
02371     }
02372 
02373     if (td.getType() == typeId)
02374     { // type of transition not changed
02375         m_undoStack->push(
02376             new OneStateTransitionEditCommand
02377             (selectedTr, td.getLabel(), td.getLabelPos(),
02378              td.getDirection(), td.isDimmed())
02379         );
02380     }
02381     else
02382     {
02383         State *s1 = selectedTr->getStartState();
02384 
02385         Transition *tr = transitionManager->createOneStateTransition
02386             (this, s1, td);
02387         tr->setLabelPos(td.getLabelPos());
02388 
02389         m_undoStack->push(new TransitionEditWithDelCommand(this, selectedTr, tr));
02390         selectedTransition = tr;
02391         tr->adjust();
02392     }
02393 }
02394 
02395 void Editor::editTransition(TwoStatesTransition *selectedTr)
02396 {
02397     DBGLOG("ok" << selectedTr);
02398     
02399     TransitionManager *transitionManager = TransitionManager::getInstance();
02400 
02401     int typeId = transitionManager->getTypeNameId(selectedTr->getTypeName());
02402 
02403     TransitionDialog td(TransitionDialog::eEdit, this);
02404     td.setName(selectedTr->getLabelText());
02405     td.setTrOrientation(selectedTr->isLeftOriented());    
02406     td.setType(typeId);
02407     td.setLabelPos(selectedTr->getLabelPos());        
02408     // used only for some types of transition!
02409     td.setArcAngle(selectedTr->getArcAngle());
02410     td.setArcAngleB(selectedTr->getArcAngleB());
02411     td.setNCurv(selectedTr->getNCurv());
02412 
02413     td.setDimmed(selectedTr->isDimmed());
02414 
02415     int ret = td.exec();
02416     
02417     selectedTr->setChecked(false);
02418 
02419     if (ret == QDialog::Rejected) 
02420     {    
02421         return;
02422     }    
02423 
02424     if (typeId == td.getType())
02425     { // transition type preserved
02426         m_undoStack->push(
02427             new TwoStatesTransitionEditCommand
02428                 (selectedTr, td.getLabel(), td.getLabelPos(), td.isDimmed(), 
02429                 td.isLeftOriented(), td.getArcAngle(),
02430                 td.getArcAngleB(), td.getNCurv())
02431             );
02432         selectedTr->adjust();
02433     }
02434     else
02435     { // transition type changed
02436         State *s1, *s2;
02437         Transition *tr;
02438         s1 = selectedTr->getStartState();
02439         s2 = selectedTr->getEndState();
02440 
02441         tr = transitionManager->createTwoStatesTransition
02442             (this, s1, s2, td);
02443         tr->setLabelPos(td.getLabelPos());
02444         tr->setArcAngle(td.getArcAngle());
02445         tr->setArcAngleB(td.getArcAngleB());
02446         tr->setNCurv(td.getNCurv());
02447 
02448         mw->setStatusBar(tr->getTypeName() +
02449                          tr->getTypeNameSuffix() +
02450                          " inserted", 2000);
02451         m_undoStack->push(new TransitionEditWithDelCommand(this,selectedTr,tr));
02452         selectedTransition = tr;
02453         tr->adjust();
02454     }
02455     update();
02456 }
02457 
02458 void Editor::editNextLabels()
02459 {
02460     NextLabelsDialog nld(this, selectedTransition, this);
02461     nld.exec();
02462     selectedTransition->adjust();
02463 }
02464 
02465 void Editor::editTransitionParams()
02466 {
02467   TransitionExtendedDialog ted(this);
02468   
02469   ted.setParams(selectedTransition);
02470   
02471   if (ted.exec() == QDialog::Rejected) return;
02472   
02473   m_undoStack->push(
02474     new TransitionEditExtendedCommand(selectedTransition, ted.getLineStyle(), ted.getLineWidth(),
02475         ted.getLineColor(), ted.getLabelColor(), ted.getLabelScale(), ted.getDblStatus(),
02476         ted.getDimLineStyle(), ted.getDimLineColor(), ted.getDimLineCoef(),
02477         ted.getDimLabelColor(), ted.getLineBorderCoef(), ted.getLineBorderColor(),
02478         ted.getLineDblCoef(), ted.getLineDblSep())
02479   );
02480   
02481   mw->setStatusBar("Selected transition's parameters edited", 2000);
02482 }
02483 
02484 void Editor::editTransitionStyleParams(){
02485     TransitionStyleDialog tsd(this);
02486     tsd.exec();
02487 }
02488 
02489 void Editor::removeTransition()
02490 {
02491     m_undoStack->push(new TransitionDeleteCommand(this,selectedTransition));
02492 }
02493 
02494 // private members
02495 void Editor::insertState(const QPoint& point)
02496 {
02497     StateManager *stateManager = StateManager::getInstance();
02498     StateDialog sd(this, stateManager->getTypeNameList(), StateDialog::eAdd, false, this);
02499   
02500     QString stateName = getUniqueAutoName();
02501 
02502     sd.setName(stateName, false);
02503     sd.setAutoNammed(true);
02504     if (sd.exec() == QDialog::Rejected) return;
02505 
02506     State *newState;
02507       
02508     newState = stateManager->createState(this, point, sd);
02509     newState->setAutoNammed(sd.isAutoNammed());
02510 
02511     QUndoCommand *command;
02512     if (sd.quickInitial()) // add initial transition quickly
02513     {
02514         command = new QUndoCommand(QString("Insert state (%1) + quick initial add").arg(newState->getName()));
02515         new StateAddCommand(this, newState, command);
02516         TransitionManager *trManager = TransitionManager::getInstance();
02517         Transition *initial = trManager->createOneStateTransition("Initial", this, newState, "", WEST, false);
02518         new TransitionAddCommand(this, initial, command);
02519     }
02520     else
02521     {
02522         command = new StateAddCommand(this, newState);
02523     }
02524 
02525     m_undoStack->push(
02526         command
02527     );
02528  
02529     mw->setStatusBar("New state inserted", 2000);
02530 }
02531 
02532 QPoint Editor::toScenePos(const QPointF &gridPos)
02533 {
02534     return QPoint((int)((gridPos.x() - gridRect.x()) * GRID_STEP + GRID_STEP / 2),
02535                   (int)(scene()->height()-2 - (gridPos.y()-gridRect.y()) * GRID_STEP));         
02536 }
02537     
02538 // for parser ..
02539 State* Editor::insertState(State *state)
02540 {
02541     QRegExp rx("^Q[0-9]{1,10}$"); // check if name is autoNammed
02542     QRegExpValidator v(rx,this);
02543     int pos = 0; QString tested = state->getName();
02544     
02545     state->setAutoNammed(v.validate(tested,pos) == QValidator::Acceptable);
02546    
02547     addToListsAndScene(state);
02548    
02549     return state;
02550 };
02551 
02552 void Editor::insertTransition()
02553 {
02554     DBGLOG_ADD("called");
02555     if (selectedState)
02556     {        
02557         if (startState == NULL)
02558         { // first state inserted
02559             startState = selectedState;
02560             mw->setStatusBar("First state selected; Select second state", 2000);
02561         }
02562         else
02563         { // maybe new transiton            
02564             TransitionManager *transitionManager = TransitionManager::getInstance();
02565             Transition *tr = NULL;
02566             if (startState==selectedState)
02567             { // one state transition
02568                 TransitionLoopSEDialog td(TransitionLoopSEDialog::eAdd, this);
02569                 if (!(td.exec() == QDialog::Rejected))
02570                 {
02571                     tr = transitionManager->createOneStateTransition
02572                             (this, startState, td);
02573                     tr->setLabelPos(td.getLabelPos());
02574                     mw->setStatusBar(tr->getTypeName() +
02575                                      tr->getTypeNameSuffix() +
02576                                      " inserted", 2000);
02577                     m_undoStack->push(new TransitionAddCommand(this, tr));
02578                 }
02579             }
02580             else
02581             {
02582                 // two states transition
02583                 TransitionDialog td(TransitionDialog::eAdd, this);
02584                 if (!(td.exec() == QDialog::Rejected))
02585                 {
02586                     tr = transitionManager->createTwoStatesTransition
02587                             (this, startState, selectedState, td);                 
02588                     
02589                     tr->setLabelPos(td.getLabelPos());
02590                     tr->setArcAngle(td.getArcAngle());
02591                     tr->setArcAngleB(td.getArcAngleB());
02592                     tr->setNCurv(td.getNCurv());
02593 
02594                     mw->setStatusBar(tr->getTypeName() +
02595                                      tr->getTypeNameSuffix() +
02596                                      " inserted", 2000);
02597                     m_undoStack->push(new TransitionAddCommand(this, tr));
02598                 }
02599             }      
02600             if (selectedState != startState)
02601             { // only two states transition
02602                 startState->setChecked(false); 
02603                 startState->update();
02604                 startState = NULL;
02605             }
02606             else
02607             {
02608                 startState = NULL;
02609             }
02610             selectedState->setChecked(false);
02611             selectedState = NULL;            
02612             if (tr) tr->adjust();
02613         }
02614     }
02615 }
02616 
02617 QString Editor::getUniqueAutoName()
02618 {
02619     return getUniqueAutoName(m_stateMap);
02620 }
02621 
02622 QString Editor::getUniqueAutoName(const TStateMap &stateMap)
02623 {
02624     QString autoName;
02625     bool ok;
02626     do
02627     {
02628         ok = true; // osetreni proti dvojimu pouziti tehoz jmena
02629         autoName = QString("Q%1").arg(getNewStateNumber());
02630         if(testStateName(autoName, stateMap))
02631         {
02632             increaseNewStateNumber();
02633             ok = false;
02634         } 
02635     }
02636     while(!ok);
02637     
02638     return autoName;
02639 }
02640 
02641 State* Editor::getStateByName(const TStateMap &stateMap, const QString &name) const
02642 {    
02643     if (stateMap.contains(name))
02644         return stateMap[name];
02645 
02646     return 0; // state not founded!
02647 }
02648 
02649 void Editor::drawBackground(QPainter *painter, const QRectF &)
02650 {
02651     int fontHeight = 12;
02652     int fontWidth;
02653     QFont font;
02654     font.setPixelSize(fontHeight);
02655     painter->setFont(font);
02656     QFontMetrics fm(font);
02657     if (showGrid || showFrame)
02658     {
02659         int pop = gridRect.x(); //lowerLeftX
02660         for (int x = GRID_STEP / 2; x < scene()->width();x += GRID_STEP)
02661         {
02662             if (showGrid) // create lines
02663             {
02664                 if (pop)
02665                     painter->setPen(QPen(Qt::lightGray, 1, Qt::DotLine));
02666                 else // bold x-axis
02667                     painter->setPen(QPen(Qt::darkGray, 1, Qt::DotLine));
02668                 
02669                 painter->drawLine(x, GRID_STEP/2, x, (int)scene()->height());       
02670             }
02671             if (showFrame) // create numbers
02672             {
02673                 painter->setPen(QPen(Qt::lightGray));
02674                 QString s = QString("%1").arg(pop);
02675                 fontWidth = fm.width(s, s.length());
02676                 painter->drawText(x-fontWidth/2,fontHeight,s);        
02677             }
02678             pop++;
02679         }
02680         pop = gridRect.y() + gridRect.height(); //upperRightY - from up
02681         for (int y = GRID_STEP/2; y < scene()->height(); y+=GRID_STEP)
02682         {
02683             if (showGrid) // create lines
02684             {
02685                 if (pop)
02686                     painter->setPen(QPen(Qt::lightGray, 1, Qt::DotLine));
02687                 else // bold y-axis
02688                     painter->setPen(QPen(Qt::darkGray, 1, Qt::DotLine));
02689                 
02690                 painter->drawLine(GRID_STEP/2, y, (int)scene()->width(), y);
02691             }
02692             if (showFrame) // create numbers
02693             {
02694                 painter->setPen(QPen(Qt::lightGray));
02695                 painter->drawText(2, y + fontHeight/2,QString("%1").arg(pop));
02696             }
02697             pop--; // to lower
02698         }
02699     }
02700 }
02701 
02702 void Editor::setStatusBar(const QString &text, int ms)
02703 {
02704     mw->setStatusBar(text, ms); // hlavne kvuli commandum
02705 }
02706 
02707 // public slots:
02708 
02709 void Editor::showGridRectDialog()
02710 {
02711     GridRectDialog grd(this);
02712     grd.setLowerLeftX(gridRect.x());
02713     grd.setLowerLeftY(gridRect.y());
02714     grd.setUpperRightX(gridRect.x() + gridRect.width());
02715     grd.setUpperRightY(gridRect.y() + gridRect.height());
02716     grd.setBorder(sceneBorder);
02717   
02718     if (grd.exec() == QDialog::Rejected) 
02719     {
02720         return;
02721     }
02722     
02723     QRect gridRect_new = QRect(grd.getLowerLeftX(), grd.getLowerLeftY(),
02724                                grd.getUpperRightX() - grd.getLowerLeftX(),
02725                                grd.getUpperRightY() - grd.getLowerLeftY());
02726     
02727     m_undoStack->push(
02728         new EditorChangeGridRectCommand(this, gridRect_new, grd.getBorder())
02729     );
02730 }
02731 
02732 void Editor::undo()
02733 {
02734     startState = NULL;
02735     scene()->clearSelection();
02736     m_undoStack->undo();
02737 }
02738 
02739 void Editor::redo()
02740 {
02741     startState = NULL; // to avoid problem with transition adding to NULL state
02742     scene()->clearSelection();
02743     m_undoStack->redo();
02744 }
02745 
02746 
02747 void Editor::showUndoView(bool show)
02748 {
02749     if (show)
02750         m_undoView->show();
02751     else
02752         m_undoView->hide();
02753 }
02754 
02755 void Editor::zoomIn()
02756 {
02757     scaleView(m_zoomInFactor);
02758 }
02759 
02760 void Editor::zoomOut()
02761 {
02762     scaleView(1/m_zoomInFactor);
02763 }
02764 
02765 void Editor::resetZoom()
02766 {
02767     // TODO: check if this is true even if other transformations are done!
02768     scaleView(1/transform().m11()); // m11 is x scale value 
02769 }
02770 
02771 void Editor::stateMoved(State *state, const QPointF &oldPos)
02772 {
02773     m_undoStack->push(new StateMoveCommand(state, oldPos));
02774     update();
02775 }
02776 
02777 void Editor::removeFromListsAndScene(Transition *transition)
02778 {
02779     removeFromListAndScene(transition);
02780   
02781     transition->unassign();
02782 }
02783 
02784 void Editor::removeFromListsAndScene(State *state)
02785 {
02786     if (state == selectedState) selectedState = NULL;
02787     
02788     DBGLOG_ADD("state ->" << (void*)state << DBGPAR(state->getName()));
02789     
02790     int count = m_stateMap.remove(state->getName());
02791     Q_UNUSED(count);
02792     Q_ASSERT(count == 1);
02793 
02794     scene()->removeItem(state);
02795 }
02796 
02797 void Editor::removeFromListAndScene(Transition *transition)
02798 {
02799     DBGLOG_ADD("transition ->" << (void*)transition);
02800     int i = m_transitionList.indexOf(transition);
02801     if (i != -1) m_transitionList.removeAt(i);
02802   
02803     scene()->removeItem(transition);
02804     
02805     if (transition->getLabel())
02806     {
02807         DBGLOG_ADD("transition -> label" << (void*)(transition->getLabel()));
02808         scene()->removeItem(transition->getLabel());
02809     }
02810 
02811     const Transition::TLabelXList& labelList = transition->getNextLabels();
02812     for (Transition::TLabelXList::ConstIterator labelIt = labelList.begin();
02813          labelIt != labelList.end();
02814          ++labelIt)
02815     {
02816         DBGLOG_ADD("transition -> label" << (void*)(*labelIt));
02817         scene()->removeItem(*labelIt);
02818     }
02819 }
02820 
02821 void Editor::removeFromListAndScene(LabelX *pLabel)
02822 {
02823     DBGLOG_ADD("label" << (void*)(pLabel));
02824     scene()->removeItem(pLabel);
02825     pLabel->getTransition()->removeNextLabel(pLabel);
02826 }
02827 
02828 void Editor::addToListAndScene(Transition *transition)
02829 {
02830     DBGLOG_ADD("transition ->" << (void*)transition);
02831     m_transitionList << transition;
02832     scene()->addItem(transition);
02833     
02834     if (transition->getLabel() != NULL)
02835     {
02836         DBGLOG_ADD("transition -> label" << (void*)(transition->getLabel()));
02837         scene()->addItem(transition->getLabel());  
02838     }
02839 
02840     const Transition::TLabelXList& labelList = transition->getNextLabels();
02841     for (Transition::TLabelXList::ConstIterator labelIt = labelList.begin();
02842          labelIt != labelList.end();
02843          ++labelIt)
02844     {
02845         DBGLOG_ADD("transition -> label" << (void*)(*labelIt));
02846         scene()->addItem(*labelIt);
02847     }
02848 }
02849 
02850 void Editor::addToListAndScene(LabelX *pLabel)
02851 {    
02852     DBGLOG_ADD("label" << (void*)(pLabel));
02853     scene()->addItem(pLabel);
02854     pLabel->getTransition()->addNextLabel(pLabel);
02855 }
02856 
02857 void Editor::addToListsAndScene(Transition *transition)
02858 {
02859     addToListAndScene(transition);
02860   
02861     transition->assign();
02862 }
02863 
02864 void Editor::addToListsAndScene(State *state)
02865 {
02866     DBGLOG_ADD("state ->" << (void*)state << DBGPAR(state->getName()));
02867     
02868     Q_ASSERT(!m_stateMap.contains(state->getName()));
02869     m_stateMap[state->getName()] = state;
02870     
02871     scene()->addItem(state);
02872 }
02873 
02874 void Editor::renameState(State *state, const QString &name)
02875 {
02876     if (state->getName() == name) return;
02877     
02878     if (m_stateMap.contains(state->getName()))
02879     {
02880         int count = m_stateMap.remove(state->getName());
02881         Q_UNUSED(count);
02882         Q_ASSERT(count == 1);
02883         Q_ASSERT(!m_stateMap.contains(state->getName()));
02884         m_stateMap[name] = state;
02885     }
02886     state->setName(name);
02887 }
02888 
02889 void Editor::switchAntialiasing()
02890 {
02891     antial = !antial;
02892     DBGLOG(DBGPAR(antial));
02893     if (antial)
02894     {
02895         setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); // nicier        
02896     }
02897     else
02898     {
02899         setRenderHint(QPainter::Antialiasing, false);
02900         setRenderHint(QPainter::SmoothPixmapTransform,true); // for slower engines
02901     }
02902 }
02903 
02904 void Editor::generateGraph()
02905 {
02906   GraphGenerationDialog ggd(this);
02907   if (ggd.exec() == QDialog::Rejected) {
02908     return; 
02909   }
02910   
02911   int type = ggd.getType();
02912   QString string = ggd.getString();
02913   int len = string.length();
02914   QPoint startPoint = ggd.getStartPoint();
02915   int distance = ggd.getDistance();
02916   
02917   if (distance > len-1) distance = len-1;
02918   
02919   QList<State *> sList;
02920   
02921   switch (type)
02922   {
02923     case 0: // EXACT MATCHING
02924       sList = generateExactMatching(string,ggd.getStartPoint());
02925       break;
02926     case 1: // HAMMING DISTANCE
02927       sList = generateDistance(1,string, distance, startPoint);
02928       break;
02929     case 2: // LEVENSTHEIN DISTANCE
02930       sList = generateDistance(2,string, distance, startPoint);
02931       break;
02932     default:;
02933   }
02934   
02935   QRect gridRect_new = gridRect;
02936   
02937   if (ggd.isExpandRequired())
02938   {
02939     int llx, lly, urx, ury, lly_new, urx_new;
02940     llx = gridRect.x();
02941     lly = gridRect.y();
02942     urx = gridRect.x() + gridRect.width();
02943     ury = gridRect.y() + gridRect.height();
02944   
02945     if (startPoint.x() < llx) llx = startPoint.x();
02946     if (startPoint.y() > ury) ury = startPoint.y();
02947     if (startPoint.x() > urx) urx = startPoint.x();
02948     if (startPoint.y() < lly) lly = startPoint.y();
02949     
02950     if (type == 0) // EXACT MATCHING
02951     {
02952       urx_new = startPoint.x() + len * EXACT_HSPACE + 1; // 1 is because not margins set
02953       lly_new = startPoint.y();
02954     }
02955     else
02956     {
02957       urx_new = startPoint.x() + len * (type == 1 ? HAMMING_HSPACE : LEVEN_VSPACE) + 1;
02958       lly_new = startPoint.y() - distance * (type == 1 ? HAMMING_VSPACE : LEVEN_VSPACE) - 1;
02959     } // if
02960 
02961     if (urx < urx_new) urx = urx_new;
02962     if (lly > lly_new) lly = lly_new;
02963 
02964     DBGLOG(llx << lly << urx << ury << lly_new << urx_new);
02965     
02966     gridRect_new = QRect(llx, lly, urx - llx, ury - lly);
02967   }
02968   
02969     m_undoStack->push(
02970         new ItemsAddCommand(this, sList, gridRect_new)
02971     );
02972 
02973     setActionInternal(eSelection);
02974 
02975     foreach(State *state, sList)
02976     {
02977         state->setSelected(true);
02978         foreach(Transition *tr, state->getTransitionList())
02979         {
02980             tr->setSelected(true);
02981         }
02982     }
02983 }
02984 
02985 // generating
02986 
02987 QList<State *> Editor::generateExactMatching(QString string, QPoint startPoint)
02988 {
02989     QString stateType, newName;
02990     Transition *tr;
02991     StateManager *stateManager = StateManager::getInstance();
02992     TransitionManager *transitionManager = TransitionManager::getInstance();
02993     QList<State *> sList;
02994     State *s1 = NULL, *s2 = NULL;
02995 
02996     TStateMap stateMapCopy = m_stateMap;
02997 
02998     for (int i = 0; i <= string.length(); i++)
02999     {
03000         newName = getUniqueAutoName(stateMapCopy);
03001         stateMapCopy[newName] = NULL;
03002 
03003         stateType = i == string.length() ? "FinalState" : "State";
03004         s2 = stateManager->createState(stateType, this, toScenePos(startPoint + i*QPoint(EXACT_HSPACE, 0)),
03005                                    QString("%1").arg(i), newName, false);
03006         sList << s2;
03007     
03008         if (i > 0)
03009         { // paint transitions
03010             tr = transitionManager->createTwoStatesTransition("Edge",this, s1, s2, QString(string[i-1]),true, false);
03011             tr->assign();
03012         } 
03013         else
03014         {
03015             tr = transitionManager->createOneStateTransition("Initial", this, s2, "", WEST, false);      
03016             tr->assign();
03017             tr = transitionManager->createOneStateTransition("Loop", this, s2, "A", NORTH, false);
03018             tr->assign();
03019         }
03020         s1 = s2;
03021     }
03022   
03023     return sList;
03024 }
03025 
03026 QList<State *> Editor::generateDistance(int typ, QString string, int distance, QPoint startPoint)
03027 {
03028     QString stateType, newName;
03029     int len = string.length();
03030   
03031     int labNumb = -1;
03032   
03033     QList<State *> sList;
03034     State *s1 = NULL, *s2 = NULL;
03035     StateManager *stateManager = StateManager::getInstance();
03036     Transition *tr;
03037     TransitionManager *transitionManager = TransitionManager::getInstance();
03038   
03039     TStateMap stateMapCopy = m_stateMap;
03040   
03041     for (int j = 0; j <= distance; j++)
03042     {
03043         for (int i = j; i <= len; i++)
03044         {
03045             newName = getUniqueAutoName(stateMapCopy);
03046             stateMapCopy[newName] = NULL;
03047       
03048             stateType = (i == string.length()) ? "FinalState" : "State";
03049             s2 = stateManager->
03050                 createState(stateType, this,
03051                             toScenePos(
03052                                 startPoint + 
03053                                     QPoint((typ==1 ? HAMMING_HSPACE : LEVEN_HSPACE) * i,
03054                                     (typ==1 ? -HAMMING_VSPACE : -LEVEN_VSPACE) * j)
03055                             ),
03056                             QString("%1").arg(++labNumb),
03057                             newName,
03058                             false);
03059         
03060             sList << s2;
03061       
03062             if (i != j)
03063             { // paint transitions
03064                 tr = transitionManager->createTwoStatesTransition
03065                     ("Edge", this, s1, s2, QString(string[i-1]), true, false);
03066 
03067                 tr->assign();
03068             } 
03069             else if (j == 0)
03070             {
03071                 tr = transitionManager->createOneStateTransition
03072                     ("Initial", this, s2, "", WEST, false);                
03073                 tr->assign();
03074                 tr = transitionManager->createOneStateTransition
03075                     ("Loop", this, s2, "A", NORTH, false);                
03076                 tr->assign();
03077             }
03078       
03079             if (j > 0)
03080             { // transitions diagonal, horizontal, curved
03081               // (max_i + 1)*j + i - (j + j^2)/2  -- cislo stavu v sListu
03082         
03083                 s1 = sList[(len+1)*(j-1) + (i-1) - (j-1)*(1+(j-1))/2]; // diag and curved line
03084                 if (s1)
03085                 {    
03086                     tr = transitionManager->createTwoStatesTransition
03087                         ("Edge", this, s1, s2, "A", typ == 1, false);
03088                     tr->assign();
03089         
03090                     if (typ == 2)
03091                     {
03092                         tr = transitionManager->createTwoStatesTransition
03093                             ("Arc", this, s1, s2, "\\varepsilon", false, false);
03094                         tr->assign();
03095                         tr->adjust();
03096             
03097                         if (i != len)
03098                         {
03099                             s1 = sList[(len+1)*(j-1) + (i) - (j-1)*(1+(j-1))/2]; // horizontal
03100                             if (s1)
03101                             {
03102                                 tr = transitionManager->createTwoStatesTransition
03103                                     ("Edge", this, s1, s2, "A", true, false);                                
03104                                 tr->assign();
03105                             }
03106                         }
03107                     }
03108                 }
03109             }
03110       
03111             s1 = s2;
03112         }   
03113     }
03114     return sList;
03115 }
03116 
03117 void Editor::createLaTeXTable()
03118 {
03119     QSharedPointer<IAutomaton> automaton = loadAutomaton("LaTeX table");
03120     
03121     if (!automaton)
03122     {
03123         RELLOG("no automaton detected!");
03124         return;
03125     }
03126     
03127     LaTeXTableDialog ltd(this, automaton->getTransitionTable());
03128 
03129     ltd.exec();
03130 }
03131 
03132 void Editor::addToUndoStack(QUndoCommand *command)
03133 {
03134     m_undoStack->push(command);
03135 }
03136 
03137 int Editor::addAlgorithm(const QSharedPointer<IAlgorithm> &algorithm)
03138 {
03139     if (algorithm->requireCreator())
03140         algorithm->setAutomataCreator(getAutomataCreator());
03141 
03142     m_algorithmList << algorithm;
03143     return m_algorithmList.count()-1;
03144 }
03145 
03146 void Editor::addGraphVizDrawAlgorithm(IGraphViz *graphVizWrapper)
03147 {
03148     DBGLOG("GraphViz version: " << graphVizWrapper->getGraphVizVersion());
03149     if (graphVizWrapper->getGraphVizVersion() != QString(GRAPHVIZ_VERSION))
03150     {
03151         RELLOG("Cannot be used with GraphViz version " << graphVizWrapper->getGraphVizVersion() <<
03152                ", required version is " << GRAPHVIZ_VERSION << "!!!");
03153         return;
03154     }
03155     m_drawAlgorithmList << QSharedPointer<IDrawAlgorithm>(new GraphVizDrawAlgorithm(graphVizWrapper));
03156     m_currentDrawAlgorithm = m_drawAlgorithmList.count()-1;
03157 }
03158 
03159 QStringList Editor::getDrawAlgorithms() const
03160 {
03161     QStringList result;
03162     foreach(const QSharedPointer<IDrawAlgorithm> &drawAlg, m_drawAlgorithmList)
03163     {
03164         result << drawAlg->getName();
03165     }
03166     Q_ASSERT(!result.empty() && "no drawing algorithm was set!");
03167     return result;
03168 }
03169 
03170 QSharedPointer<AutomatonImpl> Editor::loadAutomaton(const QString &dialogTitle)
03171 {    
03172     LoadAutomataDialog lad(this, dialogTitle, 0, QStringList(), true, NULL); // use only current automaton (0)
03173     if (!lad.exec())
03174         return QSharedPointer<AutomatonImpl>();
03175     
03176     ITransition::TCharSet   alphabet;
03177     QString                 alphabetSymbol;
03178     QString                 epsilonSymbol;
03179     
03180     if (lad.alphabetIsSet())
03181         alphabet = lad.getAlphabet();
03182     if (lad.alphabetSymbolIsSet())
03183         alphabetSymbol = lad.getAlphabetSymbol();
03184     if (lad.epsilonSymbolIsSet())
03185         epsilonSymbol = lad.getEpsilonSymbol();
03186     
03187     if (m_stateMap.empty())
03188     {
03189         QMessageBox::information(this, "No automaton", 
03190                                  "There is no automaton on scene!" , QMessageBox::Ok);
03191         return QSharedPointer<AutomatonImpl>();
03192     }
03193 
03194     return getAutomaton(getStateList(), alphabet, alphabetSymbol, epsilonSymbol);
03195 }
03196 
03197 IAutomaton::TAutomataList Editor::loadAutomata(const QString &dialogTitle, int count,
03198                                                QStringList &fileNames, IAlgorithm *algorithm)
03199 {
03200     LoadAutomataDialog lad(this, dialogTitle, count, getDrawAlgorithms(), !m_stateMap.empty(), algorithm);
03201     
03202     Q_ASSERT(m_currentDrawAlgorithm < m_drawAlgorithmList.count());
03203     lad.setDrawAlgorithmIndex(m_currentDrawAlgorithm);
03204 
03205     if (QDialog::Rejected == lad.exec())
03206         return IAutomaton::TAutomataList();
03207     
03208     fileNames = lad.getFileNames();
03209     
03210     DBGLOG_AI(DBGPAR(fileNames));
03211     
03212     IAutomaton::TAutomataList automata;
03213     QSharedPointer<IAutomaton> automaton;
03214     Parser parser(this, false);
03215     bool okParse = true;
03216     bool okAutomata = true;
03217     QStringList invalidFiles;
03218     
03219     QList<State *>  parsedStates;
03220     QRect           newGridRect;
03221     QString         report;
03222     
03223     ITransition::TCharSet alphabet;
03224     if (lad.alphabetIsSet()) alphabet = lad.getAlphabet();
03225     QString alphabetSymbol;
03226     if (lad.alphabetSymbolIsSet()) alphabetSymbol = lad.getAlphabetSymbol();
03227     QString epsilonSymbol;
03228     if (lad.epsilonSymbolIsSet()) epsilonSymbol = lad.getEpsilonSymbol();
03229     
03230     if (lad.useCurrentAutomaton())
03231     {
03232 #ifdef MEASURE_AUTOMATA_RECOGNIZATION 
03233         QTime timer;
03234         timer.start();
03235 #endif
03236         ITransition::TCharSet alphabetTmp = alphabet;
03237         QString alphabetSymbTmp = alphabetSymbol;
03238         QString epsilonSymbTmp = epsilonSymbol;
03239         automaton = getAutomaton(getStateList(), alphabetTmp, alphabetSymbTmp, epsilonSymbTmp);
03240 #ifdef MEASURE_AUTOMATA_RECOGNIZATION
03241         RELLOG("Calling getAutomaton() have taken" << timer.elapsed() << "ms");
03242 #endif
03243         if (automaton)
03244         {
03245             automata << automaton;
03246         }
03247         else
03248         {
03249             okAutomata &= false;
03250             invalidFiles << "Current file";
03251         }
03252     }
03253     
03254     int i = lad.useCurrentAutomaton() ? 1 : 0;
03255     for (; i<count; ++i)
03256     {
03257         if (!parser.run(fileNames[i], parsedStates, newGridRect))        
03258         {
03259             report += fileNames[i] + "<br>" + parser.getReport() + "<br><br>";
03260             okParse &= false;
03261         }
03262         
03263         if (!parsedStates.empty())
03264         {
03265 #ifdef MEASURE_AUTOMATA_RECOGNIZATION 
03266             QTime timer;
03267             timer.start();
03268 #endif
03269             ITransition::TCharSet alphabetTmp = alphabet;
03270             QString alphabetSymbTmp = alphabetSymbol;
03271             QString epsilonSymbTmp = epsilonSymbol;
03272             automaton = getAutomaton(parsedStates, alphabetTmp, alphabetSymbTmp, epsilonSymbTmp);
03273 #ifdef MEASURE_AUTOMATA_RECOGNIZATION
03274             RELLOG("Calling getAutomaton() have taken" << timer.elapsed() << "ms");
03275 #endif
03276             if (automaton)
03277             {
03278                 automata << automaton;
03279             }
03280             else
03281             {
03282                 okAutomata &= false;
03283                 invalidFiles << fileNames[i];
03284             }   
03285         }        
03286         parsedStates.clear();
03287         automaton.clear();
03288     }
03289     
03290     if (!okParse)
03291     {
03292         ReportDialog prd(report, this);
03293         prd.exec();
03294     }
03295     
03296     if (!okAutomata)
03297     {
03298         report = "Some automata are defined incorrectly! Please check it!<br>"
03299                  "Incorrectly defined files:<br>"
03300                  "--------------------------------<br>";
03301         for (int idx=0; idx<invalidFiles.count(); ++idx)
03302         {
03303             report += invalidFiles.join("<br>");
03304         }
03305         ReportDialog prd(report, this);
03306         prd.exec();
03307     }
03308     
03309     m_currentDrawAlgorithm = lad.getDrawAlgorithmIndex();
03310     return automata;
03311 }
03312 
03313 QList<State*> Editor::createGraphicsItems(const QSharedPointer<IAutomaton> &automaton)
03314 {
03315     QList<State*> result;
03316     
03317     if (!automaton->hasPositions()) return result;
03318     
03319     // TODO: implement this
03320     
03321     return result;
03322 }
03323 
03324 void Editor::expandGrid(int bound)
03325 {    
03326     m_undoStack->push(
03327         new EditorChangeGridRectCommand(this, getExpandedGridRect(m_stateMap.values(), bound), getBorder())
03328     );
03329 }
03330 
03331 QRect Editor::getExpandedGridRect(const TStateList &states, int bound)
03332 {
03333     Q_ASSERT(bound >= 0);
03334     
03335     QRectF bb;
03336     foreach(State* state, states)
03337     {
03338         bb |= state->boundingRect().translated(state->pos());
03339         TTransitionList transitions = state->getOutgoingTransitions();
03340         foreach(Transition* transition, transitions)
03341         {
03342             bb |= transition->boundingRect().translated(transition->pos());
03343         }
03344     }
03345 
03346     QPointF topLeft = mapToGrid(bb.topLeft());
03347     QPointF bottomRight = mapToGrid(bb.bottomRight());
03348     
03349     QRectF newGridRect(topLeft.x(), bottomRight.y(),
03350                        bottomRight.x()-topLeft.x(), topLeft.y()-bottomRight.y());
03351     
03352     DBGLOG(DBGPAR(newGridRect));
03353 
03354     return newGridRect.toAlignedRect().adjusted(-bound,-bound,bound,bound);
03355 }
03356 
03357 void Editor::runAlgorithm()
03358 {
03359     DBGLOG_AI("called");
03360     
03361     QAction *action = qobject_cast<QAction*>(sender());
03362     bool ok;
03363     int algIndex = action->data().toInt(&ok);
03364 
03365     if (!ok)
03366     {
03367         Q_ASSERT(0 && "incorrect action!!!");
03368         RELLOG("incorrect action!!!");
03369         return;
03370     }    
03371 
03372     if (! (algIndex < m_algorithmList.count()))
03373     {
03374         Q_ASSERT(0 && "bad algorithm index given from action!!!");
03375         RELLOG("bad algorithm index given from action!!!");
03376         return;
03377     }
03378 
03379     QSharedPointer<IAlgorithm> algorithm = m_algorithmList[algIndex];
03380     IAutomaton::TAutomataList automata;
03381     QStringList fileNames;
03382 
03383     if (algorithm->getInputCount())
03384         automata = loadAutomata(algorithm->getName(), algorithm->getInputCount(), fileNames, algorithm.data());
03385     
03386     if (automata.size() != algorithm->getInputCount())
03387     {
03388         return;
03389     }
03390 
03391     QSharedPointer<IAutomaton> resultAutomaton;
03392     QString report;
03393     if (algorithm->run(automata, resultAutomaton, &report))
03394     {
03395         QUndoCommand *command = new QUndoCommand(QString("RunAlgorith -> %1").arg(algorithm->getName()));
03396         new ItemsRemoveCommand(this, getStateList(), m_transitionList, command);
03397         
03398         QList<State *> newStates;
03399         
03400         newStates = createGraphicsItems(resultAutomaton);
03401         
03402         if (newStates.isEmpty())
03403         {
03404             Q_ASSERT(m_drawAlgorithmList.size() > m_currentDrawAlgorithm && "inconsistency with LoadAutomataDialog!");
03405             newStates = m_drawAlgorithmList[m_currentDrawAlgorithm]->drawAutomaton(this, resultAutomaton);
03406         }
03407         
03408         new ItemsAddCommand(this, newStates, gridRect, command);
03409 
03410         new EditorChangeGridRectCommand(this, getExpandedGridRect(newStates, 0), getBorder(), command);
03411 
03412         m_undoStack->push(command);
03413         
03414         DBGLOG("Algorithm '" << algorithm->getName() << "' successfull." << endl 
03415                << "Report: " << report << ".");
03416     }
03417     else
03418     {
03419         DBGLOG("Algorithm '" << algorithm->getName() << "' failed.");
03420         ReportDialog rd(report, this);
03421         rd.exec();
03422     }
03423 }
03424 
03425 void Editor::simulateAutomatonWork()
03426 {
03427     QSharedPointer<AutomatonImpl> automaton = loadAutomaton("Simulation");
03428     if (!automaton) return;
03429     
03430     Q_ASSERT(automaton);
03431         
03432     AutomataWorkSimulator *aws = new AutomataWorkSimulator(this, *m_undoStack, automaton);
03433     connect(aws, SIGNAL(finished()), this, SLOT(simulationFinished()));
03434     connect(aws, SIGNAL(setStatesMarked(QList<State*>, bool)), this, SLOT(setStatesMarked(QList<State*>, bool)));
03435     
03436     m_simulationIsRun = true;
03437     updateMenuState();
03438     aws->run();
03439 }
03440 
03441 void Editor::simulationFinished()
03442 {
03443     m_simulationIsRun = false;
03444     updateMenuState();
03445     
03446     AutomataWorkSimulator *simulator = qobject_cast<AutomataWorkSimulator*>(sender());
03447     simulator->disconnect();
03448     Q_ASSERT(simulator);
03449     delete simulator;
03450 }
03451 
03452 void Editor::setStatesMarked(QList<State*> states, bool marked)
03453 {
03454     m_undoStack->push(
03455         new StatesSetMarkedCommand(states, marked)
03456     );
03457 }
03458 
03459 void Editor::updateMenuState()
03460 {
03461     // TODO: check all possiblities - is this sufficient?
03462     emit canNewFile(!m_simulationIsRun);
03463     emit canOpenFile(!m_simulationIsRun);
03464     emit canSaveFile(!m_simulationIsRun);
03465     
03466     emit itemsAvailable(!m_simulationIsRun);
03467     emit toolsAvailable(!m_simulationIsRun);
03468     emit utilsAvailable(!m_simulationIsRun);
03469     
03470 #ifndef ALLOW_UNDO_VIEW_WHILE_SIMULATION_RUNNING
03471     m_undoView->close();
03472     emit showUndoStackAvailable(!m_simulationIsRun);
03473 #endif
03474     emit canUndoChanged(!m_simulationIsRun && m_undoStack->canUndo());
03475     emit canRedoChanged(!m_simulationIsRun && m_undoStack->canRedo());       
03476 }
03477 
03478 QSharedPointer<AutomatonImpl> Editor::getAutomaton(const TStateList &stateList,
03479                                                    ITransition::TCharSet &alphabet,
03480                                                    QString &alphabetSymbol,
03481                                                    QString &epsilonSymbol)
03482 {
03483     // TODO: make error reporting better
03484     if (getInitialStates(stateList).isEmpty())
03485     {
03486         QMessageBox::information(this, "No initial state",
03487                                  "There is no initial state on scene!\nSuch automaton has no sense" , QMessageBox::Ok);
03488         return QSharedPointer<AutomatonImpl>(NULL);
03489     }
03490 
03491     if (alphabet.isEmpty() || alphabetSymbol == "" || epsilonSymbol == "")
03492     {
03493         bool ok = detectAutomataSettings(stateList, alphabet, alphabetSymbol, epsilonSymbol);
03494 
03495         if (!ok) return QSharedPointer<AutomatonImpl>(NULL);
03496     }
03497 
03498     if (alphabetSymbol == "") alphabetSymbol = AutomataCreator::defaultAlphabetSymbList[0];
03499     if (epsilonSymbol == "") epsilonSymbol = AutomataCreator::defaultEpsilonSymbList[0];
03500 
03501     DBGLOG("Automata settings:"     << endl <<
03502            DBGPAR(alphabet)         << endl <<
03503            DBGPAR(alphabetSymbol)   << endl <<
03504            DBGPAR(epsilonSymbol));
03505 
03506     QScopedPointer<AutomataCreator> creator(new AutomataCreator());
03507     QSharedPointer<AutomatonImpl> automaton = creator->createPrivateAutomaton(alphabet, alphabetSymbol, epsilonSymbol);
03508     for (TStateList::ConstIterator stateIt = stateList.begin();
03509          stateIt != stateList.end();
03510          ++stateIt)
03511     {
03512         State* state = (*stateIt);
03513         bool ok = automaton->addState(
03514             creator->createPrivateState(state->getName(), state->getLabel(), state->isInitial(), state->isFinal(), state)
03515         );
03516 
03517         Q_UNUSED(ok);
03518         Q_ASSERT(ok && "some problem when adding state!");
03519     }
03520 
03521     for (TStateList::ConstIterator stateIt = stateList.begin();
03522          stateIt != stateList.end();
03523          ++stateIt)
03524     {
03525         TTransitionList trList = (*stateIt)->getOutgoingTransitions();
03526         for (TTransitionList::ConstIterator trIt = trList.begin();
03527              trIt != trList.end();
03528              ++trIt)
03529         {
03530             Transition* transition = (*trIt);
03531             Q_ASSERT(transition->getTypeName() != "Initial" && transition->getTypeName() != "Final");
03532 
03533             ITransition::TCharSet characters;
03534             bool ok = transition->getCharacters(characters, alphabet, alphabetSymbol, epsilonSymbol);
03535 
03536             if (!ok)
03537             {
03538                 return QSharedPointer<AutomatonImpl>(NULL); // report already showen in Transition::getCharacters
03539             }
03540 
03541             automaton->createAndAddPrivateTransition(transition->getStartStateName(), transition->getEndStateName(),
03542                                                      characters, transition);
03543         }
03544     }
03545 
03546     DBGLOG("automaton created, consists of:" << endl
03547                    << automaton->getStates().count() << "states" << endl
03548                    << automaton->getInitialStates().count() << "initial states" << endl
03549                    << automaton->getFinalStates().count() << "final states" << endl
03550                    << "alphabet:" << automaton->getAlphabet() << endl
03551                    << "alphabetSymb:" << automaton->getAlphabetSymbol() << endl
03552                    << "epsilonSymb:" << automaton->getEpsilonSymbol());
03553 
03554     return automaton;
03555 }
03556 
03557 bool Editor::detectAutomataSettings(const QList<State *> &stateList,
03558                                     ITransition::TCharSet &alphabet,
03559                                     QString &alphabetSymbol,
03560                                     QString &epsilonSymbol)
03561 {
03562     QString report = "";
03563 
03564     ITransition::TCharSet a;
03565     foreach (State *state, stateList)
03566     {        
03567         foreach(Transition *transition, state->getOutgoingTransitions())
03568         {
03569             transition->getCharactersOccurences(a);
03570         }
03571     }
03572     
03573     DBGLOG_AI("Character occurences: " << a);
03574     
03575     // if alphabet is set manually, only alphabetSymbol or epsilonSymbol can be in rest of occurences
03576     if (!alphabet.isEmpty())
03577     {
03578         a -= alphabet;
03579         DBGLOG_AI("Adepts to alphabet or epsilon symbol: " << a);
03580     }
03581     
03582     // detect alphabet symbol
03583     if (!a.isEmpty() && alphabetSymbol == "")
03584     {
03585         QString aSymb = "";
03586         foreach(const QString &symb, AutomataCreator::defaultAlphabetSymbList)
03587         {
03588             if (a.contains(symb))
03589             {
03590                 if (aSymb == "")
03591                 {
03592                     aSymb = symb;
03593                     a -= symb;
03594                 }
03595                 else if (aSymb != symb)
03596                 {
03597                     report += "Mismatch in alphabet symbol usage - " + aSymb + ", " + symb + "\n"
03598                            +  "Please set alphabet symbol manually.\n";
03599                     break;
03600                 }
03601             }
03602         }
03603         alphabetSymbol = aSymb;
03604     }
03605     if (alphabetSymbol == "")
03606     {
03607         alphabetSymbol = AutomataCreator::defaultAlphabetSymbList.first();
03608     }    
03609     a -= alphabetSymbol; // remove from alphabet (or rest of characters)
03610     
03611     DBGLOG_AI("Adepts to epsilon symbol: " << a);
03612     // detect epsilon symbol
03613     if (!a.isEmpty() && epsilonSymbol == "")
03614     {
03615         QString eSymb = "";
03616         foreach(const QString &symb, AutomataCreator::defaultEpsilonSymbList)
03617         {
03618             if (a.contains(symb))
03619             {
03620                 if (eSymb == "")
03621                 {
03622                     eSymb = symb;
03623                     a -= symb;
03624                 }
03625                 else if (eSymb != symb)
03626                 {
03627                     report += "Mismatch in epsilon symbol usage - " + eSymb + ", " + symb + "\n"
03628                            +  "Please set epsilon symbol manually.\n";
03629                     break;
03630                 }
03631             }
03632         }
03633         epsilonSymbol = eSymb;
03634     }
03635     if (epsilonSymbol == "")
03636     {
03637         epsilonSymbol = AutomataCreator::defaultEpsilonSymbList.first();
03638     }
03639     a -= epsilonSymbol; // remove from alphabet (or rest of characters)
03640     
03641     if (alphabet.isEmpty())
03642     {
03643         if (a.isEmpty())
03644         {
03645             report += "Alphabet detection failed! No symbols found.\n";
03646         }
03647         else
03648         {
03649             alphabet = a;
03650         }
03651     }
03652     else
03653     {        
03654         if (!a.isEmpty())
03655         {
03656             RELLOG("Found characters which are unexpected: " << a);
03657             report += "Unexpected characters found: ";
03658             int count = 0;
03659             foreach(const QString &character, a)
03660             {                
03661                 if (count != 0) report += ", ";
03662                 if (count % 10 == 0)
03663                 {
03664                     report += "\n\t";
03665                 }
03666                 ++count;
03667                 report += character;
03668             }
03669             report += "\n";
03670         }
03671     }
03672     
03673     // check logic errors
03674     if (alphabetSymbol == epsilonSymbol ||
03675         alphabet.contains(alphabetSymbol) ||
03676         alphabet.contains(epsilonSymbol))
03677     {
03678         report += "Automaton settings couldn't be detected correctly, please set it manually.\n";
03679     }
03680         
03681     if (report != "")
03682     {
03683         ReportDialog rd(report, this);
03684         rd.exec();
03685         return false;
03686     }    
03687     
03688     Q_ASSERT(!alphabet.isEmpty() && alphabetSymbol != "" && epsilonSymbol != ""
03689              && "Settings detection failed!!!");
03690     
03691     return true;
03692 }
03693 
03694 #if 0
03695 // TODO: not actual, now each file contains single automaton - this code is depraceted, possible to reuse
03696 //       it when it will be required to detect more automata from single file (single scene)
03697 
03698 AutomatonImpl::TAutomatonList Editor::getAutomata(const QList<State*> &stateList,
03699                                                   ITransition::TCharSet &alphabet,
03700                                                   QString &alphabetSymbol,
03701                                                   QString &epsilonSymbol)
03702 {
03703     // TODO: maybe not written so effective as could be possible, so check performance enhancement
03704     QScopedPointer<AutomataCreator> creator(new AutomataCreator);
03705     
03706     if (alphabet.isEmpty() || alphabetSymbol == "" || epsilonSymbol == "")
03707     {        
03708         bool ok = detectAutomataSettings(stateList, alphabet, alphabetSymbol, epsilonSymbol);
03709     
03710         if (!ok) return AutomatonImpl::TAutomatonList();
03711     }
03712     
03713     Q_ASSERT(!alphabet.isEmpty());
03714     if (alphabetSymbol == "") alphabetSymbol = AutomataCreator::defaultAlphabetSymbList[0];
03715     if (epsilonSymbol == "") epsilonSymbol = AutomataCreator::defaultEpsilonSymbList[0];
03716 
03717     DBGLOG("Automata settings:"     << endl <<
03718            DBGPAR(alphabet)         << endl <<
03719            DBGPAR(alphabetSymbol)   << endl <<
03720            DBGPAR(epsilonSymbol));
03721 
03722 // start looking for automata --->
03723     
03724     AutomatonImpl::TAutomatonList automataList;
03725     
03726     // all inital state in editor
03727     QList<State*> allInitialStates = getInitialStates(stateList);
03728     
03729     QList<State*> currentInitialStates;
03730     QList<State*> currentFinalStates;
03731     QList<State*> currentStates;
03732     QSet<Transition*> currentTransitions;
03733 
03734     QSharedPointer<AutomatonImpl> automaton;
03735     // starts looking from first inital states, when some other inital state is reached,
03736     // remove it form allInitialStates (foreclose looking same automaton again)
03737     while (!allInitialStates.empty())
03738     {
03739         State *currentState = allInitialStates.takeFirst();
03740         currentStates << currentState;
03741         currentInitialStates << currentState;
03742 
03743         // BFS implementation
03744         QQueue<State*> openedStates;
03745         openedStates.enqueue(currentState);        
03746 
03747         while(!openedStates.empty())
03748         {
03749             currentState = openedStates.dequeue();
03750             foreach(Transition *tr, currentState->getOutgoingTransitions())
03751             {
03752                 currentTransitions << tr;
03753             }
03754 
03755             foreach(State *newState, currentState->getAccessibleStates())
03756             {
03757                 if (newState->isInitial()) allInitialStates.removeAll(newState); // belongs to current automaton
03758 
03759                 if (currentStates.contains(newState)) continue;
03760                 currentStates << newState;
03761                 
03762                 foreach(Transition *tr, newState->getOutgoingTransitions())
03763                 {
03764                     currentTransitions << tr;
03765                 }
03766                 
03767                 if (newState->isInitial())
03768                     currentInitialStates << newState;
03769                 if (newState->isFinal())
03770                     currentFinalStates << newState;
03771 
03772                 if (openedStates.contains(newState)) continue;
03773                 openedStates.enqueue(newState);
03774             }
03775         }
03776 
03777         automaton = creator->createPrivateAutomaton(alphabet, alphabetSymbol, epsilonSymbol);
03778         
03779         foreach(State *state, currentStates)
03780         {
03781             bool ok;
03782             ok = automaton->addState(
03783                 creator->createPrivateState(state->getName(), state->getLabel(), state->isInitial(), state->isFinal(), state)
03784             );
03785 
03786             Q_ASSERT(ok && "some problem when adding state!");
03787         }
03788 
03789         foreach(Transition *transition, currentTransitions)
03790         {
03791             bool ok;
03792             ITransition::TCharSet characters;
03793             ok = transition->getCharacters(characters, alphabet, alphabetSymbol, epsilonSymbol);
03794 
03795             if (!ok)
03796             {                
03797                 return AutomatonImpl::TAutomatonList();
03798             }
03799             
03800             ok = automaton->addTransition(
03801                 creator->createPrivateTransition(transition->getStartStateName(),
03802                                                  transition->getEndStateName(),
03803                                                  characters,
03804                                                  transition)
03805             );
03806 
03807             Q_ASSERT(ok && "some problem when adding transition!");
03808         }
03809 
03810         DBGLOG("automaton added, consists of:" << endl
03811                << currentStates.count() << "states" << endl
03812                << currentInitialStates.count() << "initial states" << endl
03813                << currentFinalStates.count() << "final states" << endl
03814                << "alphabet:" << automaton->getAlphabet() << endl
03815                << "alphabetSymb:" << automaton->getAlphabetSymbol() << endl
03816                << "epsilonSymb:" << automaton->getEpsilonSymbol());
03817 
03818         automataList << automaton;
03819         automaton.clear();
03820 
03821         currentInitialStates.clear();
03822         currentFinalStates.clear();
03823         currentStates.clear();
03824         currentTransitions.clear();
03825     }
03826     
03827     return automataList;
03828 }
03829 
03830 // TODO: remove or rename to joinAutomata or something similar
03831 QSharedPointer<AutomatonImpl> Editor::getAutomaton(const QList<State*> &stateList,
03832                                                    ITransition::TCharSet &alphabet,
03833                                                    QString &alphabetSymbol,
03834                                                    QString &epsilonSymbol)
03835 {
03836     AutomatonImpl::TAutomatonList automataList =
03837         getAutomata(stateList, alphabet, alphabetSymbol, epsilonSymbol);
03838 
03839     if (automataList.empty())
03840     {
03841         RELLOG("No automaton found using given states!!!");
03842         return QSharedPointer<AutomatonImpl>(NULL);
03843     }
03844 
03845     Q_ASSERT(!alphabet.isEmpty());
03846     Q_ASSERT(alphabetSymbol != "");
03847     Q_ASSERT(epsilonSymbol != "");
03848 
03849     if (automataList.count() == 1)
03850         return automataList[0];
03851 
03852     QScopedPointer<AutomataCreator> creator(new AutomataCreator);
03853 
03854     StateImpl::TStateList states;
03855     TransitionImpl::TTransitionList transitions;
03856 
03857     foreach(const QSharedPointer<AutomatonImpl> &automaton, automataList)
03858     {
03859         states << automaton->getPrivateStates();
03860         transitions << automaton->getPrivateTransitions();
03861 
03862         // should be set and checked in getAutomata()
03863         Q_ASSERT(alphabet == automaton->getAlphabet());
03864         Q_ASSERT(alphabetSymbol == automaton->getAlphabetSymbol());
03865         Q_ASSERT(epsilonSymbol == automaton->getEpsilonSymbol());
03866     }
03867 
03868     QSharedPointer<AutomatonImpl> automaton =
03869         creator->createPrivateAutomaton(alphabet, alphabetSymbol, epsilonSymbol);
03870     automaton->addLists(states, transitions);
03871 
03872     return automaton;
03873 }
03874 
03875 #endif
03876 
03877 
03878 QSharedPointer<IAutomataCreator> Editor::getAutomataCreator()
03879 {
03880     return QSharedPointer<IAutomataCreator>(new AutomataCreator());
03881 }
03882 
03883 QList<State*> Editor::getInitialStates(const QList<State*> &stateList)
03884 {
03885     QList<State*> initialStates;
03886     foreach(State *state, stateList)
03887     {
03888         if (state->isInitial())
03889         {
03890             initialStates << state;
03891         }
03892     }
03893     return initialStates;
03894 }
03895 
03896 QList<State*> Editor::getFinalStates(const QList<State*> &stateList)
03897 {
03898     QList<State*> finalStates;
03899     foreach(State *state, stateList)
03900     {
03901         if (state->isFinal())
03902         {
03903             finalStates << state;
03904         }
03905     }
03906     return finalStates;
03907 }
03908 
03909 // TODO: is this good place for such methods?
03910 ITransition::TCharSet Editor::parseCharSet(const QString &text)
03911 {
03912     StringProcessor::TCharacterList charList = StringProcessor::computeCharacterList(text);
03913     
03914     ITransition::TCharSet result;
03915     
03916     StringProcessor::TCharacterList::const_iterator charIt = charList.begin();
03917     while(charIt != charList.end())
03918     {
03919         result << charIt->character;
03920         
03921         if (++charIt == charList.end()) break;
03922 
03923         if (charIt->character != ",") return ITransition::TCharSet();
03924         ++charIt;
03925     }
03926     
03927     return result;
03928 }
03929 
03930 QString Editor::parseCharacter(const QString &text)
03931 {
03932     StringProcessor::TCharacterList charList = StringProcessor::computeCharacterList(text);
03933     if (charList.count() != 1) return QString("");
03934     
03935     return charList[0].character;
03936 }
03937 
03938 //---------------------------------------------------------------- Editor -->
03939 
03940 
03941 //<-- UndoView --------------------------------------------------------------
03942 
03943 UndoView::UndoView(QUndoStack *stack, QWidget *parent)
03944 : QUndoView(stack, parent)
03945 {
03946   setMaximumSize(200,600);
03947   
03948   QShortcut *closeShortcut = new QShortcut(tr("Ctrl+W"), this);
03949   connect(closeShortcut, SIGNAL(activated()), this, SLOT(close()));
03950 }
03951 
03952 void UndoView::closeEvent(QCloseEvent *event)
03953 {
03954     if (event->type() == QEvent::Close) emit closed();
03955 }
03956 
03957 //-------------------------------------------------------------- UndoView -->

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