root/FalconView/trunk/public/Plugins/Overlays/GeodataOverlayServer/DataSourceTree.cs @ 2267

Revision 2267, 23.3 KB (checked in by JO94, 6 months ago)

tree now honors <open> tag in KML

Line 
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
19using FvDataSourcesLib;
20using fvw;
21using MAPENGINELib;
22using MAPSCALEUTILSERVERLib;
23
24using Microsoft.Win32;
25using SharedDotNetUtils;
26
27using System;
28using System.Collections.Generic;
29using System.ComponentModel;
30using System.Drawing;
31using System.Data;
32using System.Text;
33using System.Windows.Forms;
34using System.Runtime.InteropServices;
35
36namespace 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}
Note: See TracBrowser for help on using the browser.