private void RepairWithDataset(IDataLayer2 dataLayer, Moves.GisDataset oldDataset, Moves.GisDataset newDataset, AlertForm alert) { // This routine, can only repair workspace path, and dataset name. // The workspace type and data type must be the same. // This can be checked with the CSV verifier. Violations will be ignored in the CSV loader if (oldDataset.DatasourceType != newDataset.DatasourceType || oldDataset.WorkspaceProgId != newDataset.WorkspaceProgId) { return; } var helper = (IDataSourceHelperLayer) new DataSourceHelper(); if (oldDataset.DatasourceName == newDataset.DatasourceName) { helper.FindAndReplaceWorkspaceNamePath((ILayer)dataLayer, oldDataset.Workspace.Folder, newDataset.Workspace.Folder, false); } else { // I can't find a way to simply change the name of the dataset in a layer. // To set the data source of a layer I need to first open the data source (using the newDataset properties) // I can then use the Name (as IName) of the data source to fix the layer. IDataset dataset = TryOpenDataset(newDataset); if (dataset == null) { alert.Text = @"Error"; alert.msgBox.Text = $"Map Fixer is unable to repair the layer {((ILayer2)dataLayer).Name}. " + "Use the 'Set Data Source button' on the Source tab of the layer properties dialog to " + $"set the data source to {newDataset.Workspace.Folder}\\{newDataset.DatasourceName}"; alert.ShowDialog(new WindowWrapper(new IntPtr(ArcMap.Application.hWnd))); return; } helper.ReplaceName((ILayer)dataLayer, dataset.FullName, false); } }
private IDataset TryOpenDataset(Moves.GisDataset dataset, IWorkspace workspace, IDatasetName datasetName) { if (dataset.DatasourceType.AsDatasetType() == null) { return(null); } var datasetType = dataset.DatasourceType.AsDatasetType().Value; if (datasetType == esriDatasetType.esriDTFeatureClass) { try { IFeatureWorkspace featureWorkspace = (IFeatureWorkspace)workspace; IFeatureClass featureClass = featureWorkspace.OpenFeatureClass(datasetName.Name); return((IDataset)featureClass); } catch (Exception) { return(null); } } // For opening raster data see https://desktop.arcgis.com/en/arcobjects/10.5/net/webframe.htm#62937a09-b1c5-47d7-a1ac-f7a5daab3c89.htm if (datasetType == esriDatasetType.esriDTRasterDataset) { try { // ReSharper disable once SuspiciousTypeConversion.Global // Raster Workspace Class is in ESRI.ArcGIS.DataSourcesRaster IRasterWorkspace2 rasterWorkspace = (IRasterWorkspace2)workspace; IRasterDataset rasterDataset = rasterWorkspace.OpenRasterDataset(datasetName.Name); // ReSharper disable once SuspiciousTypeConversion.Global // Three possible co-classes FunctionRasterDataset, RasterBand, RasterDataset are in ESRI.ArcGIS.DataSourcesRaster return((IDataset)rasterDataset); } catch (Exception) { return(null); } } if (datasetType == esriDatasetType.esriDTRasterCatalog || datasetType == esriDatasetType.esriDTMosaicDataset) { try { IRasterWorkspaceEx rasterWorkspace = (IRasterWorkspaceEx)workspace; IRasterDataset rasterDataset = rasterWorkspace.OpenRasterDataset(datasetName.Name); // ReSharper disable once SuspiciousTypeConversion.Global // Three possible co-classes FunctionRasterDataset, RasterBand, RasterDataset are in ESRI.ArcGIS.DataSourcesRaster return((IDataset)rasterDataset); } catch (Exception) { return(null); } } //TODO: Open additional types of data sources, support at least all in theme Manager return(null); }
private IDataset TryOpenDataset(Moves.GisDataset dataset) { IWorkspaceName workspaceName = new WorkspaceNameClass() { WorkspaceFactoryProgID = dataset.WorkspaceProgId, // i.e. "esriDataSourcesGDB.AccessWorkspaceFactory"; PathName = dataset.Workspace.Folder }; IWorkspace workspace; try { workspace = workspaceName.WorkspaceFactory.Open(null, 0); } catch (Exception) { // This may fail for any number of reasons, bad input (progID or path), network or filesystem error permissions, ... return(null); } if (workspace == null) { return(null); } if (dataset.DatasourceType.AsDatasetType() == null) { return(null); } var datasetNames = workspace.DatasetNames[dataset.DatasourceType.AsDatasetType().Value]; IDatasetName datasetName; while ((datasetName = datasetNames.Next()) != null) { if (datasetName.ToString() == dataset.DatasourceType && string.Compare(datasetName.Name, dataset.DatasourceName, StringComparison.OrdinalIgnoreCase) == 0) { return(TryOpenDataset(dataset, workspace, datasetName)); } } return(null); }
private static void RepairWithDataset(Layer layer, Moves.GisDataset oldDataset, Moves.GisDataset newDataset) { // This routine, can only repair workspace path, and dataset name. // The workspace type and data type must be the same. // This is checked with a warning in the CSV verifier. // Violations are silently ignored in the CSV loader so this code should never see it // however if it escapes, it will also be ignored here as well. if (oldDataset.DatasourceType != newDataset.DatasourceType || oldDataset.WorkspaceProgId != newDataset.WorkspaceProgId) { return; } if (oldDataset.DatasourceName == newDataset.DatasourceName) { try { // This threw an underlying COM exception with a test case with valid input, so wrap in the try for safely layer.FindAndReplaceWorkspacePath(oldDataset.Workspace.Folder, newDataset.Workspace.Folder, false); } catch { var title = @"Map Fixer Error"; var msg = $"Map Fixer failed to repair the layer {layer.Name}. " + "Use the 'Set Data Source button' on the Source tab of the layer properties dialog to " + $"set the data source to {newDataset.Workspace.Folder}\\{newDataset.DatasourceName}"; MessageBox.Show(msg, title, System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error); } } else { if (Enum.TryParse(newDataset.DatasourceType, out esriDatasetType dataType) && Enum.TryParse(newDataset.WorkspaceProgId, out WorkspaceFactory workspaceFactory)) { //TODO: Replace the existing data connection with the same sub class of CIMDataConnection, // Need support from the moves database and GetDataset() below to support this. // Currently GetDataset() will ignore all but CIMStandardDataConnection, so we can // safely assume that is what we need to create string workspaceConnection = "DATABASE=" + newDataset.Workspace.Folder; CIMStandardDataConnection updatedDataConnection = new CIMStandardDataConnection() { WorkspaceConnectionString = workspaceConnection, WorkspaceFactory = workspaceFactory, Dataset = newDataset.DatasourceName, DatasetType = dataType }; layer.SetDataConnection(updatedDataConnection); } else { var title = @"Map Fixer Error"; var msg = $"Map Fixer is unable to repair the layer {layer.Name}. " + "Use the 'Set Data Source button' on the Source tab of the layer properties dialog to " + $"set the data source to {newDataset.Workspace.Folder}\\{newDataset.DatasourceName}"; MessageBox.Show(msg, title, System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error); } } // Alternative implementation // switch on newDataset.WorkspaceProgId, newDataset.DatasourceType // uri = Uri(Path.Join(newDataset.Workspace.Folder, newDataset.DatasourceName) // connection = <Type>ConnectionPath(uri, newDataset.DatasourceType) // var dataset = OpenDataset<Type>(new <Type>DataSource(connection)) // i.e. file geodatabase DatasourceType = .fgdb //ArcGIS.Core.CIM.esriDatasetType, ArcGIS.Core.CIM.WorkspaceFactory // var connection = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(@"newDataset.Workspace.Folder"))) // var dataset = connection.OpenDataset<FeatureDataset>(newDataset.DatasourceName) // for .raster and .shape // var connection = new FileSystemDataStore(new FileSystemConnectionPath(new Uri(@"newDataset.Workspace.Folder"))) // var dataset = connection.OpenDataset<BasicRasterDataset>(newDataset.DatasourceName) }
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))); } }