/// <summary> /// Resets the available range labels /// </summary> private void UpdateAvailableRanges() { List <Range> availableFrom = null; List <Range> availableTo = null; // Get the ranges and connections based on whether we are port-strand or strand-port #region Determine Direction if (cboFrom.SelectedItem is FiberCableWrapper && cboTo.SelectedItem is ConnectableDeviceWrapper) { FiberCableWrapper cable = (FiberCableWrapper)cboFrom.SelectedItem; ConnectableDeviceWrapper device = (ConnectableDeviceWrapper)cboTo.SelectedItem; availableFrom = SpliceAndConnectionUtils.GetAvailableRanges(cable, device.IsCableFromEnd); availableTo = SpliceAndConnectionUtils.GetAvailableRanges(device, PortType.Input); } else if (cboFrom.SelectedItem is DeviceWrapper && cboTo.SelectedItem is ConnectableCableWrapper) { DeviceWrapper device = (DeviceWrapper)cboFrom.SelectedItem; ConnectableCableWrapper cable = (ConnectableCableWrapper)cboTo.SelectedItem; availableFrom = SpliceAndConnectionUtils.GetAvailableRanges(device, PortType.Output); availableTo = SpliceAndConnectionUtils.GetAvailableRanges(cable, cable.IsThisFromEnd); } #endregion lblAvailableFrom.Text = GetAvailableRangesString(availableFrom); lblAvailableTo.Text = GetAvailableRangesString(availableTo); }
/// <summary> /// Load the B dropdown with spliceable cables /// </summary> /// <param name="helper">SpliceEditorHelper</param> /// <param name="cableA">A Cable</param> private void PopulateBCables(FiberSpliceHelper helper, FiberCableWrapper cableA) { try { // Clear anything that is dependent on what we are about to load ClearGrid(); cboCableB.Items.Clear(); lblAvailableA.Text = ""; lblAvailableB.Text = ""; SpliceClosureWrapper splice = cboSpliceClosure.SelectedItem as SpliceClosureWrapper; if (null != splice) { List <SpliceableCableWrapper> spliceableCables = _spliceHelper.GetSpliceableCables(cableA, splice); for (int i = 0; i < spliceableCables.Count; i++) { cboCableB.Items.Add(spliceableCables[i]); } if (0 < cboCableB.Items.Count) { cboCableB.SelectedItem = cboCableB.Items[0]; } } } catch (Exception e) { _logHelper.addLogEntry(DateTime.Now.ToString(), "ERROR", "Splice Connection Window (PopulateBCables): ", e.Message); } }
/// <summary> /// Prompts the user about saving pending edits /// </summary> /// <param name="spliceWrapper"></param> /// <param name="cableAWrapper"></param> /// <param name="cableBWrapper"></param> /// <returns>False if the user chooses to cancel what they were doing; True if they choose Yes or No /// (which means they are OK with what they are doing)</returns> private bool IsUserSure(SpliceClosureWrapper spliceWrapper, FiberCableWrapper cableAWrapper, SpliceableCableWrapper cableBWrapper) { bool result = true; // Assume they do not want to save and do want to continue DialogResult dialogResult = DialogResult.No; dialogResult = MessageBox.Show("You have unsaved edits. Would you like to save them before closing?", "Connection Editor", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); if (DialogResult.Cancel == dialogResult) { // The user isn't sure about what they are doing and wants to cancel it result = false; } else if (DialogResult.Yes == dialogResult) { bool isSaveOk = SaveChanges(spliceWrapper, cableAWrapper, cableBWrapper); if (!isSaveOk) { // They wanted to save but it didn't work. They probably got a message telling them what to fix. Cancel // whatever they were doing so that they have a chance to do so result = false; } } return(result); }
/// <summary> /// Load the A dropdown with selected cables /// </summary> /// <param name="helper">SpliceEditorHelper</param> private void PopulateACables(FiberSpliceHelper helper, SpliceClosureWrapper spliceWrapper) { try { // Clear anything that is dependent on what we are about to load ClearGrid(); cboCableA.Items.Clear(); cboCableB.Items.Clear(); lblAvailableA.Text = ""; lblAvailableB.Text = ""; List <ESRI.ArcGIS.Geodatabase.IFeature> selectedCables = helper.GetConnectedCables(spliceWrapper); ESRI.ArcGIS.Carto.IFeatureLayer ftLayer = _hookHelper.FindFeatureLayer(ConfigUtil.FiberCableFtClassName); int displayIdx = ftLayer.FeatureClass.FindField(ftLayer.DisplayField); for (int i = 0; i < selectedCables.Count; i++) { FiberCableWrapper w = new FiberCableWrapper(selectedCables[i], displayIdx); cboCableA.Items.Add(w); } if (0 < cboCableA.Items.Count) { cboCableA.SelectedItem = cboCableA.Items[0]; } } catch (Exception e) { _logHelper.addLogEntry(DateTime.Now.ToString(), "ERROR", "Splice Connection Window (PopulateACables): ", e.Message); } }
/// <summary> /// Generates a splice closure at the coincident endpoint. Does not start an edit operation. /// </summary> /// <param name="cableA">Cable A</param> /// <param name="cableB">Cable B</param> /// <returns>SpliceClosureWRapper based on new feature</returns> private SpliceClosureWrapper GenerateSpliceClosure(FiberCableWrapper cableA, SpliceableCableWrapper cableB) { SpliceClosureWrapper wrapper = null; #region Validation if (null == cableA) { throw new ArgumentNullException("cableA"); } if (null == cableB) { throw new ArgumentNullException("cableB"); } if (ESRI.ArcGIS.Editor.esriEditState.esriStateNotEditing == _editor.EditState) { throw new InvalidOperationException("You must be editing to perform this operation"); } #endregion // Populate an IPID; we will need it Guid g = Guid.NewGuid(); string spliceIpid = g.ToString("B").ToUpper(); try { ESRI.ArcGIS.Geometry.IPolyline line = cableB.Feature.Shape as ESRI.ArcGIS.Geometry.IPolyline; if (null != line) { ESRI.ArcGIS.Geometry.IPoint splicePoint = null; if (cableB.IsThisFromEnd) { splicePoint = line.FromPoint; } else { splicePoint = line.ToPoint; } ESRI.ArcGIS.Geodatabase.IFeatureClass spliceClosureFtClass = _wkspHelper.FindFeatureClass(ConfigUtil.SpliceClosureFtClassName); // ESRI.ArcGIS.Geodatabase.IFeatureClass spliceClosureFtClass = GdbUtils.GetFeatureClass(cableA.Feature.Class, ConfigUtil.SpliceClosureFtClassName); ESRI.ArcGIS.Geodatabase.IFeature spliceFt = spliceClosureFtClass.CreateFeature(); spliceFt.Shape = splicePoint; spliceFt.set_Value(spliceClosureFtClass.Fields.FindField(ConfigUtil.IpidFieldName), spliceIpid); spliceFt.Store(); wrapper = new SpliceClosureWrapper(spliceFt); } } catch { wrapper = null; } return(wrapper); }
/// <summary> /// Deletes all splices for a cable to any other at any splice closure /// </summary> /// <param name="cable">Cable</param> /// <param name="isExistingOperation">Are we already in an edit operation?</param> /// <returns>Success</returns> public bool BreakAllSplices(FiberCableWrapper cable, bool isExistingOperation) { bool success = false; bool isOperationOpen = false; #region Validation if (null == cable) { throw new ArgumentNullException("cable"); } if (ESRI.ArcGIS.Editor.esriEditState.esriStateNotEditing == _editor.EditState) { throw new InvalidOperationException("You must be editing to perform this operation"); } #endregion if (!isExistingOperation) { _editor.StartOperation(); isOperationOpen = true; } try { ESRI.ArcGIS.Geodatabase.ITable spliceTable = _wkspHelper.FindTable(ConfigUtil.FiberSpliceTableName); // ESRI.ArcGIS.Geodatabase.ITable spliceTable = GdbUtils.GetTable(cable.Feature.Class, ConfigUtil.FiberSpliceTableName); ESRI.ArcGIS.Geodatabase.IQueryFilter filter = new ESRI.ArcGIS.Geodatabase.QueryFilterClass(); // A and B is arbitrary, so we check the given combinations going both ways. The structure is: // Where either the A or B cableID is our cable ID filter.WhereClause = string.Format("{0}='{1}' OR {2}='{1}'", ConfigUtil.ACableIdFieldName, cable.IPID, ConfigUtil.BCableIdFieldName); spliceTable.DeleteSearchedRows(filter); ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(filter); if (isOperationOpen) { _editor.StopOperation("Break Splices"); isOperationOpen = false; } success = true; } catch { if (isOperationOpen) { _editor.AbortOperation(); } success = false; } return(success); }
/// <summary> /// Gets a list of all strand numbers from a cable that are spliced on the given end /// </summary> /// <param name="cable">Cable to check</param> /// <param name="isFromEnd">True to check from end, False to check to end</param> /// <returns>List of int</returns> private static List <int> GetSplicedStrands(FiberCableWrapper cable, bool isFromEnd) { if (null == cable) { throw new ArgumentNullException("cable"); } List <int> result = new List <int>(); using (ESRI.ArcGIS.ADF.ComReleaser releaser = new ESRI.ArcGIS.ADF.ComReleaser()) { ESRI.ArcGIS.Geodatabase.ITable fiberSpliceTable = TelecomWorkspaceHelper.Instance().FindTable(ConfigUtil.FiberSpliceTableName); // ESRI.ArcGIS.Geodatabase.ITable fiberSpliceTable = GdbUtils.GetTable(cable.Feature.Class, ConfigUtil.FiberSpliceTableName); ESRI.ArcGIS.Geodatabase.IQueryFilter filter = new ESRI.ArcGIS.Geodatabase.QueryFilterClass(); releaser.ManageLifetime(filter); filter.WhereClause = string.Format("{0}='{1}' AND {2}='{3}'", ConfigUtil.ACableIdFieldName, cable.IPID, ConfigUtil.IsAFromEndFieldName, (isFromEnd ? "T" : "F")); ESRI.ArcGIS.Geodatabase.ICursor spliceCursor = fiberSpliceTable.Search(filter, true); ESRI.ArcGIS.Geodatabase.IRow spliceRow = spliceCursor.NextRow(); int fiberIdIdx = fiberSpliceTable.FindField(ConfigUtil.AFiberNumberFieldName); while (null != spliceRow) { result.Add((int)spliceRow.get_Value(fiberIdIdx)); ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(spliceRow); spliceRow = spliceCursor.NextRow(); } ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(spliceCursor); filter.WhereClause = string.Format("{0}='{1}' AND {2}='{3}'", ConfigUtil.BCableIdFieldName, cable.IPID, ConfigUtil.IsBFromEndFieldName, (isFromEnd ? "T" : "F")); spliceCursor = fiberSpliceTable.Search(filter, true); spliceRow = spliceCursor.NextRow(); fiberIdIdx = fiberSpliceTable.FindField(ConfigUtil.BFiberNumberFieldName); while (null != spliceRow) { result.Add((int)spliceRow.get_Value(fiberIdIdx)); ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(spliceRow); spliceRow = spliceCursor.NextRow(); } ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(spliceCursor); } return(result); }
/// <summary> /// Cable features can have related: /// splices, /// connections, /// strands /// buffer tubes, /// maintenance loop /// </summary> /// <param name="cableFeature">Deleted IFeature</param> private void CascadeFiberCableDelete(ESRI.ArcGIS.Geodatabase.IFeature cableFeature) { FiberCableWrapper cable = new FiberCableWrapper(cableFeature); // Delete splices (to other cables) _spliceHelper.BreakAllSplices(cable, true); // Delete connections (to equipment) _connectionHelper.BreakAllConnections(cable, true); }
/// <summary> /// The form is closing; check for unsaved edits to the grid /// </summary> private void SpliceEditorForm_FormClosing(object sender, FormClosingEventArgs e) { if (btnSave.Enabled) { SpliceClosureWrapper spliceWrapper = cboSpliceClosure.SelectedItem as SpliceClosureWrapper; FiberCableWrapper cableA = cboCableA.SelectedItem as FiberCableWrapper; SpliceableCableWrapper cableB = cboCableB.SelectedItem as SpliceableCableWrapper; e.Cancel = !IsUserSure(spliceWrapper, cableA, cableB); } }
/// <summary> /// Loads the grid with existing splice ranges between the given features /// </summary> /// <param name="spliceWrapper">Selected Splice Closure</param> /// <param name="cableA">Selected Cable A</param> /// <param name="cableB">Selected Cable B</param> private void LoadExistingRecords(SpliceClosureWrapper spliceWrapper, FiberCableWrapper cableA, SpliceableCableWrapper cableB) { ClearGrid(); if (null != spliceWrapper && null != cableA && null != cableB) { List <FiberSplice> rangesAtoB = SpliceAndConnectionUtils.GetSplicedRanges(cableA, cableB, spliceWrapper); for (int i = 0; i < rangesAtoB.Count; i++) { FiberSplice fiberSplice = rangesAtoB[i]; int rowIdx = grdSplices.Rows.Add(fiberSplice.ARange, fiberSplice.BRange, fiberSplice.Loss, fiberSplice.Type); grdSplices.Rows[rowIdx].ReadOnly = true; // Allow this to be deleted, but not edited. Range a = fiberSplice.ARange; Range b = fiberSplice.BRange; int numUnits = a.High - a.Low + 1; for (int offset = 0; offset < numUnits; offset++) { int aUnit = a.Low + offset; int bUnit = b.Low + offset; FiberSplice originalSplice = new FiberSplice(new Range(aUnit, aUnit), new Range(bUnit, bUnit), fiberSplice.Loss, fiberSplice.Type); _original[aUnit] = originalSplice; } } // These are valid for display because it is these two cables at this splice, the A and B side assignment is // arbitrary. We do need to reverse them in the display though. For example is Cable X (1-12) is spliced to // Cable Y (36-47), and they have selected X/Y in the form -- the grid should show X's units on the left and // Y's on the right. Here we are requesting them as Y/X though. List <FiberSplice> rangesBtoA = SpliceAndConnectionUtils.GetSplicedRanges((FiberCableWrapper)cboCableB.SelectedItem, (FiberCableWrapper)cboCableA.SelectedItem, spliceWrapper); for (int i = 0; i < rangesBtoA.Count; i++) { FiberSplice fiberSplice = rangesBtoA[i]; int rowIdx = grdSplices.Rows.Add(fiberSplice.BRange, fiberSplice.ARange, fiberSplice.Loss, fiberSplice.Type); grdSplices.Rows[rowIdx].ReadOnly = true; // Allow this to be deleted, but not edited. Range a = fiberSplice.ARange; Range b = fiberSplice.BRange; int numUnits = a.High - a.Low + 1; for (int offset = 0; offset < numUnits; offset++) { int aUnit = a.Low + offset; int bUnit = b.Low + offset; FiberSplice originalSplice = new FiberSplice(new Range(bUnit, bUnit), new Range(aUnit, aUnit), fiberSplice.Loss, fiberSplice.Type); _original[bUnit] = originalSplice; } } } btnSave.Enabled = false; btnSave.Tag = false; // No edits made yet }
/// <summary> /// Update the dropdowns of features on the UI /// </summary> /// <param name="helper">Helper class</param> private void PopulateDropDowns(FiberDeviceConnectionHelper helper) { // Clear the existing choices cboFrom.Items.Clear(); cboTo.Items.Clear(); lblAvailableFrom.Text = ""; lblAvailableTo.Text = ""; // Get the features and the display index for use when creating the wrapper ESRI.ArcGIS.Carto.IFeatureLayer ftLayer = _hookHelper.FindFeatureLayer(ConfigUtil.FiberCableFtClassName); int displayIdx = ftLayer.FeatureClass.FindField(ftLayer.DisplayField); // Get the selected features List <ESRI.ArcGIS.Geodatabase.IFeature> selectedFts = _hookHelper.GetSelectedFeatures(ftLayer); // Add each of the fiber features to the drop down for (int ftIdx = 0; ftIdx < selectedFts.Count; ftIdx++) { FiberCableWrapper w = new FiberCableWrapper(selectedFts[ftIdx], displayIdx); cboFrom.Items.Add(w); } // Now do that same thing for each of the device feature classes string[] deviceClassNames = ConfigUtil.DeviceFeatureClassNames; for (int deviceClassIdx = 0; deviceClassIdx < deviceClassNames.Length; deviceClassIdx++) { string ftClassName = deviceClassNames[deviceClassIdx]; // Get the features and the display index for use when creating the wrapper ftLayer = _hookHelper.FindFeatureLayer(ftClassName); if (ftLayer != null) // what if layer removed from map { selectedFts = _hookHelper.GetSelectedFeatures(ftLayer); displayIdx = ftLayer.FeatureClass.FindField(ftLayer.DisplayField); for (int ftIdx = 0; ftIdx < selectedFts.Count; ftIdx++) { DeviceWrapper w = new DeviceWrapper(selectedFts[ftIdx], displayIdx); cboFrom.Items.Add(w); } } } // Preselect the first choice if (0 < cboFrom.Items.Count) { cboFrom.SelectedItem = cboFrom.Items[0]; } }
/// <summary> /// The user changed a different cable for the B cable /// </summary> private void cboCableB_SelectedIndexChanged(object sender, EventArgs e) { if (!_isReverting) { bool isChangeAccepted = !btnSave.Enabled; // If the save button is disabled, there aren't edits to prompt about // Get the current A cable and splice FiberCableWrapper cableA = cboCableA.SelectedItem as FiberCableWrapper; SpliceClosureWrapper splice = cboSpliceClosure.SelectedItem as SpliceClosureWrapper; if (!isChangeAccepted) { // Get the B Cable that was selected before the index changed, so we can prompt for unsaved edits SpliceableCableWrapper preChangeB = null; if (-1 < _lastSelectedBIdx && _lastSelectedBIdx < cboCableB.Items.Count) { preChangeB = cboCableB.Items[_lastSelectedBIdx] as SpliceableCableWrapper; } isChangeAccepted = IsUserSure(splice, cableA, preChangeB); } if (isChangeAccepted) { _lastSelectedBIdx = cboCableB.SelectedIndex; SpliceableCableWrapper cableB = cboCableB.SelectedItem as SpliceableCableWrapper; if (null != cableA && null != cableB && null != splice) { lblAvailableA.Text = GetAvailableRangeString(cableA, cableB.IsOtherFromEnd); lblAvailableB.Text = GetAvailableRangeString(cableB, cableB.IsThisFromEnd); LoadExistingRecords(splice, cableA, cableB); } } else { // Cancel the change by re-selecting the previous from feature _isReverting = true; cboCableB.SelectedIndex = _lastSelectedBIdx; _isReverting = false; } } }
/// <summary> /// Creates a label string for the available ranges of a cable at a certain end /// </summary> /// <param name="cable">Cable to check</param> /// <param name="isFromEnd">End to check</param> /// <returns>string</returns> private string GetAvailableRangeString(FiberCableWrapper cable, bool isFromEnd) { List <Range> availableRanges = SpliceAndConnectionUtils.GetAvailableRanges(cable, isFromEnd); string result = "No available ranges!"; if (0 < availableRanges.Count) { StringBuilder availableLabel = new StringBuilder(64); for (int i = 0; i < availableRanges.Count; i++) { availableLabel.AppendFormat("{0},", availableRanges[i].ToString()); } availableLabel.Remove(availableLabel.Length - 1, 1); result = string.Format("Available: {0}", availableLabel.ToString()); } return(result); }
/// <summary> /// Finds ranges of fibers that are not yet spliced or connected /// </summary> /// <param name="cable">Cable to check</param> /// <param name="isFromEnd">Flag of which side of the cable to check</param> /// <returns>List of Range</returns> public static List <Range> GetAvailableRanges(FiberCableWrapper cable, bool isFromEnd) { List <Range> result = new List <Range>(); if (null == cable) { throw new ArgumentNullException("cable"); } List <int> usedStrands = new List <int>(); usedStrands.AddRange(GetSplicedStrands(cable, isFromEnd)); // Gets the ones that are spliced to another cable usedStrands.AddRange(GetConnectedStrands(cable, isFromEnd)); // Gets the ones that are connected to a device usedStrands.Sort(); List <Range> splicedRanges = MergeRanges(usedStrands); // int? fiberCount = GdbUtils.GetDomainedIntName(cable.Feature, ConfigUtil.NumberOfFibersFieldName); int?fiberCount = cable.fibers; if (null != fiberCount) { int lowFiber = 1; for (int i = 0; i < splicedRanges.Count; i++) { Range range = splicedRanges[i]; if (lowFiber != range.Low) { // We are good until this range starts result.Add(new Range(lowFiber, range.Low - 1)); } lowFiber = range.High + 1; } if (lowFiber <= fiberCount) { result.Add(new Range(lowFiber, (int)fiberCount)); } } return(result); }
/// <summary> /// Determines if all given ranges are available (neither spliced nor connected) /// </summary> /// <param name="units">Units to check</param> /// <param name="cableWrapper">Cable to check</param> /// <param name="isFromEnd">Flag of which end we are checking</param> /// <returns>True if they are all available</returns> public static bool AreRangesAvailable(ICollection <int> units, FiberCableWrapper cableWrapper, bool isFromEnd) { bool result = true; List <int> splicedStrands = GetSplicedStrands(cableWrapper, isFromEnd); List <int> connectedStrands = GetConnectedStrands(cableWrapper, isFromEnd); foreach (int unit in units) { if (splicedStrands.Contains(unit) || connectedStrands.Contains(unit)) { result = false; break; } } return(result); }
/// <summary> /// Returns devices at the endpoints of the given cable /// </summary> /// <param name="deviceWrapper">Cable to check</param> /// <returns>List of ConnectableDeviceWrapper</returns> public List <ConnectableDeviceWrapper> GetCoincidentDevices(FiberCableWrapper fiberCableWrapper) { List <ConnectableDeviceWrapper> result = new List <ConnectableDeviceWrapper>(); if (null == fiberCableWrapper) { throw new ArgumentNullException("fiberCableWrapper"); } ESRI.ArcGIS.Geometry.IPolyline cableGeometry = (ESRI.ArcGIS.Geometry.IPolyline)fiberCableWrapper.Feature.Shape; string[] deviceFtClassNames = ConfigUtil.DeviceFeatureClassNames; double buffer = _hookHelper.ConvertPixelsToMapUnits(1); for (int i = 0; i < deviceFtClassNames.Length; i++) { string ftClassName = deviceFtClassNames[i]; ESRI.ArcGIS.Carto.IFeatureLayer ftLayer = _hookHelper.FindFeatureLayer(ftClassName); if (ftLayer == null) { // Layer might not be in the map so just skip if not found. continue; } ESRI.ArcGIS.Geodatabase.IFeatureClass ftClass = ftLayer.FeatureClass; int displayIdx = ftClass.FindField(ftLayer.DisplayField); List <ESRI.ArcGIS.Geodatabase.IFeature> fromFts = GdbUtils.GetFeaturesWithCoincidentVertices(cableGeometry.FromPoint, ftClass, false, buffer); for (int fromIdx = 0; fromIdx < fromFts.Count; fromIdx++) { result.Add(new ConnectableDeviceWrapper(fromFts[fromIdx], true, displayIdx)); } List <ESRI.ArcGIS.Geodatabase.IFeature> toFts = GdbUtils.GetFeaturesWithCoincidentVertices(cableGeometry.ToPoint, ftClass, false, buffer); for (int toIdx = 0; toIdx < toFts.Count; toIdx++) { result.Add(new ConnectableDeviceWrapper(toFts[toIdx], false, displayIdx)); } } return(result); }
/// <summary> /// The user changed a different cable for the A cable /// </summary> private void cboCableA_SelectedIndexChanged(object sender, EventArgs e) { if (!_isReverting) { bool isChangeAccepted = !btnSave.Enabled; // If the save button is disabled, there aren't edits to prompt about if (!isChangeAccepted) { // Get the current B cable and splice, and the A Cable that was selected before the index changed, // so we can prompt for unsaved edits SpliceClosureWrapper splice = cboSpliceClosure.SelectedItem as SpliceClosureWrapper; SpliceableCableWrapper cableB = cboCableB.SelectedItem as SpliceableCableWrapper; FiberCableWrapper preChangeA = null; if (-1 < _lastSelectedAIdx && _lastSelectedAIdx < cboCableA.Items.Count) { preChangeA = cboCableA.Items[_lastSelectedAIdx] as FiberCableWrapper; } isChangeAccepted = IsUserSure(splice, preChangeA, cableB); } if (isChangeAccepted) { _lastSelectedAIdx = cboCableA.SelectedIndex; FiberCableWrapper cableA = cboCableA.SelectedItem as FiberCableWrapper; if (null != cableA) { PopulateBCables(_spliceHelper, cableA); } } else { // Cancel the change by re-selecting the previous from feature _isReverting = true; cboCableA.SelectedIndex = _lastSelectedAIdx; _isReverting = false; } } }
/// <summary> /// The user has clicked the save button /// </summary> private void btnSave_Click(object sender, EventArgs e) { try { SpliceClosureWrapper spliceWrapper = cboSpliceClosure.SelectedItem as SpliceClosureWrapper; FiberCableWrapper cableA = cboCableA.SelectedItem as FiberCableWrapper; SpliceableCableWrapper cableB = cboCableB.SelectedItem as SpliceableCableWrapper; SaveChanges(spliceWrapper, cableA, cableB); lblAvailableA.Text = GetAvailableRangeString(cableA, cableB.IsOtherFromEnd); lblAvailableB.Text = GetAvailableRangeString(cableB, cableB.IsThisFromEnd); } catch (Exception ex) { _logHelper.addLogEntry(DateTime.Now.ToString(), "ERROR", "Error saving connections.", ex.ToString()); MessageBox.Show("Error saving connections: \n" + ex.ToString()); } }
/// <summary> /// Gets the connections for the current combo drop down status /// </summary> private List <Connection> getConnections() { List <Connection> connections = null; if (cboFrom.SelectedItem is FiberCableWrapper && cboTo.SelectedItem is ConnectableDeviceWrapper) { FiberCableWrapper cable = (FiberCableWrapper)cboFrom.SelectedItem; ConnectableDeviceWrapper device = (ConnectableDeviceWrapper)cboTo.SelectedItem; connections = _connectionHelper.GetConnections(cable, device, device.IsCableFromEnd, PortType.Input); } else if (cboFrom.SelectedItem is DeviceWrapper && cboTo.SelectedItem is ConnectableCableWrapper) { DeviceWrapper device = (DeviceWrapper)cboFrom.SelectedItem; ConnectableCableWrapper cable = (ConnectableCableWrapper)cboTo.SelectedItem; connections = _connectionHelper.GetConnections(cable, device, cable.IsThisFromEnd, PortType.Output); } return(connections); }
/// <summary> /// Determines if a cable has any connections or splices on its strands /// </summary> /// <param name="cableWrapper">Cable to check</param> /// <returns>True if any strand is connected or spliced</returns> public static bool HasAnyConnections(FiberCableWrapper cableWrapper) { int?fiberCount = cableWrapper.fibers; List <Range> ranges = null; bool isFromClear = true; bool isToClear = true; if (null != fiberCount && 0 < fiberCount) { ranges = GetAvailableRanges(cableWrapper, true); isFromClear = AreRangesWholeUnitCount(ranges, (int)fiberCount); ranges = GetAvailableRanges(cableWrapper, false); isToClear = AreRangesWholeUnitCount(ranges, (int)fiberCount); } // If either end is not clear, there are connections return(!isFromClear || !isToClear); }
/// <summary> /// Determines if all the ranges fall between 1 to fibercount /// </summary> /// <param name="ranges">Ranges to check</param> /// <param name="cable">Cable to check on</param> /// <returns>True if valid ranges</returns> public static bool AreRangesWithinFiberCount(List <Range> ranges, FiberCableWrapper cable) { bool result = true; #region Validation if (null == cable) { throw new ArgumentNullException("cable"); } if (null == ranges) { throw new ArgumentNullException("ranges"); } #endregion // int? fiberCount = GdbUtils.GetDomainedIntName(cable.Feature, ConfigUtil.NumberOfFibersFieldName); int?fiberCount = cable.fibers; if (null == fiberCount) { result = false; } else { foreach (Range r in ranges) { if (r.High > fiberCount || 1 > r.Low) { result = false; break; } } } return(result); }
/// <summary> /// Break all connections for a given cable /// </summary> /// <param name="cable">Cable to break connections</param> /// <param name="isExistingOperation">Should we start/stop the edit operation, or are we already in one?</param> /// <returns>Success</returns> public bool BreakAllConnections(FiberCableWrapper cable, bool isExistingOperation) { bool success = false; bool isOperationOpen = false; #region Validation if (null == cable) { throw new ArgumentNullException("cable"); } if (ESRI.ArcGIS.Editor.esriEditState.esriStateNotEditing == _editor.EditState) { throw new InvalidOperationException("You must be editing to perform this operation"); } #endregion if (!isExistingOperation) { _editor.StartOperation(); isOperationOpen = true; } try { using (ESRI.ArcGIS.ADF.ComReleaser releaser = new ESRI.ArcGIS.ADF.ComReleaser()) { ESRI.ArcGIS.Geodatabase.IFeatureClass cableFtClass = cable.Feature.Class as ESRI.ArcGIS.Geodatabase.IFeatureClass; ESRI.ArcGIS.Geodatabase.IQueryFilter filter = new ESRI.ArcGIS.Geodatabase.QueryFilterClass(); releaser.ManageLifetime(filter); filter.WhereClause = string.Format("{0}='{1}'", ConfigUtil.ConnectedCableFieldName, cable.IPID); filter.SubFields = string.Format("{0},{1},{2}", ConfigUtil.ConnectedCableFieldName, ConfigUtil.ConnectedFiberFieldName, ConfigUtil.ConnectedEndFieldName); string[] deviceClassNames = ConfigUtil.DeviceFeatureClassNames; for (int i = 0; i < deviceClassNames.Length; i++) { string deviceClassName = deviceClassNames[i]; ESRI.ArcGIS.Geodatabase.IFeatureClass deviceFtClass = _wkspHelper.FindFeatureClass(deviceClassName); // ESRI.ArcGIS.Geodatabase.IFeatureClass deviceFtClass = GdbUtils.GetFeatureClass(cableFtClass, deviceClassName); ESRI.ArcGIS.Geodatabase.ITable portTable = ConfigUtil.GetPortTable(deviceFtClass); ESRI.ArcGIS.Geodatabase.IRowBuffer buffer = portTable.CreateRowBuffer(); // We want to set them to null, so we can just send the empty buffer portTable.UpdateSearchedRows(filter, buffer); ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(buffer); } if (isOperationOpen) { _editor.StopOperation("Break Connections"); isOperationOpen = false; } success = true; } } catch { if (isOperationOpen) { _editor.AbortOperation(); } success = false; } return(success); }
/// <summary> /// Deletes given connections between cable to device /// </summary> /// <param name="cable">Cable</param> /// <param name="device">Device</param> /// <param name="units">Units to connect</param> /// <param name="portType">Input or Output?</param> /// <param name="isExistingOperation">Flag to control whether we need to wrap this in an edit operation</param> /// <returns>Success</returns> public bool BreakConnections(FiberCableWrapper cable, DeviceWrapper device, Dictionary <int, int> units, PortType portType, bool isExistingOperation) { bool success = false; bool isOperationOpen = false; #region Validation if (null == cable) { throw new ArgumentNullException("cable"); } if (null == device) { throw new ArgumentNullException("device"); } if (null == units) { throw new ArgumentNullException("units"); } if (ESRI.ArcGIS.Editor.esriEditState.esriStateNotEditing == _editor.EditState) { throw new InvalidOperationException("You must be editing to perform this operation"); } #endregion if (0 < units.Count) { if (!isExistingOperation) { _editor.StartOperation(); isOperationOpen = true; } try { ESRI.ArcGIS.Geodatabase.IFeatureClass deviceFtClass = device.Feature.Class as ESRI.ArcGIS.Geodatabase.IFeatureClass; ESRI.ArcGIS.Geodatabase.IRelationshipClass deviceHasPorts = ConfigUtil.GetPortRelationship(deviceFtClass); if (null == deviceFtClass) { throw new Exception("Unable to find port relationship class."); } ESRI.ArcGIS.Geodatabase.ITable portTable = deviceHasPorts.DestinationClass as ESRI.ArcGIS.Geodatabase.ITable; if (null == portTable) { throw new Exception("Invalid destination on port relationship class."); } using (ESRI.ArcGIS.ADF.ComReleaser releaser = new ESRI.ArcGIS.ADF.ComReleaser()) { ESRI.ArcGIS.Geodatabase.IQueryFilter filter = new ESRI.ArcGIS.Geodatabase.QueryFilterClass(); releaser.ManageLifetime(filter); StringBuilder inList = new StringBuilder(1024); foreach (KeyValuePair <int, int> pair in units) { string appendFormat = "{0},"; if (PortType.Input == portType) { inList.AppendFormat(appendFormat, pair.Key); } else { inList.AppendFormat(appendFormat, pair.Value); } } inList.Remove(inList.Length - 1, 1); string format = "{0}='{1}' AND {2}='{3}' AND {4}='{5}' AND {6} IN ({7})"; filter.WhereClause = string.Format(format, deviceHasPorts.OriginForeignKey, device.Feature.get_Value(deviceFtClass.FindField(deviceHasPorts.OriginPrimaryKey)), ConfigUtil.ConnectedCableFieldName, cable.IPID, ConfigUtil.PortTypeFieldName, (PortType.Input == portType ? "1" : "2"), ConfigUtil.ConnectedFiberFieldName, inList.ToString()); filter.SubFields = string.Format("{0},{1},{2}", ConfigUtil.ConnectedEndFieldName, ConfigUtil.ConnectedFiberFieldName, ConfigUtil.ConnectedCableFieldName); ESRI.ArcGIS.Geodatabase.IRowBuffer buffer = portTable.CreateRowBuffer(); releaser.ManageLifetime(buffer); // We want to set them to null, so we can just send the empty buffer portTable.UpdateSearchedRows(filter, buffer); if (isOperationOpen) { _editor.StopOperation("Break Connections"); isOperationOpen = false; } success = true; } } catch { if (isOperationOpen) { _editor.AbortOperation(); } success = false; } } return(success); }
/// <summary> /// Creates given connections between cable and device /// </summary> /// <param name="cable">Cable</param> /// <param name="device">Device</param> /// <param name="units">Units to connect</param> /// <param name="isFromEnd">Is it the cable's from end?</param> /// <param name="portType">Input or Output?</param> /// <param name="isExistingOperation">Flag to control whether we need to wrap this in a new edit operation</param> /// <returns>Success</returns> public bool MakeConnections(FiberCableWrapper cable, DeviceWrapper device, Dictionary <int, int> units, bool isFromEnd, PortType portType, bool isExistingOperation) { bool success = false; bool isOperationOpen = false; #region Validation if (null == cable) { throw new ArgumentNullException("cable"); } if (null == device) { throw new ArgumentNullException("device"); } if (null == units) { throw new ArgumentNullException("units"); } if (ESRI.ArcGIS.Editor.esriEditState.esriStateNotEditing == _editor.EditState) { throw new InvalidOperationException("You must be editing to perform this operation"); } #endregion if (!isExistingOperation) { _editor.StartOperation(); isOperationOpen = true; } try { ESRI.ArcGIS.Geodatabase.IFeatureClass deviceFtClass = device.Feature.Class as ESRI.ArcGIS.Geodatabase.IFeatureClass; ESRI.ArcGIS.Geodatabase.IRelationshipClass deviceHasPorts = ConfigUtil.GetPortRelationship(deviceFtClass); if (null == deviceHasPorts) { throw new Exception("Unable to get port relationship class."); } ESRI.ArcGIS.Geodatabase.ITable portTable = deviceHasPorts.DestinationClass as ESRI.ArcGIS.Geodatabase.ITable; if (null == portTable) { throw new Exception("Invalid destination on port relationship class."); } int portIdIdx = portTable.FindField(ConfigUtil.PortIdFieldName); int fiberNumberIdx = portTable.FindField(ConfigUtil.ConnectedFiberFieldName); int cableIdIdx = portTable.FindField(ConfigUtil.ConnectedCableFieldName); int isFromEndIdx = portTable.FindField(ConfigUtil.ConnectedEndFieldName); string isFromEndValue = isFromEnd ? "T" : "F"; Dictionary <int, int> portsAsKeys = units; if (PortType.Input == portType) { portsAsKeys = new Dictionary <int, int>(); foreach (KeyValuePair <int, int> pair in units) { portsAsKeys[pair.Value] = pair.Key; } } using (ESRI.ArcGIS.ADF.ComReleaser releaser = new ESRI.ArcGIS.ADF.ComReleaser()) { ESRI.ArcGIS.Geodatabase.IQueryFilter filter = new ESRI.ArcGIS.Geodatabase.QueryFilterClass(); releaser.ManageLifetime(filter); string format = "{0}='{1}' AND {2}='{3}'"; filter.WhereClause = string.Format(format, deviceHasPorts.OriginForeignKey, device.Feature.get_Value(deviceFtClass.FindField(deviceHasPorts.OriginPrimaryKey)), ConfigUtil.PortTypeFieldName, (PortType.Input == portType ? "1" : "2")); // Non recylcing cursor since we are doing updates. ESRI.ArcGIS.Geodatabase.ICursor portCursor = portTable.Update(filter, false); releaser.ManageLifetime(portCursor); ESRI.ArcGIS.Geodatabase.IRow portRow = portCursor.NextRow(); while (null != portRow) { object portIdObj = portRow.get_Value(portIdIdx); if (DBNull.Value != portIdObj) { int portId = System.Convert.ToInt32(portIdObj); if (portsAsKeys.ContainsKey(portId)) { portRow.set_Value(cableIdIdx, cable.IPID); portRow.set_Value(isFromEndIdx, isFromEndValue); portRow.set_Value(fiberNumberIdx, portsAsKeys[portId]); portRow.Store(); } } ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(portRow); portRow = portCursor.NextRow(); } if (isOperationOpen) { _editor.StopOperation("Create Connections"); isOperationOpen = false; } success = true; } } catch (Exception ex) { if (isOperationOpen) { _editor.AbortOperation(); } success = false; throw new Exception("Save operation failed."); } return(success); }
/// <summary> /// Returns a list of connections between the cable and the device, at the cable's given end, to the device's given port type /// </summary> /// <param name="cable">Cable to check</param> /// <param name="device">Device to check</param> /// <param name="isFromEnd">Digitized end of cable</param> /// <param name="portType">Input or output</param> /// <returns>List of Connection</returns> public List <Connection> GetConnections(FiberCableWrapper cable, DeviceWrapper device, bool isFromEnd, PortType portType) { if (null == cable) { throw new ArgumentNullException("cable"); } if (null == device) { throw new ArgumentNullException("device"); } List <Connection> result = new List <Connection>(); List <int> ports = new List <int>(); List <int> strands = new List <int>(); using (ESRI.ArcGIS.ADF.ComReleaser releaser = new ESRI.ArcGIS.ADF.ComReleaser()) { ESRI.ArcGIS.Geodatabase.IFeatureClass deviceFtClass = device.Feature.Class as ESRI.ArcGIS.Geodatabase.IFeatureClass; ESRI.ArcGIS.Geodatabase.IRelationshipClass deviceHasPorts = ConfigUtil.GetPortRelationship(deviceFtClass); if (null == deviceHasPorts) { throw new Exception("Unable to find port relationship class."); } ESRI.ArcGIS.Geodatabase.ITable portTable = deviceHasPorts.DestinationClass as ESRI.ArcGIS.Geodatabase.ITable; if (null == portTable) { throw new Exception("Invalid destination on port relationship class."); } ESRI.ArcGIS.Geodatabase.IQueryFilter filter = new ESRI.ArcGIS.Geodatabase.QueryFilterClass(); releaser.ManageLifetime(filter); filter.WhereClause = string.Format("{0}='{1}' AND {2}='{3}' AND {4}='{5}' AND {6}='{7}' AND {8} IS NOT NULL AND {9} IS NOT NULL", deviceHasPorts.OriginForeignKey, device.Feature.get_Value(deviceFtClass.FindField(deviceHasPorts.OriginPrimaryKey)), ConfigUtil.ConnectedCableFieldName, cable.IPID, ConfigUtil.PortTypeFieldName, (PortType.Input == portType ? "1" : "2"), ConfigUtil.ConnectedEndFieldName, (isFromEnd ? "T" : "F"), ConfigUtil.ConnectedFiberFieldName, ConfigUtil.PortIdFieldName); // ORDER BY does not work outside of SDE. // Removing for now, should not be important. string orderFormat = "ORDER BY {0}"; if (PortType.Input == portType) { // ((ESRI.ArcGIS.Geodatabase.IQueryFilterDefinition2)filter).PostfixClause = string.Format(orderFormat, ConfigUtil.ConnectedFiberFieldName); } else { // ((ESRI.ArcGIS.Geodatabase.IQueryFilterDefinition2)filter).PostfixClause = string.Format(orderFormat, ConfigUtil.PortIdFieldName); } ESRI.ArcGIS.Geodatabase.ICursor portCursor = portTable.Search(filter, true); ESRI.ArcGIS.Geodatabase.IRow portRow = portCursor.NextRow(); int portIdIdx = portTable.FindField(ConfigUtil.PortIdFieldName); int fiberNumberIdx = portTable.FindField(ConfigUtil.ConnectedFiberFieldName); while (null != portRow) { ports.Add((int)portRow.get_Value(portIdIdx)); strands.Add((int)portRow.get_Value(fiberNumberIdx)); ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(portRow); portRow = portCursor.NextRow(); } ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(portCursor); } List <Range> portRanges = SpliceAndConnectionUtils.MergeRanges(ports); List <Range> strandRanges = SpliceAndConnectionUtils.MergeRanges(strands); if (PortType.Input == portType) { result = SpliceAndConnectionUtils.MatchUp(strandRanges, portRanges); } else { result = SpliceAndConnectionUtils.MatchUp(portRanges, strandRanges); } return(result); }
/// <summary> /// Check changes to the grid and save them to the database /// </summary> /// <param name="splice">The associated splice closure</param> /// <param name="cableA">A cable</param> /// <param name="cableB">The other cable</param> /// <returns>Success</returns> private bool SaveChanges(SpliceClosureWrapper splice, FiberCableWrapper cableA, SpliceableCableWrapper cableB) { bool result = false; string isNotOkString = string.Empty; Dictionary <int, FiberSplice> currentGrid = new Dictionary <int, FiberSplice>(); List <int> currentBStrands = new List <int>(); try { int aIdx = colRangeA.Index; int bIdx = colRangeB.Index; int lossIdx = colLoss.Index; int typeIdx = grdSplices.Columns[colType.Name].Index; // If we had to use colTypeText, it will be using the same name // Less than count-1 lets us avoid the insert row for (int i = 0; i < grdSplices.Rows.Count - 1; i++) { if (grdSplices[aIdx, i].Value == null || grdSplices[bIdx, i].Value == null) { isNotOkString = "A or B unit range missing."; } if (0 < isNotOkString.Length) { // No need to check the rest if this one was not OK break; } List <Range> aRanges = SpliceAndConnectionUtils.ParseRanges(grdSplices[aIdx, i].Value.ToString()); List <Range> bRanges = SpliceAndConnectionUtils.ParseRanges(grdSplices[bIdx, i].Value.ToString()); if (!SpliceAndConnectionUtils.AreCountsEqual(aRanges, bRanges)) { isNotOkString = "Number of units from A to B must match on each row."; } else if (!SpliceAndConnectionUtils.AreRangesWithinFiberCount(aRanges, cableA)) { isNotOkString = "Selected units exceed fiber count for cable A."; } else if (!SpliceAndConnectionUtils.AreRangesWithinFiberCount(bRanges, cableB)) { isNotOkString = "Selected units exceed fiber count for cable B."; } if (0 < isNotOkString.Length) { // No need to check the rest if this one was not OK break; } List <Connection> matchedUp = SpliceAndConnectionUtils.MatchUp(aRanges, bRanges); foreach (Connection range in matchedUp) { Range a = range.ARange; Range b = range.BRange; int numUnits = a.High - a.Low + 1; for (int offset = 0; offset < numUnits; offset++) { int aUnit = a.Low + offset; int bUnit = b.Low + offset; if (currentGrid.ContainsKey(aUnit)) { isNotOkString = string.Format("Duplicate splicing found for A Strand {0}", aUnit); // No need to check the rest if this one was not OK break; } else if (currentBStrands.Contains(bUnit)) { isNotOkString = string.Format("Duplicate splicing found for B Strand {0}", bUnit); // No need to check the rest if this one was not OK break; } else { object lossObj = grdSplices[lossIdx, i].Value; object typeObj = grdSplices[typeIdx, i].Value; double?loss = null; if (null != lossObj) { double dblLoss = -1; if (double.TryParse(lossObj.ToString(), out dblLoss)) { loss = dblLoss; } else { MessageBox.Show("Loss value on row {0} could not be parsed. Using null.", "Splice Editor", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } FiberSplice fiberSplice = new FiberSplice(new Range(aUnit, aUnit), new Range(bUnit, bUnit), loss, typeObj); currentGrid[aUnit] = fiberSplice; currentBStrands.Add(bUnit); } } } } } catch (Exception ex) { isNotOkString = ex.Message; } // Check the ranges are within the feature's units List <int> checkToUnits = new List <int>(); List <int> checkFromUnits = new List <int>(); // Anything that is in the current grid, we will see if it is available. But if it was deleted, we can ignore // checking its availabilty, because we are about to free it up. Also if it was original, we can ignore it, // since we are reprocessing it. Duplicates ON the grid have already been checked for. // NOTE: We can simplify this to just check original, since any deleted ones were in the original. foreach (FiberSplice checkSplice in currentGrid.Values) { int unit = checkSplice.BRange.Low; checkToUnits.Add(unit); } foreach (FiberSplice checkSplice in _original.Values) { int unit = checkSplice.BRange.Low; if (checkToUnits.Contains(unit)) { checkToUnits.Remove(unit); } } foreach (int fromUnit in currentGrid.Keys) { if (!_original.ContainsKey(fromUnit)) { checkFromUnits.Add(fromUnit); } } if (!SpliceAndConnectionUtils.AreRangesAvailable(checkFromUnits, cableA, cableB.IsOtherFromEnd)) { isNotOkString = "Some A units are not in the available ranges for the A Cable."; } else if (!SpliceAndConnectionUtils.AreRangesAvailable(checkToUnits, cableB, cableB.IsThisFromEnd)) { isNotOkString = "Some B units are not in the available ranges for the B Cable."; } if (0 < isNotOkString.Length) { string message = string.Format("{0}\nPlease correct this and try again.", isNotOkString); MessageBox.Show(message, "Splice Editor", MessageBoxButtons.OK, MessageBoxIcon.Error); } else { if (null != cableA && null != cableB) { // For the deleted ones, if they were added back, don't delete them... List <int> keys = new List <int>(); keys.AddRange(_deleted.Keys); foreach (int key in keys) { if (currentGrid.ContainsKey(key)) { FiberSplice fiberSplice = currentGrid[key]; if (fiberSplice.BRange.Low == _deleted[key].BRange.Low && fiberSplice.Loss == _deleted[key].Loss && fiberSplice.Type == _deleted[key].Type) { // It is added back, so don't delete it _deleted.Remove(key); } } } if (0 < _deleted.Count) { _spliceHelper.BreakSplices(cableA, cableB, splice, _deleted, false); } // For the added ones, if they already exist or are not available, don't add them // Since we already know they are in the fiber count range, the only problem would be if they were already // spliced. This would be the case if (1) it was part of the original or (2) has already appeared higher // on the currentGrid. (2) is handled when building currentGrid, by checking if the aUnit or bUnit was already used. keys.Clear(); keys.AddRange(currentGrid.Keys); foreach (int key in keys) { if (_original.ContainsKey(key)) { FiberSplice fiberSplice = currentGrid[key]; if (fiberSplice.BRange.Low == _original[key].BRange.Low && fiberSplice.Loss == _original[key].Loss && fiberSplice.Type == _original[key].Type) { // It was on the original, so we don't need to create it currentGrid.Remove(key); } } } if (0 < currentGrid.Count) { _spliceHelper.CreateSplices(cableA, cableB, splice, currentGrid, false); } // These are no longer part of the originals foreach (KeyValuePair <int, FiberSplice> deletedPair in _deleted) { _original.Remove(deletedPair.Key); } // These are now part of the originals foreach (KeyValuePair <int, FiberSplice> addedPair in currentGrid) { _original[addedPair.Key] = addedPair.Value; } _deleted.Clear(); // The grid is fresh // Set the existing rows as committed data. Less than count-1 lets us avoid the insert row for (int i = 0; i < grdSplices.Rows.Count - 1; i++) { grdSplices.Rows[i].ReadOnly = true; } btnSave.Enabled = false; btnSave.Tag = false; // No edits made yet result = true; } } return(result); }
/// <summary> /// Ripple down from the desired start point tracing and highlighting the results. /// </summary> public void TraceTriggered(FeatureWrapper feature, int unit, PortType port = PortType.Input) { try { if (null == feature) { throw new ArgumentNullException("FeatureWrapper"); } FiberCableWrapper fiberCableWrapper = feature as FiberCableWrapper; DeviceWrapper deviceWrapper = feature as DeviceWrapper; int fiberNumber = unit; _startedOnFiber = true; if (null != deviceWrapper) { fiberCableWrapper = GetConnectedFiber(deviceWrapper, unit, port, out fiberNumber); _startedOnFiber = false; } List <Range> traceRange = new List <Range>(new Range[] { new Range(fiberNumber, fiberNumber) }); if (null != fiberCableWrapper) { if (SpliceAndConnectionUtils.AreRangesWithinFiberCount(traceRange, fiberCableWrapper)) { ESRI.ArcGIS.Geodatabase.IFeature ft = fiberCableWrapper.Feature; _traceResults.Clear(); _traceResults = TracePath(ft, fiberNumber, true); _traceResults.Reverse(); // This went down the "from end", so they are backwards _startFiberIdx = _traceResults.Count; // Now add ourselves _traceResults.Add(ft); _traceResults.Add(GetFiberRecord(ft, fiberNumber)); // Now add everything going the other way List <ESRI.ArcGIS.Geodatabase.IRow> resultsAtToEnd = TracePath(ft, fiberNumber, false); _traceResults.AddRange(resultsAtToEnd); if (TraceCompleted != null) { TraceCompleted(this, null); } } else { System.Windows.Forms.MessageBox.Show("Fiber strand number is not within the fiber cable's number of fibers.", "Telecom Trace", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information); } } else { System.Windows.Forms.MessageBox.Show("No fiber cable / strand was specified, or none was connected to the specified port.", "Telecom Trace", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information); } // --------------------------------------- // This causes a refresh of the selection // and we see the results of the trace on // the map // --------------------------------------- _hookHelper.ActiveView.PartialRefresh(ESRI.ArcGIS.Carto.esriViewDrawPhase.esriViewGeoSelection, null, null); // ActiveView.PartialRefresh(ESRI.ArcGIS.Carto.esriViewDrawPhase.esriViewGeoSelection, null, null); } catch (Exception ex) { System.Diagnostics.Trace.WriteLine(ex.Message, "ERROR"); System.Diagnostics.Trace.WriteLine(ex.StackTrace, "DETAILS"); } finally { } }
private FiberCableWrapper GetConnectedFiber(DeviceWrapper device, int portId, PortType portType, out int fiberNumber) { FiberCableWrapper result = null; fiberNumber = -1; ESRI.ArcGIS.Geodatabase.IFeatureClass deviceFtClass = (ESRI.ArcGIS.Geodatabase.IFeatureClass)device.Feature.Class; ESRI.ArcGIS.Geodatabase.IRelationshipClass deviceHasPorts = ConfigUtil.GetPortRelationship(deviceFtClass); if (null == deviceHasPorts) { throw new Exception("Device to port relationship is missing or cannot be opened."); } ESRI.ArcGIS.Geodatabase.ITable portTable = deviceHasPorts.DestinationClass as ESRI.ArcGIS.Geodatabase.ITable; if (null == portTable) { throw new Exception("Port table is missing or cannot be opened."); } using (ESRI.ArcGIS.ADF.ComReleaser releaser = new ESRI.ArcGIS.ADF.ComReleaser()) { ESRI.ArcGIS.Geodatabase.IQueryFilter filter = new ESRI.ArcGIS.Geodatabase.QueryFilterClass(); releaser.ManageLifetime(filter); filter.WhereClause = string.Format("{0}='{1}' AND {2}={3} AND {4}='{5}'", deviceHasPorts.OriginForeignKey, device.Feature.get_Value(deviceFtClass.FindField(deviceHasPorts.OriginPrimaryKey)), ConfigUtil.PortIdFieldName, portId, ConfigUtil.PortTypeFieldName, PortType.Input == portType ? 1 : 2); ESRI.ArcGIS.Geodatabase.ICursor cursor = portTable.Search(filter, false); releaser.ManageLifetime(cursor); ESRI.ArcGIS.Geodatabase.IRow portRow = cursor.NextRow(); if (null != portRow) { //releaser.ManageLifetime(portRow); object cableIdValue = portRow.get_Value(portTable.FindField(ConfigUtil.ConnectedCableFieldName)); if (DBNull.Value != cableIdValue) { ESRI.ArcGIS.Geodatabase.IFeatureClass cableFtClass = _wkspHelper.FindFeatureClass(ConfigUtil.FiberCableFtClassName); filter.WhereClause = string.Format("{0}='{1}'", ConfigUtil.IpidFieldName, cableIdValue); ESRI.ArcGIS.Geodatabase.IFeatureCursor cableCursor = cableFtClass.Search(filter, false); releaser.ManageLifetime(cableCursor); ESRI.ArcGIS.Geodatabase.IFeature cable = cableCursor.NextFeature(); if (null != cable) { result = new FiberCableWrapper(cable); object fiberNumberValue = portRow.get_Value(portTable.FindField(ConfigUtil.ConnectedFiberFieldName)); if (DBNull.Value != fiberNumberValue) { int.TryParse(fiberNumberValue.ToString(), out fiberNumber); } } } } } return(result); }
/// <summary> /// A "from" item has been selected; load "to" choices /// </summary> private void cboFrom_SelectedIndexChanged(object sender, EventArgs e) { if (!_isReverting) { bool isChangeAccepted = !btnSave.Enabled; // If the save button is disabled, there is no reason to cancel the change if (!isChangeAccepted) { // Get the current to feature and the from feature that was selected before the index changed, so we can // prompt for unsaved edits FeatureWrapper to = cboTo.SelectedItem as FeatureWrapper; FeatureWrapper preChangeFrom = null; if (-1 < _lastSelectedFromIdx && _lastSelectedFromIdx < cboFrom.Items.Count) { preChangeFrom = cboFrom.Items[_lastSelectedFromIdx] as FeatureWrapper; } isChangeAccepted = IsUserSure(preChangeFrom, to); } if (isChangeAccepted) { // The current index is committed _lastSelectedFromIdx = cboFrom.SelectedIndex; // Unload anything that is dependent on the selection of the From Feature ClearGrid(); cboTo.Items.Clear(); lblAvailableFrom.Text = ""; lblAvailableTo.Text = ""; if (null != cboFrom.SelectedItem) { FiberCableWrapper cableWrapper = cboFrom.SelectedItem as FiberCableWrapper; DeviceWrapper deviceWrapper = cboFrom.SelectedItem as DeviceWrapper; if (null != cableWrapper) { List <ConnectableDeviceWrapper> devices = _connectionHelper.GetCoincidentDevices(cableWrapper); for (int i = 0; i < devices.Count; i++) { cboTo.Items.Add(devices[i]); } } else if (null != deviceWrapper) { List <ConnectableCableWrapper> cables = _connectionHelper.GetCoincidentCables(deviceWrapper); for (int i = 0; i < cables.Count; i++) { cboTo.Items.Add(cables[i]); } } // Preselect the first item if (0 < cboTo.Items.Count) { cboTo.SelectedItem = cboTo.Items[0]; } } } else { // Cancel the change by re-selecting the previous from feature _isReverting = true; cboFrom.SelectedIndex = _lastSelectedFromIdx; _isReverting = false; } } }
/// <summary> /// Check changes to the grid and save them to the database /// </summary> /// <param name="from">From feature</param> /// <param name="to">To feature</param> /// <returns>Success</returns> private bool SaveChanges(FeatureWrapper from, FeatureWrapper to) { bool result = false; string isNotOkString = string.Empty; Dictionary <int, int> currentGrid = new Dictionary <int, int>(); FiberCableWrapper cable = null; DeviceWrapper device = null; bool isFromEnd = false; PortType portType = PortType.Input; #region Detect Direction try { if (from is FiberCableWrapper && to is ConnectableDeviceWrapper) { cable = cboFrom.SelectedItem as FiberCableWrapper; device = cboTo.SelectedItem as DeviceWrapper; isFromEnd = ((ConnectableDeviceWrapper)device).IsCableFromEnd; portType = PortType.Input; } else if (from is DeviceWrapper && to is ConnectableCableWrapper) { device = cboFrom.SelectedItem as DeviceWrapper; cable = cboTo.SelectedItem as FiberCableWrapper; isFromEnd = ((ConnectableCableWrapper)cable).IsThisFromEnd; portType = PortType.Output; } else { isNotOkString = "Must connect a cable to a device, or device to a cable."; } } catch (Exception ex) { isNotOkString = ex.Message; } #endregion try { if (null != cable && null != device) { // Only continue if we have a valid setup try { int aIdx = colFromRange.Index; int bIdx = colToRange.Index; // Less than count-1 lets us avoid the insert row for (int i = 0; i < grdConnections.Rows.Count - 1; i++) { object aRanges = (grdConnections[aIdx, i].Value != null ? grdConnections[aIdx, i].Value : ""); object bRanges = (grdConnections[bIdx, i].Value != null ? grdConnections[bIdx, i].Value : ""); List <Range> fromRanges = SpliceAndConnectionUtils.ParseRanges(aRanges.ToString()); List <Range> toRanges = SpliceAndConnectionUtils.ParseRanges(bRanges.ToString()); // Check that counts match up if (!SpliceAndConnectionUtils.AreCountsEqual(fromRanges, toRanges)) { isNotOkString = "Number of units from A to B must match on each row."; } // Check the ranges are within the feature's units if (PortType.Input == portType) { if (!SpliceAndConnectionUtils.AreRangesWithinFiberCount(fromRanges, cable)) { isNotOkString = "Selected units exceed fiber count for cable."; } else if (!SpliceAndConnectionUtils.AreRangesWithinPortCount(toRanges, device, portType)) { isNotOkString = "Selected units exceed input port count for device."; } } else { if (!SpliceAndConnectionUtils.AreRangesWithinFiberCount(toRanges, cable)) { isNotOkString = "Selected units exceed fiber count for cable."; } else if (!SpliceAndConnectionUtils.AreRangesWithinPortCount(fromRanges, device, portType)) { isNotOkString = "Selected units exceed output port count for device."; } } if (0 < isNotOkString.Length) { // No need to check the rest if this one was not OK break; } List <Connection> matchedUp = SpliceAndConnectionUtils.MatchUp(fromRanges, toRanges); foreach (Connection connection in matchedUp) { Range a = connection.ARange; Range b = connection.BRange; int numUnits = a.High - a.Low + 1; for (int offset = 0; offset < numUnits; offset++) { int aUnit = a.Low + offset; int bUnit = b.Low + offset; if (currentGrid.ContainsKey(aUnit) || currentGrid.ContainsValue(bUnit)) { isNotOkString = string.Format("Duplicate connection found from {0} to {1}.", aUnit, bUnit); // No need to check the rest if this one was not OK break; } else { currentGrid[aUnit] = bUnit; } } } } } catch (Exception ex) { isNotOkString = ex.Message; MessageBox.Show(ex.Message); } // Check the ranges are within the feature's units List <int> checkToUnits = new List <int>(); List <int> checkFromUnits = new List <int>(); // Anything that is in the current grid, we will see if it is available. But if it was deleted, we can ignore // checking its availabilty, because we are about to free it up. Also if it was original, we can ignore it, // since we are reprocessing it. Duplicates ON the grid have already been checked for. // NOTE: We can simplify this to just check original, since any deleted ones were in the original. foreach (int toUnit in currentGrid.Values) { if (!_original.ContainsValue(toUnit)) { checkToUnits.Add(toUnit); } } foreach (int fromUnit in currentGrid.Keys) { if (!_original.ContainsKey(fromUnit)) { checkFromUnits.Add(fromUnit); } } if (PortType.Input == portType) { if (!SpliceAndConnectionUtils.AreRangesAvailable(checkToUnits, device, portType)) { isNotOkString = "Some To units are not in the available ranges for the device."; } else if (!SpliceAndConnectionUtils.AreRangesAvailable(checkFromUnits, cable, isFromEnd)) { isNotOkString = "Some From units are not in the available ranges for the cable."; } } else { if (!SpliceAndConnectionUtils.AreRangesAvailable(checkFromUnits, device, portType)) { isNotOkString = "Some From units are not in the available ranges for the device."; } else if (!SpliceAndConnectionUtils.AreRangesAvailable(checkToUnits, cable, isFromEnd)) { isNotOkString = "Some To units are not in the available ranges for the cable."; } } if (0 == isNotOkString.Length) { // For the deleted ones, if they were added back, don't delete them... List <int> keys = new List <int>(); keys.AddRange(_deleted.Keys); foreach (int key in keys) { if (currentGrid.ContainsKey(key) && currentGrid[key] == _deleted[key]) { // It is added back, so don't delete it _deleted.Remove(key); } } _connectionHelper.BreakConnections(cable, device, _deleted, portType, false); // For the added ones, if they already exist or are not available, don't add them // Since we already know they are in the fiber count range, the only problem would be if they were already // spliced. This would be the case if (1) it was part of the original, (2) has already appeared higher // on the currentGrid, (3) is spliced to something else. (2) is handled when building currentGrid, by checking // if the aUnit or bUnit was already used and (3) is checked in the AreRangesAvailable checks. So now we will // confirm (1)... keys.Clear(); keys.AddRange(currentGrid.Keys); foreach (int key in keys) { if (_original.ContainsKey(key) && _original[key] == currentGrid[key]) { currentGrid.Remove(key); } } _connectionHelper.MakeConnections(cable, device, currentGrid, isFromEnd, portType, false); // These are no longer part of the originals foreach (int deletedKey in _deleted.Keys) { _original.Remove(deletedKey); } // These are now part of the originals foreach (KeyValuePair <int, int> addedPair in currentGrid) { _original[addedPair.Key] = addedPair.Value; } _deleted.Clear(); // The grid is fresh // Set the existing rows as committed data. Less than count-1 lets us avoid the insert row for (int i = 0; i < grdConnections.Rows.Count - 1; i++) { grdConnections.Rows[i].ReadOnly = true; } btnSave.Enabled = false; btnSave.Tag = false; // No edits have been made result = true; } } } catch (Exception ex) { MessageBox.Show("Error: " + ex.ToString()); } if (0 < isNotOkString.Length) { string message = string.Format("{0}\nPlease correct this and try again.", isNotOkString); MessageBox.Show(message, "Connection Editor", MessageBoxButtons.OK, MessageBoxIcon.Error); } return(result); }