| 1 | // Copyright (c) 1994-2010 Georgia Tech Research Corporation, Atlanta, GA
|
|---|
| 2 | // This file is part of FalconView(tm).
|
|---|
| 3 |
|
|---|
| 4 | // FalconView(tm) is free software: you can redistribute it and/or modify
|
|---|
| 5 | // it under the terms of the GNU Lesser General Public License as published by
|
|---|
| 6 | // the Free Software Foundation, either version 3 of the License, or
|
|---|
| 7 | // (at your option) any later version.
|
|---|
| 8 |
|
|---|
| 9 | // FalconView(tm) is distributed in the hope that it will be useful,
|
|---|
| 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 12 | // GNU Lesser General Public License for more details.
|
|---|
| 13 |
|
|---|
| 14 | // You should have received a copy of the GNU Lesser General Public License
|
|---|
| 15 | // along with FalconView(tm). If not, see <http://www.gnu.org/licenses/>.
|
|---|
| 16 |
|
|---|
| 17 | // FalconView(tm) is a trademark of Georgia Tech Research Corporation.
|
|---|
| 18 |
|
|---|
| 19 | using FvDataSourcesLib;
|
|---|
| 20 | using fvw;
|
|---|
| 21 | using MAPENGINELib;
|
|---|
| 22 | using MAPSCALEUTILSERVERLib;
|
|---|
| 23 |
|
|---|
| 24 | using Microsoft.Win32;
|
|---|
| 25 | using SharedDotNetUtils;
|
|---|
| 26 |
|
|---|
| 27 | using System;
|
|---|
| 28 | using System.Collections.Generic;
|
|---|
| 29 | using System.ComponentModel;
|
|---|
| 30 | using System.Drawing;
|
|---|
| 31 | using System.Data;
|
|---|
| 32 | using System.Text;
|
|---|
| 33 | using System.Windows.Forms;
|
|---|
| 34 | using System.Runtime.InteropServices;
|
|---|
| 35 |
|
|---|
| 36 | namespace GeodataOverlayServer
|
|---|
| 37 | {
|
|---|
| 38 | public partial class DataSourceTree : UserControl
|
|---|
| 39 | {
|
|---|
| 40 | public delegate void TreeNodeRefreshed(object sender, FvDataTreeNode oldNode, FvDataTreeNode newNode);
|
|---|
| 41 | public event TreeNodeRefreshed OnTreeNodeRefreshed;
|
|---|
| 42 |
|
|---|
| 43 | private TreeViewEventHandler m_clickHandler;
|
|---|
| 44 | private MenuItem[] m_contextMenu;
|
|---|
| 45 | private IMapRenderingEngineDataCheck m_datacheck;
|
|---|
| 46 | private IMap m_map = new MapClass();
|
|---|
| 47 | private IMap3 m_map3 = new Map3Class();
|
|---|
| 48 | private IMapRenderingEngine m_renderingEngine = new MapRenderingEngineClass();
|
|---|
| 49 | private bool m_bAddingDataSource = false;
|
|---|
| 50 |
|
|---|
| 51 | public TreeView Tree
|
|---|
| 52 | {
|
|---|
| 53 | get { return tree; }
|
|---|
| 54 | }
|
|---|
| 55 |
|
|---|
| 56 | public DataSourceTree()
|
|---|
| 57 | {
|
|---|
| 58 | InitializeComponent();
|
|---|
| 59 | tree.Parent = this;
|
|---|
| 60 | tree.Dock = DockStyle.Fill;
|
|---|
| 61 | tree.CheckBoxes = true;
|
|---|
| 62 |
|
|---|
| 63 | try
|
|---|
| 64 | {
|
|---|
| 65 |
|
|---|
| 66 | RegistryKey key = Registry.LocalMachine.OpenSubKey("Software\\PFPS\\FalconView\\Main");
|
|---|
| 67 | string dataPath = key.GetValue("HD_DATA").ToString();
|
|---|
| 68 |
|
|---|
| 69 | ImageList imageList = new ImageList();
|
|---|
| 70 | imageList.Images.Add(Image.FromFile(dataPath + @"\icons\Geodata\Data Source.ico"));
|
|---|
| 71 | imageList.Images.Add(Image.FromFile(dataPath + @"\icons\Geodata\Feature Data Set.ico"));
|
|---|
| 72 | imageList.Images.Add(Image.FromFile(dataPath + @"\icons\Geodata\Raster Data Set.ico"));
|
|---|
| 73 | tree.ImageList = imageList;
|
|---|
| 74 | }
|
|---|
| 75 | catch (Exception ex)
|
|---|
| 76 | {
|
|---|
| 77 | LoggingUtils.ReportError(ex);
|
|---|
| 78 | }
|
|---|
| 79 |
|
|---|
| 80 | m_renderingEngine.Init(null);
|
|---|
| 81 | m_datacheck = (IMapRenderingEngineDataCheck)m_renderingEngine;
|
|---|
| 82 |
|
|---|
| 83 | m_clickHandler = new TreeViewEventHandler(Tree_AfterCheck);
|
|---|
| 84 |
|
|---|
| 85 | Tree.AfterCheck += m_clickHandler;
|
|---|
| 86 |
|
|---|
| 87 | m_contextMenu = new MenuItem[3];
|
|---|
| 88 | int index = 0;
|
|---|
| 89 |
|
|---|
| 90 | m_contextMenu[index] = new MenuItem("Check All Children");
|
|---|
| 91 | m_contextMenu[index++].Click += new EventHandler(CheckAllChildren_Click);
|
|---|
| 92 | m_contextMenu[index] = new MenuItem("Get Description");
|
|---|
| 93 | m_contextMenu[index++].Click += new EventHandler(GetDescription_Click);
|
|---|
| 94 | m_contextMenu[index] = new MenuItem("Scale to Extents");
|
|---|
| 95 | m_contextMenu[index++].Click += new EventHandler(ScaleToExtents_Click);
|
|---|
| 96 |
|
|---|
| 97 | Tree.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(Tree_NodeMouseClick);
|
|---|
| 98 |
|
|---|
| 99 | // add listener for when nodes are expanded or collapsed
|
|---|
| 100 | TreeViewEventHandler handler = new TreeViewEventHandler(UpdateDataSourceExpandedState);
|
|---|
| 101 | Tree.AfterCollapse += handler;
|
|---|
| 102 | Tree.AfterExpand += handler;
|
|---|
| 103 | }
|
|---|
| 104 |
|
|---|
| 105 | private void UpdateDataSourceExpandedState(object sender, TreeViewEventArgs e)
|
|---|
| 106 | {
|
|---|
| 107 | if (!m_bAddingDataSource)
|
|---|
| 108 | {
|
|---|
| 109 | FvDataTreeNode node = e.Node as FvDataTreeNode;
|
|---|
| 110 | if (node != null)
|
|---|
| 111 | {
|
|---|
| 112 | IUIState uiState = node.Source as IUIState;
|
|---|
| 113 | if (uiState != null)
|
|---|
| 114 | {
|
|---|
| 115 | switch (e.Action)
|
|---|
| 116 | {
|
|---|
| 117 | case TreeViewAction.Collapse:
|
|---|
| 118 | uiState.Expanded = false;
|
|---|
| 119 | break;
|
|---|
| 120 | case TreeViewAction.Expand:
|
|---|
| 121 | uiState.Expanded = true;
|
|---|
| 122 | break;
|
|---|
| 123 | }
|
|---|
| 124 | }
|
|---|
| 125 | }
|
|---|
| 126 | }
|
|---|
| 127 | }
|
|---|
| 128 |
|
|---|
| 129 | private void GetDescription_Click(object sender, EventArgs e)
|
|---|
| 130 | {
|
|---|
| 131 | FvDataTreeNode dataTreeNode = Tree.SelectedNode as FvDataTreeNode;
|
|---|
| 132 | if (dataTreeNode != null)
|
|---|
| 133 | new DescriptionForm(dataTreeNode).Show(Tree);
|
|---|
| 134 | }
|
|---|
| 135 |
|
|---|
| 136 | public class DataSourceCallbackHandler : IFvDataSourceCallback
|
|---|
| 137 | {
|
|---|
| 138 | private FvDataTreeNode m_node;
|
|---|
| 139 | private DataSourceTree m_tree;
|
|---|
| 140 | private bool m_bRefreshPending = false;
|
|---|
| 141 |
|
|---|
| 142 | public DataSourceCallbackHandler(FvDataTreeNode node, DataSourceTree tree)
|
|---|
| 143 | {
|
|---|
| 144 | LoggingUtils.Assert(node.Source != null, "node must have a data source");
|
|---|
| 145 | m_node = node;
|
|---|
| 146 | m_tree = tree;
|
|---|
| 147 | s_callbackHandlerList.Add(this);
|
|---|
| 148 | }
|
|---|
| 149 |
|
|---|
| 150 | public void DataSourceChanged()
|
|---|
| 151 | {
|
|---|
| 152 | try
|
|---|
| 153 | {
|
|---|
| 154 | // hold refresh until whatever operation has put a hold on refreshing completes
|
|---|
| 155 |
|
|---|
| 156 | if (s_bHoldDataSourceCallbacks)
|
|---|
| 157 | {
|
|---|
| 158 | m_bRefreshPending = true;
|
|---|
| 159 | return;
|
|---|
| 160 | }
|
|---|
| 161 |
|
|---|
| 162 | m_bRefreshPending = false;
|
|---|
| 163 |
|
|---|
| 164 | // create a new node that contains all the new stuff
|
|---|
| 165 | FvDataTreeNode new_node = new FvDataTreeNode(m_node.Source);
|
|---|
| 166 |
|
|---|
| 167 | // replace the old node with the new node
|
|---|
| 168 | TreeNodeCollection treeNodeCollection = m_tree.Tree.Nodes;
|
|---|
| 169 | int index = treeNodeCollection.IndexOf(m_node);
|
|---|
| 170 | treeNodeCollection.RemoveAt(index);
|
|---|
| 171 | treeNodeCollection.Insert(index, new_node);
|
|---|
| 172 | FvDataTreeNode old_node = m_node;
|
|---|
| 173 | m_node = new_node;
|
|---|
| 174 |
|
|---|
| 175 | // let the world know that we replaced a tree node
|
|---|
| 176 | m_tree.FireOnTreeNodeRefreshed(old_node, new_node);
|
|---|
| 177 | }
|
|---|
| 178 | catch (Exception ex)
|
|---|
| 179 | {
|
|---|
| 180 | LoggingUtils.ReportError(ex);
|
|---|
| 181 | }
|
|---|
| 182 | }
|
|---|
| 183 |
|
|---|
| 184 | private static bool s_bHoldDataSourceCallbacks = false;
|
|---|
| 185 | private static List<DataSourceCallbackHandler> s_callbackHandlerList = new List<DataSourceCallbackHandler>();
|
|---|
| 186 |
|
|---|
| 187 | // This is a global hold on refresh callbacks. Set this if you want to hold refresh callbacks globally until
|
|---|
| 188 | // some operation is complete.
|
|---|
| 189 | public static bool HoldDataSourceChangedCallbacks
|
|---|
| 190 | {
|
|---|
| 191 | get { return s_bHoldDataSourceCallbacks; }
|
|---|
| 192 |
|
|---|
| 193 | set
|
|---|
| 194 | {
|
|---|
| 195 | s_bHoldDataSourceCallbacks = value;
|
|---|
| 196 |
|
|---|
| 197 | if (!s_bHoldDataSourceCallbacks)
|
|---|
| 198 | {
|
|---|
| 199 | // handlers may now fire their refresh events
|
|---|
| 200 | foreach (DataSourceCallbackHandler handler in s_callbackHandlerList)
|
|---|
| 201 | {
|
|---|
| 202 | if (handler.m_bRefreshPending)
|
|---|
| 203 | handler.DataSourceChanged();
|
|---|
| 204 | }
|
|---|
| 205 | }
|
|---|
| 206 | }
|
|---|
| 207 | }
|
|---|
| 208 |
|
|---|
| 209 | public void Uninitialize()
|
|---|
| 210 | {
|
|---|
| 211 | // call when this callback handler is no longer used
|
|---|
| 212 | s_callbackHandlerList.Remove(this);
|
|---|
| 213 | }
|
|---|
| 214 | }
|
|---|
| 215 |
|
|---|
| 216 | private Dictionary<IFvDataSource, DataSourceCallbackHandler> m_callbackHandlers = new Dictionary<IFvDataSource, DataSourceCallbackHandler>();
|
|---|
| 217 |
|
|---|
| 218 | public FvDataTreeNode AddDataSource(IFvDataSource dataSource)
|
|---|
| 219 | {
|
|---|
| 220 | try
|
|---|
| 221 | {
|
|---|
| 222 | m_bAddingDataSource = true;
|
|---|
| 223 |
|
|---|
| 224 | // create a tree node and add it to the tree
|
|---|
| 225 | FvDataTreeNode node = new FvDataTreeNode(dataSource);
|
|---|
| 226 | tree.Nodes.Add(node);
|
|---|
| 227 |
|
|---|
| 228 | // create a callback handler and register for callbacks
|
|---|
| 229 | m_callbackHandlers[dataSource] = new DataSourceCallbackHandler(node, this);
|
|---|
| 230 | try
|
|---|
| 231 | {
|
|---|
| 232 | dataSource.RegisterForCallbacks(m_callbackHandlers[dataSource]);
|
|---|
| 233 | }
|
|---|
| 234 | catch (NotImplementedException)
|
|---|
| 235 | {
|
|---|
| 236 | m_callbackHandlers[dataSource].Uninitialize();
|
|---|
| 237 | }
|
|---|
| 238 |
|
|---|
| 239 | return node;
|
|---|
| 240 | }
|
|---|
| 241 | finally
|
|---|
| 242 | {
|
|---|
| 243 | m_bAddingDataSource = false;
|
|---|
| 244 | }
|
|---|
| 245 | }
|
|---|
| 246 |
|
|---|
| 247 | public void FireOnTreeNodeRefreshed(FvDataTreeNode oldNode, FvDataTreeNode newNode)
|
|---|
| 248 | {
|
|---|
| 249 | OnTreeNodeRefreshed(this, oldNode, newNode);
|
|---|
| 250 | }
|
|---|
| 251 |
|
|---|
| 252 | private void BestResolution(double centerLat, double centerLon,
|
|---|
| 253 | double rotation, int zoom, int projection,
|
|---|
| 254 | string mapSource, IMapScaleUtil scaleUtil,
|
|---|
| 255 | double resolution, out Array aScales, out Array aScaleUnits,
|
|---|
| 256 | out Array aMapSeries, out int preferredIndex, out double bestResolution)
|
|---|
| 257 | {
|
|---|
| 258 | object oScales, oScaleUnits, oMapSeries;
|
|---|
| 259 | m_datacheck.GetAvailableMapSeries(mapSource, centerLat, centerLon,
|
|---|
| 260 | rotation, zoom, (ProjectionEnum)projection, 0,
|
|---|
| 261 | out oScales, out oScaleUnits, out oMapSeries);
|
|---|
| 262 |
|
|---|
| 263 | aScales = oScales as Array;
|
|---|
| 264 | aScaleUnits = oScaleUnits as Array;
|
|---|
| 265 | aMapSeries = oMapSeries as Array;
|
|---|
| 266 |
|
|---|
| 267 | //scale out until we fail or until we fit the space
|
|---|
| 268 | preferredIndex = 0;
|
|---|
| 269 | bestResolution = double.MaxValue;
|
|---|
| 270 |
|
|---|
| 271 | if (!(aScales is Array && aScaleUnits is Array && aMapSeries is Array))
|
|---|
| 272 | return;
|
|---|
| 273 |
|
|---|
| 274 | double bestDiff = double.MaxValue;
|
|---|
| 275 | for (int i = aScales.GetLowerBound(0);
|
|---|
| 276 | i < aScales.GetUpperBound(0);
|
|---|
| 277 | i++)
|
|---|
| 278 | {
|
|---|
| 279 | double indexScale = double.Parse(aScales.GetValue(i).ToString());
|
|---|
| 280 | MAPSCALEUTILSERVERLib.MapScaleUnitsEnum indexScaleUnits = (MAPSCALEUTILSERVERLib.MapScaleUnitsEnum)(int.Parse(aScaleUnits.GetValue(i).ToString()));
|
|---|
| 281 |
|
|---|
| 282 | double newResolution = indexScale;
|
|---|
| 283 | if (!indexScaleUnits.Equals(MAPSCALEUTILSERVERLib.MapScaleUnitsEnum.MAP_SCALE_DENOMINATOR))
|
|---|
| 284 | {
|
|---|
| 285 | newResolution = scaleUtil.ResolutionToScale(indexScale, indexScaleUnits);
|
|---|
| 286 | }
|
|---|
| 287 |
|
|---|
| 288 | double diff = Math.Abs(resolution - newResolution);
|
|---|
| 289 | if (diff < bestDiff)
|
|---|
| 290 | {
|
|---|
| 291 | bestDiff = diff;
|
|---|
| 292 | bestResolution = newResolution;
|
|---|
| 293 | preferredIndex = i;
|
|---|
| 294 | }
|
|---|
| 295 | }
|
|---|
| 296 | }
|
|---|
| 297 |
|
|---|
| 298 | void CheckAllChildren_Click(object sender, EventArgs e)
|
|---|
| 299 | {
|
|---|
| 300 | FvDataTreeNode node = (FvDataTreeNode)Tree.SelectedNode;
|
|---|
| 301 | SetCheckNodeAndChildren(node, true);
|
|---|
| 302 | SetCheckNodeAndParents(node, true);
|
|---|
| 303 | }
|
|---|
| 304 |
|
|---|
| 305 | private void CurrentMapSettings(double lonDiff, double latDiff, out double rotation, out int zoom, out int projection, out string mapSource, out IMapScaleUtil scaleUtil, out double resolution)
|
|---|
| 306 | {
|
|---|
| 307 | //find map pixel bounds
|
|---|
| 308 | double scale = 0;
|
|---|
| 309 | double currentLat = 0;
|
|---|
| 310 | double currentLon = 0;
|
|---|
| 311 | rotation = 0;
|
|---|
| 312 | int scaleUnits = 0;
|
|---|
| 313 | zoom = 0;
|
|---|
| 314 | projection = 0;
|
|---|
| 315 | int currentHeight = 0;
|
|---|
| 316 | int currentWidth = 0;
|
|---|
| 317 | mapSource = "";
|
|---|
| 318 | string mapSeries = "";
|
|---|
| 319 | m_map3.GetMapDisplayEx(
|
|---|
| 320 | ref mapSource,
|
|---|
| 321 | ref scale,
|
|---|
| 322 | ref scaleUnits,
|
|---|
| 323 | ref mapSeries,
|
|---|
| 324 | ref currentLat,
|
|---|
| 325 | ref currentLon,
|
|---|
| 326 | ref rotation,
|
|---|
| 327 | ref zoom,
|
|---|
| 328 | ref projection);
|
|---|
| 329 |
|
|---|
| 330 | m_map.GetMapDimensions(ref currentHeight, ref currentWidth);
|
|---|
| 331 |
|
|---|
| 332 | //calculate the ratios to use in degrees per pixel
|
|---|
| 333 | double widthRatio = lonDiff / currentWidth;
|
|---|
| 334 | double heightRatio = latDiff / currentHeight;
|
|---|
| 335 | double resolutionDegreesPerPixel = Math.Max(heightRatio, widthRatio);
|
|---|
| 336 |
|
|---|
| 337 | //minimal resolution is 1/10 of a second per pixel
|
|---|
| 338 | double minResolution = 1.0 / 60.0 / 60.0 / 10.0;
|
|---|
| 339 | resolutionDegreesPerPixel = Math.Max(resolutionDegreesPerPixel, minResolution);
|
|---|
| 340 |
|
|---|
| 341 | scaleUtil = new MapScaleUtilClass();
|
|---|
| 342 | resolution = scaleUtil.ResolutionToScale(resolutionDegreesPerPixel, MAPSCALEUTILSERVERLib.MapScaleUnitsEnum.MAP_SCALE_ARC_DEGREES);
|
|---|
| 343 | }
|
|---|
| 344 |
|
|---|
| 345 | public void ScaleToExtents()
|
|---|
| 346 | {
|
|---|
| 347 | try
|
|---|
| 348 | {
|
|---|
| 349 | double centerLat, centerLon;
|
|---|
| 350 | double lonDiff = 0;
|
|---|
| 351 | double latDiff = 0;
|
|---|
| 352 | if (Tree.SelectedNode is FvDataTreeNode)
|
|---|
| 353 | {
|
|---|
| 354 | double westLon, eastLon, southLat, northLat;
|
|---|
| 355 | FvDataTreeNode node = Tree.SelectedNode as FvDataTreeNode;
|
|---|
| 356 | node.Center(out centerLat, out centerLon);
|
|---|
| 357 | node.Extent2D(out westLon, out southLat, out eastLon, out northLat);
|
|---|
| 358 | lonDiff = Math.Abs(westLon - eastLon);
|
|---|
| 359 | latDiff = Math.Abs(northLat - southLat);
|
|---|
| 360 | }
|
|---|
| 361 | else
|
|---|
| 362 | {
|
|---|
| 363 | return;
|
|---|
| 364 | }
|
|---|
| 365 |
|
|---|
| 366 | double rotation;
|
|---|
| 367 | int zoom;
|
|---|
| 368 | int projection;
|
|---|
| 369 | string mapSource;
|
|---|
| 370 | IMapScaleUtil scaleUtil;
|
|---|
| 371 | double resolution;
|
|---|
| 372 | CurrentMapSettings(lonDiff, latDiff, out rotation, out zoom, out projection, out mapSource, out scaleUtil, out resolution);
|
|---|
| 373 |
|
|---|
| 374 | string source = "Tiros";
|
|---|
| 375 | double scale = 1;
|
|---|
| 376 | int scaleUnits = (int)(MAPENGINELib.MapScaleUnitsEnum.MAP_SCALE_WORLD);
|
|---|
| 377 | string series = "";
|
|---|
| 378 |
|
|---|
| 379 | double bestDiff = double.MaxValue;
|
|---|
| 380 | MDSLib.IMapHandlersRowset rowset = new MDSLib.MapHandlersRowsetClass();
|
|---|
| 381 | object productsObj = rowset.SelectDistinctProducts();
|
|---|
| 382 | Array products = (productsObj as Array);
|
|---|
| 383 | foreach (object o in products)
|
|---|
| 384 | {
|
|---|
| 385 | string product = o as string;
|
|---|
| 386 |
|
|---|
| 387 | Array aScales;
|
|---|
| 388 | Array aScaleUnits;
|
|---|
| 389 | Array aMapSeries;
|
|---|
| 390 | int preferredIndex;
|
|---|
| 391 | double bestResolution;
|
|---|
| 392 | BestResolution(centerLat, centerLon,
|
|---|
| 393 | rotation, zoom, projection, product,
|
|---|
| 394 | scaleUtil, resolution,
|
|---|
| 395 | out aScales, out aScaleUnits, out aMapSeries,
|
|---|
| 396 | out preferredIndex, out bestResolution);
|
|---|
| 397 | double diff = Math.Abs(resolution - bestResolution);
|
|---|
| 398 | if (diff < bestDiff)
|
|---|
| 399 | {
|
|---|
| 400 | bestDiff = diff;
|
|---|
| 401 | source = product;
|
|---|
| 402 | scale = double.Parse(aScales.GetValue(preferredIndex).ToString());
|
|---|
| 403 | scaleUnits = int.Parse(aScaleUnits.GetValue(preferredIndex).ToString());
|
|---|
| 404 | series = aMapSeries.GetValue(preferredIndex).ToString();
|
|---|
| 405 | }
|
|---|
| 406 | }
|
|---|
| 407 |
|
|---|
| 408 | m_map3.SetMapDisplayEx(
|
|---|
| 409 | source,
|
|---|
| 410 | scale,
|
|---|
| 411 | scaleUnits,
|
|---|
| 412 | series,
|
|---|
| 413 | centerLat,
|
|---|
| 414 | centerLon,
|
|---|
| 415 | rotation,
|
|---|
| 416 | zoom,
|
|---|
| 417 | projection);
|
|---|
| 418 | }
|
|---|
| 419 | catch (Exception ex)
|
|---|
| 420 | {
|
|---|
| 421 | LoggingUtils.ReportError(ex);
|
|---|
| 422 | }
|
|---|
| 423 | }
|
|---|
| 424 |
|
|---|
| 425 | void ScaleToExtents_Click(object sender, EventArgs e)
|
|---|
| 426 | {
|
|---|
| 427 | ScaleToExtents();
|
|---|
| 428 | //hide the context menu
|
|---|
| 429 | SendKeys.SendWait("{ESC}");
|
|---|
| 430 | }
|
|---|
| 431 |
|
|---|
| 432 | public static void SetCheckNodeAndChildren(FvDataTreeNode parentNode, bool check)
|
|---|
| 433 | {
|
|---|
| 434 | parentNode.Checked = check;
|
|---|
| 435 | IUIState uiState = parentNode.Set as IUIState;
|
|---|
| 436 | if (uiState == null) uiState = parentNode.Source as IUIState;
|
|---|
| 437 | if (uiState != null) uiState.Visible = check;
|
|---|
| 438 | foreach (FvDataTreeNode node in parentNode.Nodes)
|
|---|
| 439 | SetCheckNodeAndChildren(node, check);
|
|---|
| 440 | }
|
|---|
| 441 |
|
|---|
| 442 | public static void SetCheckNodeAndParents(FvDataTreeNode childNode, bool check)
|
|---|
| 443 | {
|
|---|
| 444 | childNode.Checked = check;
|
|---|
| 445 | IUIState uiState = childNode.Set as IUIState;
|
|---|
| 446 | if (uiState == null) uiState = childNode.Source as IUIState;
|
|---|
| 447 | if (uiState != null) uiState.Visible = check;
|
|---|
| 448 | if (childNode.Parent != null)
|
|---|
| 449 | SetCheckNodeAndParents((FvDataTreeNode)childNode.Parent, check);
|
|---|
| 450 | }
|
|---|
| 451 |
|
|---|
| 452 | void Tree_AfterCheck(object sender, TreeViewEventArgs e)
|
|---|
| 453 | {
|
|---|
| 454 | Tree.AfterCheck -= m_clickHandler;
|
|---|
| 455 | if (!e.Node.Checked)
|
|---|
| 456 | {
|
|---|
| 457 | SetCheckNodeAndChildren((FvDataTreeNode)e.Node, false);
|
|---|
| 458 | }
|
|---|
| 459 | if (e.Node.Checked)
|
|---|
| 460 | {
|
|---|
| 461 | SetCheckNodeAndParents((FvDataTreeNode)e.Node, true);
|
|---|
| 462 | }
|
|---|
| 463 | Tree.AfterCheck += m_clickHandler;
|
|---|
| 464 | }
|
|---|
| 465 |
|
|---|
| 466 | void Tree_NodeMouseClick(object sender, System.Windows.Forms.TreeNodeMouseClickEventArgs e)
|
|---|
| 467 | {
|
|---|
| 468 | Tree.SelectedNode = e.Node;
|
|---|
| 469 | if (e.Button == MouseButtons.Right)
|
|---|
| 470 | {
|
|---|
| 471 | ContextMenu menu = new ContextMenu(m_contextMenu);
|
|---|
| 472 | menu.Show(Tree, e.Location);
|
|---|
| 473 | }
|
|---|
| 474 | }
|
|---|
| 475 |
|
|---|
| 476 | public void Unload(FvDataTreeNode dataSource)
|
|---|
| 477 | {
|
|---|
| 478 | Unload(dataSource, Tree.Nodes);
|
|---|
| 479 | }
|
|---|
| 480 |
|
|---|
| 481 | public bool Unload(FvDataTreeNode dataSource, TreeNodeCollection nodes)
|
|---|
| 482 | {
|
|---|
| 483 | foreach (TreeNode node in nodes)
|
|---|
| 484 | {
|
|---|
| 485 | if (node is FvDataTreeNode)
|
|---|
| 486 | {
|
|---|
| 487 | FvDataTreeNode dsNode = node as FvDataTreeNode;
|
|---|
| 488 | if (dsNode.Source == dataSource.Source && m_callbackHandlers.ContainsKey(dataSource.Source))
|
|---|
| 489 | {
|
|---|
| 490 | // unregister callback handler
|
|---|
| 491 | try
|
|---|
| 492 | {
|
|---|
| 493 | dataSource.Source.UnregisterForCallbacks(m_callbackHandlers[dataSource.Source]);
|
|---|
| 494 | m_callbackHandlers[dataSource.Source].Uninitialize();
|
|---|
| 495 | }
|
|---|
| 496 | catch (NotImplementedException)
|
|---|
| 497 | {
|
|---|
| 498 | //this means we didn't register it in the first place during adding - any reporting should
|
|---|
| 499 | //be done at that point. We have nothing to do here.
|
|---|
| 500 | }
|
|---|
| 501 | m_callbackHandlers.Remove(dataSource.Source);
|
|---|
| 502 | if (m_callbackHandlers.ContainsKey(dataSource.Source))
|
|---|
| 503 | {
|
|---|
| 504 | dataSource.Source.UnregisterForCallbacks(m_callbackHandlers[dataSource.Source]);
|
|---|
| 505 | m_callbackHandlers[dataSource.Source].Uninitialize();
|
|---|
| 506 | m_callbackHandlers.Remove(dataSource.Source);
|
|---|
| 507 | }
|
|---|
| 508 |
|
|---|
| 509 | // remove the node from the tree
|
|---|
| 510 | tree.Nodes.Remove(dsNode);
|
|---|
| 511 |
|
|---|
| 512 | return true;
|
|---|
| 513 | }
|
|---|
| 514 | //check children
|
|---|
| 515 | if (node.Nodes != null && Unload(dataSource, node.Nodes))
|
|---|
| 516 | {
|
|---|
| 517 | return true;
|
|---|
| 518 | }
|
|---|
| 519 | }
|
|---|
| 520 | }
|
|---|
| 521 | return false;
|
|---|
| 522 | }
|
|---|
| 523 | }
|
|---|
| 524 |
|
|---|
| 525 | public class FvDataTreeNode : TreeNode
|
|---|
| 526 | {
|
|---|
| 527 | private IFvDataSet m_set;
|
|---|
| 528 | private IFvDataSource m_source;
|
|---|
| 529 |
|
|---|
| 530 | public IFvDataSet Set
|
|---|
| 531 | {
|
|---|
| 532 | get { return m_set; }
|
|---|
| 533 | }
|
|---|
| 534 |
|
|---|
| 535 | public IFvDataSource Source
|
|---|
| 536 | {
|
|---|
| 537 | get { return m_source; }
|
|---|
| 538 | }
|
|---|
| 539 |
|
|---|
| 540 | public FvDataTreeNode(IFvDataSource dataSource) : base(dataSource.Name)
|
|---|
| 541 | {
|
|---|
| 542 | m_source = dataSource;
|
|---|
| 543 | Checked = true;
|
|---|
| 544 | ImageIndex = 0;
|
|---|
| 545 | SelectedImageIndex = ImageIndex;
|
|---|
| 546 |
|
|---|
| 547 | //set data set after setting ImageIndex & SelectedImageIndex to make sure these are correct
|
|---|
| 548 | IFvDataSet dataSet = m_source as IFvDataSet;
|
|---|
| 549 | if (dataSet != null) SetDataSet(dataSet);
|
|---|
| 550 |
|
|---|
| 551 | // set the check state
|
|---|
| 552 | IUIState uiState = m_source as IUIState;
|
|---|
| 553 | this.Checked = uiState != null ? uiState.Visible : true;
|
|---|
| 554 |
|
|---|
| 555 | // don't add any objects twice (some data sets and data sources are the same object)
|
|---|
| 556 | Dictionary<IntPtr, object> objectsAlreadyAdded = new Dictionary<IntPtr, object>();
|
|---|
| 557 |
|
|---|
| 558 | //add all data sources
|
|---|
| 559 | for (int i = 0; i < dataSource.DataSourceCount; i++)
|
|---|
| 560 | {
|
|---|
| 561 | IFvDataSource source = dataSource.GetDataSource(i);
|
|---|
| 562 | Add(source);
|
|---|
| 563 | // "For any one object, a specific query for the IUnknown interface on any of the object's interfaces must
|
|---|
| 564 | // always return the same pointer value." from http://msdn.microsoft.com/en-us/library/ms682521(VS.85).aspx
|
|---|
| 565 | IntPtr iunk = Marshal.GetIUnknownForObject(source);
|
|---|
| 566 | objectsAlreadyAdded[iunk] = null;
|
|---|
| 567 | Marshal.Release(iunk); // required after GetIUnknownForObject
|
|---|
| 568 | }
|
|---|
| 569 |
|
|---|
| 570 | for (int i = 0; i < dataSource.DataSetCount; i++)
|
|---|
| 571 | {
|
|---|
| 572 | IFvDataSet set = dataSource.GetDataSet(i);
|
|---|
| 573 | IntPtr iunk = Marshal.GetIUnknownForObject(set);
|
|---|
| 574 | if (!objectsAlreadyAdded.ContainsKey(iunk))
|
|---|
| 575 | Add(set);
|
|---|
| 576 | Marshal.Release(iunk); // required after GetIUnknownForObject
|
|---|
| 577 | }
|
|---|
| 578 |
|
|---|
| 579 | // set the expanded state
|
|---|
| 580 | if (uiState != null)
|
|---|
| 581 | if (uiState.Expanded) Expand(); else Collapse();
|
|---|
| 582 | else
|
|---|
| 583 | Expand();
|
|---|
| 584 | }
|
|---|
| 585 |
|
|---|
| 586 | public FvDataTreeNode(IFvDataSet dataSet) : base(dataSet.Name)
|
|---|
| 587 | {
|
|---|
| 588 | SetDataSet(dataSet);
|
|---|
| 589 | IUIState uiState = dataSet as IUIState;
|
|---|
| 590 | this.Checked = uiState != null ? uiState.Visible : true;
|
|---|
| 591 | }
|
|---|
| 592 |
|
|---|
| 593 | public void Add(IFvDataSet dataSet)
|
|---|
| 594 | {
|
|---|
| 595 | this.Nodes.Add(new FvDataTreeNode(dataSet));
|
|---|
| 596 | }
|
|---|
| 597 |
|
|---|
| 598 | public void Add(IFvDataSource dataSource)
|
|---|
| 599 | {
|
|---|
| 600 | FvDataTreeNode node = new FvDataTreeNode(dataSource);
|
|---|
| 601 | this.Nodes.Add(node);
|
|---|
| 602 | }
|
|---|
| 603 |
|
|---|
| 604 | public void Center(out double latitude, out double longitude)
|
|---|
| 605 | {
|
|---|
| 606 | double northLat;
|
|---|
| 607 | double southLat;
|
|---|
| 608 | double eastLon;
|
|---|
| 609 | double westLon;
|
|---|
| 610 |
|
|---|
| 611 | Extent2D(out westLon, out southLat, out eastLon, out northLat);
|
|---|
| 612 |
|
|---|
| 613 | double latDiff = northLat - southLat;
|
|---|
| 614 | latitude = southLat + (latDiff / 2);
|
|---|
| 615 |
|
|---|
| 616 | double lonDiff = eastLon - westLon;
|
|---|
| 617 | if (lonDiff < 0)
|
|---|
| 618 | {
|
|---|
| 619 | lonDiff = (180.0 - westLon) + (eastLon - -180.0);
|
|---|
| 620 | }
|
|---|
| 621 | longitude = westLon + (lonDiff / 2);
|
|---|
| 622 | while (longitude >= 180.0)
|
|---|
| 623 | {
|
|---|
| 624 | longitude -= 360.0;
|
|---|
| 625 | }
|
|---|
| 626 | }
|
|---|
| 627 |
|
|---|
| 628 | public void Extent2D(out double westLon, out double southLat, out double eastLon, out double northLat)
|
|---|
| 629 | {
|
|---|
| 630 | if (m_source != null)
|
|---|
| 631 | {
|
|---|
| 632 | m_source.Extent2D(out westLon, out southLat, out eastLon, out northLat);
|
|---|
| 633 | return;
|
|---|
| 634 | }
|
|---|
| 635 | else if (m_set != null)
|
|---|
| 636 | {
|
|---|
| 637 | m_set.Extent2D(out westLon, out southLat, out eastLon, out northLat);
|
|---|
| 638 | return;
|
|---|
| 639 | }
|
|---|
| 640 |
|
|---|
| 641 | //since either m_source or m_set must be valid, one of the above will work
|
|---|
| 642 | //but we have to assign something because the compiler doesn't realize that
|
|---|
| 643 | westLon = 0;
|
|---|
| 644 | eastLon = 0;
|
|---|
| 645 | northLat = 0;
|
|---|
| 646 | southLat = 0;
|
|---|
| 647 | }
|
|---|
| 648 |
|
|---|
| 649 | private void SetDataSet(IFvDataSet dataSet)
|
|---|
| 650 | {
|
|---|
| 651 | m_set = dataSet;
|
|---|
| 652 | ImageIndex = dataSet is IRasterDataSet ? 2 : 1;
|
|---|
| 653 | SelectedImageIndex = ImageIndex;
|
|---|
| 654 | }
|
|---|
| 655 | }
|
|---|
| 656 | }
|
|---|