/// <summary> /// Fix the broken links in map that have solutions in moves. /// Must be called on the MCT (inside QueuedTask.Run) /// </summary> /// <param name="map">The map to check</param> /// <param name="moves">A database of known solutions to broken links</param> public static void FixMap(Map map, Moves moves) { if (map == null) { return; } var autoFixesApplied = 0; var unFixableLayers = 0; var intentionallyBroken = 0; foreach (var layer in map.GetLayersAsFlattenedList().Where(l => l.ConnectionStatus == ConnectionStatus.Broken)) { Moves.GisDataset?oldDataset = GetDataset(layer); if (oldDataset == null) { unFixableLayers += 1; continue; } Moves.Solution?maybeSolution = moves.GetSolution(oldDataset.Value); if (maybeSolution == null) { unFixableLayers += 1; continue; } Moves.Solution solution = maybeSolution.Value; if (solution.NewDataset != null && solution.ReplacementDataset == null && solution.ReplacementLayerFilePath == null && solution.Remarks == null) { // This is the typical solution (only choice is to update the dataset path). // The user is not prompted, since there is no good reason for a user not to click OK. // The user will be warned that layers have been fixed, and they can choose to not save the changes. autoFixesApplied += 1; RepairWithDataset(layer, oldDataset.Value, solution.NewDataset.Value); } else { var selector = new SelectorWindow { // TODO: fix this - // Setting the owner to the MainWindow will keep the dialog tied to the MainWindow, but it causes the following exception // System.InvalidOperationException: 'The calling thread cannot access this object because a different thread owns it.' // neither Dispatch.invoke(() => { ... }) on selector or the MainWindow worked. //Owner = FrameworkApplication.Current.MainWindow, LayerName = layer.Name, Solution = solution }; selector.ShowDialog(); if (selector.UseLayerFile) { RepairWithLayerFile(map, layer, selector.LayerFile, selector.KeepBrokenLayer); if (selector.KeepBrokenLayer) { intentionallyBroken += 1; } } else if (selector.UseDataset && selector.Dataset.HasValue) { RepairWithDataset(layer, oldDataset.Value, selector.Dataset.Value); } else { intentionallyBroken += 1; } } } // Print a Summary var brokenDataSourcesCount = map.GetLayersAsFlattenedList().Count(l => l.ConnectionStatus == ConnectionStatus.Broken); // Some unfixable layers may actually have been corrected by fixing the Mosaic Dataset Layer // Limit unfixable to no more than the actual number of broken layers unFixableLayers = Math.Min(unFixableLayers, brokenDataSourcesCount); if (autoFixesApplied > 0 || unFixableLayers > 0 || brokenDataSourcesCount > intentionallyBroken) { string msg = ""; if (autoFixesApplied > 0) { var plural = autoFixesApplied == 1 ? " was" : "s were"; msg += $"{autoFixesApplied} broken layer{plural} automatically fixed based on the new locations of known data sources. " + "Close the document without saving if this is not what you want."; } if (autoFixesApplied > 0 && (unFixableLayers > 0 || brokenDataSourcesCount > 0)) { msg += "\n\n"; } if (unFixableLayers > 0) { msg += $"{unFixableLayers} broken layers could not be fixed; breakage is not due to changes on the PDS (X drive)."; } if (unFixableLayers < brokenDataSourcesCount - intentionallyBroken) { // We know that brokenDataSources.Count must be >= unFixableLayers, therefore some of the fixes need fixing if (unFixableLayers > 0) { msg += "\n\n"; } msg += "Additional fixes are possible and needed. Please save, close and reopen your map."; } var title = @"Map Fixer Summary"; MessageBox.Show(msg, title); } }
public void FixMap(Moves moves) { var brokenDataSources = GetBrokenDataSources(); // We do not need to do anything if there was nothing to fix if (brokenDataSources.Count == 0) { return; } var alert = new AlertForm(); var selector = new SelectionForm(); var autoFixesApplied = 0; var unFixableLayers = 0; var intentionallyBroken = 0; foreach (var item in brokenDataSources) { var mapIndex = item.Key; foreach (IDataLayer2 dataLayer in item.Value) { var layerName = dataLayer is IDataset dataset ? dataset.Name : ((ILayer2)dataLayer).Name; Moves.GisDataset oldDataset = GetDataset(dataLayer); Moves.Solution? maybeSolution = moves.GetSolution(oldDataset); if (maybeSolution == null) { unFixableLayers += 1; continue; } Moves.Solution solution = maybeSolution.Value; if (solution.NewDataset != null && solution.ReplacementDataset == null && solution.ReplacementLayerFilePath == null && solution.Remarks == null) { // This is the optimal action. // The user is not prompted, since there is no good reason for a user not to click OK. // The user will be warned that layers have been fixed, and they can choose to not save the changes. autoFixesApplied += 1; RepairWithDataset(dataLayer, oldDataset, solution.NewDataset.Value, alert); } else { selector.LayerName = layerName; //selector.GisDataset = oldDataset; selector.Solution = solution; selector.ShowDialog(new WindowWrapper(new IntPtr(ArcMap.Application.hWnd))); if (selector.UseLayerFile) { RepairWithLayerFile(mapIndex, dataLayer, selector.LayerFile, selector.KeepBrokenLayer, alert); if (selector.KeepBrokenLayer) { intentionallyBroken += 1; } } else if (selector.UseDataset && selector.Dataset.HasValue) { RepairWithDataset(dataLayer, oldDataset, selector.Dataset.Value, alert); } else { intentionallyBroken += 1; } } } } // Refresh TOC ArcMap.Document.UpdateContents(); //update the TOC ArcMap.Document.ActivatedView.Refresh(); // refresh the view // Print a Summary brokenDataSources = GetBrokenDataSources(); // Some unfixable layers may actually have been corrected by fixing the Mosaic Dataset Layer // Limit unfixable to no more than the actual number of broken layers unFixableLayers = Math.Min(unFixableLayers, brokenDataSources.Count); if (autoFixesApplied > 0 || unFixableLayers > 0 || brokenDataSources.Count > intentionallyBroken) { string msg = ""; if (autoFixesApplied > 0) { msg += $"{autoFixesApplied} broken layers were automatically fixed based on the new locations of known data sources. " + "Close the document without saving if this is not what you want."; } if (autoFixesApplied > 0 && (unFixableLayers > 0 || brokenDataSources.Count > 0)) { msg += "\n\n"; } if (unFixableLayers > 0) { msg += $"{unFixableLayers} broken layers could not be fixed; breakage is not due to changes on the PDS (X drive)."; } if (unFixableLayers < brokenDataSources.Count - intentionallyBroken) { // We know that brokenDataSources.Count must be >= unFixableLayers, therefore some of the fixes need fixing if (unFixableLayers > 0) { msg += "\n\n"; } msg += "Additional fixes are possible and needed. Please save, close and reopen your map."; } alert.Text = @"Map Fixer Summary"; alert.msgBox.Text = msg; alert.ShowDialog(new WindowWrapper(new IntPtr(ArcMap.Application.hWnd))); } }