/// <summary> /// Check if all connectors are visible in diagram (global approach). It uses the direction of UML/EA. /// </summary> /// <returns></returns> public bool IsCompleteGlobal() { EA.Diagram dia = Rep.GetDiagramByID(_diaObj.DiagramID); List <int> globalIds = new List <int>(); globalIds.AddRange(from Connector c in Rep.GetElementByID(_diaObj.ElementID).Connectors select c.ConnectorID); List <int> diagramConnectorIds = new List <int>(); foreach (EA.DiagramLink l in dia.DiagramLinks) { if (l.IsHidden == false) { diagramConnectorIds.Add(l.ConnectorID); } } foreach (int id in globalIds) { if (!diagramConnectorIds.Contains(id)) { return(false); } } return(true); }
/// <summary> /// Sort diagram objects alphabetic like: /// - Classifier /// - Port, Parameter, Pin /// - Packages /// If it sorts for Ports, it ignores other element types. /// </summary> /// <returns></returns> public override bool SortAlphabetic() { //EA.Element el = _rep.GetElementByID(diaObj.ElementID); var list = from item in _eaDia.SelObjects let el = Rep.GetElementByID(item.ElementID) select new { item.ElementID, el.Name, el.Type, item.left, item.right, item.top, item.bottom, item } into temp where temp.Type != "RequiredInterface" && temp.Type != "ProvidedInterface" orderby temp.Name select temp; var llist = list.ToList(); // run query // sort only Port, Pin, Parameter if (llist.Count(t => t.Type == "Port" || t.Type == "Pin" || t.Type == "Parameter") > 0) { llist = llist.Where(t => t.Type == "Port" || t.Type == "Pin" || t.Type == "Parameter").ToList(); } // nothing to sort if (llist.Count() < 2) { return(false); } // estimate the direction bool isVertical = (Math.Abs(llist[0].top - llist[1].top)) > (Math.Abs(llist[0].left - llist[1].left)) ? true : false; if (isVertical) { // vertical int topItem = llist.Max(t => t.top); int bottomItem = llist.Min(t => t.bottom); int sum = llist.Sum(t => t.top - t.bottom); int diff = (topItem - bottomItem - sum) / (llist.Count - 1); int top = topItem; foreach (var item in llist) { int itemDif = item.item.top - item.item.bottom; item.item.top = top; item.item.bottom = item.item.top - itemDif; top = item.item.bottom - diff; item.item.Update(); } Rep.ReloadDiagram(_eaDia.Dia.DiagramID); return(true); } else { // horizontal int leftItem = llist.Min(t => t.left); int rightItem = llist.Max(t => t.right); int sum = llist.Sum(t => t.right - t.left); int diff = (rightItem - leftItem - sum) / (llist.Count - 1); int left = leftItem; foreach (var item in llist) { int itemDif = item.item.right - item.item.left; item.item.left = left; item.item.right = item.item.left + itemDif; left = item.item.right + diff; item.item.Update(); } Rep.ReloadDiagram(_eaDia.Dia.DiagramID); return(true); } }
/// <summary> /// Import and update ReqIF Requirements. You can set EA ObjectType like "Requirement" or EA Stereotype like "FunctionalRequirement" /// </summary> /// async Task public override bool ImportForFile(string eaObjectType = "Requirement", string eaStereotype = "", string stateNew = "", string stateChanged = "") { bool result = true; Rep.BatchAppend = true; Rep.EnableUIUpdates = false; // Deserialize var reqIf = DeSerializeReqIf(ImportModuleFile, validate: Settings.ValidateReqIF); if (reqIf == null) { return(false); } InitializeDoorsRequirementsTable(reqIf); //reqIf.CoreContent[0].Specifications.Dump(); // over all submodules Specification elModule = reqIf.CoreContent[0].Specifications[0]; AddRequirements(DtRequirements, elModule.Children, 1); base.ReadEaPackageRequirements(); CreateEaPackageDeletedObjects(); Count = 0; CountChanged = 0; CountNew = 0; List <int> parentElementIdsPerLevel = new List <int> { 0 }; int parentElementId = 0; int lastElementId = 0; int oldLevel = 0; foreach (DataRow row in DtRequirements.Rows) { Count += 1; string objectId = row["Id"].ToString(); string reqAbsNumber = objectId; //string reqAbsNumber = GetAbsoluteNumerFromDoorsId(objectId); int objectLevel = Int32.Parse(row["Object Level"].ToString()) - 1; string objectNumber = row["Object Number"].ToString(); string objectType = row["Object Type"].ToString(); string objectHeading = row["Object Heading"].ToString(); // Maintain parent ids of level // get parent id if (objectLevel > oldLevel) { if (parentElementIdsPerLevel.Count <= objectLevel) { parentElementIdsPerLevel.Add(lastElementId); } else { parentElementIdsPerLevel[objectLevel] = lastElementId; } parentElementId = lastElementId; } if (objectLevel < oldLevel) { parentElementId = parentElementIdsPerLevel[objectLevel]; } oldLevel = objectLevel; string name; string notes; // Estimate if header if (objectType == "headline" || !String.IsNullOrWhiteSpace(objectHeading)) { name = $"{objectNumber} {objectHeading}"; notes = row["Object Heading"].ToString(); } else { notes = row["Object Text"].ToString(); string objectShorttext = GetTextExtract(notes); objectShorttext = objectShorttext.Length > ShortNameLength?objectShorttext.Substring(0, ShortNameLength) : objectShorttext; name = objectShorttext; //name = $"{reqAbsNumber.PadRight(7)} {objectShorttext}"; } // Check if requirement with Doors ID already exists bool isExistingRequirement = DictPackageRequirements.TryGetValue(reqAbsNumber, out int elId); EA.Element el; if (isExistingRequirement) { el = (EA.Element)Rep.GetElementByID(elId); if (el.Alias != objectId || el.Name != name || el.Notes != notes || el.Type != eaObjectType || el.Stereotype != eaStereotype) { if (stateChanged != "") { el.Status = stateChanged; } CountChanged += 1; } } else { el = (EA.Element)Pkg.Elements.AddNew(name, "Requirement"); if (stateNew != "") { el.Status = stateNew; } CountChanged += 1; } el.Alias = objectId; el.Name = name; el.Multiplicity = reqAbsNumber; el.Notes = notes; el.TreePos = Count * 10; el.PackageID = Pkg.PackageID; el.ParentID = parentElementId; el.Type = eaObjectType; el.Stereotype = eaStereotype; el.Update(); Pkg.Elements.Refresh(); lastElementId = el.ElementID; // handle the remaining columns/ tagged values var cols = from c in DtRequirements.Columns.Cast <DataColumn>() where !ColumnNamesNoTaggedValues.Any(n => n == c.ColumnName) select new { Name = c.ColumnName, Value = row[c].ToString() } ; // Update/Create Tagged value foreach (var c in cols) { TaggedValue.SetUpdate(el, c.Name, c.Value); } } MoveDeletedRequirements(); UpdatePackage(); Rep.BatchAppend = false; Rep.EnableUIUpdates = true; Rep.ReloadPackage(Pkg.PackageID); return(result); }
/// <summary> /// Create, update, delete requirements in EA Package from Requirement DataTable. /// </summary> /// <param name="eaObjectType"></param> /// <param name="eaStereotype"></param> /// <param name="stateNew"></param> /// <param name="stateChanged"></param> /// <param name="importFile"></param> private void CreateUpdateDeleteEaRequirements(string eaObjectType, string eaStereotype, string stateNew, string stateChanged, string importFile) { Count = 0; CountChanged = 0; CountNew = 0; List <int> parentElementIdsPerLevel = new List <int> { 0 }; int parentElementId = 0; int lastElementId = 0; int oldLevel = 0; string notesColumn = Settings.AttrNotes ?? ""; foreach (DataRow row in DtRequirements.Rows) { Count += 1; string objectId = row["Id"].ToString(); SpecObject specObject = (SpecObject)row["specObject"]; int objectLevel = Int32.Parse(row["Object Level"].ToString()) - 1; // Maintain parent ids of level // get parent id if (objectLevel > oldLevel) { if (parentElementIdsPerLevel.Count <= objectLevel) { parentElementIdsPerLevel.Add(lastElementId); } else { parentElementIdsPerLevel[objectLevel] = lastElementId; } parentElementId = lastElementId; } if (objectLevel < oldLevel) { parentElementId = parentElementIdsPerLevel[objectLevel]; } oldLevel = objectLevel; CombineAttrValues(Settings.AliasList, row, out string alias, ShortNameLength, makeName: true); CombineAttrValues(Settings.AttrNameList, row, out string name, ShortNameLength, makeName: true); string notes = GetStringAttrValue(notesColumn != "" ? row[notesColumn].ToString() : row[1].ToString()); // Check if requirement with Doors ID already exists bool isExistingRequirement = DictPackageRequirements.TryGetValue(objectId, out int elId); EA.Element el; if (isExistingRequirement) { el = Rep.GetElementByID(elId); if (el.Alias != alias || el.Name != name || el.Notes != notes) { if (stateChanged != "") { el.Status = stateChanged; } CountChanged += 1; } } else { el = (EA.Element)Pkg.Elements.AddNew(name, "Requirement"); if (stateNew != "") { el.Status = stateNew; } CountChanged += 1; } try { el.Alias = alias; el.Name = name; el.Multiplicity = objectId; el.Notes = notes; el.TreePos = Count * 10; el.PackageID = Pkg.PackageID; el.ParentID = parentElementId; el.Type = eaObjectType; el.Stereotype = eaStereotype; el.Update(); Pkg.Elements.Refresh(); lastElementId = el.ElementID; } catch (Exception e) { if (MessageBox.Show($@"Name: '{name}' Alias: '{alias} ObjectId/Multiplicity: '{objectId} {e}", @"Error update EA Element, skip!", MessageBoxButtons.OKCancel) == DialogResult.Cancel) { break; } else { continue; } } // handle the remaining columns/ tagged values var cols = from c in DtRequirements.Columns.Cast <DataColumn>() join v in specObject.SpecType.SpecAttributes on c.ColumnName equals v.LongName // specObject.Values on c.ColumnName equals v.AttributeDefinition.LongName where !ColumnNamesNoTaggedValues.Any(n => n == c.ColumnName) select new { Name = c.ColumnName, Value = row[c].ToString(), AttrDef = v } ; // Handle *.rtf/*.docx content string rtfValue = CombineRtfAttrValues(Settings.RtfNameList, row); // Update EA linked documents by graphics and embedded elements UpdateLinkedDocument(el, rtfValue, importFile); // Update/Create Tagged value DeleteWritableTaggedValuesForElement(el); // over all columns foreach (var c in cols) { // suppress column if already schown in notes if (notesColumn != c.Name) { // Enum with multivalue if (c.AttrDef is AttributeDefinitionEnumeration attrDefinitionEnumeration && attrDefinitionEnumeration.IsMultiValued) { // Enum values available var arrayEnumValues = ((DatatypeDefinitionEnumeration)c.AttrDef.DatatypeDefinition) .SpecifiedValues .Select(x => x.LongName).ToArray(); Regex rx = new Regex(@"\r\n| "); var values = rx.Replace(c.Value, ",").Split(','); var found = from all in arrayEnumValues from s1 in values.Where(xxx => all == xxx).DefaultIfEmpty() select new { All = all, Value = s1 }; var value = ""; var del = ""; foreach (var f in found) { if (f.Value == null) { value = $"{value}{del}0"; } else { value = $"{value}{del}1"; } del = ","; } CreateUpdateTaggedValueDuringInput(el, c.Name, c.Value, c.AttrDef); } else { // handle roundtrip attributes CreateUpdateTaggedValueDuringInput(el, c.Name, c.Value, c.AttrDef); } } } }
/// <summary> /// Move down /// </summary> /// <returns></returns> public bool MoveDown() { EA.Repository rep = _eaDia.Rep; EA.Diagram dia = _eaDia.Dia; var list = from item in _eaDia.SelObjects let el = Rep.GetElementByID(item.ElementID) select new { item.ElementID, el.Name, el, el.Type, item.left, item.right, item.top, item.bottom, item } into temp where temp.el.IsEmbeddedElement(rep) orderby temp.bottom select temp; var llist = list.ToList(); if (llist.Count < 2) { return(false); } // get parent element EA.DiagramObject diaParentObj = llist[0].item.GetParentOfEmbedded(rep, dia); int bottomLimit = diaParentObj.bottom; // left alignment / left bound int leftLimit = diaParentObj.left + (llist.Count - 1) * (Distant2Element + 15); int direction = -1; // start left bound or right bound if (llist[0].left - 30 > diaParentObj.left) { // right alignment / right bound leftLimit = diaParentObj.right - (llist.Count - 1) * (Distant2Element + 15); direction = 1; } // estimate the mode to shift // bool isAccross = (Math.Abs(llist[0].bottom - llist[1].bottom)) < (Math.Abs(llist[0].left - llist[1].left)); if (isAccross) { // jump to bottom left -> to right lined foreach (var el in llist) { el.item.top = bottomLimit + 8; el.item.bottom = bottomLimit - 7; el.item.Update(); } return(true); } else { // shift up, bottom element found, line them on left/right edge if (llist[0].bottom < bottomLimit + OffsetFirstElement) { // position top left, sequence down int left = leftLimit; int pos = 0; foreach (var el in llist) { el.item.bottom = bottomLimit - 7; el.item.top = bottomLimit + 8; el.item.left = left + (pos * Distant2Element) * direction; el.item.right = el.item.left + 15; el.item.Update(); pos = pos + 1; } } else { // shift one step to top foreach (var el in llist) { el.item.top = el.item.top - DistantToMove; el.item.bottom = el.item.bottom - DistantToMove; el.item.Update(); } } return(true); } }
/// <summary> /// Move left /// </summary> /// <returns></returns> public bool MoveRight() { EA.Repository rep = _eaDia.Rep; EA.Diagram dia = _eaDia.Dia; var list = from item in _eaDia.SelObjects let el = Rep.GetElementByID(item.ElementID) select new { item.ElementID, el.Name, el, el.Type, item.left, item.right, item.top, item.bottom, item } into temp where temp.el.IsEmbeddedElement(rep) orderby temp.right descending select temp; var llist = list.ToList(); if (llist.Count < 2) { return(false); } // get parent element EA.DiagramObject diaParentObj = llist[0].item.GetParentOfEmbedded(rep, dia); int rightLimit = diaParentObj.right; // top alignment / top bound int topLimit = diaParentObj.top - (llist.Count - 1) * (Distant2Element + 15); int direction = -1; // start bottom bound or bottom bound if (llist[0].top + 30 < diaParentObj.top) { // right alignment / right bound topLimit = diaParentObj.bottom + (llist.Count - 1) * (Distant2Element + 15); direction = 1; } // estimate the mode to shift // bool isAccross = (Math.Abs(llist[0].top - llist[1].top)) > (Math.Abs(llist[0].left - llist[1].left)); if (isAccross) { foreach (var el in llist) { el.item.left = rightLimit - 7; el.item.right = rightLimit + 8; el.item.Update(); } return(true); } else { if (llist[0].right > rightLimit - OffsetFirstElement) { // position top left, sequence down int top = topLimit; int pos = 0; foreach (var el in llist) { el.item.left = rightLimit - 7; el.item.right = rightLimit + 8; el.item.top = top - (pos * Distant2Element) * direction; el.item.bottom = el.item.top - 15; el.item.Update(); pos = pos + 1; } } else { // shift to right foreach (var el in llist) { el.item.left = el.item.left + DistantToMove; el.item.right = el.item.right + DistantToMove; el.item.Update(); } } return(true); } }
/// <summary> /// Import and update Requirements. You can set EA ObjectType like "Requirement" or EA Stereotype like "FunctionalRequirement" /// </summary> /// async Task public override bool ImportForFile(string eaObjectType = "Requirement", string eaStereotype = "", string stateNew = "", string stateChanged = "") { bool result = true; Rep.BatchAppend = true; Rep.EnableUIUpdates = false; // Read xml file XElement xElFile; try { xElFile = XElement.Parse(HoUtil.ReadAllText(ImportModuleFile)); } catch (Exception e) { Rep.BatchAppend = false; Rep.EnableUIUpdates = true; MessageBox.Show($@"File: {ImportModuleFile}{Environment.NewLine}{Environment.NewLine}{e}", @"Can't import structured *.xml"); return(false); } InitializeXmlStructTable(xElFile); // Go through hierarchy and store in DataTable var level = 1; var children = xElFile.Descendants(xmlChildrenName).FirstOrDefault(); //.Dump(); if (OutputChildren(children, level) == false) { return(false); } ReadEaPackageRequirements(); CreateEaPackageDeletedObjects(); Count = 0; CountChanged = 0; CountNew = 0; List <int> parentElementIdsPerLevel = new List <int> { 0 }; int parentElementId = 0; int lastElementId = 0; int oldLevel = 0; string notesColumn = _settings.AttrNotes ?? ""; foreach (DataRow row in DtRequirements.Rows) { Count += 1; int objectLevel = Int32.Parse(row["Object Level"].ToString()) - 1; // Maintain parent ids of level // get parent id if (objectLevel > oldLevel) { if (parentElementIdsPerLevel.Count <= objectLevel) { parentElementIdsPerLevel.Add(lastElementId); } else { parentElementIdsPerLevel[objectLevel] = lastElementId; } parentElementId = lastElementId; } if (objectLevel < oldLevel) { parentElementId = parentElementIdsPerLevel[objectLevel]; } oldLevel = objectLevel; string objectId = CombineAttrValues(_settings.IdList, row, ShortNameLength); string alias = CombineAttrValues(_settings.AliasList, row, ShortNameLength); string name = CombineAttrValues(_settings.AttrNameList, row, ShortNameLength); string notes = notesColumn != "" ? row[notesColumn].ToString() : row[1].ToString(); string nameShort = name.Length > ShortNameLength?name.Substring(0, ShortNameLength) : name; // Check if requirement with Doors ID already exists bool isExistingRequirement = DictPackageRequirements.TryGetValue(objectId, out int elId); EA.Element el; if (isExistingRequirement) { el = Rep.GetElementByID(elId); if (el.Alias != alias || el.Name != nameShort || el.Notes != notes) { if (stateChanged != "") { el.Status = stateChanged; } CountChanged += 1; } } else { el = (EA.Element)Pkg.Elements.AddNew(name, "Requirement"); if (stateNew != "") { el.Status = stateNew; } CountChanged += 1; } el.Alias = alias; el.Name = name; el.Multiplicity = objectId; el.Notes = notes; el.TreePos = Count * 10; el.PackageID = Pkg.PackageID; el.ParentID = parentElementId; el.Type = eaObjectType; el.Stereotype = eaStereotype; el.Update(); Pkg.Elements.Refresh(); lastElementId = el.ElementID; // handle the remaining columns/ tagged values var cols = from c in DtRequirements.Columns.Cast <DataColumn>() where !ColumnNamesNoTaggedValues.Any(n => n == c.ColumnName) select new { Name = c.ColumnName, Value = row[c].ToString() } ; // Update/Create Tagged value foreach (var c in cols) { if (notesColumn != c.Name) { TaggedValue.SetUpdate(el, c.Name, c.Value ?? ""); } } } MoveDeletedRequirements(); UpdatePackage(xElFile); Rep.BatchAppend = false; Rep.EnableUIUpdates = true; Rep.ReloadPackage(Pkg.PackageID); return(result); }
public bool IsToProcess() { if (Type.Length == 0) { return(true); } bool isToProcessType = true; bool isToProcessStereotype = true; bool isIncompleteLinks = true; bool isCompleteLinks = true; EA.Element el = Rep.GetElementByID(_diaObj.ElementID); foreach (var type in Type) { if (String.IsNullOrWhiteSpace(type)) { continue; } if (!GetNameValueFromString(type, out string name, out string value)) { continue; } switch (name.Substring(0, 4).ToLower()) { case "type": string nameType; string valueTypes; if (!GetNameValueFromString(type, out nameType, out valueTypes)) { continue; } if (valueTypes.Trim() == "") { continue; } // must be a supported Type value isToProcessType = false; foreach (var t in valueTypes.Split(',')) { string elType = t.Trim(); if (elType == "") { continue; } if (elType.Equals(el.Type)) { isToProcessType = true; break; } } break; case @"ster": string nameStereotype; string valueStereotypes; if (!GetNameValueFromString(type, out nameStereotype, out valueStereotypes)) { continue; } if (valueStereotypes.Trim() == "") { continue; } // must be a supported Stereotype value isToProcessStereotype = false; foreach (var objStereo in valueStereotypes.Split(',')) { if (objStereo == "") { continue; } // check if stereotype exists if (Array.IndexOf(el.StereotypeEx.Split(','), objStereo) > -1) { isToProcessStereotype = true; break; } } break; // IncompleLinks 'InCompleteLinks' case @"inco": isIncompleteLinks = IsCompleteDiagram() ^ true; break; // compleLinks 'CompleteLinks' case @"compl": isCompleteLinks = IsCompleteDiagram(); break; } } return(isToProcessType && isToProcessStereotype && isIncompleteLinks && isCompleteLinks); }