#region Disclaimer / License // Copyright (C) 2011, Jackie Ng // http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie@gmail.com // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // #endregion using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Text; using System.Windows.Forms; using OSGeo.MapGuide.ObjectModels.FeatureSource; using OSGeo.MapGuide.MaestroAPI.SchemaOverrides; using System.Xml; using OSGeo.MapGuide.MaestroAPI.Schema; using System.IO; using Maestro.Shared.UI; using OSGeo.MapGuide.MaestroAPI.Resource; using OSGeo.MapGuide.ObjectModels; using OSGeo.MapGuide.MaestroAPI; using System.Collections.Specialized; using Maestro.Editors.Common; using System.Globalization; namespace Maestro.Editors.FeatureSource.Providers.Gdal { [ToolboxItem(false)] internal partial class CompositeFileCtrl : EditorBase { internal CompositeFileCtrl() { InitializeComponent(); } private IFeatureSource _fs; private GdalConfigurationDocument _conf; private IEditorService _service; public override void Bind(IEditorService service) { _service = service; _service.RegisterCustomNotifier(this); _fs = (IFeatureSource)_service.GetEditedResource(); InitDefaults(); } internal void InitDefaults() { string xml = _fs.GetConfigurationContent(); if (!string.IsNullOrEmpty(xml)) { try { _conf = (GdalConfigurationDocument)ConfigurationDocument.LoadXml(xml); } catch { BuildDefaultDocument(); } lstView.Items.Clear(); List<string> files = new List<string>(); foreach (var loc in _conf.RasterLocations) { AddRasterItems(loc.Location, loc.Items); } } } private void AddRasterItems(string dir, GdalRasterItem[] items) { foreach (var item in items) { AddRasterItem(dir, item); } } private void AddRasterItem(string dir, GdalRasterItem item) { foreach (ListViewItem li in lstView.Items) { //A list view item of the same file name exist. Abort. if (((GdalRasterItem)li.Tag).FileName == item.FileName) return; } ListViewItem lvi = new ListViewItem(); lvi.Name = Path.Combine(dir, item.FileName); lvi.Text = lvi.Name; lvi.Tag = item; lvi.ImageIndex = 0; lstView.Items.Add(lvi); } // This should really come from GetSchemaMapping, but it's broken: minX, minY, maxX, maxY private const string TEMPLATE_CFG = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><fdo:DataStore xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:fdo=\"http://fdo.osgeo.org/schemas\" xmlns:fds=\"http://fdo.osgeo.org/schemas/fds\"><gml:DerivedCRS gml:id=\"Default\"><gml:metaDataProperty><gml:GenericMetaData><fdo:SCExtentType>dynamic</fdo:SCExtentType><fdo:XYTolerance>0.001000</fdo:XYTolerance><fdo:ZTolerance>0.001000</fdo:ZTolerance></gml:GenericMetaData></gml:metaDataProperty><gml:remarks>System generated default FDO Spatial Context</gml:remarks><gml:srsName>Default</gml:srsName><gml:validArea><gml:boundingBox><gml:pos>{0} {1}</gml:pos><gml:pos>{2} {3}</gml:pos></gml:boundingBox></gml:validArea><gml:baseCRS>" + "<fdo:WKTCRS gml:id=\"Default\"><gml:srsName>Default</gml:srsName><fdo:WKT>LOCAL_CS[\"*XY-MT*\",LOCAL_DATUM[\"*X-Y*\",10000],UNIT[\"Meter\", 1],AXIS[\"X\",EAST],AXIS[\"Y\",NORTH]]</fdo:WKT></fdo:WKTCRS></gml:baseCRS><gml:definedByConversion xlink:href=\"http://fdo.osgeo.org/coord_conversions#identity\"/><gml:derivedCRSType codeSpace=\"http://fdo.osgeo.org/crs_types\">geographic</gml:derivedCRSType><gml:usesCS xlink:href=\"http://fdo.osgeo.org/cs#default_cartesian\"/></gml:DerivedCRS><xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:fdo=\"http://fdo.osgeo.org/schemas\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:default=\"http://fdo.osgeo.org/schemas/feature/default\" targetNamespace=\"http://fdo.osgeo.org/schemas/feature/default\" elementFormDefault=\"qualified\" attributeFormDefault=\"unqualified\"><xs:annotation><xs:appinfo source=\"http://fdo.osgeo.org/schemas\"/></xs:annotation><xs:element name=\"default\" type=\"default:defaultType\" abstract=\"false\" substitutionGroup=\"gml:_Feature\"><xs:key name=\"defaultKey\"><xs:selector xpath=\".//default\"/>" + "<xs:field xpath=\"FeatId\"/></xs:key></xs:element><xs:complexType name=\"defaultType\" abstract=\"false\" fdo:hasGeometry=\"false\"><xs:annotation><xs:appinfo source=\"http://fdo.osgeo.org/schemas\"/></xs:annotation><xs:complexContent><xs:extension base=\"gml:AbstractFeatureType\"><xs:sequence><xs:element name=\"FeatId\"><xs:annotation><xs:appinfo source=\"http://fdo.osgeo.org/schemas\"/></xs:annotation><xs:simpleType><xs:restriction base=\"xs:string\"><xs:maxLength value=\"256\"/></xs:restriction></xs:simpleType></xs:element><xs:element name=\"Raster\" type=\"fdo:RasterPropertyType\" fdo:defaultImageXSize=\"1024\" fdo:defaultImageYSize=\"1024\" fdo:srsName=\"Default\"><xs:annotation>" + "<xs:appinfo source=\"http://fdo.osgeo.org/schemas\"><fdo:DefaultDataModel dataModelType=\"Bitonal\" dataType=\"Unknown\" organization=\"Pixel\" bitsPerPixel=\"1\" tileSizeX=\"256\" tileSizeY=\"256\"/></xs:appinfo></xs:annotation></xs:element></xs:sequence></xs:extension></xs:complexContent></xs:complexType></xs:schema><SchemaMapping xmlns=\"http://fdogrfp.osgeo.org/schemas\" provider=\"OSGeo.Gdal.3.2\" name=\"default\"></SchemaMapping></fdo:DataStore>"; private void BuildDefaultDocument() { _conf = (GdalConfigurationDocument)ConfigurationDocument.LoadXml(string.Format(TEMPLATE_CFG, -10000000, -10000000, 10000000, 10000000)); } private void btnDelete_Click(object sender, EventArgs e) { List<string> files = new List<string>(); List<ListViewItem> items = new List<ListViewItem>(); foreach (ListViewItem item in lstView.SelectedItems) { items.Add(item); files.Add(item.Text); } DoUpdateConfiguration(new string[0], files.ToArray()); foreach (var it in items) { lstView.Items.Remove(it); } } private void lstView_SelectedIndexChanged(object sender, EventArgs e) { //btnRefresh.Enabled = btnDelete.Enabled = (lstView.SelectedItems.Count > 0); } private void btnRebuild_Click(object sender, EventArgs e) { BuildDefaultDocument(); List<string> files = new List<string>(); foreach (ListViewItem item in lstView.Items) { files.Add(item.Text); } lstView.Clear(); //Clear now. It will be repopulated after rebuild DoUpdateConfiguration(files.ToArray(), new string[0]); } private void browseFilesToolStripMenuItem_Click(object sender, EventArgs e) { if (openFileDialog.ShowDialog() == DialogResult.OK) { DoUpdateConfiguration(openFileDialog.FileNames, new string[0]); } } private void DoUpdateConfiguration(string[] toAdd, string[] toRemove) { DoUpdateConfiguration(toAdd, toRemove, false); } private void DoUpdateConfiguration(string[] toAdd, string[] toRemove, bool isAlias) { if (_conf == null) BuildDefaultDocument(); var pdlg = new ProgressDialog(); pdlg.CancelAbortsThread = true; var worker = new ProgressDialog.DoBackgroundWork(UpdateConfigurationDocument); var result = (UpdateConfigResult)pdlg.RunOperationAsync(null, worker, _conf, _fs.CurrentConnection, toAdd, toRemove, isAlias); if (result.Added.Count > 0 || result.Removed.Count > 0) { _fs.SetConfigurationContent(_conf.ToXml()); List<ListViewItem> remove = new List<ListViewItem>(); foreach (ListViewItem lvi in lstView.Items) { if (result.Removed.Contains(lvi.Text)) remove.Add(lvi); } foreach (var added in result.Added) { string dir = null; string fileName = null; if (isAlias) { dir = added.Substring(0, added.LastIndexOf("\\")); fileName = added.Substring(added.LastIndexOf("\\") + 1); } else { dir = Path.GetDirectoryName(added); fileName = Path.GetFileName(added); } foreach (var loc in _conf.RasterLocations) { if (loc.Location == dir) { foreach (var item in loc.Items) { if (item.FileName == fileName) { AddRasterItem(dir, item); } } } } } OnResourceChanged(); } } class UpdateConfigResult { public List<string> Added { get; set; } public List<string> Removed { get; set; } } object UpdateConfigurationDocument(BackgroundWorker worker, DoWorkEventArgs e, params object[] args) { GdalConfigurationDocument conf = (GdalConfigurationDocument)args[0]; IServerConnection conn = (IServerConnection)args[1]; string [] toAdd = args[2] as string[]; string [] toRemove = args[3] as string[]; bool isAlias = (bool)args[4]; worker.ReportProgress(0, Properties.Resources.UpdatingConfiguration); int total = toAdd.Length + toRemove.Length; int unit = (total / 100); int progress = 0; var result = new UpdateConfigResult() { Added = new List<string>(), Removed = new List<string>() }; //Remove first foreach (var remove in toRemove) { string dir = null; if (isAlias) { dir = remove.Substring(0, remove.LastIndexOf("\\")); } else { dir = Path.GetDirectoryName(remove); } var loc = FindLocation(conf, dir); if (null != loc) { string f = isAlias ? remove.Substring(remove.LastIndexOf("\\") + 1) : Path.GetFileName(remove); loc.RemoveItem(f); result.Removed.Add(remove); if (loc.Items.Length == 0) conf.RemoveLocation(loc); } progress += unit; worker.ReportProgress(progress, string.Format(Properties.Resources.ProcessedItem, remove)); } //Then add foreach (var add in toAdd) { string dir = null; if (isAlias) { dir = add.Substring(0, add.LastIndexOf("/")); } else { dir = Path.GetDirectoryName(add); } var loc = conf.AddLocation(dir); //Create a temp feature source to attempt interrogation of extents var values = new NameValueCollection(); values["DefaultRasterFileLocation"] = add; var fs = ObjectFactory.CreateFeatureSource(conn, "OSGeo.Gdal", values); var resId = new ResourceIdentifier("Session:" + conn.SessionID + "//" + Guid.NewGuid() + ".FeatureSource"); fs.ResourceID = resId.ToString(); conn.ResourceService.SaveResource(fs); var scList = fs.GetSpatialInfo(false); var raster = new GdalRasterItem() { FileName = isAlias ? add.Substring(add.LastIndexOf("/") + 1) : Path.GetFileName(add) }; if (scList.SpatialContext.Count > 0) { raster.MinX = Convert.ToDouble(scList.SpatialContext[0].Extent.LowerLeftCoordinate.X, CultureInfo.InvariantCulture); raster.MinY = Convert.ToDouble(scList.SpatialContext[0].Extent.LowerLeftCoordinate.Y, CultureInfo.InvariantCulture); raster.MaxX = Convert.ToDouble(scList.SpatialContext[0].Extent.UpperRightCoordinate.X, CultureInfo.InvariantCulture); raster.MaxY = Convert.ToDouble(scList.SpatialContext[0].Extent.UpperRightCoordinate.Y, CultureInfo.InvariantCulture); } else { raster.MinX = -10000000; raster.MinY = -10000000; raster.MaxX = 10000000; raster.MaxY = 10000000; } loc.AddItem(raster); result.Added.Add(Path.Combine(dir, raster.FileName)); progress += unit; worker.ReportProgress(progress, string.Format(Properties.Resources.ProcessedItem, add)); } //Re-calculate combined extent for spatial context var env = conf.CalculateExtent(); if (env != null) conf.SpatialContexts[0].Extent = env; return result; } private static GdalRasterLocationItem FindLocation(GdalConfigurationDocument conf, string directory) { foreach (var loc in conf.RasterLocations) { if (loc.Location == directory) return loc; } return null; } private void browseFolderToolStripMenuItem_Click(object sender, EventArgs e) { if (folderBrowserDialog.ShowDialog() == DialogResult.OK) { List<string> files = new List<string>(); files.AddRange(Directory.GetFiles(folderBrowserDialog.SelectedPath, "*.png")); files.AddRange(Directory.GetFiles(folderBrowserDialog.SelectedPath, "*.jpg")); files.AddRange(Directory.GetFiles(folderBrowserDialog.SelectedPath, "*.jpeg")); files.AddRange(Directory.GetFiles(folderBrowserDialog.SelectedPath, "*.tif")); files.AddRange(Directory.GetFiles(folderBrowserDialog.SelectedPath, "*.tiff")); files.AddRange(Directory.GetFiles(folderBrowserDialog.SelectedPath, "*.ecw")); files.AddRange(Directory.GetFiles(folderBrowserDialog.SelectedPath, "*.sid")); files.AddRange(Directory.GetFiles(folderBrowserDialog.SelectedPath, "*.dem")); files.AddRange(Directory.GetFiles(folderBrowserDialog.SelectedPath, "*.gif")); files.AddRange(Directory.GetFiles(folderBrowserDialog.SelectedPath, "*.bmp")); DoUpdateConfiguration(files.ToArray(), new string[0]); } } private void browseAliasedFileToolStripMenuItem_Click(object sender, EventArgs e) { using (var picker = new UnmanagedFileBrowser(_service.ResourceService)) { picker.AllowMultipleSelection = true; if (picker.ShowDialog() == DialogResult.OK) { DoUpdateConfiguration(picker.SelectedItems, new string[0], true); } } } private void browseAliasedFolderToolStripMenuItem_Click(object sender, EventArgs e) { using (var picker = new UnmanagedFileBrowser(_service.ResourceService)) { picker.AllowMultipleSelection = false; picker.SelectFoldersOnly = true; if (picker.ShowDialog() == DialogResult.OK) { List<string> files = new List<string>(); var folder = picker.SelectedItem; if (!string.IsNullOrEmpty(folder)) { folder = folder.Replace("%MG_DATA_PATH_ALIAS[", "[") .Replace("]%", "]"); } var list = _service.ResourceService.EnumerateUnmanagedData(folder, string.Empty, false, UnmanagedDataTypes.Files); var extensions = new List<string>(new string[] { ".png", ".jpg", ".jpeg", ".tif", ".tiff", ".ecw", ".sid", ".dem", ".gif", ".bmp" }); foreach (var f in list.Items) { var file = f as OSGeo.MapGuide.ObjectModels.Common.UnmanagedDataListUnmanagedDataFile; if (file != null) { foreach (var ext in extensions) { if (file.FileName.ToLower().EndsWith(ext)) { var leftpart = file.UnmanagedDataId.Substring(0, file.UnmanagedDataId.IndexOf("]")); var rightpart = file.UnmanagedDataId.Substring(file.UnmanagedDataId.IndexOf("]") + 1); var item = "%MG_DATA_PATH_ALIAS" + leftpart + "]%" + rightpart; files.Add(item); break; } } } } DoUpdateConfiguration(files.ToArray(), new string[0], true); } } } } }