[Mmclibrary-svn] SF.net SVN: mmclibrary: [4] MMCLib2/Nodes/ReportNode.cs
Brought to you by:
imjimmurphy,
kachalkov
From: <tig...@us...> - 2007-03-15 12:28:39
|
Revision: 4 http://svn.sourceforge.net/mmclibrary/?rev=4&view=rev Author: tigerharry Date: 2007-03-15 05:28:35 -0700 (Thu, 15 Mar 2007) Log Message: ----------- Binkle: added: support for sorting columns on header click Modified Paths: -------------- MMCLib2/Nodes/ReportNode.cs Modified: MMCLib2/Nodes/ReportNode.cs =================================================================== --- MMCLib2/Nodes/ReportNode.cs 2006-09-19 11:55:12 UTC (rev 3) +++ MMCLib2/Nodes/ReportNode.cs 2007-03-15 12:28:35 UTC (rev 4) @@ -2,6 +2,7 @@ using System.Runtime.InteropServices; using System.Text.RegularExpressions; using System.Collections; +using System.Collections.Generic; using System.Threading; using Ironring.MMC.Core; using Ironring.MMC.Nodes.NodeEvents; @@ -12,847 +13,909 @@ namespace Ironring.MMC.Nodes { - // TBD: overridable data binding methods to augment GetDisplayInfo - /// <summary> - /// Configures the resultview as a Listview control. - /// </summary> - public class ReportNode : BaseNode, IMMCSaneNode - { - ////////////////////////////////////////////////////////////////////// - // - // Private vars - // - #region - //Added by Alexander Kachalkov - /// <summary> - /// A cached reference to the MMC console - /// </summary> - private IConsole2 _console = null; - - // MAM: the filtersets that are active. - /// <summary> - /// The currently active filters. The keys are the columns (integer), the values - /// are filter expressions. The expressions are simply matched - /// by testing if they occur anywhere within the value. - /// </summary> - private Hashtable _filters = null; + // TBD: overridable data binding methods to augment GetDisplayInfo + /// <summary> + /// Configures the resultview as a Listview control. + /// </summary> + public class ReportNode : BaseNode, IMMCSaneNode + { + ////////////////////////////////////////////////////////////////////// + // + // Private vars + // + #region + //Added by Alexander Kachalkov + /// <summary> + /// A cached reference to the MMC console + /// </summary> + private IConsole2 _console = null; - private ResultViewItem[] _currentSelectedItems = null; - private ArrayList _items = new ArrayList(); - private ArrayList _columns = new ArrayList(); - #endregion + // MAM: the filtersets that are active. + /// <summary> + /// The currently active filters. The keys are the columns (integer), the values + /// are filter expressions. The expressions are simply matched + /// by testing if they occur anywhere within the value. + /// </summary> + private Hashtable _filters = null; - ////////////////////////////////////////////////////////////////////// - // - // Properties - // - #region - //Added by Alexander Kachalkov - /// <summary> - /// Return the cached member variable to get at MMC - /// </summary> - public IHeaderCtrl2 HeaderCtrl - { - get { return (IHeaderCtrl2)_console; } - } + private ResultViewItem[] _currentSelectedItems = null; + private ArrayList _items = new ArrayList(); + private ArrayList _columns = new ArrayList(); + #endregion - //Added by Alexander Kachalkov - /// <summary> - /// Return the cached member variable to get at MMC - /// </summary> - public IResultData ResultData - { - get { return (IResultData)_console; } - } + ////////////////////////////////////////////////////////////////////// + // + // Properties + // + #region + //Added by Alexander Kachalkov + /// <summary> + /// Return the cached member variable to get at MMC + /// </summary> + public IHeaderCtrl2 HeaderCtrl + { + get { return (IHeaderCtrl2)_console; } + } - /// <summary> - /// Get/set the resultview items. - /// </summary> - public virtual ArrayList Items - { - get {return _items;} - set { _items = value;} - } + //Added by Alexander Kachalkov + /// <summary> + /// Return the cached member variable to get at MMC + /// </summary> + public IResultData ResultData + { + get { return (IResultData)_console; } + } - /// <summary> - /// Get/set the columns for this view. Override for results. - /// </summary> - public virtual ArrayList Columns - { - get { return _columns; } - set { _columns = value;} - } - #endregion + /// <summary> + /// Get/set the resultview items. + /// </summary> + public virtual ArrayList Items + { + get { return _items; } + set { _items = value; } + } - ////////////////////////////////////////////////////////////////////// - // - // Constructors - // - #region /// <summary> - /// ctor takes the snapin to register with - /// </summary> - /// <param name="snapin"></param> - public ReportNode(SnapinBase snapin) : base(snapin) - { - } + /// Get/set the columns for this view. Override for results. + /// </summary> + public virtual ArrayList Columns + { + get { return _columns; } + set { _columns = value; } + } + #endregion - /// <summary> - /// ctor takes the snapin to register with - /// </summary> - /// <param name="snapin">Link back to the SnapinBase</param> - /// <param name="parentNode"></param> - public ReportNode(SnapinBase snapin, BaseNode parentNode) : base(snapin, parentNode) - { - } + ////////////////////////////////////////////////////////////////////// + // + // Constructors + // + #region + /// <summary> + /// ctor takes the snapin to register with + /// </summary> + /// <param name="snapin"></param> + public ReportNode(SnapinBase snapin) + : base(snapin) + { + } - protected internal ReportNode(SnapinBase snapin, String name, bool multiselect) : base(snapin) - { - base.DisplayName = name; - this.MultiSelectMode = multiselect; - } + /// <summary> + /// ctor takes the snapin to register with + /// </summary> + /// <param name="snapin">Link back to the SnapinBase</param> + /// <param name="parentNode"></param> + public ReportNode(SnapinBase snapin, BaseNode parentNode) + : base(snapin, parentNode) + { + } - public ReportNode(SnapinBase snapin, String name, String closedIco, String openIco) : base(snapin, name, closedIco, openIco) - { - } - #endregion - - #region ResultView handling - public override string GetResultViewType(ref int pViewOptions) - { - // Call the base version first and toggle the options later. - string returnValue = base.GetResultViewType(ref pViewOptions); - // Allow multiselect - if(MultiSelectMode) - pViewOptions |= (int)MMC_VIEW_OPTIONS.MULTISELECT; - return returnValue; - } + protected internal ReportNode(SnapinBase snapin, String name, bool multiselect) + : base(snapin) + { + base.DisplayName = name; + this.MultiSelectMode = multiselect; + } - /// <summary> - /// Get the ordinal index of the given item. This does a simple scan - /// on all items and returns the - /// </summary> - /// <param name="item">The item to look for.</param> - /// <returns>The ordinal index, or -1 if the item is not found.</returns> - public virtual int getIndex(ResultViewItem item) - { - ArrayList items = this.Items; - int retval = -1; - int max = items.Count; - for(int i=0; i<max; i++) - { - if(items[i] == item) - { - retval = i; - break; - } - } - return retval; - } - - /// <summary> - /// Check if the given item should be added according to the given filter criteria. - /// </summary> - public virtual bool CheckItem(ResultViewItem item) - { - // Short-circuit the check if there are no filters. - if(this._filters == null) - return true; + public ReportNode(SnapinBase snapin, String name, String closedIco, String openIco) + : base(snapin, name, closedIco, openIco) + { + } + #endregion - // Column-0 is special: it's the display name of the item. - ResultViewColumn col0 = (ResultViewColumn)this.Columns[0]; + #region ResultView handling + public override string GetResultViewType(ref int pViewOptions) + { + // Call the base version first and toggle the options later. + string returnValue = base.GetResultViewType(ref pViewOptions); + // Allow multiselect + if (MultiSelectMode) + pViewOptions |= (int)MMC_VIEW_OPTIONS.MULTISELECT; + return returnValue; + } - // There are filters defined. Column-0 is as it is the display name of the item. - foreach(int i in this._filters.Keys) - { - ResultViewColumn filterColumn = (ResultViewColumn)this.Columns[i]; - String data = (String)this._filters[i]; - String itemValue; - if(filterColumn.Equals(col0)) - itemValue = item.DisplayName; - else - itemValue = (String)item.Details[filterColumn]; + /// <summary> + /// Get the ordinal index of the given item. This does a simple scan + /// on all items and returns the + /// </summary> + /// <param name="item">The item to look for.</param> + /// <returns>The ordinal index, or -1 if the item is not found.</returns> + public virtual int getIndex(ResultViewItem item) + { + ArrayList items = this.Items; + int retval = -1; + int max = items.Count; + for (int i = 0; i < max; i++) + { + if (items[i] == item) + { + retval = i; + break; + } + } + return retval; + } - // When itemValue == null, the column could not be found. - // Assume that a null value does not equal an empty string. A - // null value means we will not filter on the column/item combination, - // an empty string will lead to filtering (and possible rejection of the item). - if(itemValue != null) - { - if(itemValue.IndexOf(data) == -1) - { - // Not found - return false; - } - } - } - return true; - } + /// <summary> + /// Check if the given item should be added according to the given filter criteria. + /// </summary> + public virtual bool CheckItem(ResultViewItem item) + { + // Short-circuit the check if there are no filters. + if (this._filters == null) + return true; - public override void GetDisplayInfo(ref RESULTDATAITEM resultDataItem) - { - bool bCallbase = true; + // Column-0 is special: it's the display name of the item. + ResultViewColumn col0 = (ResultViewColumn)this.Columns[0]; - // the "cell" data - int nRow = (resultDataItem.lParam >> 16) - 1; - int nCol = resultDataItem.nCol; + // There are filters defined. Column-0 is as it is the display name of the item. + foreach (int i in this._filters.Keys) + { + ResultViewColumn filterColumn = (ResultViewColumn)this.Columns[i]; + String data = (String)this._filters[i]; + String itemValue; + if (filterColumn.Equals(col0)) + itemValue = item.DisplayName; + else + itemValue = (String)item.Details[filterColumn]; - ArrayList myColumns = this.Columns; - ArrayList myItems = this.Items; + // When itemValue == null, the column could not be found. + // Assume that a null value does not equal an empty string. A + // null value means we will not filter on the column/item combination, + // an empty string will lead to filtering (and possible rejection of the item). + if (itemValue != null) + { + if (itemValue.IndexOf(data) == -1) + { + // Not found + return false; + } + } + } + return true; + } - string data = DisplayName; - int maxCol = myColumns.Count; - int maxItems = myItems.Count; + public override void GetDisplayInfo(ref RESULTDATAITEM resultDataItem) + { + bool bCallbase = true; - if ((resultDataItem.mask & (uint)RDI.STR) > 0) - { - if (nRow >= 0 && nRow < maxItems && nCol >= 0 && nCol < maxCol) - { - ResultViewItem ri = (ResultViewItem)myItems[nRow]; - if(nCol == 0) - { // get the display name: a special attribute - data = ri.DisplayName; - } - else - { - ResultViewColumn col = (ResultViewColumn)myColumns[nCol]; - data = (String)ri.GetDetail(col); - } - bCallbase = false; - } - resultDataItem.str = Marshal.StringToCoTaskMemUni(data); - } + // the "cell" data + int nRow = (resultDataItem.lParam >> 16) - 1; + int nCol = resultDataItem.nCol; - // the image - requires 2 images in the image list - // small - 0 - // large - 1 - if ((resultDataItem.mask & (uint)RDI.IMAGE) > 0) - { - if (nRow >= 0 && nRow < maxItems && nCol >= 0 && nCol < maxCol) - { - resultDataItem.nImage = GetResultViewImageIndex((ResultViewItem)myItems[nRow]); - bCallbase=false; - } - } - if (bCallbase) - base.GetDisplayInfo(ref resultDataItem); - } + ArrayList myColumns = this.Columns; + ArrayList myItems = this.Items; - /// <summary> - /// prepared for multiselect - /// </summary> - /// <param name="index"></param> - /// <returns></returns> - public virtual ResultViewItem[] GetCurrentSelected() - { - ArrayList retval = new ArrayList(); - IConsole2 console = Snapin.ResultViewConsole; - IResultData pResultData = console as IResultData; + string data = DisplayName; + int maxCol = myColumns.Count; + int maxItems = myItems.Count; - RESULTDATAITEM rdi; - int nIndex = -1; - int nIndexCookies = 0; + if ((resultDataItem.mask & (uint)RDI.STR) > 0) + { + if (nRow >= 0 && nRow < maxItems && nCol >= 0 && nCol < maxCol) + { + ResultViewItem ri = (ResultViewItem)myItems[nRow]; + if (nCol == 0) + { // get the display name: a special attribute + data = ri.DisplayName; + } + else + { + ResultViewColumn col = (ResultViewColumn)myColumns[nCol]; + data = (String)ri.GetDetail(col); + } + bCallbase = false; + } + resultDataItem.str = Marshal.StringToCoTaskMemUni(data); + } - // scope items are shown in the resultview too, ignore those - for(int i = 0 + NumChildren, max=this.Items.Count + NumChildren; i < max; i++) - { - try - { - rdi = new RESULTDATAITEM(); - - rdi.mask = 0x8; // RDI_STATE nState is valid - rdi.nIndex = nIndex; // nIndex == -1 to start at first item - rdi.nState = 0x002; // LVIS_SELECTED only interested in selected items + // the image - requires 2 images in the image list + // small - 0 + // large - 1 + if ((resultDataItem.mask & (uint)RDI.IMAGE) > 0) + { + if (nRow >= 0 && nRow < maxItems && nCol >= 0 && nCol < maxCol) + { + resultDataItem.nImage = GetResultViewImageIndex((ResultViewItem)myItems[nRow]); + bCallbase = false; + } + } + if (bCallbase) + base.GetDisplayInfo(ref resultDataItem); + } - // get next selected item - pResultData.GetNextItem(ref rdi); - if (rdi.nIndex != -1) - { - //rdi is the RESULTDATAITEM of a selected item. add its - //lParam to the pCookies array of the pMultiSelectDataObject data object - nIndexCookies++; - nIndex = rdi.nIndex; - retval.Add(Items[rdi.nIndex - NumChildren]); - } - } - catch(Exception) - { - // We can get out of index. Ignore it, it will break MMC when we don't catch. - // This seems to happen sometimes (deep within COM world, so no way that we can debug that). - } - } - return (ResultViewItem[])retval.ToArray(new ResultViewItem().GetType()); - } - #endregion - - ////////////////////////////////////////////////////////////////////// - // - // Selection Handling - // This is done by hand because the events did not propagate as we would like them too. - // - #region - /// <summary> - /// Called when a result item is selected. Sets the property-page flag. - /// </summary> - public override void OnSelectResult() - { - // clear the selected nodes - this.Snapin.RemoveSelectedNode(this); + /// <summary> + /// prepared for multiselect + /// </summary> + /// <param name="index"></param> + /// <returns></returns> + public virtual ResultViewItem[] GetCurrentSelected() + { + ArrayList retval = new ArrayList(); + IConsole2 console = Snapin.ResultViewConsole; + IResultData pResultData = console as IResultData; - System.Diagnostics.Debug.WriteLine("ReportNode::OnSelect"); - this._currentSelectedItems = GetCurrentSelected(); - bool havePropertyPage = false; - for(int i=0; i<this._currentSelectedItems.Length; i++) - { - this._currentSelectedItems[i].OnSelect(); - if(!havePropertyPage && this._currentSelectedItems[i].PropertyPages.Count != 0) - { - havePropertyPage = true; - } - } - - IConsoleVerb icv; - Snapin.ResultViewConsole.QueryConsoleVerb(out icv); + RESULTDATAITEM rdi; + int nIndex = -1; + int nIndexCookies = 0; - // See if we need to enable then property sheets item on the popup menu - if (havePropertyPage) - { - icv.SetVerbState(MMC_CONSOLE_VERB.PROPERTIES, MMC_BUTTON_STATE.ENABLED, 1); - System.Diagnostics.Debug.WriteLine("Properties enabled"); - } - else - { - icv.SetVerbState(MMC_CONSOLE_VERB.PROPERTIES, MMC_BUTTON_STATE.ENABLED, 0); - System.Diagnostics.Debug.WriteLine("Properties disabled"); - } - } + // scope items are shown in the resultview too, ignore those + for (int i = 0 + NumChildren, max = this.Items.Count + NumChildren; i < max; i++) + { + try + { + rdi = new RESULTDATAITEM(); - /// <summary> - /// Call when the an item is deselected. Deselects the old item. - /// </summary> - /// <remarks>Should this be done like this: it seems a bit slow.</remarks> - public override void OnDeselectResult() - { - System.Diagnostics.Debug.WriteLine("ReportNode::Deselect"); - // Get the new set of selected items. - Hashtable oldItems = new Hashtable(); - Hashtable newItems = new Hashtable(); + rdi.mask = 0x8; // RDI_STATE nState is valid + rdi.nIndex = nIndex; // nIndex == -1 to start at first item + rdi.nState = 0x002; // LVIS_SELECTED only interested in selected items - ResultViewItem[] items = GetCurrentSelected(); - if(items != null) - { - for(int i=0; i<items.Length; i++) - { - newItems.Add(items[i], null); - } - } - for(int i=0; i<this._currentSelectedItems.Length; i++) - { - oldItems.Add(this._currentSelectedItems[i], null); - } + // get next selected item + pResultData.GetNextItem(ref rdi); + if (rdi.nIndex != -1) + { + //rdi is the RESULTDATAITEM of a selected item. add its + //lParam to the pCookies array of the pMultiSelectDataObject data object + nIndexCookies++; + nIndex = rdi.nIndex; + retval.Add(Items[rdi.nIndex - NumChildren]); + } + } + catch (Exception) + { + // We can get out of index. Ignore it, it will break MMC when we don't catch. + // This seems to happen sometimes (deep within COM world, so no way that we can debug that). + } + } + return (ResultViewItem[])retval.ToArray(new ResultViewItem().GetType()); + } + #endregion - for(int i=0; i<items.Length; i++) - { - if(oldItems.ContainsKey(items[i])) - { - // It was selected, and is selected again - } - else - { - // It was not selected, but is selected now - ((ResultViewItem)items[i]).OnSelect(); - } - } + ////////////////////////////////////////////////////////////////////// + // + // Selection Handling + // This is done by hand because the events did not propagate as we would like them too. + // + #region + /// <summary> + /// Called when a result item is selected. Sets the property-page flag. + /// </summary> + public override void OnSelectResult() + { + // clear the selected nodes + this.Snapin.RemoveSelectedNode(this); - for(int i=0; i<this._currentSelectedItems.Length; i++) - { - if(newItems.ContainsKey(this._currentSelectedItems[i])) - { - // It was selected and is selected again - } - else - { - // It was selected, but is not selected now - this._currentSelectedItems[i].OnDeselect(); - } - } + System.Diagnostics.Debug.WriteLine("ReportNode::OnSelect"); + this._currentSelectedItems = GetCurrentSelected(); + bool havePropertyPage = false; + for (int i = 0; i < this._currentSelectedItems.Length; i++) + { + this._currentSelectedItems[i].OnSelect(); + if (!havePropertyPage && this._currentSelectedItems[i].PropertyPages.Count != 0) + { + havePropertyPage = true; + } + } - this._currentSelectedItems = items; - } - + IConsoleVerb icv; + Snapin.ResultViewConsole.QueryConsoleVerb(out icv); - /// <summary> - /// Filters should be cleared onm deselect - /// </summary> - public override void OnDeselectScope() - { - if(_filters !=null ) - this._filters.Clear(); - base.OnDeselectScope(); - } - #endregion + // See if we need to enable then property sheets item on the popup menu + if (havePropertyPage) + { + icv.SetVerbState(MMC_CONSOLE_VERB.PROPERTIES, MMC_BUTTON_STATE.ENABLED, 1); + System.Diagnostics.Debug.WriteLine("Properties enabled"); + } + else + { + icv.SetVerbState(MMC_CONSOLE_VERB.PROPERTIES, MMC_BUTTON_STATE.ENABLED, 0); + System.Diagnostics.Debug.WriteLine("Properties disabled"); + } + } - ////////////////////////////////////////////////////////////////////// - // - // PropertyPages handling for items - // - #region - /// <summary> - /// This function will create property sheet pages based - /// on the information stored in its m_propertyPages field. - /// It registers the property page along with the callback - /// functions. - /// </summary> - /// <param name="lpProvider"></param> - /// <param name="handle"></param> - public virtual void CreatePropertyPagesForItems(IPropertySheetCallback lpProvider, IntPtr handle) - { - ResultViewItem[] items = GetCurrentSelected(); - for(int i=0; i<items.Length; i++) - { - if(items[i].PropertyPages.Count > 0) - { - if (items[i].PropertySheet == null || items[i].PropertySheet.isClosed) - { - // We need to spin off a new thread for this. - // Why? - // For winforms forms to work correctly (including accelerators, etc) - // we need to use a winforms message pump. We can accomplish that - // by showing our form using Form.ShowDialog(). - // However, this blocks the thread's execution until the dialog - // is dismissed. We'll get around this by spinning off another thread - // to handle the form. - //ThreadPool.QueueUserWorkItem(new WaitCallback(CreatePropertySheetForItems), (object)items[i]); - if (PropertyPageSettings.Instance.ShowModalPropertySheets) - CreatePropertySheetForItems((object)items[i]); - else - ThreadPool.QueueUserWorkItem(new WaitCallback(CreatePropertySheetForItems), (object)items[i]); - } - else - { - items[i].PropertySheet.Activate(); - } - } - } - } + /// <summary> + /// Call when the an item is deselected. Deselects the old item. + /// </summary> + /// <remarks>Should this be done like this: it seems a bit slow.</remarks> + public override void OnDeselectResult() + { + System.Diagnostics.Debug.WriteLine("ReportNode::Deselect"); + // Get the new set of selected items. + Hashtable oldItems = new Hashtable(); + Hashtable newItems = new Hashtable(); - protected virtual void CreatePropertySheetForItems(object item) - { - ResultViewItem m_item = item as ResultViewItem; - m_item.PropertySheet = new PropertySheet(this); + ResultViewItem[] items = GetCurrentSelected(); + if (items != null) + { + for (int i = 0; i < items.Length; i++) + { + newItems.Add(items[i], null); + } + } + for (int i = 0; i < this._currentSelectedItems.Length; i++) + { + oldItems.Add(this._currentSelectedItems[i], null); + } - ArrayList pages = m_item.PropertyPages; + for (int i = 0; i < items.Length; i++) + { + if (oldItems.ContainsKey(items[i])) + { + // It was selected, and is selected again + } + else + { + // It was not selected, but is selected now + ((ResultViewItem)items[i]).OnSelect(); + } + } - foreach(PropertyPage page in pages) - { - m_item.PropertySheet.Pages.Add(page); - } + for (int i = 0; i < this._currentSelectedItems.Length; i++) + { + if (newItems.ContainsKey(this._currentSelectedItems[i])) + { + // It was selected and is selected again + } + else + { + // It was selected, but is not selected now + this._currentSelectedItems[i].OnDeselect(); + } + } - m_item.PropertySheet.Text = m_item.DisplayName + " " + SnapinBase.Translate("Properties"); + this._currentSelectedItems = items; + } - IntPtr ctx = new System.IntPtr(); - if(HasThemes()) - ctx = TurnOnThemes(); + /// <summary> + /// Filters should be cleared on deselect + /// </summary> + public override void OnDeselectScope() + { + if (_filters != null) + this._filters.Clear(); + base.OnDeselectScope(); + } + + /// <summary> + /// Sort items on column click + /// Added by Binkle 15.03.07 + /// </summary> + public override void OnColumnClick(int nCol, bool bAscending) + { + base.OnColumnClick(nCol, bAscending); + + this._items.Sort(new ResultViewItemComparer(bAscending, (ResultViewColumn)this.Columns[nCol], nCol)); + } + #endregion + + ////////////////////////////////////////////////////////////////////// + // + // PropertyPages handling for items + // + #region + /// <summary> + /// This function will create property sheet pages based + /// on the information stored in its m_propertyPages field. + /// It registers the property page along with the callback + /// functions. + /// </summary> + /// <param name="lpProvider"></param> + /// <param name="handle"></param> + public virtual void CreatePropertyPagesForItems(IPropertySheetCallback lpProvider, IntPtr handle) + { + ResultViewItem[] items = GetCurrentSelected(); + for (int i = 0; i < items.Length; i++) + { + if (items[i].PropertyPages.Count > 0) + { + if (items[i].PropertySheet == null || items[i].PropertySheet.isClosed) + { + // We need to spin off a new thread for this. + // Why? + // For winforms forms to work correctly (including accelerators, etc) + // we need to use a winforms message pump. We can accomplish that + // by showing our form using Form.ShowDialog(). + // However, this blocks the thread's execution until the dialog + // is dismissed. We'll get around this by spinning off another thread + // to handle the form. + //ThreadPool.QueueUserWorkItem(new WaitCallback(CreatePropertySheetForItems), (object)items[i]); + if (PropertyPageSettings.Instance.ShowModalPropertySheets) + CreatePropertySheetForItems((object)items[i]); + else + ThreadPool.QueueUserWorkItem(new WaitCallback(CreatePropertySheetForItems), (object)items[i]); + + } + else + { + items[i].PropertySheet.Activate(); + } + } + } + } + + protected virtual void CreatePropertySheetForItems(object item) + { + ResultViewItem m_item = item as ResultViewItem; + m_item.PropertySheet = new PropertySheet(this); + + ArrayList pages = m_item.PropertyPages; + + foreach (PropertyPage page in pages) + { + m_item.PropertySheet.Pages.Add(page); + } + + m_item.PropertySheet.Text = m_item.DisplayName + " " + SnapinBase.Translate("Properties"); + + IntPtr ctx = new System.IntPtr(); + if (HasThemes()) + ctx = TurnOnThemes(); + m_item.PropertySheet.ShowDialog(); - foreach (PropertyPage page in pages) - if(page.Applied) - Snapin.Invoke(((PropertyPageBase)page.MainControl).Action); + foreach (PropertyPage page in pages) + if (page.Applied) + Snapin.Invoke(((PropertyPageBase)page.MainControl).Action); - if(HasThemes()) - ReleaseActCtx(ctx); + if (HasThemes()) + ReleaseActCtx(ctx); - m_item.PropertySheet.Pages.Clear( ); - m_item.PropertySheet = null; - } + m_item.PropertySheet.Pages.Clear(); + m_item.PropertySheet = null; + } - /// <summary> - /// Returns true when an item has a property page. - /// </summary> - /// <returns>True when the item has a property page, false otherwise.</returns> - public virtual bool ItemsHavePropertyPages() - { - bool havePropertyPage = false; - if(_currentSelectedItems != null) - { - for(int i=0; i<this._currentSelectedItems.Length; i++) - { - if(this._currentSelectedItems[i].PropertyPages.Count > 0) - { - havePropertyPage = true; - } - } - } - return havePropertyPage; - } - #endregion + /// <summary> + /// Returns true when an item has a property page. + /// </summary> + /// <returns>True when the item has a property page, false otherwise.</returns> + public virtual bool ItemsHavePropertyPages() + { + bool havePropertyPage = false; + if (_currentSelectedItems != null) + { + for (int i = 0; i < this._currentSelectedItems.Length; i++) + { + if (this._currentSelectedItems[i].PropertyPages.Count > 0) + { + havePropertyPage = true; + } + } + } + return havePropertyPage; + } + #endregion - /// <summary> - /// BaseNode override to populate the treeview control - /// with column information and data - /// </summary> - public override void OnResultShow() - { - _console = Snapin.ResultViewConsole; + /// <summary> + /// BaseNode override to populate the treeview control + /// with column information and data + /// </summary> + public override void OnResultShow() + { + _console = Snapin.ResultViewConsole; - // setup the header for the columns we want to show - OnShowHeader(HeaderCtrl); - - // add the actual data items - OnShowData(ResultData); + // setup the header for the columns we want to show + OnShowHeader(HeaderCtrl); - ResultData.SetViewMode(this.GetViewType()); + // add the actual data items + OnShowData(ResultData); - base.OnResultShow(); - } + ResultData.SetViewMode(this.GetViewType()); - /// <summary> - /// Overrideable method to get the actual type of view for this report-node. - /// Return one of the ViewMode enum. values. - /// </summary> - /// <returns></returns> - public virtual int GetViewType() { - return (int)ViewMode.Report; - } + base.OnResultShow(); + } - //////////////////////////////////////////////////////////////////// - // - // Helper methods - // - #region - public virtual void OnShowHeader(IHeaderCtrl2 header) - { - int idx = 0; - foreach(ResultViewColumn col in this.Columns) - { - header.InsertColumn(idx, col.ColumnName, col.Format, col.Width); - idx++; - } - } + /// <summary> + /// Overrideable method to get the actual type of view for this report-node. + /// Return one of the ViewMode enum. values. + /// </summary> + /// <returns></returns> + public virtual int GetViewType() + { + return (int)ViewMode.Report; + } - public virtual void OnShowData(IResultData resultData) - { - RESULTDATAITEM rdi = new RESULTDATAITEM(); - int nRow = 1; - ArrayList myItems = this.Items; - - int max = myItems.Count; - for(nRow = 1; nRow <=max; nRow++) - { - if(CheckItem((ResultViewItem)myItems[nRow - 1])) - { - // Each item has a String, an Image and the LPARAM field should be kept as our user object. - rdi.mask = (uint)RDI.STR | (uint)RDI.IMAGE | (uint)RDI.PARAM; + //////////////////////////////////////////////////////////////////// + // + // Helper methods + // + #region + public virtual void OnShowHeader(IHeaderCtrl2 header) + { + int idx = 0; + foreach (ResultViewColumn col in this.Columns) + { + header.InsertColumn(idx, col.ColumnName, col.Format, col.Width); + idx++; + } + } - // TBD: what image? - rdi.nImage = -1; - rdi.str = (IntPtr)(-1); // callback for names - rdi.nCol = 0; + public virtual void OnShowData(IResultData resultData) + { + RESULTDATAITEM rdi = new RESULTDATAITEM(); + int nRow = 1; + ArrayList myItems = this.Items; - // The low word contains the cookie for the node, while the high word - // contains the row number + 1 we're inserting - rdi.lParam = Cookie | (nRow << 16); - resultData.InsertItem(ref rdi); - ((ResultViewItem)myItems[nRow - 1]).ItemID = (uint)rdi.itemID; - } - } - } - - /// <summary> - /// Overridable helper method to UpdateItem - /// </summary> - /// <param name="lParam"></param> - public virtual void UpdateItem(int lParam) { - uint pItemID; - //Find ItemID - ResultData.FindItemByLParam(lParam, out pItemID); - ResultData.UpdateItem(pItemID); - } + int max = myItems.Count; + for (nRow = 1; nRow <= max; nRow++) + { + if (CheckItem((ResultViewItem)myItems[nRow - 1])) + { + // Each item has a String, an Image and the LPARAM field should be kept as our user object. + rdi.mask = (uint)RDI.STR | (uint)RDI.IMAGE | (uint)RDI.PARAM; - /// <summary> - /// Overridable helper method to DeleteItem - /// </summary> - /// <param name="lParam"></param> - public virtual void DeleteItem(int lParam) { - uint pItemID; - //Find ItemID - ResultData.FindItemByLParam(lParam, out pItemID); - ResultData.DeleteItem(pItemID, 0); - } + // TBD: what image? + rdi.nImage = -1; + rdi.str = (IntPtr)(-1); // callback for names + rdi.nCol = 0; - /// <summary> - /// Overridable helper method to GetItem - /// </summary> - /// <param name="ResultDataItem"></param> - /// <param name="pItemID"></param> - public virtual void GetItem(out RESULTDATAITEM resultDataItem, uint pItemID) { - RESULTDATAITEM rdi = new RESULTDATAITEM(); + // The low word contains the cookie for the node, while the high word + // contains the row number + 1 we're inserting + rdi.lParam = Cookie | (nRow << 16); + resultData.InsertItem(ref rdi); + ((ResultViewItem)myItems[nRow - 1]).ItemID = (uint)rdi.itemID; + } + } + } - rdi.mask = (uint)RDI.STR; // STR is valid - rdi.itemID = (int)pItemID; - rdi.nCol = 0; + /// <summary> + /// Overridable helper method to UpdateItem + /// </summary> + /// <param name="lParam"></param> + public virtual void UpdateItem(int lParam) + { + uint pItemID; + //Find ItemID + ResultData.FindItemByLParam(lParam, out pItemID); + ResultData.UpdateItem(pItemID); + } - ResultData.GetItem(ref rdi); - - resultDataItem = rdi; - } + /// <summary> + /// Overridable helper method to DeleteItem + /// </summary> + /// <param name="lParam"></param> + public virtual void DeleteItem(int lParam) + { + uint pItemID; + //Find ItemID + ResultData.FindItemByLParam(lParam, out pItemID); + ResultData.DeleteItem(pItemID, 0); + } + /// <summary> + /// Overridable helper method to GetItem + /// </summary> + /// <param name="ResultDataItem"></param> + /// <param name="pItemID"></param> + public virtual void GetItem(out RESULTDATAITEM resultDataItem, uint pItemID) + { + RESULTDATAITEM rdi = new RESULTDATAITEM(); - /// <summary> - /// Overridable helper method to SelectItem - /// </summary> - /// <param name="nRow"></param> - public virtual void SelectItem(int nRow) - { - int lParam = GetItemLParam(nRow); - uint pItemID; + rdi.mask = (uint)RDI.STR; // STR is valid + rdi.itemID = (int)pItemID; + rdi.nCol = 0; - //Find ItemID - ResultData.FindItemByLParam(lParam, out pItemID); + ResultData.GetItem(ref rdi); - //ResultData.SetItem(ref rdi); - ResultData.ModifyItemState(0, pItemID, (uint)LVIS.SELECTED | (uint)LVIS.FOCUSED, 0); - } + resultDataItem = rdi; + } - /// <summary> - /// Overridable helper method to ClearSelection - /// </summary> - public virtual void ClearSelection() - { - ResultViewItem[] rvi = GetCurrentSelected(); - // FIXME: not tested - for(int i=0;i<rvi.Length;i++) - ResultData.ModifyItemState(i,rvi[i].ItemID, 0, (uint)LVIS.SELECTED | (uint)LVIS.FOCUSED); - } + /// <summary> + /// Overridable helper method to SelectItem + /// </summary> + /// <param name="nRow"></param> + public virtual void SelectItem(int nRow) + { + int lParam = GetItemLParam(nRow); + uint pItemID; - /// <summary> - /// Overridable helper method to Set - /// </summary> - /// <param name="nRow"></param> - public virtual void SetFocus(int nRow) - { - int lParam = GetItemLParam(nRow); - uint pItemID; + //Find ItemID + ResultData.FindItemByLParam(lParam, out pItemID); - //Find ItemID - ResultData.FindItemByLParam(lParam, out pItemID); + //ResultData.SetItem(ref rdi); + ResultData.ModifyItemState(0, pItemID, (uint)LVIS.SELECTED | (uint)LVIS.FOCUSED, 0); + } - RESULTDATAITEM rdi = new RESULTDATAITEM(); - rdi.itemID = (int)pItemID; - rdi.mask = (uint)RDI.STATE; - rdi.nState = (uint)LVIS.SELECTED; // select the item - rdi.nCol = 0; + /// <summary> + /// Overridable helper method to ClearSelection + /// </summary> + public virtual void ClearSelection() + { + ResultViewItem[] rvi = GetCurrentSelected(); - ResultData.SetItem(ref rdi); - } + // FIXME: not tested + for (int i = 0; i < rvi.Length; i++) + ResultData.ModifyItemState(i, rvi[i].ItemID, 0, (uint)LVIS.SELECTED | (uint)LVIS.FOCUSED); + } - /// <summary> - /// helper method to get item row ID by lParam - /// </summary> - /// <param name="lParam"></param> - public virtual int GetTableRowID(int lParam) { - return (lParam >> 16) - 1; - } - /// <summary> - /// helper method to get item lParam by nRow - /// The low word contains the cookie for the node, while the high word - /// contains the row number + 1 we're inserting - /// </summary> - /// <param name="nRow"></param> - public virtual int GetItemLParam(int nRow) { - return Cookie | (nRow << 16); - } - #endregion + /// <summary> + /// Overridable helper method to Set + /// </summary> + /// <param name="nRow"></param> + public virtual void SetFocus(int nRow) + { + int lParam = GetItemLParam(nRow); + uint pItemID; - ////////////////////////////////////////////////////////////// - // - // Filtering implementation - // - #region Filtering + //Find ItemID + ResultData.FindItemByLParam(lParam, out pItemID); - // MAM: override the filter-event and do something (only called when the - // view-mode is also filtered). - /// <summary> - /// When we receive a filter event, we construct a full set of filters per column. - /// </summary> - /// <param name="code">The filter-change operator.</param> - /// <param name="col">The column for which the change is.</param> - public override void OnFilterChange(MMC_FILTER_CHANGE_CODE code, int col) - { - switch(code) - { - case MMC_FILTER_CHANGE_CODE.MFCC_DISABLE: - this._filters = null; - break; - case MMC_FILTER_CHANGE_CODE.MFCC_ENABLE: - // ignore - break; - case MMC_FILTER_CHANGE_CODE.MFCC_VALUE_CHANGE: - - try - { - // COM magic. - int bufLen = 1000; - string strData = GetColumnFilter(col, bufLen); - - // Get the column object and set the string - if(this._filters == null) - this._filters = new Hashtable(); - - // Huh? We get a string back: instead of a null-ptr or zero-terminated string - // we get some strange characters. Assume that if we get a really large string an - // empty string is meant. Probably some funky interop is needed to get this - // correct in microsoft parlance. - // TODO: get this verified/looked at by some COM guru. - if (!Regex.IsMatch(strData, @"\w") || strData.Length >= (bufLen / 2)) - this._filters.Remove(col); - else - this._filters[col] = strData; - - // Performance: unset the filter object when no filters are active. - if(this._filters.Count == 0) - this._filters = null; + RESULTDATAITEM rdi = new RESULTDATAITEM(); + rdi.itemID = (int)pItemID; + rdi.mask = (uint)RDI.STATE; + rdi.nState = (uint)LVIS.SELECTED; // select the item + rdi.nCol = 0; - // Do a forced refresh of all items. - RefreshResultConsole(); - } - catch(Exception e) - { - System.Diagnostics.Debug.WriteLine(e.Message); - ceh.OnThreadException(this, new ThreadExceptionEventArgs(e)); - } - break; - } - base.OnFilterChange(code, col); - } + ResultData.SetItem(ref rdi); + } - //Added by Alexande Kachalkov - /// <summary> - /// Overridable helper method to GetColumnFilter - /// </summary> - /// <param name="col">Filter column</param> - /// <param name="bufLen">Buffer length</param> - /// <returns>string</returns> - public virtual string GetColumnFilter(int col, int bufLen) - { - int retval = 0; - MMC_FILTERDATA data = new MMC_FILTERDATA(); - - try - { - uint type = 0; - // Some arbitrary buffer length. - data.pszText = IntPtr.Zero; - - // COM magic. - data.pszText = Marshal.AllocCoTaskMem(bufLen); - data.cchTextMax = bufLen; - - retval = HeaderCtrl.GetColumnFilter((uint)col, ref type, ref data); - string strData = Marshal.PtrToStringAuto(data.pszText); // the size doesn't change?, data.cchTextMax); - System.Diagnostics.Debug.WriteLine("Got: " + strData + " for column: " + col + " Length of string: " + strData.Length); - - return strData; - } - catch(Exception e) - { - System.Diagnostics.Debug.WriteLine(e.Message); - //throw e; - ceh.OnThreadException(this, new ThreadExceptionEventArgs(e)); - } - finally - { - if(! data.pszText.Equals(System.IntPtr.Zero)) - { - Marshal.FreeCoTaskMem(data.pszText); - } - } - return null; - } - - //Added by Alexande Kachalkov - /// <summary> - /// Overridable helper method to SetColumnFilter - /// </summary> - /// <param name="col">Filter column</param> - /// <param name="type">Filter type</param> - /// <param name="text">Filter text</param> - /// <returns></returns> - public virtual int SetColumnFilter(int col, MMC_FILTER_TYPE type, string text) - { - int retval = 0; - MMC_FILTERDATA2 data = new MMC_FILTERDATA2(); - - try - { - data.pszText = text; - - retval = HeaderCtrl.SetColumnFilter((uint)col, (uint)type, data); - } - catch(Exception e) - { - System.Diagnostics.Debug.WriteLine(e.Message); - //throw e; - ceh.OnThreadException(this, new ThreadExceptionEventArgs(e)); - } - - return retval; - } + /// <summary> + /// helper method to get item row ID by lParam + /// </summary> + /// <param name="lParam"></param> + public virtual int GetTableRowID(int lParam) + { + return (lParam >> 16) - 1; + } + /// <summary> + /// helper method to get item lParam by nRow + /// The low word contains the cookie for the node, while the high word + /// contains the row number + 1 we're inserting + /// </summary> + /// <param name="nRow"></param> + public virtual int GetItemLParam(int nRow) + { + return Cookie | (nRow << 16); + } + #endregion - #endregion + ////////////////////////////////////////////////////////////// + // + // Filtering implementation + // + #region Filtering - /// <summary> - /// Refreshes the ResultConsole - /// - /// thanks too Arunjeet Singh for the reselecting idea - /// </summary> - public virtual void RefreshResultConsole() - { - if(GetViewType() != (int)ViewMode.Filtered || this._filters == null) - Snapin.SelectScopeNode(this); - else - ResetResultViewConsole(); - } + // MAM: override the filter-event and do something (only called when the + // view-mode is also filtered). + /// <summary> + /// When we receive a filter event, we construct a full set of filters per column. + /// </summary> + /// <param name="code">The filter-change operator.</param> + /// <param name="col">The column for which the change is.</param> + public override void OnFilterChange(MMC_FILTER_CHANGE_CODE code, int col) + { + switch (code) + { + case MMC_FILTER_CHANGE_CODE.MFCC_DISABLE: + this._filters = null; + break; + case MMC_FILTER_CHANGE_CODE.MFCC_ENABLE: + // ignore + break; + case MMC_FILTER_CHANGE_CODE.MFCC_VALUE_CHANGE: - /// <summary> - /// Remove all items from the view and forces a refresh. - /// </summary> - private void ResetResultViewConsole() - { - try - { - IConsole2 console = base.Snapin.ResultViewConsole; - if(console != null) - { - // add the actual data items - IResultData rdata = console as IResultData; - if(rdata != null) - { - rdata.DeleteAllRsltItems(); - this.OnShowData(rdata); - } - else - { - System.Diagnostics.Debug.WriteLine("Rdata cannot be cast"); - } - } - else - { - System.Diagnostics.Debug.WriteLine("Cannot find console"); - } - } - catch(Exception e) - { - System.Diagnostics.Debug.WriteLine("Aaargh: " + e); - ceh.OnThreadException(this, new ThreadExceptionEventArgs(e)); - } - } + try + { + // COM magic. + int bufLen = 1000; + string strData = GetColumnFilter(col, bufLen); + // Get the column object and set the string + if (this._filters == null) + this._filters = new Hashtable(); - } + // Huh? We get a string back: instead of a null-ptr or zero-terminated string + // we get some strange characters. Assume that if we get a really large string an + // empty string is meant. Probably some funky interop is needed to get this + // correct in microsoft parlance. + // TODO: get this verified/looked at by some COM guru. + if (!Regex.IsMatch(strData, @"\w") || strData.Length >= (bufLen / 2)) + this._filters.Remove(col); + else + this._filters[col] = strData; + // Performance: unset the filter object when no filters are active. + if (this._filters.Count == 0) + this._filters = null; + // Do a forced refresh of all items. + RefreshResultConsole(); + } + catch (Exception e) + { + System.Diagnostics.Debug.WriteLine(e.Message); + ceh.OnThreadException(this, new ThreadExceptionEventArgs(e)); + } + break; + } + base.OnFilterChange(code, col); + } + + //Added by Alexande Kachalkov + /// <summary> + /// Overridable helper method to GetColumnFilter + /// </summary> + /// <param name="col">Filter column</param> + /// <param name="bufLen">Buffer length</param> + /// <returns>string</returns> + public virtual string GetColumnFilter(int col, int bufLen) + { + int retval = 0; + MMC_FILTERDATA data = new MMC_FILTERDATA(); + + try + { + uint type = 0; + // Some arbitrary buffer length. + data.pszText = IntPtr.Zero; + + // COM magic. + data.pszText = Marshal.AllocCoTaskMem(bufLen); + data.cchTextMax = bufLen; + + retval = HeaderCtrl.GetColumnFilter((uint)col, ref type, ref data); + string strData = Marshal.PtrToStringAuto(data.pszText); // the size doesn't change?, data.cchTextMax); + System.Diagnostics.Debug.WriteLine("Got: " + strData + " for column: " + col + " Length of string: " + strData.Length); + + return strData; + } + catch (Exception e) + { + System.Diagnostics.Debug.WriteLine(e.Message); + //throw e; + ceh.OnThreadException(this, new ThreadExceptionEventArgs(e)); + } + finally + { + if (!data.pszText.Equals(System.IntPtr.Zero)) + { + Marshal.FreeCoTaskMem(data.pszText); + } + } + return null; + } + + //Added by Alexande Kachalkov + /// <summary> + /// Overridable helper method to SetColumnFilter + /// </summary> + /// <param name="col">Filter column</param> + /// <param name="type">Filter type</param> + /// <param name="text">Filter text</param> + /// <returns></returns> + public virtual int SetColumnFilter(int col, MMC_FILTER_TYPE type, string text) + { + int retval = 0; + MMC_FILTERDATA2 data = new MMC_FILTERDATA2(); + + try + { + data.pszText = text; + + retval = HeaderCtrl.SetColumnFilter((uint)col, (uint)type, data); + } + catch (Exception e) + { + System.Diagnostics.Debug.WriteLine(e.Message); + //throw e; + ceh.OnThreadException(this, new ThreadExceptionEventArgs(e)); + } + + return retval; + } + + #endregion + + /// <summary> + /// Refreshes the ResultConsole + /// + /// thanks too Arunjeet Singh for the reselecting idea + /// </summary> + public virtual void RefreshResultConsole() + { + if (GetViewType() != (int)ViewMode.Filtered || this._filters == null) + Snapin.SelectScopeNode(this); + else + ResetResultViewConsole(); + } + + /// <summary> + /// Remove all items from the view and forces a refresh. + /// </summary> + private void ResetResultViewConsole() + { + try + { + IConsole2 console = base.Snapin.ResultViewConsole; + if (console != null) + { + // add the actual data items + IResultData rdata = console as IResultData; + if (rdata != null) + { + rdata.DeleteAllRsltItems(); + this.OnShowData(rdata); + } + else + { + System.Diagnostics.Debug.WriteLine("Rdata cannot be cast"); + } + } + else + { + System.Diagnostics.Debug.WriteLine("Cannot find console"); + } + } + catch (Exception e) + { + System.Diagnostics.Debug.WriteLine("Aaargh: " + e); + ceh.OnThreadException(this, new ThreadExceptionEventArgs(e)); + } + } + + + } + + /// <summary> + /// Comparer for sorting ResultViewItems on clicking on header columns + /// Added by Binkle 15.03.07 + /// </summary> + public class ResultViewItemComparer : IComparer + { + private ResultViewColumn m_ColToSort; + private int m_nCol; + private bool m_Ascending; + + public ResultViewItemComparer(bool bAscending, ResultViewColumn Col, int nCol) + { + this.m_ColToSort = Col; + this.m_nCol = nCol; + this.m_Ascending = bAscending; + } + + #region IComparer Members + + public int Compare(object x, object y) + { + string strx; + string stry; + if (m_nCol == 0) // colunm 0 is not not a detail in a ResultViewItem + { + strx = ((ResultViewItem)x).DisplayName; + stry = ((ResultViewItem)y).DisplayName; + } + else + { + strx = ((ResultViewItem)x).GetDetail(m_ColToSort); + stry = ((ResultViewItem)y).GetDetail(m_ColToSort); + } + + return m_Ascending ? strx.CompareTo(stry) : stry.CompareTo(strx); + } + + #endregion + + + } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |