diff --git a/README.md b/README.md index cf6d9f2..c4b38a3 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ **[Video overview - v.2.2](https://youtu.be/30dyXAs-m1A)** -# Scxml Editor 2.5.3 +# Scxml Editor 2.5.4 Powerful tool for creating, editing and debugging SCXML charts. ![MainExample](Images/Inheritance_TV_example.gif) @@ -24,6 +24,7 @@ Powerful tool for creating, editing and debugging SCXML charts. [![Discord](Images/Discord.svg)](https://discord.gg/5XWDsbEXzn) ### Changelog +**2.5.4:** Nested initial state indication
**2.5.3:** Chart Draw Constraints, Select Chart Elements
**2.5.1:** [Fast Triggers](Doc/DebugScxmlStateCharts.md#transition-triggers)
**2.5:** [Virtual Invoke](Doc/VisualStateChartSplitting.md#virtual-invoke)
@@ -51,7 +52,7 @@ Powerful tool for creating, editing and debugging SCXML charts. ## Installation You can find portable version as attached Zip in ScxmlEditor Github Release page -Latest version: **[2.5.3.1759]** +Latest version: **[2.5.4.1768]** ### Windows Installation #### First Install diff --git a/Src/ScxmlEditor.cbproj b/Src/ScxmlEditor.cbproj index 21989de..16b3c63 100644 --- a/Src/ScxmlEditor.cbproj +++ b/Src/ScxmlEditor.cbproj @@ -1015,13 +1015,13 @@ alexander.zhornyak@gmail.com Scxml State Charts Editor - 2.5.3.1760 + 2.5.4.1768 alexander.zhornyak@gmail.com ScxmlEditor - 2.5.3.0 + 2.5.4.0 diff --git a/Src/ScxmlEditor.res b/Src/ScxmlEditor.res index 79fb0b7..6017eb6 100644 Binary files a/Src/ScxmlEditor.res and b/Src/ScxmlEditor.res differ diff --git a/Src/ScxmlEditor_resources.rc b/Src/ScxmlEditor_resources.rc index e0aceaf..8878f79 100644 --- a/Src/ScxmlEditor_resources.rc +++ b/Src/ScxmlEditor_resources.rc @@ -1,40 +1,40 @@ -PngFinalize RCData "Images\\finalize_16_16.png" -PngForeach RCData "Images\\foreach_16_16.png" -CompleteBasic RCData "complete_basic.lua" -PngDatamodel RCData "Images\\datamodel_16_16.png" -PngVirtualFolder RCData "Images\\virtual_folder_16_16.png" +PngIf RCData "Images\\if_16_16.png" +CompleteCPP RCData "complete_all_CPP.txt" +PngLog RCData "Images\\log_16_16.png" +PngError RCData "Images\\error_16.png" +PngWatch RCData "Images\\watch_16_16.png" +PngData RCData "Images\\data_16_16.png" +PngAssign RCData "Images\\assign_16_16.png" +PngParam RCData "Images\\param_16_16.png" +PngSessionState RCData "Images\\statemachine_16_16.png" +PngProtocol RCData "Images\\protocol_16_16.png" +PngTransitionXML RCData "Images\\XMLText_Transition_16.png" +CompletePython RCData "complete_all_python.txt" +CompleteDebug RCData "complete_debug.lua" +PngTrigger RCData "Images\\trigger_16_16.png" +ResLogProperties RCData "ScxmlEditor.properties" +PngScript RCData "Images\\script_16_16.png" +PngCancel RCData "Images\\cancel_16_16.png" +CompleteString RCData "complete_string.lua" +PngProtocolWeak RCData "Images\\protocol_weak_16_16.png" PngSend RCData "Images\\send_16_16.png" +PngVirtualFolder RCData "Images\\virtual_folder_16_16.png" PngComment RCData "Images\\comment_16_16.png" PngRaise RCData "Images\\raise_16_16.png" -PngExtraContent RCData "Images\\extracontent_16_16.png" -CompleteTable RCData "complete_table.lua" +CompleteBasic RCData "complete_basic.lua" +PngDatamodel RCData "Images\\datamodel_16_16.png" CompleteEcmascript RCData "complete_all_js.txt" CompleteUtf8 RCData "complete_utf8.lua" -PngOnExit RCData "Images\\onexit_16_16.png" -PngDoneData RCData "Images\\donedata_16_16.png" -CompleteOs RCData "complete_os.lua" -PngInvoke RCData "Images\\invoke_16_16.png" -PngSetValue RCData "Images\\setvalue_16_16.png" +PngExtraContent RCData "Images\\extracontent_16_16.png" +CompleteTable RCData "complete_table.lua" +PngForeach RCData "Images\\foreach_16_16.png" +PngFinalize RCData "Images\\finalize_16_16.png" PngOnEntry RCData "Images\\onenter_16_16.png" -PngContent RCData "Images\\content_16_16.png" -ResCurPan Cursor "Images\\PanningCursor.cur" +PngSetValue RCData "Images\\setvalue_16_16.png" +PngInvoke RCData "Images\\invoke_16_16.png" CompleteMath RCData "complete_math.lua" -PngData RCData "Images\\data_16_16.png" -PngAssign RCData "Images\\assign_16_16.png" -PngProtocol RCData "Images\\protocol_16_16.png" -PngParam RCData "Images\\param_16_16.png" -PngSessionState RCData "Images\\statemachine_16_16.png" -CompleteCPP RCData "complete_all_CPP.txt" -PngIf RCData "Images\\if_16_16.png" -PngError RCData "Images\\error_16.png" -PngWatch RCData "Images\\watch_16_16.png" -PngLog RCData "Images\\log_16_16.png" -CompleteString RCData "complete_string.lua" -PngCancel RCData "Images\\cancel_16_16.png" -PngProtocolWeak RCData "Images\\protocol_weak_16_16.png" -ResLogProperties RCData "ScxmlEditor.properties" -PngScript RCData "Images\\script_16_16.png" -PngTrigger RCData "Images\\trigger_16_16.png" -PngTransitionXML RCData "Images\\XMLText_Transition_16.png" -CompleteDebug RCData "complete_debug.lua" -CompletePython RCData "complete_all_python.txt" +ResCurPan Cursor "Images\\PanningCursor.cur" +PngContent RCData "Images\\content_16_16.png" +PngDoneData RCData "Images\\donedata_16_16.png" +CompleteOs RCData "complete_os.lua" +PngOnExit RCData "Images\\onexit_16_16.png" diff --git a/Src/TreeEditor/TreeEditorEx.cpp b/Src/TreeEditor/TreeEditorEx.cpp index cd9f5e8..3af84e7 100644 --- a/Src/TreeEditor/TreeEditorEx.cpp +++ b/Src/TreeEditor/TreeEditorEx.cpp @@ -222,10 +222,14 @@ void __fastcall TTreeEditorEx::OnDectivateTreeEditor(TObject *Sender) { // --------------------------------------------------------------------------- void __fastcall TTreeEditorEx::DoInvalidateTrees() { - if (NodeTree && IsWindowVisible(NodeTree->Handle)) { - NodeTree->Invalidate(); + try { + if (NodeTree && IsWindowVisible(NodeTree->Handle)) { + NodeTree->Invalidate(); + } + DoInvalidateFocusedTheTree(); + } + catch(Exception * e) { } - DoInvalidateFocusedTheTree(); } // --------------------------------------------------------------------------- @@ -1119,8 +1123,12 @@ void __fastcall TTreeEditorEx::PopupNodePopup(System::TObject* Sender) { // --------------------------------------------------------------------------- void __fastcall TTreeEditorEx::DoInvalidateFocusedTheTree(void) { - if (TheTree && IsWindowVisible(TheTree->Handle) && TheTree->Focused()) { - this->InvalidateTheTreeWithTemp(); + try { + if (TheTree && IsWindowVisible(TheTree->Handle) && TheTree->Focused()) { + this->InvalidateTheTreeWithTemp(); + } + } + catch(Exception * E) { } } diff --git a/Src/UnitScxmlBaseShape.cpp b/Src/UnitScxmlBaseShape.cpp index 44a66bf..66f8954 100644 --- a/Src/UnitScxmlBaseShape.cpp +++ b/Src/UnitScxmlBaseShape.cpp @@ -1,4 +1,4 @@ -/*********************************************************************************** +/** ********************************************************************************* BSD 3-Clause License Copyright (c) 2018, https://github.com/alexzhornyak @@ -28,7 +28,7 @@ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ***************************************************************************************/ + ************************************************************************************** */ #include #pragma hdrstop @@ -107,7 +107,8 @@ class TEditByDefaultPropEditor : public TLMDStringPropEditor { int GetMaxBrotherRight(TVisualScxmlBaseShape *AVisualParentShape) { int iX = 0; for (int i = 0; i < AVisualParentShape->Children->Count; i++) { - TVisualScxmlBaseShape *AVisualShape = dynamic_cast(AVisualParentShape->Children->Items[i]); + TVisualScxmlBaseShape *AVisualShape = dynamic_cast + (AVisualParentShape->Children->Items[i]); if (AVisualShape) { if (AVisualShape->X1 > iX) { iX = AVisualShape->X1; @@ -121,7 +122,8 @@ int GetMaxBrotherRight(TVisualScxmlBaseShape *AVisualParentShape) { int GetMaxBrotherBottom(TVisualScxmlBaseShape *AVisualParentShape, TVisualScxmlBaseShape *ACurrentShape) { int iY = 0; for (int i = 0; i < AVisualParentShape->Children->Count; i++) { - TVisualScxmlBaseShape *AVisualShape = dynamic_cast(AVisualParentShape->Children->Items[i]); + TVisualScxmlBaseShape *AVisualShape = dynamic_cast + (AVisualParentShape->Children->Items[i]); // чтобы не смещать на собственную высоту if (AVisualShape && (ACurrentShape != AVisualShape)) { WLOG_DEBUG(L"Current child is <%s>", AVisualShape->SimpleText.c_str()); @@ -137,22 +139,25 @@ int GetMaxBrotherBottom(TVisualScxmlBaseShape *AVisualParentShape, TVisualScxmlB bool IsOverlappedWithSomebody(TVisualScxmlBaseShape *AVisualParentShape, TVisualScxmlBaseShape *ACurrentShape) { bool bOverlapped = false; for (int i = 0; i < AVisualParentShape->Children->Count; i++) { - TVisualScxmlBaseShape *AVisualShape = dynamic_cast(AVisualParentShape->Children->Items[i]); + TVisualScxmlBaseShape *AVisualShape = dynamic_cast + (AVisualParentShape->Children->Items[i]); // чтобы не сравнивать с собой if (AVisualShape && (ACurrentShape != AVisualShape)) { TRect AIntersect; - // WLOG_DEBUG(L"Comparing overlapping between [%s] and [%d][%s]", ACurrentShape->SimpleText.c_str(), i, - // AVisualShape->SimpleText.c_str()); + // WLOG_DEBUG(L"Comparing overlapping between [%s] and [%d][%s]", ACurrentShape->SimpleText.c_str(), i, + // AVisualShape->SimpleText.c_str()); - bOverlapped = IntersectRect(AIntersect, TRect(AVisualShape->X0, AVisualShape->Y0, AVisualShape->X1, AVisualShape->Y1), - TRect(ACurrentShape->X0, ACurrentShape->Y0, ACurrentShape->X1, ACurrentShape->Y1)); + bOverlapped = IntersectRect(AIntersect, TRect(AVisualShape->X0, AVisualShape->Y0, AVisualShape->X1, + AVisualShape->Y1), TRect(ACurrentShape->X0, ACurrentShape->Y0, ACurrentShape->X1, + ACurrentShape->Y1)); if (bOverlapped) { WLOG_DEBUG(L"Intersect %s=[%d,%d,%d,%d] with %s=[%d,%d,%d,%d]", AVisualShape->SimpleText.c_str(), - AVisualShape->Bounds().left, AVisualShape->Bounds().top, AVisualShape->Bounds().right, AVisualShape->Bounds().bottom, - ACurrentShape->SimpleText.c_str(), ACurrentShape->Bounds().left, ACurrentShape->Bounds().top, - ACurrentShape->Bounds().right, ACurrentShape->Bounds().bottom); + AVisualShape->Bounds().left, AVisualShape->Bounds().top, AVisualShape->Bounds().right, + AVisualShape->Bounds().bottom, ACurrentShape->SimpleText.c_str(), + ACurrentShape->Bounds().left, ACurrentShape->Bounds().top, ACurrentShape->Bounds().right, + ACurrentShape->Bounds().bottom); break; } } @@ -168,14 +173,16 @@ void CheckVisualScxmlShapePos(TCustomTree *ATree, TVisualScxmlBaseShape *AVisual if (AVisualShape->X0 <= AVisualShapeParent->X0) { AVisualShape->X0 = AVisualShapeParent->X0 + 30; - WLOG_DEBUG(L"Moved %s on X axis %d,%d,%d,%d", AVisualShape->SimpleText.c_str(), AVisualShape->Bounds().left, - AVisualShape->Bounds().top, AVisualShape->Bounds().right, AVisualShape->Bounds().bottom); + WLOG_DEBUG(L"Moved %s on X axis %d,%d,%d,%d", AVisualShape->SimpleText.c_str(), + AVisualShape->Bounds().left, AVisualShape->Bounds().top, AVisualShape->Bounds().right, + AVisualShape->Bounds().bottom); } if (AVisualShape->Y0 <= AVisualShapeParent->Y0) { AVisualShape->Y0 = AVisualShapeParent->Y0 + 30; - WLOG_DEBUG(L"Moved %s on Y axis %d,%d,%d,%d", AVisualShape->SimpleText.c_str(), AVisualShape->Bounds().left, - AVisualShape->Bounds().top, AVisualShape->Bounds().right, AVisualShape->Bounds().bottom); + WLOG_DEBUG(L"Moved %s on Y axis %d,%d,%d,%d", AVisualShape->SimpleText.c_str(), + AVisualShape->Bounds().left, AVisualShape->Bounds().top, AVisualShape->Bounds().right, + AVisualShape->Bounds().bottom); } if (iVisualIndex > 0 && IsOverlappedWithSomebody(AVisualShapeParent, AVisualShape)) { @@ -189,7 +196,8 @@ void CheckVisualScxmlShapePos(TCustomTree *ATree, TVisualScxmlBaseShape *AVisual // итерация дочерних int iIndex = 0; for (int i = 0; i < AVisualShape->Children->Count; i++) { - TVisualScxmlBaseShape *AVisualChild = dynamic_cast(AVisualShape->Children->Items[i]); + TVisualScxmlBaseShape *AVisualChild = dynamic_cast + (AVisualShape->Children->Items[i]); if (AVisualChild) { CheckVisualScxmlShapePos(ATree, AVisualChild, iIndex); iIndex++; @@ -262,7 +270,8 @@ __fastcall TScxmlBaseShape::~TScxmlBaseShape() { // --------------------------------------------------------------------------- void __fastcall TScxmlBaseShape::DrawShapeCanvas(Tecanvas::TCanvas3D * ACanvas, const Types::TRect & R) { /* INHERITANCE */ - if (this->Locked && !this->InheritanceMismatch && StateMachineEditorUnit && StateMachineEditorUnit->IsInherited && StateMachineEditor) { + if (this->Locked && !this->InheritanceMismatch && StateMachineEditorUnit && StateMachineEditorUnit->IsInherited && + StateMachineEditor) { StateMachineEditor->EnqueeScxmlShapeForInheritanceCheck(this); } @@ -434,7 +443,8 @@ TStateMachineEditor * __fastcall TScxmlBaseShape::GetStateMachineEditor(void) { } // --------------------------------------------------------------------------- -void __fastcall TScxmlBaseShape::OnGetPropEditorClass(TPersistent *AInstance, ILMDProperty *APropInfo, TLMDPropEditorClass &AEditorClass) { +void __fastcall TScxmlBaseShape::OnGetPropEditorClass(TPersistent *AInstance, ILMDProperty *APropInfo, + TLMDPropEditorClass &AEditorClass) { const UnicodeString sPropName = APropInfo->Name(); if (APropInfo && !IsPublishedProp(__classid(TTreeNodeShape), sPropName)) { @@ -483,7 +493,8 @@ bool __fastcall TScxmlBaseShape::OnFilterPropEvent(const UnicodeString & sPropNa } // --------------------------------------------------------------------------- -void __fastcall TScxmlBaseShape::OnGetPropCaptionColor(TObject *Sender, Lmdinspropinsp::TLMDPropertyInspectorItem *AItem, TColor &AColor) { +void __fastcall TScxmlBaseShape::OnGetPropCaptionColor(TObject *Sender, + Lmdinspropinsp::TLMDPropertyInspectorItem *AItem, TColor &AColor) { // специальный случай if (AItem->PropName == L"InheritanceResolver") { AColor = clTeal; @@ -492,7 +503,8 @@ void __fastcall TScxmlBaseShape::OnGetPropCaptionColor(TObject *Sender, Lmdinspr if (AItem->TypeInfo->Kind != tkClass && !AItem->Parent && AItem->PropInfo[0]->IsWritable()) { - if (!IsPublishedProp(__classid(TTreeNodeShape), AItem->PropName) && IsPublishedProp(__classid(TScxmlBaseShape), AItem->PropName)) { + if (!IsPublishedProp(__classid(TTreeNodeShape), AItem->PropName) && IsPublishedProp(__classid(TScxmlBaseShape), + AItem->PropName)) { AColor = clTeal; } } @@ -515,7 +527,8 @@ UnicodeString __fastcall TScxmlBaseShape::OnGetHTMLPropertyInfo(const UnicodeStr if (sPropName == L"ExcludeFromSave") { return L"The element will not be saved to the resulting scxml file\n" // - "P.S. You can exclude the element by ExcludeConditions also (see ExcludeConditions for more details)" // + "P.S. You can exclude the element by ExcludeConditions also (see ExcludeConditions for more details)" + // ; } @@ -588,7 +601,7 @@ UnicodeString __fastcall TScxmlBaseShape::OnGetHTMLPropertyInfo(const UnicodeStr } if (sPropName == L"InheritanceResolver") { - return L"String list of properties which will be skipped during inheritance comparison\n"// + return L"String list of properties which will be skipped during inheritance comparison\n" // ; } @@ -658,7 +671,8 @@ TScxmlBaseShape * __fastcall TScxmlBaseShape::AddStateChild(TStateChildType AChi TVisualScxmlBaseShape *AVisualShape = dynamic_cast(this); if (AVisualShape) { for (int i = 0; i < AVisualShape->Count(); i++) { - TVisualScxmlBaseShape *AChildVisualShape = dynamic_cast(AVisualShape->Children->Items[i]); + TVisualScxmlBaseShape *AChildVisualShape = dynamic_cast + (AVisualShape->Children->Items[i]); if (AChildVisualShape) { if (AChildVisualShape->Bounds().Bottom > iTop) { iTop = AChildVisualShape->Bounds().Bottom; @@ -757,7 +771,8 @@ TScxmlBaseShape * __fastcall TScxmlBaseShape::AddStateChild(TStateChildType AChi AShape = AddScxmlClassShape(this, TScxmlBaseShape::TypeToXMLNodeName(AChildType), false); break; case sctWeakProtocolBinding: - AShape = AddScxmlClassShape(this, TScxmlBaseShape::TypeToXMLNodeName(AChildType), false); + AShape = AddScxmlClassShape(this, TScxmlBaseShape::TypeToXMLNodeName(AChildType), + false); break; case sctSetValue: AShape = AddScxmlClassShape(this, TScxmlBaseShape::TypeToXMLNodeName(AChildType), false); @@ -866,7 +881,8 @@ void __fastcall TScxmlBaseShape::PropsToAttributes(ILMDXmlElement * ANode) { if (bRequiredOrDefault && sAttrValue.IsEmpty()) throw EScxmlBaseShapeException(this, L"Empty '" + sAttrName + "'", - L"Required attribute '" + sAttrName + "' can not be empty! Shape id:["+this->SimpleText + "] name:["+this->Name + "]"); + L"Required attribute '" + sAttrName + "' can not be empty! Shape id:["+this->SimpleText + + "] name:["+this->Name + "]"); bool bDoSave = true; @@ -909,7 +925,8 @@ TStateChildType __fastcall TScxmlBaseShape::XMLNodeNameToType(const UnicodeStrin PPropInfo APropInfo = GetPropInfo(__classid(TScxmlBaseShape), "StateChildType"); assert(APropInfo != NULL); const TStateChildType AType = TStateChildType(i); - const UnicodeString sEnumName = StringReplace(GetEnumName(*(APropInfo->PropType), AType), L"sct", L"", TReplaceFlags()); + const UnicodeString sEnumName = StringReplace(GetEnumName(*(APropInfo->PropType), AType), L"sct", L"", + TReplaceFlags()); if (sEnumName.UpperCase() == sNodeName.UpperCase()) { return AType; } @@ -992,24 +1009,27 @@ void __fastcall TScxmlBaseShape::ValidateChild(TScxmlBaseShape *AChild) { return; if (this->AvailableTypes.find(AChild->StateChildType) == this->AvailableTypes.end()) - throw EScxmlBaseShapeException(AChild, L"Not valid child", UnicodeString().sprintf(L"<%s> is not a valid child of <%s>", // + throw EScxmlBaseShapeException(AChild, L"Not valid child", + UnicodeString().sprintf(L"<%s> is not a valid child of <%s>", // AChild->XMLName.c_str(), this->XMLName.c_str())); if (AChild->OccursOnce) { if (AChild->Parent != this) - throw EScxmlBaseShapeException(AChild, L"Program logic", UnicodeString().sprintf - (L"ValidateChild> Program logic error! [%s] is not a child of [%s]", // + throw EScxmlBaseShapeException(AChild, L"Program logic", + UnicodeString().sprintf(L"ValidateChild> Program logic error! [%s] is not a child of [%s]", // AChild->SimpleText.c_str(), this->SimpleText.c_str())); if (AChild->ChildIndex >= this->Children->Count) throw EScxmlBaseShapeException(AChild, L"Program logic", // - UnicodeString().sprintf(L"ValidateChild> Program logic error! ChildIndex:[%s]:[%d] is out of range [%s]:[0...%d]", // + UnicodeString().sprintf( + L"ValidateChild> Program logic error! ChildIndex:[%s]:[%d] is out of range [%s]:[0...%d]", // AChild->SimpleText.c_str(), AChild->ChildIndex, this->SimpleText.c_str(), this->Children->Count)); // проверяем все предыдущие for (int i = 0; i < AChild->ChildIndex; i++) { if (this->Children->Items[i]->ClassType() == AChild->ClassType()) { - throw EScxmlBaseShapeException(AChild, L"Duplicated", L"<" + AChild->XMLName + "> must occur only 1 time!"); + throw EScxmlBaseShapeException(AChild, L"Duplicated", + L"<" + AChild->XMLName + "> must occur only 1 time!"); } } } @@ -1027,8 +1047,9 @@ void __fastcall TScxmlBaseShape::ValidateShape() { } } else { - const UnicodeString sMsg = UnicodeString().sprintf(L"E%d:%s> text=[%s] name=[%s]", SCXML_ERROR_WRONG_CHILD_TYPE, - GetErrorDescription(SCXML_ERROR_WRONG_CHILD_TYPE).c_str(), this->SimpleText.c_str(), this->Name.c_str()); + const UnicodeString sMsg = UnicodeString().sprintf(L"E%d:%s> text=[%s] name=[%s]", + SCXML_ERROR_WRONG_CHILD_TYPE, GetErrorDescription(SCXML_ERROR_WRONG_CHILD_TYPE).c_str(), + this->SimpleText.c_str(), this->Name.c_str()); if (it == FErrorMap.end()) { WLOG_WARNING(L"%s", sMsg.c_str()); @@ -1060,9 +1081,10 @@ void __fastcall TScxmlBaseShape::ValidateSimpleText(TCustomTree *ATree) { TStateErrorMap::iterator it = ABaseShape->FErrorMap.find(SCXML_ERROR_NAME_DUPLICATED); if (ANamesList->IndexOf(ABaseShape->SimpleText) != -1) { - const UnicodeString sMsg = UnicodeString().sprintf(L"E%d:%s> text=[%s] name=[%s]", SCXML_ERROR_NAME_DUPLICATED, - ABaseShape->GetErrorDescription(SCXML_ERROR_NAME_DUPLICATED).c_str(), ABaseShape->SimpleText.c_str(), - ABaseShape->Name.c_str()); + const UnicodeString sMsg = UnicodeString().sprintf(L"E%d:%s> text=[%s] name=[%s]", + SCXML_ERROR_NAME_DUPLICATED, + ABaseShape->GetErrorDescription(SCXML_ERROR_NAME_DUPLICATED).c_str(), + ABaseShape->SimpleText.c_str(), ABaseShape->Name.c_str()); if (it == ABaseShape->FErrorMap.end()) { WLOG_WARNING(sMsg.c_str()); bValid = false; @@ -1211,7 +1233,8 @@ void __fastcall TScxmlBaseShape::SetInheritanceMismatch(bool val) { } // --------------------------------------------------------------------------- -void __fastcall TScxmlBaseShape::StoreInheritedVisualsParentOffsets(void) // сохранит положение дочерних относительно родителя +void __fastcall TScxmlBaseShape::StoreInheritedVisualsParentOffsets(void) +// сохранит положение дочерних относительно родителя { // запомним дочерние не наследованные for (int i = 0; i < this->Children->Count; i++) { @@ -1229,7 +1252,8 @@ void __fastcall TScxmlBaseShape::SetInheritanceMismatch(bool val) { // сдвинем дочерние не наследованные for (int i = 0; i < this->Children->Count; i++) { TVisualScxmlBaseShape * AVisualScxmlBaseShape = dynamic_cast(this->Children->Items[i]); - if (AVisualScxmlBaseShape && !AVisualScxmlBaseShape->Locked && !AVisualScxmlBaseShape->ParentOffsetStored->IsEmpty()) { + if (AVisualScxmlBaseShape && !AVisualScxmlBaseShape->Locked && + !AVisualScxmlBaseShape->ParentOffsetStored->IsEmpty()) { const int iOffsetX = AVisualScxmlBaseShape->ParentOffsetStored->X - AVisualScxmlBaseShape->ParentOffsetX; const int iOffsetY = AVisualScxmlBaseShape->ParentOffsetStored->Y - AVisualScxmlBaseShape->ParentOffsetY; @@ -1341,8 +1365,8 @@ bool __fastcall TScxmlBaseShape::ShouldDrawVectorImages(void) { // --------------------------------------------------------------------------- // TVisualScxmlBaseShape // --------------------------------------------------------------------------- -__fastcall TVisualScxmlBaseShape::TVisualScxmlBaseShape(Classes::TComponent * AOwner) : TScxmlBaseShape(AOwner), FEntered(false), -FInitial(L""), FExamined(false), FSkipDebugging(false), FBreakpointSet(false) { +__fastcall TVisualScxmlBaseShape::TVisualScxmlBaseShape(Classes::TComponent * AOwner) : TScxmlBaseShape(AOwner), +FEntered(false), FInitial(L""), FExamined(false), FSkipDebugging(false), FBreakpointSet(false) { FAvailableTypes.insert(sctProtocolBinding); FAvailableTypes.insert(sctWeakProtocolBinding); @@ -1450,16 +1474,16 @@ bool __fastcall TVisualScxmlBaseShape::OnFilterPropEvent(const UnicodeString & s } // --------------------------------------------------------------------------- -void __fastcall TVisualScxmlBaseShape::OnGetPropCaptionColor(TObject *Sender, Lmdinspropinsp::TLMDPropertyInspectorItem *AItem, - TColor &AColor) { +void __fastcall TVisualScxmlBaseShape::OnGetPropCaptionColor(TObject *Sender, + Lmdinspropinsp::TLMDPropertyInspectorItem *AItem, TColor &AColor) { TScxmlBaseShape::OnGetPropCaptionColor(Sender, AItem, AColor); if (AItem->TypeInfo->Kind != tkClass && !AItem->Parent && AItem->PropInfo[0]->IsWritable()) { if (IsPublishedProp(__classid(TVisualScxmlBaseShape), AItem->PropName)) { - // if (!IsPublishedProp(__classid(TScxmlBaseShape), AItem->PropName)) { - // AColor = RGB(90,90,0); - // } + // if (!IsPublishedProp(__classid(TScxmlBaseShape), AItem->PropName)) { + // AColor = RGB(90,90,0); + // } } else { AColor = clNavy; @@ -1547,13 +1571,15 @@ UnicodeString __fastcall TVisualScxmlBaseShape::OnGetHTMLPropertyInfo(const Unic if (sPropName == L"ChildrenAlignXOffset") { return // - L"children are aligned to the left, right or center of the shape + 'ChildrenAlignXOffset'\n" // + L"children are aligned to the left, right or center of the shape + 'ChildrenAlignXOffset'\n" + // ; } if (sPropName == L"ChildrenAlignY") { return // - L"scayClusterTop - children are aligned to the top corner of the shape in cluster mode\n" // + L"scayClusterTop - children are aligned to the top corner of the shape in cluster mode\n" + // "scayAlwaysBottom - children are aligned to the bottom corner of the shape\n" // "scayAlwaysTop - children are aligned to the top corner of the shape\n" // ; @@ -1562,6 +1588,24 @@ UnicodeString __fastcall TVisualScxmlBaseShape::OnGetHTMLPropertyInfo(const Unic return L""; } +// --------------------------------------------------------------------------- +bool TVisualScxmlBaseShape::FindChildInitial(TVisualScxmlBaseShape *AShape, const UnicodeString &sInitial) { + for (int i = 0; i < AShape->Children->Count; i++) { + TVisualScxmlBaseShape * AVisualScxmlBaseShape = dynamic_cast + (AShape->Children->Items[i]); + if (AVisualScxmlBaseShape) { + if ((AVisualScxmlBaseShape->SimpleText == sInitial) || + // we skip virtual substates, they will be checked later + (AVisualScxmlBaseShape->StateChildType == sctVirtual) || + // рекурсивно поиск по вложенным + FindChildInitial(AVisualScxmlBaseShape, sInitial)) { + return true; + } + } + } + return false; +} + // --------------------------------------------------------------------------- void __fastcall TVisualScxmlBaseShape::SetSelfConnectionTextOffsets(TPersistentRect *val) { FSelfConnectionTextOffsets->Assign(val); @@ -1603,7 +1647,8 @@ void __fastcall TVisualScxmlBaseShape::UpdateStateChildren(void) { const int iWasIndex = AChildShape->ChildIndex; if (iWasIndex != iBrotherIndex) { AChildShape->ChildIndex = iBrotherIndex; - WLOG_DEBUG(L"[%s] Reassigned brother index from[%d] to[%d]", AChildShape->SimpleText.c_str(), iWasIndex, iBrotherIndex); + WLOG_DEBUG(L"[%s] Reassigned brother index from[%d] to[%d]", AChildShape->SimpleText.c_str(), + iWasIndex, iBrotherIndex); } iBrotherIndex++; // применяем автопозицию @@ -1631,13 +1676,13 @@ UnicodeString __fastcall TVisualScxmlBaseShape::GetInitial(void) { if (!FInitial.IsEmpty()) { // если классический Initial с указанием только одного элемента if (!FInitial.Pos(" ")) { - for (int i = 0; i < this->Children->Count; i++) { - TVisualScxmlBaseShape * AVisualScxmlBaseShape = dynamic_cast(this->Children->Items[i]); - if (AVisualScxmlBaseShape && AVisualScxmlBaseShape->SimpleText == FInitial) { - return FInitial; - } + // если есть хоть в одном из дочерних + if (this->FindChildInitial(this, FInitial)) { + return FInitial; } - WLOG_WARNING(L"Initial element [%s] is not a valid child element of [%s]!", FInitial.c_str(), this->SimpleText.c_str()); + + WLOG_WARNING(L"Initial element [%s] is not a valid child element of [%s]!", FInitial.c_str(), + this->SimpleText.c_str()); FInitial = L""; // не знаю, правильно или нет } @@ -1778,7 +1823,8 @@ void __fastcall TVisualScxmlBaseShape::UpdateBreakpointView() { // --------------------------------------------------------------------------- TVertTextAlign __fastcall TVisualScxmlBaseShape::GetVertTextAlign(void) { - return this->IsCluster() ? Teetree::vtaTop : (FAutoVertTextAlign ? Teetree::vtaCenter : TScxmlBaseShape::GetVertTextAlign()); + return this->IsCluster() ? Teetree::vtaTop : + (FAutoVertTextAlign ? Teetree::vtaCenter : TScxmlBaseShape::GetVertTextAlign()); } // --------------------------------------------------------------------------- @@ -1963,11 +2009,10 @@ void __fastcall TVisualScxmlBaseShape::DrawShapeCanvas(Tecanvas::TCanvas3D * ACa } if (TVisualScxmlBaseShape * AVisualParent = this->VisualParent) { - switch(AVisualParent->StateChildType) { case sctScxml: case sctState: { - if (AVisualParent->Initial.IsEmpty()) { + if (AVisualParent->FInitial.IsEmpty()) { TVisualScxmlBaseShape *AFirstVisual = NULL; @@ -2010,7 +2055,49 @@ void __fastcall TVisualScxmlBaseShape::DrawShapeCanvas(Tecanvas::TCanvas3D * ACa default: break; } + + TTreeNodeShape *AParent = dynamic_cast(AVisualParent->Parent); + while (AParent) { + + TVisualScxmlBaseShape * AVisualUpperParent = dynamic_cast(AParent); + if (AVisualUpperParent) { + if (AVisualUpperParent->ExcludeFromSave) { + break; + } + + bool bIsNestedInitial = false; + + switch(AVisualUpperParent->StateChildType) { + case sctScxml: + case sctState: { + if (AVisualUpperParent->FInitial == this->SimpleText) { + bIsNestedInitial = true; + } + }break; + } + + if (bIsNestedInitial) { + ACanvas->Brush->Color = SettingsData->ThemeSettings->StateInitialBorderColor; + ACanvas->Pen->Color = clBlack; + + if (this->StateChildType == sctFinal) { + + ACanvas->EllipseWithZ(TRect(R.Left - 4, R.Top - 10, R.Left + 6, R.Top), TeeTreeZ); + + } + else { + ACanvas->EllipseWithZ(TRect(R.Left + 4, R.Top + 4, R.Left + 14, R.Top + 14), TeeTreeZ); + } + + break; + } + } + + AParent = AParent->Parent; + } + } + } } @@ -2023,7 +2110,8 @@ void __fastcall TVisualScxmlBaseShape::SetEntered(bool val) { } // --------------------------------------------------------------------------- -void __fastcall TVisualScxmlBaseShape::SetChildrenEntered(TNodeShapeList *AShapes, bool bVal, bool bRecursive /* =true */ ) { +void __fastcall TVisualScxmlBaseShape::SetChildrenEntered(TNodeShapeList *AShapes, bool bVal, + bool bRecursive /* =true */ ) { for (int i = 0; i < AShapes->Count; i++) { TVisualScxmlBaseShape *AVisualShape = dynamic_cast(AShapes->Items[i]); if (AVisualShape) { @@ -2100,7 +2188,8 @@ void __fastcall TVisualScxmlBaseShape::ArrangeSelfConnections(void) { for (int i = 0; i < this->Connections->Count; i++) { if (this->Connections->Items[i]->ToShape == this) { - TStateMachineConnection * AStateMachineConnection = dynamic_cast(this->Connections->Items[i]); + TStateMachineConnection * AStateMachineConnection = dynamic_cast + (this->Connections->Items[i]); if (AStateMachineConnection) { const TSelfConnectionInfo AInfo = AStateMachineConnection->SelfConnectionInfo; @@ -2113,7 +2202,8 @@ void __fastcall TVisualScxmlBaseShape::ArrangeSelfConnections(void) { // некрасиво, когда вылазит соединение за пределы фигуры, // поэтому будем рассматривать варианты только когда оно в пределах AStateMachineConnection->AlignSelfConnection(AInfo.Align, - ASelfAlignMap[AInfo.Align].LengthOffsetBegin < 0 ? 0 : ASelfAlignMap[AInfo.Align].LengthOffsetBegin, + ASelfAlignMap[AInfo.Align].LengthOffsetBegin < 0 ? 0 : ASelfAlignMap[AInfo.Align] + .LengthOffsetBegin, ASelfAlignMap[AInfo.Align].LengthOffsetEnd < 0 ? 0 : ASelfAlignMap[AInfo.Align].LengthOffsetEnd, ASelfAlignMap[AInfo.Align].TextOffset); } @@ -2126,7 +2216,8 @@ void __fastcall TVisualScxmlBaseShape::ArrangeDefaultSelfConnections(void) { for (int i = 0; i < this->Connections->Count; i++) { - TStateMachineConnection * AStateMachineConnection = dynamic_cast(this->Connections->Items[i]); + TStateMachineConnection * AStateMachineConnection = dynamic_cast + (this->Connections->Items[i]); if (AStateMachineConnection && AStateMachineConnection->IsSelfConnection) { AStateMachineConnection->AlignSelfConnection(scaTop); @@ -2173,10 +2264,13 @@ void __fastcall TVisualScxmlBaseShape::SetExcludeFromSave(bool val) { TStateMachineConnection * __fastcall TVisualScxmlBaseShape::HasInternalInOutConnections(void) { if (Tree) { for (int i = 0; i < Tree->Connections->Count; i++) { - TStateMachineConnection * AStateMachineConnection = dynamic_cast(Tree->Connections->Items[i]); + TStateMachineConnection * AStateMachineConnection = dynamic_cast + (Tree->Connections->Items[i]); if (AStateMachineConnection && !AStateMachineConnection->IsSelfConnection) { - TVisualScxmlBaseShape * AVisualFrom = dynamic_cast(AStateMachineConnection->FromShape); - TVisualScxmlBaseShape * AVisualTo = dynamic_cast(AStateMachineConnection->ToShape); + TVisualScxmlBaseShape * AVisualFrom = dynamic_cast + (AStateMachineConnection->FromShape); + TVisualScxmlBaseShape * AVisualTo = dynamic_cast + (AStateMachineConnection->ToShape); if (AVisualFrom && AVisualTo) { const bool bThisFromParent = AVisualFrom->HasAsParent(this); const bool bThisToParent = AVisualTo->HasAsParent(this); @@ -2342,8 +2436,8 @@ bool __fastcall TChildScxmlBaseShape::OnFilterPropEvent(const UnicodeString &sPr } // --------------------------------------------------------------------------- -void __fastcall TChildScxmlBaseShape::OnGetPropCaptionColor(TObject *Sender, Lmdinspropinsp::TLMDPropertyInspectorItem *AItem, - TColor &AColor) { +void __fastcall TChildScxmlBaseShape::OnGetPropCaptionColor(TObject *Sender, + Lmdinspropinsp::TLMDPropertyInspectorItem *AItem, TColor &AColor) { TScxmlBaseShape::OnGetPropCaptionColor(Sender, AItem, AColor); @@ -2395,7 +2489,8 @@ UnicodeString __fastcall TChildScxmlBaseShape::OnGetHTMLPropertyInfo(const Unico if (sPropName == L"ClipOutMax") { return // - "If ClipOutValue is set to true then the shape's text will be cut until ClipOutMax position\n" // + "If ClipOutValue is set to true then the shape's text will be cut until ClipOutMax position\n" + // "For example:\n" // " Text='Very long string'\n" // " ClipOutValue=true\n" // @@ -2479,8 +2574,8 @@ void __fastcall TChildScxmlBaseShape::UpdateSimpleText() { } } - SimpleText = sOut.IsEmpty() ? sXMLName : UnicodeString().sprintf(L"%s%s {%s}", sXMLName.c_str(), sXMLTextInfo.c_str(), - sOut.c_str()); + SimpleText = sOut.IsEmpty() ? sXMLName : UnicodeString().sprintf(L"%s%s {%s}", sXMLName.c_str(), + sXMLTextInfo.c_str(), sOut.c_str()); UpdateParentSimpleText(); @@ -2586,8 +2681,9 @@ void __fastcall TChildScxmlBaseShape::DrawShapeCanvas(Tecanvas::TCanvas3D* ACanv // --------------------------------------------------------------------------- // -------------------- EScxmlDuplicateStateIDException ---------------------- // --------------------------------------------------------------------------- -__fastcall EScxmlDuplicateStateIDException::EScxmlDuplicateStateIDException(const UnicodeString &sMsg, const UnicodeString &sScxmlName, - const UnicodeString &sID) : Exception(sMsg), FScxmlName(sScxmlName), FStateID(sID) { +__fastcall EScxmlDuplicateStateIDException::EScxmlDuplicateStateIDException(const UnicodeString &sMsg, + const UnicodeString &sScxmlName, const UnicodeString &sID) : Exception(sMsg), FScxmlName(sScxmlName), +FStateID(sID) { } diff --git a/Src/UnitScxmlBaseShape.h b/Src/UnitScxmlBaseShape.h index 02123ec..9d26eb4 100644 --- a/Src/UnitScxmlBaseShape.h +++ b/Src/UnitScxmlBaseShape.h @@ -502,6 +502,8 @@ class TVisualScxmlBaseShape : public TScxmlBaseShape { inline virtual bool __fastcall MustSimpleTextBeUnique(void) { return true;} /* override */ + bool FindChildInitial(TVisualScxmlBaseShape *AShape, const UnicodeString &sInitial); + // возвращает первое соединение, которое выходит наружу изнутри, или приходит внутрь // гарантирует FromShape, ToShape != NULL TStateMachineConnection * __fastcall HasInternalInOutConnections(void); diff --git a/Src/UnitScxmlShape.cpp b/Src/UnitScxmlShape.cpp index 5a1ddd7..de4b29a 100644 --- a/Src/UnitScxmlShape.cpp +++ b/Src/UnitScxmlShape.cpp @@ -47,20 +47,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma package(smart_init) -bool FindChildInitial(TVisualScxmlBaseShape *AShape, const UnicodeString &sInitial) { - for (int i = 0; i < AShape->Children->Count; i++) { - TVisualScxmlBaseShape * AVisualScxmlBaseShape = dynamic_cast(AShape->Children->Items[i]); - if (AVisualScxmlBaseShape) { - if ((AVisualScxmlBaseShape->SimpleText == sInitial) || - // рекурсивно поиск по вложенным - FindChildInitial(AVisualScxmlBaseShape, sInitial)) { - return true; - } - } - } - return false; -} - // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- @@ -89,31 +75,6 @@ __fastcall TScxmlShape::~TScxmlShape() { } -// --------------------------------------------------------------------------- -UnicodeString __fastcall TScxmlShape::GetInitial(void) { - // проверка, является ли валидным указатель на начальный элемент - if (!FInitial.IsEmpty()) { - // если классический Initial с указанием только одного элемента - if (!FInitial.Pos(" ")) { - // если есть хоть в одном из дочерних - if (FindChildInitial(this, FInitial)) { - return FInitial; - } - - WLOG_WARNING(L"Initial element [%s] is not a valid child element of [%s]!", FInitial.c_str(), this->SimpleText.c_str()); - - FInitial = L""; // не знаю, правильно или нет - } - else { - // иначе просто возвращаем список без всяких проверок - return FInitial; - } - - } - // в этом случае невозвращаем начальный элемент, но пока сохраняем FInitial - return L""; -} - // --------------------------------------------------------------------------- void __fastcall TScxmlShape::OnGetPropEditorClass(TPersistent *AInstance, ILMDProperty *APropInfo, TLMDPropEditorClass &AEditorClass) { diff --git a/Src/UnitScxmlShape.h b/Src/UnitScxmlShape.h index bd6977d..b135549 100644 --- a/Src/UnitScxmlShape.h +++ b/Src/UnitScxmlShape.h @@ -75,9 +75,6 @@ class TScxmlShape : public TVisualScxmlBaseShape { virtual void __fastcall DrawShapeCanvas(Tecanvas::TCanvas3D * ACanvas, const Types::TRect & R); - /* может быть любой элемент в этом SCXML */ - virtual UnicodeString __fastcall GetInitial(void); - inline virtual bool __fastcall GetOccursOnce(void) { return true; } void __fastcall SyncByInvokeID(void); diff --git a/Src/UnitStateMachineConnection.cpp b/Src/UnitStateMachineConnection.cpp index 6651a41..459e1c7 100644 --- a/Src/UnitStateMachineConnection.cpp +++ b/Src/UnitStateMachineConnection.cpp @@ -662,18 +662,29 @@ void __fastcall TStateMachineConnection::UpdateDummyText(void) { void __fastcall TStateMachineConnection::UpdateAppearance() { if (!this->ComponentState.Contains(csLoading)) { + const int iLineWidth1 = SettingsData->ThemeSettings->TransitionLineWidth; + const int iLineWidth2 = SettingsData->ThemeSettings->TransitionLineWidth + 1; + const int iLineWidth3 = SettingsData->ThemeSettings->TransitionLineWidth + 2; + if (IsSelfConnection || (Type == external && IsTargetDescendant)) { this->Border->Style = IsTargetStored ? psDash : psDot; + this->Border->Color = IsTargetStored ? clRed : clBlue; - this->Border->Width = IsTargetStored ? 2 : 1; + this->Border->Width = IsTargetStored ? iLineWidth2 : iLineWidth1; this->Border->SmallDots = false; } else { this->Border->Style = IsTargetDescendant ? psDot : psSolid; this->Border->Color = clBlack; - this->Border->Width = 1; - this->Border->SmallDots = IsTargetDescendant == false; + this->Border->Width = iLineWidth1; + this->Border->SmallDots = IsTargetDescendant == false && iLineWidth1 == 1; + } + + // NOTE: it looks ugly on Windows without aliasing + if (this->Border->Style == psDot && this->Border->Width != 1) { + this->Border->Style = psSolid; } + this->Format->Visible = ContentTrigger->Enabled == true; this->Format->Color = clInfoBk; this->Format->Gradient->Visible = false; @@ -692,10 +703,13 @@ void __fastcall TStateMachineConnection::UpdateAppearance() { TColor AToBackColor = Locked ? (InheritanceMismatch ? clRed : (InheritanceResolver->ResolvedProps->Count ? TColor(RGB(255, 150, 50)) : clYellow)) : (InheritanceMismatch ? clFuchsia : clBlack); + const int iArrowFromSize1 = SettingsData->ThemeSettings->TransitionFromCircleSize; + const int iArrowFromSize2 = SettingsData->ThemeSettings->TransitionFromCircleSize + 5; + switch(SWITCH) { case tstINVERT_CONDITION: { this->ArrowFrom->Style = casSolid; - this->ArrowFrom->Size = 15; + this->ArrowFrom->Size = iArrowFromSize2; this->Border->SmallDots = false; this->Border->Style = psDash; this->Border->Color = TColor(RGB(200, 0, 0)); @@ -709,7 +723,7 @@ void __fastcall TStateMachineConnection::UpdateAppearance() { }break; case tstSIMPLE: { this->ArrowFrom->Style = casSolid; - this->ArrowFrom->Size = 15; + this->ArrowFrom->Size = iArrowFromSize2; this->Border->SmallDots = false; this->Border->Style = psDash; this->Border->Color = clGray; @@ -724,7 +738,7 @@ void __fastcall TStateMachineConnection::UpdateAppearance() { case tstNONE: default: { this->ArrowFrom->Style = casCircle; - this->ArrowFrom->Size = 10; + this->ArrowFrom->Size = iArrowFromSize1; }break; } @@ -735,14 +749,14 @@ void __fastcall TStateMachineConnection::UpdateAppearance() { if (this == StateMachineEditor->FActiveDebugConnection) { this->Border->Color = clRed; this->Border->Style = psSolid; - this->Border->Width = 3; + this->Border->Width = iLineWidth3; this->Border->SmallDots = false; } else { if (StateMachineEditor->WasEnteredConnection(this)) { this->Border->Color = SettingsData->ChartTestCoverageColor; this->Border->Style = psSolid; - this->Border->Width = 3; + this->Border->Width = iLineWidth3; this->Border->SmallDots = false; } diff --git a/Src/UnitStateMachineParser.cpp b/Src/UnitStateMachineParser.cpp index 2132fb7..47de85d 100644 --- a/Src/UnitStateMachineParser.cpp +++ b/Src/UnitStateMachineParser.cpp @@ -2047,6 +2047,62 @@ namespace Statemachine { } } + typedef std::set TUniqueIDs; + + void ValidateInitialIDs(ILMDXmlNode * AParentNode, TUniqueIDs &AParentIDs, ILMDXmlNode * AScxmlNode) { + if (AParentNode && (AParentNode->NodeType == LMD_NODE_ELEMENT || AParentNode->NodeType == LMD_NODE_DOCUMENT)) { + + TUniqueIDs AChildrenIDs; + + bool bIsScxml = false; + bool bIsState = false; + + UnicodeString sId = ""; + + // SCXML могут быть вложенными, поэтому определяем текущий, + // как только встретится новый элемент, переключаем родителя на него, + // и рекурсивно переходим, а потом возвращаемся обратно + if (AParentNode->NodeName == L"scxml") { + bIsScxml = true; + AScxmlNode = AParentNode; + sId = AParentNode->GetAttr(L"name", ""); + } + else if (VISUAL_STATE_NAMES.find(AParentNode->NodeName) != VISUAL_STATE_NAMES.end()) { + bIsState = true; + sId = AParentNode->GetAttr(L"id", ""); + if (!sId.IsEmpty()) { + AParentIDs.insert(sId); + } + } + + for (int i = 0; i < AParentNode->ChildNodes->Count; i++) { + ValidateInitialIDs(AParentNode->ChildNodes->Item[i], AChildrenIDs, AScxmlNode); + } + + if (bIsScxml || bIsState) { + std::auto_ptr AUniqueIDs(new TStringList); + AUniqueIDs->Delimiter = L' '; + AUniqueIDs->StrictDelimiter = true; + AUniqueIDs->DelimitedText = AParentNode->GetAttr(L"initial", ""); + for (int i = 0; i < AUniqueIDs->Count; i++) { + const UnicodeString sInitialID = AUniqueIDs->Strings[i]; + if (AChildrenIDs.find(sInitialID) == AChildrenIDs.end()) { + const UnicodeString sScxmlName = AScxmlNode ? UnicodeString(AScxmlNode->GetAttr(L"name", L"")) : UnicodeString(""); + throw EScxmlDuplicateStateIDException(UnicodeString().sprintf(L"Element:[%s]:[%s] initial ID:[%s] not found Scxml:[%s]", + AParentNode->NodeName.c_str(), sId.c_str(), sInitialID.c_str(), sScxmlName.c_str()), sScxmlName, sId); + } + } + + } + + if (!bIsScxml) { + if (!AChildrenIDs.empty()) { + AParentIDs.insert(AChildrenIDs.begin(), AChildrenIDs.end()); + } + } + } + } + typedef std::multimapTUnicodeDictionary; void GetInPredicateValues(const UnicodeString &sText, const std::set &AStateIDs, const bool bIsNullDatamodel) { @@ -2190,6 +2246,9 @@ namespace Statemachine { TMapUniqueStates AUniqueStates; ValidateUniqueStateIDs(AMainDoc->DocumentElement, AUniqueStates, NULL); + TUniqueIDs AUniqueIDs; + ValidateInitialIDs(AMainDoc->DocumentElement, AUniqueIDs, NULL); + #if 0 // для глубокой отладки DumpUniqueStates(AUniqueStates); #endif @@ -2309,6 +2368,10 @@ namespace Statemachine { DumpUniqueStates(AUniqueStates); #endif + // More precise check for initials + TUniqueIDs AUniqueIDs; + ValidateInitialIDs(AMainDoc->DocumentElement, AUniqueIDs, NULL); + // проверка предиката 'In()' if (SettingsData->ValidateInPredicate) { if (AScxmlShape->StateMachineEditorUnit && !AScxmlShape->StateMachineEditorUnit->IsVirtual) { diff --git a/Src/UnitThemeSettings.cpp b/Src/UnitThemeSettings.cpp index d07535b..9264b47 100644 --- a/Src/UnitThemeSettings.cpp +++ b/Src/UnitThemeSettings.cpp @@ -77,6 +77,9 @@ __fastcall TThemeSettings::TThemeSettings() { FVirtualNormalColor = clSilver; FVirtualHeadColor = clGray; + + FTransitionLineWidth = 1; + FTransitionFromCircleSize = 10; } // --------------------------------------------------------------------------- @@ -114,6 +117,8 @@ void __fastcall TThemeSettings::Assign(Classes::TPersistent* Source) { FVirtualNormalColor = AThemeSettings->FVirtualNormalColor; FVirtualHeadColor = AThemeSettings->FVirtualHeadColor; + FTransitionLineWidth = AThemeSettings->FTransitionLineWidth; + FTransitionFromCircleSize = AThemeSettings->FTransitionFromCircleSize; } else throw Exception(__FUNCTION__ "> Can not cast <" + Source->ClassName() + "> to <"+this->ClassName() + ">"); @@ -138,6 +143,20 @@ void __fastcall TThemeSettings::OnGetPropEditorClass(TPersistent *AInstance, ILM // } } +//--------------------------------------------------------------------------- +void __fastcall TThemeSettings::SetTransitionLineWidth(int val) { + if (val > 0 && val < 20) { + FTransitionLineWidth = val; + } +} + +//--------------------------------------------------------------------------- +void __fastcall TThemeSettings::SetTransitionFromCircleSize(int val) { + if (val > 6 && val < 40) { + FTransitionFromCircleSize = val; + } +} + //--------------------------------------------------------------------------- //---------------------- TThemeSettingsPropEditor ---------------------------- //--------------------------------------------------------------------------- diff --git a/Src/UnitThemeSettings.h b/Src/UnitThemeSettings.h index a5d1108..07ff283 100644 --- a/Src/UnitThemeSettings.h +++ b/Src/UnitThemeSettings.h @@ -70,6 +70,12 @@ class TThemeSettings: public TPersistent { TColor FChildNormalBorderColor; TPenStyle FChildNormalBorderStyle; + int FTransitionLineWidth; + void __fastcall SetTransitionLineWidth(int val); + + int FTransitionFromCircleSize; + void __fastcall SetTransitionFromCircleSize(int val); + protected: public: @@ -101,6 +107,9 @@ class TThemeSettings: public TPersistent { __property TColor VirtualNormalColor = {read=FVirtualNormalColor, write=FVirtualNormalColor, default=clSilver}; __property TColor VirtualHeadColor = {read=FVirtualHeadColor, write=FVirtualHeadColor, default=clGray}; + + __property int TransitionLineWidth = {read=FTransitionLineWidth, write=SetTransitionLineWidth, default=1}; + __property int TransitionFromCircleSize = {read=FTransitionFromCircleSize, write=SetTransitionFromCircleSize, default=10}; }; /* PROP EDITORS */