00001 #include "constants.h"
00002
00003 #include "state.h"
00004 #include "mainwindow.h"
00005 #include "editor.h"
00006 #include "transition.h"
00007 #include "stringProcessor.h"
00008 #include "transforms.h"
00009
00010 #include <QPoint>
00011 #include <QPointF>
00012 #include <QRect>
00013 #include <QRectF>
00014 #include <QGraphicsView>
00015 #include <QGraphicsSceneMouseEvent>
00016 #include <QColor>
00017
00018 #include <QTextStream>
00019
00020
00021 #include <QtDebug>
00022
00023
00024
00025 State::State(const QPoint &position, Editor *parent, const QString l,
00026 const QString n, bool dBorder, bool dim)
00027 : editor(parent), name(n), label(l), dimmed(dim), doubleBorder(dBorder), checked(false),
00028 checkedColor(QColor(CheckedColor::r, CheckedColor::g, CheckedColor::b, CheckedColor::a)),
00029 m_marked(false), m_otherMoved(false)
00030 {
00031 this->setZValue(Z_STATE);
00032 this->setPos(position);
00033 setFlag(QGraphicsItem::ItemIsMovable, true);
00034 setFlag(QGraphicsItem::ItemIsSelectable, true);
00035
00036
00037 #if QT_VERSION >= 0x040600
00038 setFlag(QGraphicsItem::ItemSendsGeometryChanges);
00039 setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
00040 #endif
00041
00042
00043 stateLineStyle = editor->stateLineStyle;
00044 stateLineWidth = 1;
00045 stateLineColor = editor->stateLineColor;
00046 stateLabelColor = editor->stateLabelColor;
00047 stateLabelScale = 1;
00048 stateFillStatus = editor->stateFillStatus;
00049 stateFillColor = editor->stateFillColor;
00050
00051
00052 stateLineDoubleCoef = editor->stateLineDoubleCoef;
00053 stateLineDoubleSep = editor->stateLineDoubleSep;
00054
00055
00056 dimStateLineStyle = editor->dimStateLineStyle;
00057 dimStateLineColor = editor->dimStateLineColor;
00058 dimStateLineCoef = editor->dimStateLineCoef;
00059 dimStateLabelColor = editor->dimStateLabelColor;
00060 dimStateFillColor = editor->dimStateFillColor;
00061
00062 stateLabelSize = (int) (STATE_LABEL_SIZE * editor->stateLabelScale * stateLabelScale);
00063 m_lineWidth = editor->stateLineWidth * STATE_LINE_VIEW_COEF;
00064
00065 if (dimmed)
00066 m_lineWidth *= dimStateLineCoef;
00067 else
00068 m_lineWidth *= stateLineWidth;
00069
00070 stringProcessor = new StringProcessor(label, stateLabelSize);
00071 }
00072
00073 State::~State()
00074 {
00075 delete stringProcessor;
00076 deleteTransitions();
00077 DBGLOG("called");
00078 }
00079
00080 QPolygonF State::getMyPolygon() const
00081 {
00082 return myPolygon;
00083 }
00084
00085 bool State::getVCParams(QTextStream &out, StatePrevParams &prevParams){
00086 bool stChanged = false;
00087 if (!dimmed)
00088 {
00089 if (stateLineStyle != prevParams.stateLineStyle)
00090 {
00091 prevParams.stateLineStyle = stateLineStyle;
00092 stChanged = true;
00093 if (stateLineStyle != editor->stateLineStyle)
00094 {
00095 out << endl << "\\ChgStateLineStyle{";
00096 out << trLineStyle(stateLineStyle);
00097 out << "}";
00098 }
00099 else
00100 {
00101 out << endl << "\\RstStateLineStyle";
00102 }
00103 }
00104
00105 if (stateLineWidth != prevParams.stateLineWidth)
00106 {
00107 stChanged = true;
00108 prevParams.stateLineWidth = stateLineWidth;
00109 if (stateLineWidth != 1)
00110 out << endl << "\\ChgStateLineWidth{" << stateLineWidth << "}";
00111 else
00112 out << endl << "\\RstStateLineWidth";
00113 }
00114
00115 if (stateLineColor != prevParams.stateLineColor)
00116 {
00117 stChanged = true;
00118 prevParams.stateLineColor = stateLineColor;
00119 if (stateLineColor != editor->stateLineColor)
00120 out << endl << "\\ChgStateLineColor{" << stateLineColor.toLower() << "}";
00121 else
00122 out << endl << "\\RstStateLineColor";
00123 }
00124
00125 if (stateLabelColor != prevParams.stateLabelColor)
00126 {
00127 stChanged = true;
00128 prevParams.stateLabelColor = stateLabelColor;
00129 if (stateLabelColor != editor->stateLabelColor)
00130 out << endl << "\\ChgStateLabelColor{" << stateLabelColor.toLower() << "}";
00131 else
00132 out << endl << "\\RstStateLabelColor";
00133 }
00134
00135 if (stateLabelScale != prevParams.stateLabelScale)
00136 {
00137 stChanged = true;
00138 prevParams.stateLabelScale = stateLabelScale;
00139 if (stateLabelScale != 1)
00140 out << endl << "\\ChgStateLabelScale{" << stateLabelScale << "}";
00141 else
00142 out << endl << "\\RstStateLabelScale";
00143 }
00144
00145 if (stateFillStatus != prevParams.stateFillStatus)
00146 {
00147 stChanged = true;
00148 prevParams.stateFillStatus = stateFillStatus;
00149 if (stateFillStatus != editor->stateFillStatus)
00150 out << endl << "\\ChgStateFillStatus{" << trFillStatus(stateFillStatus) << "}";
00151 else
00152 out << endl << "\\RstStateFillStatus";
00153 }
00154
00155 if (stateFillColor != prevParams.stateFillColor)
00156 {
00157 stChanged = true;
00158 prevParams.stateFillColor = stateFillColor;
00159 if (stateFillColor != editor->stateFillColor)
00160 out << endl << "\\ChgStateFillColor{" << stateFillColor.toLower() << "}";
00161 else
00162 out << endl << "\\RstStateFillColor";
00163 }
00164 }
00165 else
00166 {
00167 if (dimStateLineStyle != prevParams.dimStateLineStyle ||
00168 dimStateLineColor != prevParams.dimStateLineColor ||
00169 dimStateLineCoef != prevParams.dimStateLineCoef ||
00170 dimStateLabelColor != prevParams.dimStateLabelColor ||
00171 dimStateFillColor != prevParams.dimStateFillColor)
00172 {
00173 stChanged = true;
00174 prevParams.dimStateLineStyle = dimStateLineStyle;
00175 prevParams.dimStateLineColor = dimStateLineColor;
00176 prevParams.dimStateLineCoef = dimStateLineCoef;
00177 prevParams.dimStateLabelColor = dimStateLabelColor;
00178 prevParams.dimStateFillColor = dimStateFillColor;
00179 out << endl <<"\\FixDimState{" << trLineStyle(dimStateLineStyle) << "}"
00180 "{" << dimStateLineColor.toLower() << "}"
00181 "{" << dimStateLineCoef << "}"
00182 "{" << dimStateLabelColor.toLower() << "}"
00183 "{" << dimStateFillColor.toLower() << "}";
00184 }
00185 }
00186
00187 if (doubleBorder)
00188 {
00189 if (stateLineDoubleCoef != prevParams.stateLineDoubleCoef ||
00190 stateLineDoubleSep != prevParams.stateLineDoubleSep)
00191 {
00192 stChanged = true;
00193 prevParams.stateLineDoubleCoef = stateLineDoubleCoef;
00194 prevParams.stateLineDoubleSep = stateLineDoubleSep;
00195 out << endl << "\\FixStateLineDouble{" << stateLineDoubleCoef << "}"
00196 "{" << stateLineDoubleSep << "}";
00197 }
00198 }
00199
00200 if (stChanged) out << endl;
00201 return stChanged;
00202 }
00203
00204 QString State::getVCCommand() const
00205 {
00206 QString command = "";
00207
00208 QPointF s_pos = editor->mapToGrid(pos());
00209 command = "\\" + getTypeName();
00210 if (getLabel() != "") command += "[" + getLabel() + "]";
00211 command += QString("{(%1,%2)}{%3}")
00212 .arg(s_pos.x())
00213 .arg(s_pos.y())
00214 .arg(getName());
00215
00216 return command;
00217 }
00218
00219 void State::addTransition(Transition *transition)
00220 {
00221 if (transitionList.contains(transition))
00222 RELLOG("transition is currently assigned!!!");
00223 else
00224 transitionList << transition;
00225 }
00226
00227 void State::removeTransition(Transition *transition)
00228 {
00229 int i = transitionList.indexOf(transition);
00230 if (i != -1) transitionList.removeAt(i);
00231 }
00232
00233 void State::deleteTransitions()
00234 {
00235 Transition *tr;
00236 while (!transitionList.isEmpty())
00237 {
00238 tr = transitionList.takeFirst();
00239 tr->unassign();
00240 delete tr;
00241 }
00242 }
00243
00244 void State::setLabel(const QString &l)
00245 {
00246 prepareGeometryChange();
00247 label = l;
00248 stringProcessor->setText(label);
00249 }
00250
00251 void State::setName(const QString &n)
00252 {
00253 name = n;
00254 }
00255
00256 void State::setDoubleBorder(bool db)
00257 {
00258 if (doubleBorder == db) return;
00259
00260 prepareGeometryChange();
00261
00262 doubleBorder = db;
00263
00264 updateMyPolygon();
00265 }
00266
00267 void State::setDimmed(bool dim)
00268 {
00269 if (dimmed == dim) return;
00270
00271 dimmed = dim;
00272
00273 if (dimmed)
00274 m_lineWidth = m_lineWidth * dimStateLineCoef/stateLineWidth;
00275 else
00276 m_lineWidth = m_lineWidth * stateLineWidth/dimStateLineCoef;
00277
00278 updateMyPolygon();
00279 }
00280
00281 void State::setAutoNammed(bool aN)
00282 {
00283 autoNammed = aN;
00284 }
00285
00286 QRectF State::boundingRect() const
00287 {
00288 int width = getWidth() > getTextWidth() ? getWidth() : getTextWidth();
00289 int height = getHeight() > getTextHeight() ? getHeight() : getTextHeight();
00290
00291 QRectF ellipseRect(-width/2, -height/2, width, height);
00292 float adjust;
00293
00294 if (doubleBorder)
00295 {
00296 float doubleLineSep = m_lineWidth * stateLineDoubleSep / STATE_LINE_VIEW_COEF;
00297 float doubleLineWidth = m_lineWidth * stateLineDoubleCoef * STATE_DOUBLE_LINE_VIEW_COEF;
00298 adjust = doubleLineSep + doubleLineWidth*1.5 + 2;
00299 }
00300 else
00301 {
00302 adjust = m_lineWidth/2 + 2;
00303 }
00304
00305 return ellipseRect.adjusted(-adjust, -adjust,
00306 adjust, adjust);
00307 }
00308
00309 void State::paintSelectionDecoration(QPainter *painter)
00310 {
00311 if (isSelected())
00312 {
00313 const QColor selectedColor(SelectedColor::r,SelectedColor::g,
00314 SelectedColor::b, SelectedColor::a);
00315 painter->setPen(QPen(selectedColor,1,Qt::DashLine));
00316 painter->setBrush(Qt::NoBrush);
00317 painter->drawRect(boundingRect().adjusted(2,2,-2,-2));
00318 }
00319 }
00320
00321 void State::setChecked(bool checked)
00322 {
00323 if (this->checked == checked) return;
00324 DBGLOG_ME(DBGPAR(checked));
00325 this->checked = checked;
00326 update();
00327 }
00328
00329 QVariant State::itemChange(GraphicsItemChange change, const QVariant &value)
00330 {
00331 switch (change)
00332 {
00333 case ItemPositionHasChanged:
00334 adjustTransitions();
00335 break;
00336 default:
00337 break;
00338 }
00339
00340 return QGraphicsItem::itemChange(change, value);
00341 }
00342
00343 void State::adjustTransitions()
00344 {
00345 foreach(Transition *tr, transitionList)
00346 {
00347 tr->adjust();
00348 }
00349 }
00350
00351 void State::mousePressEvent(QGraphicsSceneMouseEvent *event)
00352 {
00353 DBGLOG_ME("called," << "pos=" << event->pos());
00354 m_lastMouseClickType = eMouseNoClick;
00355 setChecked();
00356
00357 if (editor->getAction() == Editor::eSelection &&
00358 event->button() == Qt::LeftButton)
00359 {
00360 DBGLOG_ME("cursor=ClosedHandCursor");
00361 editor->setCursor(Qt::ClosedHandCursor);
00362 }
00363
00364 if(event->button() == Qt::RightButton)
00365 {
00366 m_lastMouseClickType = eMouseRightClick;
00367 }
00368 else if (event->button() == Qt::LeftButton)
00369 {
00370 m_lastMouseClickType = eMouseLeftClick;
00371 oldPos = pos();
00372 }
00373 else if (event->button() == Qt::MidButton)
00374 {
00375 m_lastMouseClickType = eMouseMiddleClick;
00376 }
00377 else
00378 event->ignore();
00379 }
00380
00381 void State::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
00382 {
00383 DBGLOG_ME("called");
00384 if (event->button() == Qt::LeftButton && m_lastMouseClickType == eMouseMove)
00385 {
00386 if (oldPos != pos())
00387 {
00388 editor->stateMoved(this, oldPos);
00389 }
00390 setChecked(false);
00391 }
00392 else if ((m_lastMouseClickType == eMouseLeftClick && editor->getAction() == Editor::eInsertTransition) ||
00393 (m_lastMouseClickType == eMouseMiddleClick &&
00394 (editor->getAction() == Editor::eSelection || editor->getAction() == Editor::eInsertState)))
00395 {
00396 editor->setSelectedState(this);
00397 editor->insertTransition();
00398 }
00399 else if (m_lastMouseClickType == eMouseRightClick)
00400 {
00401 editor->showPopup(this);
00402 }
00403 else if (m_lastMouseClickType == eMouseDoubleClick)
00404 {
00405 editor->editState(this);
00406 setChecked(false);
00407 }
00408 else
00409 {
00410 setChecked(false);
00411 }
00412 }
00413
00414 void State::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
00415 {
00416 DBGLOG_ME("called");
00417 if (event->button() == Qt::LeftButton && editor->getAction() == Editor::eSelection)
00418 {
00419 m_lastMouseClickType = eMouseDoubleClick;
00420 setChecked();
00421 }
00422 }
00423
00424 void State::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
00425 {
00426 Q_ASSERT(event != NULL);
00427
00428 if (editor->getAction() != Editor::eSelection)
00429 return;
00430
00431 if (m_lastMouseClickType != eMouseLeftClick && m_lastMouseClickType != eMouseMove)
00432 return;
00433
00434 m_lastMouseClickType = eMouseMove;
00435
00436 QPointF g_pos = event->scenePos();
00437
00438 QPointF e_pos = mapFromScene(g_pos);
00439
00440 prepareGeometryChange();
00441
00442 QPointF movePoint(0,0);
00443
00444 if (!editor->snapped())
00445 {
00446 movePoint = e_pos;
00447 }
00448 else
00449 {
00450 editor->itemAlignToGrid(this);
00451
00452
00453 if (e_pos.toPoint().x() > (GRID_STEP / 2))
00454 {
00455 movePoint = QPoint(GRID_STEP, 0);
00456 }
00457 else if (e_pos.toPoint().x() < (-GRID_STEP / 2))
00458 {
00459 movePoint = QPoint(-GRID_STEP, 0);
00460 }
00461 if(e_pos.toPoint().y() > (GRID_STEP / 2))
00462 {
00463 movePoint = QPoint(0, GRID_STEP);
00464 }
00465 else if(e_pos.toPoint().y() < (-GRID_STEP / 2))
00466 {
00467 movePoint = QPoint(0,-GRID_STEP);
00468 }
00469 }
00470
00471 moveBy(movePoint.x(), movePoint.y());
00472 }
00473
00474 void State::setStateLabelScale(float labelScale)
00475 {
00476 if (stateLabelScale == labelScale) return;
00477
00478 prepareGeometryChange();
00479 stateLabelSize = (int) (stateLabelSize * labelScale/stateLabelScale);
00480 stateLabelScale = labelScale;
00481 stringProcessor->setFontSize(stateLabelSize);
00482 updateMyPolygon();
00483 }
00484
00485 void State::setStateLineWidth(float lineWidth)
00486 {
00487 if (stateLineWidth == lineWidth) return;
00488
00489 prepareGeometryChange();
00490
00491 if (!dimmed)
00492 m_lineWidth = m_lineWidth * lineWidth/stateLineWidth;
00493 stateLineWidth = lineWidth;
00494
00495 if (!dimmed)
00496 updateMyPolygon();
00497 }
00498
00499 void State::setDimStateLineCoef(float lineCoef)
00500 {
00501 if (dimStateLineCoef == lineCoef) return;
00502
00503 prepareGeometryChange();
00504
00505 if (dimmed)
00506 m_lineWidth = m_lineWidth * lineCoef/dimStateLineCoef;
00507 dimStateLineCoef = lineCoef;
00508
00509 if (dimmed)
00510 updateMyPolygon();
00511 }
00512
00513 void State::setStateLineDoubleCoef(float lineCoef)
00514 {
00515 if (stateLineDoubleCoef == lineCoef) return;
00516
00517 prepareGeometryChange();
00518
00519 stateLineDoubleCoef = lineCoef;
00520
00521 if (doubleBorder)
00522 updateMyPolygon();
00523 }
00524
00525 void State::setStateLineDoubleSep(float lineSep)
00526 {
00527 if (stateLineDoubleSep == lineSep) return;
00528
00529 prepareGeometryChange();
00530
00531 stateLineDoubleSep = lineSep;
00532
00533 if (doubleBorder)
00534 updateMyPolygon();
00535 }
00536
00537 void State::setMarked(bool marked)
00538 {
00539 prepareGeometryChange();
00540
00541 if (m_marked == marked) return;
00542
00543 m_marked = marked;
00544
00545 if (m_marked)
00546 {
00547 if (isDimmed())
00548 {
00549 m_origColor = dimStateFillColor;
00550 dimStateFillColor = toMarkerColor(dimStateFillColor);
00551 }
00552 else
00553 {
00554 m_origColor = stateFillColor;
00555 stateFillColor = toMarkerColor(stateFillColor);
00556 }
00557 }
00558 else
00559 {
00560 if (isDimmed())
00561 {
00562 dimStateFillColor = m_origColor;
00563 }
00564 else
00565 {
00566 stateFillColor = m_origColor;
00567 }
00568 }
00569 }
00570
00571 bool State::isInitial() const
00572 {
00573 foreach(const Transition *tr, transitionList)
00574 {
00575 if (tr->getTypeName() == "Initial")
00576 {
00577 return true;
00578 }
00579 }
00580
00581 return false;
00582 }
00583
00584 bool State::isFinal() const
00585 {
00586 if (doubleBorder) return true;
00587
00588 foreach(const Transition *tr, transitionList)
00589 {
00590 if (tr->getTypeName() == "Final")
00591 {
00592 return true;
00593 }
00594 }
00595
00596 return false;
00597 }
00598
00599 QList<Transition*> State::getOutgoingTransitions() const
00600 {
00601 QList<Transition*> transitions;
00602
00603 foreach(Transition *tr, transitionList)
00604 {
00605 if (tr->getStartState() == this &&
00606 tr->getTypeName() != "Initial" && tr->getTypeName() != "Final")
00607 {
00608 transitions << tr;
00609 }
00610 }
00611
00612 return transitions;
00613 }
00614
00615
00616 QList<State*> State::getAccessibleStates() const
00617 {
00618 QList<State*> accessibleStates;
00619
00620 foreach(Transition *tr, transitionList)
00621 {
00622 if (tr->getStartState() == this && tr->getEndState() != NULL)
00623 {
00624 accessibleStates << tr->getEndState();
00625 }
00626 else
00627 {
00628 accessibleStates << tr->getStartState();
00629 }
00630 }
00631
00632 return accessibleStates;
00633 }
00634
00635