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"
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
00060 #include <QFile>
00061 #include <QTextStream>
00062 #include <QPixmap>
00063 #include <QPrinter>
00064 #include <QImage>
00065 #include <QDate>
00066
00067
00068 #include <QRegExpValidator>
00069 #include <QRegExp>
00070
00071 #include <QUndoStack>
00072 #include <QDir>
00073 #include <QShortcut>
00074
00075
00076 #include <math.h>
00077
00078
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
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
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),
00128 m_stateIsMoving(false), m_simulationIsRun(false)
00129 {
00130
00131 m_zoomInFactor = pow(2.0, 120.0 / ZOOM_DIVIDER);
00132
00133
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
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
00148 stateLineDoubleCoef = DEF_STATE_LINE_DBL_COEF;
00149 stateLineDoubleSep = DEF_STATE_LINE_DBL_SEP;
00150
00151
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
00159 dimEdgeLineStyle = DEF_DIM_LINE_STYLE;
00160 dimEdgeLineColor = DEF_DIM_COLOR;
00161 dimEdgeLineCoef = DEF_DIM_EDGE_LINE_COEF;
00162 dimEdgeLabelColor = DEF_DIM_COLOR;
00163
00164 edgeLineBorderCoef = DEF_EDGE_LINE_BORDER_COEF;
00165 edgeLineBorderColor = DEF_EDGE_LINE_BORDER_COLOR;
00166
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);
00185 else
00186 setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
00187
00188 setCacheMode(QGraphicsView::CacheNone);
00189
00190 newStateNumber = 0;
00191
00192
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
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);
00238
00239 QFont::insertSubstitution("Arial", "Helvetica");
00240
00241
00242 setAttribute(Qt::WA_NoMousePropagation);
00243
00244
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
00262
00263 setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
00264
00265
00266 m_rubberBand = new DashedRubberBand(QRubberBand::Rectangle, this);
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 {
00284 m_undoStack->clear();
00285 delete m_undoStack;
00286
00287 QList<State*> stateList = getStateList();
00288
00289 while ( !stateList.isEmpty() )
00290 delete stateList.takeFirst();
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
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);
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
00537 m_transitionList.clear();
00538
00539 scene()->update();
00540 setFileName(NEW_FILENAME);
00541
00542 saved = false;
00543 setClean(true);
00544
00545 newStateNumber = 0;
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;
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;
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 {
00642 saveToFile(fn, additionals);
00643 }
00644
00645 void Editor::saveLaTeXHeader(QTextStream &out)
00646 {
00647
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
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
00713 int sbs = 0;
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
00776 QList<Transition *> trList;
00777 QList<Transition *> trIFList;
00778
00779 foreach(Transition *tr, m_transitionList)
00780 {
00781
00782 if (tr->getTypeName() == "Initial" ||
00783 tr->getTypeName() == "Final")
00784 {
00785 trIFList << tr;
00786 }
00787 else
00788 {
00789 trList << tr;
00790 }
00791 }
00792
00793
00794 EdgePrevParams prevTrParams;
00795 prevTrParams.edgeLineStyle = edgeLineStyle;
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
00855 out << endl;
00856
00857 out << "%" << trList.size() << " transitions";
00858 first = true;
00859
00860 sbs = SBS_TRAN;
00861
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
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;
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
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
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
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
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412 QRectF Editor::getPrintRect()
01413 {
01414 QRectF boundingBox = scene()->itemsBoundingRect();
01415
01416 const QRectF sceneRect = showFrame ? scene()->sceneRect().adjusted(0,0,2,4)
01417 : scene()->sceneRect();
01418 boundingBox = boundingBox.united(sceneRect);
01419 return boundingBox;
01420 }
01421
01422 void Editor::exportToEPS(const QString& fn)
01423 {
01424
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
01447 scene()->clearSelection();
01448
01449 QRectF boundingBox = getPrintRect();
01450
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
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
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
01499
01500
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);
01525 }
01526
01527 void Editor::scaleView(qreal scaleFactor)
01528 {
01529
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
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
01646
01647
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
01663 try
01664 {
01665 QClipboard *clipboard = QApplication::clipboard();
01666 const QMimeData *mimeData = clipboard->mimeData();
01667
01668 if (mimeData->hasFormat(CLIPBOARD_FORMAT_STATE))
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))
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
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
01803 while(!itemsOnPos.isEmpty())
01804 {
01805 if (itemsOnPos.first()->flags() & QGraphicsItem::ItemIsSelectable)
01806 break;
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 {
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 {
01828 itemsInvertSelection(itemsOnPos);
01829 }
01830 }
01831 else
01832 {
01833 if (itemsOnPos.empty())
01834 {
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)
01844 {
01845
01846 m_currentMouseAction = eMoveMultItem;
01847 DBGLOG_ME("cursor=ClosedHandCursor");
01848 setCursor(Qt::ClosedHandCursor);
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 {
01864 m_currentMouseAction = eMoveItem;
01865 scene()->clearSelection();
01866
01867 QGraphicsView::mousePressEvent(event);
01868 }
01869 }
01870 break;
01871 case Qt::RightButton:
01872 if (itemsOnPos.empty())
01873 {
01874 scene()->clearSelection();
01875 m_currentMouseAction = eShowPopup;
01876 }
01877 else if (itemsOnPos[0]->isSelected() &&
01878 scene()->selectedItems().count() > 1)
01879 {
01880 m_currentMouseAction = eShowSelectionPopup;
01881 }
01882 else
01883 {
01884 scene()->clearSelection();
01885 QGraphicsView::mousePressEvent(event);
01886 }
01887 break;
01888 case Qt::MidButton:
01889 scene()->clearSelection();
01890 QGraphicsView::mousePressEvent(event);
01891 break;
01892 default:;
01893 }
01894 }
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 {
01905 m_currentMouseAction = eShowPopup;
01906 }
01907 else if (itemsOnPos[0]->isSelected())
01908 {
01909 m_currentMouseAction = eShowSelectionPopup;
01910 }
01911 else
01912 {
01913 QGraphicsView::mousePressEvent(event);
01914 }
01915 break;
01916 case Qt::MidButton:
01917 scene()->clearSelection();
01918 QGraphicsView::mousePressEvent(event);
01919 break;
01920 default:;
01921 }
01922 }
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 {
01935 m_currentMouseAction = eShowPopup;
01936 }
01937
01938
01939
01940
01941 else
01942 {
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
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);
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 {
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
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);
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
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
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)
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
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)
02229 {
02230 selectedTransition->setChecked(false);
02231 selectedTransition->update();
02232 selectedTransition = NULL;
02233 }
02234 }
02235
02236
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());
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 {
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 {
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())
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);
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 {
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
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 {
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 {
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
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())
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
02539 State* Editor::insertState(State *state)
02540 {
02541 QRegExp rx("^Q[0-9]{1,10}$");
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 {
02559 startState = selectedState;
02560 mw->setStatusBar("First state selected; Select second state", 2000);
02561 }
02562 else
02563 {
02564 TransitionManager *transitionManager = TransitionManager::getInstance();
02565 Transition *tr = NULL;
02566 if (startState==selectedState)
02567 {
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
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 {
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;
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;
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();
02660 for (int x = GRID_STEP / 2; x < scene()->width();x += GRID_STEP)
02661 {
02662 if (showGrid)
02663 {
02664 if (pop)
02665 painter->setPen(QPen(Qt::lightGray, 1, Qt::DotLine));
02666 else
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)
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();
02681 for (int y = GRID_STEP/2; y < scene()->height(); y+=GRID_STEP)
02682 {
02683 if (showGrid)
02684 {
02685 if (pop)
02686 painter->setPen(QPen(Qt::lightGray, 1, Qt::DotLine));
02687 else
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)
02693 {
02694 painter->setPen(QPen(Qt::lightGray));
02695 painter->drawText(2, y + fontHeight/2,QString("%1").arg(pop));
02696 }
02697 pop--;
02698 }
02699 }
02700 }
02701
02702 void Editor::setStatusBar(const QString &text, int ms)
02703 {
02704 mw->setStatusBar(text, ms);
02705 }
02706
02707
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;
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
02768 scaleView(1/transform().m11());
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);
02896 }
02897 else
02898 {
02899 setRenderHint(QPainter::Antialiasing, false);
02900 setRenderHint(QPainter::SmoothPixmapTransform,true);
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:
02924 sList = generateExactMatching(string,ggd.getStartPoint());
02925 break;
02926 case 1:
02927 sList = generateDistance(1,string, distance, startPoint);
02928 break;
02929 case 2:
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)
02951 {
02952 urx_new = startPoint.x() + len * EXACT_HSPACE + 1;
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 }
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
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 {
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 {
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 {
03081
03082
03083 s1 = sList[(len+1)*(j-1) + (i-1) - (j-1)*(1+(j-1))/2];
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];
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);
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
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
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
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);
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
03576 if (!alphabet.isEmpty())
03577 {
03578 a -= alphabet;
03579 DBGLOG_AI("Adepts to alphabet or epsilon symbol: " << a);
03580 }
03581
03582
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;
03610
03611 DBGLOG_AI("Adepts to epsilon symbol: " << a);
03612
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;
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
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
03696
03697
03698 AutomatonImpl::TAutomatonList Editor::getAutomata(const QList<State*> &stateList,
03699 ITransition::TCharSet &alphabet,
03700 QString &alphabetSymbol,
03701 QString &epsilonSymbol)
03702 {
03703
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
03723
03724 AutomatonImpl::TAutomatonList automataList;
03725
03726
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
03736
03737 while (!allInitialStates.empty())
03738 {
03739 State *currentState = allInitialStates.takeFirst();
03740 currentStates << currentState;
03741 currentInitialStates << currentState;
03742
03743
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);
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
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
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
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
03939
03940
03941
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