2013-06-24 13:41:48 +02:00
/ * Copyright ( c ) Citrix Systems Inc .
* All rights reserved .
*
* Redistribution and use in source and binary forms ,
* with or without modification , are permitted provided
* that the following conditions are met :
*
* * Redistributions of source code must retain the above
* copyright notice , this list of conditions and the
* following disclaimer .
* * Redistributions in binary form must reproduce the above
* copyright notice , this list of conditions and the
* following disclaimer in the documentation and / or other
* materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES ,
* INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
* SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING ,
* BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ,
* WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING
* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
* /
using System ;
using System.Collections.Generic ;
2013-07-01 17:59:42 +02:00
using System.Linq ;
2013-06-24 13:41:48 +02:00
using System.Windows.Forms ;
using XenAdmin.Controls ;
2013-08-26 12:42:32 +02:00
using XenAdmin.Controls.MainWindowControls ;
2013-06-24 13:41:48 +02:00
using XenAdmin.Model ;
using XenAPI ;
using XenAdmin.XenSearch ;
using XenAdmin.Core ;
using System.Drawing ;
namespace XenAdmin
{
internal class MainWindowTreeBuilder
{
private readonly FlickerFreeTreeView _treeView ;
private readonly Color _treeViewForeColor ;
private readonly Color _treeViewBackColor ;
private object _highlightedDragTarget ;
private string _lastSearchText = string . Empty ;
2013-08-26 12:42:32 +02:00
private NavigationPane . NavigationMode _lastSearchMode ;
2013-10-08 11:17:57 +02:00
private readonly List < VirtualTreeNode . PersistenceInfo > _infraViewExpanded = new List < VirtualTreeNode . PersistenceInfo > ( ) ;
private readonly List < VirtualTreeNode . PersistenceInfo > _objectViewExpanded = new List < VirtualTreeNode . PersistenceInfo > ( ) ;
2013-08-26 14:08:23 +02:00
private readonly List < VirtualTreeNode . PersistenceInfo > _tagsViewExpanded = new List < VirtualTreeNode . PersistenceInfo > ( ) ;
private readonly List < VirtualTreeNode . PersistenceInfo > _foldersViewExpanded = new List < VirtualTreeNode . PersistenceInfo > ( ) ;
private readonly List < VirtualTreeNode . PersistenceInfo > _fieldsViewExpanded = new List < VirtualTreeNode . PersistenceInfo > ( ) ;
private readonly List < VirtualTreeNode . PersistenceInfo > _vappsViewExpanded = new List < VirtualTreeNode . PersistenceInfo > ( ) ;
2013-06-24 13:41:48 +02:00
private bool _rootExpanded ;
2013-10-08 11:17:57 +02:00
private readonly OrganizationViewFields viewFields = new OrganizationViewFields ( ) ;
private readonly OrganizationViewFolders viewFolders = new OrganizationViewFolders ( ) ;
private readonly OrganizationViewTags viewTags = new OrganizationViewTags ( ) ;
private readonly OrganizationViewObjects viewObjects = new OrganizationViewObjects ( ) ;
private readonly OrganizationViewVapps viewVapps = new OrganizationViewVapps ( ) ;
2013-06-24 13:41:48 +02:00
public MainWindowTreeBuilder ( FlickerFreeTreeView treeView )
{
Util . ThrowIfParameterNull ( treeView , "treeView" ) ;
Program . AssertOnEventThread ( ) ;
_treeView = treeView ;
_treeViewForeColor = treeView . ForeColor ;
_treeViewBackColor = treeView . BackColor ;
2013-08-26 14:08:23 +02:00
}
2013-07-01 17:59:42 +02:00
2013-06-24 13:41:48 +02:00
/// <summary>
/// Gets or sets an object that should be highlighted.
/// </summary>
public object HighlightedDragTarget
{
get { return _highlightedDragTarget ; }
set { _highlightedDragTarget = value ; }
}
/// <summary>
/// Updates the <see cref="TreeView"/> with the specified new root node. This is done by merging the specified
/// root node with the existing root node to minimize updates to the treeview to reduce flicker.
/// </summary>
/// <param name="newRootNode">The new root node.</param>
/// <param name="searchText">The search text for the currently active search.</param>
2013-08-26 12:42:32 +02:00
public void RefreshTreeView ( VirtualTreeNode newRootNode , string searchText , NavigationPane . NavigationMode searchMode )
2013-06-24 13:41:48 +02:00
{
Util . ThrowIfParameterNull ( newRootNode , "newRootNode" ) ;
Util . ThrowIfParameterNull ( searchText , "searchText" ) ;
Program . AssertOnEventThread ( ) ;
_treeView . BeginUpdate ( ) ;
PersistExpandedNodes ( searchText ) ;
_treeView . UpdateRootNodes ( new [ ] { newRootNode } ) ;
RestoreExpandedNodes ( searchText , searchMode ) ;
bool searchTextCleared = ( searchText . Length = = 0 & & searchText ! = _lastSearchText ) ;
_lastSearchText = searchText ;
_lastSearchMode = searchMode ;
_treeView . EndUpdate ( ) ;
// ensure that the selected nodes are visible when search text is cleared (CA-102127)
if ( searchTextCleared )
{
ExpandSelection ( ) ;
}
}
2013-10-08 11:17:57 +02:00
private void ExpandSelection ( )
2013-06-24 13:41:48 +02:00
{
foreach ( var node in _treeView . SelectedNodes )
{
node . EnsureVisible ( ) ;
}
}
2013-08-26 12:42:32 +02:00
public VirtualTreeNode CreateNewRootNode ( Search search , NavigationPane . NavigationMode mode )
2013-06-24 13:41:48 +02:00
{
2013-10-08 11:17:57 +02:00
IAcceptGroups groupAcceptor ;
2013-07-01 17:59:42 +02:00
VirtualTreeNode newRootNode ;
switch ( mode )
2013-06-24 13:41:48 +02:00
{
2013-08-26 12:42:32 +02:00
case NavigationPane . NavigationMode . Objects :
2013-10-08 11:17:57 +02:00
newRootNode = viewObjects . RootNode ;
2013-07-01 17:59:42 +02:00
groupAcceptor = CreateGroupAcceptor ( _highlightedDragTarget , newRootNode ) ;
2013-10-08 11:17:57 +02:00
viewObjects . Populate ( search , groupAcceptor ) ;
2013-07-01 17:59:42 +02:00
break ;
2013-08-26 14:08:23 +02:00
case NavigationPane . NavigationMode . Tags :
2013-10-08 11:17:57 +02:00
newRootNode = viewTags . RootNode ;
2013-08-26 14:08:23 +02:00
groupAcceptor = CreateGroupAcceptor ( _highlightedDragTarget , newRootNode ) ;
2013-10-08 11:17:57 +02:00
viewTags . Populate ( search , groupAcceptor ) ;
2013-08-26 14:08:23 +02:00
break ;
case NavigationPane . NavigationMode . Folders :
2013-10-08 11:17:57 +02:00
newRootNode = viewFolders . RootNode ;
2013-08-26 14:08:23 +02:00
groupAcceptor = CreateGroupAcceptor ( _highlightedDragTarget , newRootNode ) ;
2013-10-08 11:17:57 +02:00
viewFolders . Populate ( search , groupAcceptor ) ;
2013-08-26 14:08:23 +02:00
break ;
case NavigationPane . NavigationMode . CustomFields :
2013-10-08 11:17:57 +02:00
newRootNode = viewFields . RootNode ;
2013-08-26 14:08:23 +02:00
groupAcceptor = CreateGroupAcceptor ( _highlightedDragTarget , newRootNode ) ;
2013-10-08 11:17:57 +02:00
viewFields . Populate ( search , groupAcceptor ) ;
2013-08-26 14:08:23 +02:00
break ;
case NavigationPane . NavigationMode . vApps :
2013-10-08 11:17:57 +02:00
newRootNode = viewVapps . RootNode ;
2013-07-01 17:59:42 +02:00
groupAcceptor = CreateGroupAcceptor ( _highlightedDragTarget , newRootNode ) ;
2013-10-08 11:17:57 +02:00
viewVapps . Populate ( search , groupAcceptor ) ;
2013-07-01 17:59:42 +02:00
break ;
2013-08-28 15:44:46 +02:00
case NavigationPane . NavigationMode . SavedSearch :
Util . ThrowIfParameterNull ( search , "search" ) ;
2013-10-08 11:17:57 +02:00
newRootNode = new VirtualTreeNode ( search . Name )
{
Tag = search ,
ImageIndex = search . DefaultSearch
? ( int ) Icons . DefaultSearch
: ( int ) Icons . Search
} ;
2013-08-28 15:44:46 +02:00
groupAcceptor = CreateGroupAcceptor ( _highlightedDragTarget , newRootNode ) ;
search . PopulateAdapters ( groupAcceptor ) ;
break ;
2013-10-08 11:17:57 +02:00
default : //includes Infrastructure and Notifications
2013-07-01 17:59:42 +02:00
Util . ThrowIfParameterNull ( search , "search" ) ;
2016-01-14 11:52:53 +01:00
newRootNode = new VirtualTreeNode ( Branding . BRAND_CONSOLE ) { ImageIndex = ( int ) Icons . Home } ;
2013-07-01 17:59:42 +02:00
groupAcceptor = CreateGroupAcceptor ( _highlightedDragTarget , newRootNode ) ;
search . PopulateAdapters ( groupAcceptor ) ;
break ;
2013-06-24 13:41:48 +02:00
}
2013-10-08 11:17:57 +02:00
2013-07-01 17:59:42 +02:00
return newRootNode ;
}
2013-06-24 13:41:48 +02:00
2013-07-01 17:59:42 +02:00
private MainWindowTreeNodeGroupAcceptor CreateGroupAcceptor ( object dragTarget , VirtualTreeNode parent )
{
return new MainWindowTreeNodeGroupAcceptor ( dragTarget , _treeViewForeColor , _treeViewBackColor , parent ) ;
}
2013-10-08 11:17:57 +02:00
private List < VirtualTreeNode . PersistenceInfo > AssignList ( NavigationPane . NavigationMode mode )
2013-07-01 17:59:42 +02:00
{
switch ( mode )
2013-06-24 13:41:48 +02:00
{
2013-08-26 12:42:32 +02:00
case NavigationPane . NavigationMode . Objects :
2013-10-08 11:17:57 +02:00
return _objectViewExpanded ;
2013-08-26 14:08:23 +02:00
case NavigationPane . NavigationMode . Tags :
2013-10-08 11:17:57 +02:00
return _tagsViewExpanded ;
2013-08-26 14:08:23 +02:00
case NavigationPane . NavigationMode . Folders :
2013-10-08 11:17:57 +02:00
return _foldersViewExpanded ;
2013-08-26 14:08:23 +02:00
case NavigationPane . NavigationMode . CustomFields :
2013-10-08 11:17:57 +02:00
return _fieldsViewExpanded ;
2013-08-26 14:08:23 +02:00
case NavigationPane . NavigationMode . vApps :
2013-10-08 11:17:57 +02:00
return _vappsViewExpanded ;
2013-07-01 17:59:42 +02:00
default :
2013-10-08 11:17:57 +02:00
return _infraViewExpanded ;
2013-06-24 13:41:48 +02:00
}
}
private void PersistExpandedNodes ( string searchText )
{
2013-07-01 17:59:42 +02:00
// only persist the expansion state of nodes if there isn't an active search.
//If there's a search then we're just going to expand everything later.
2013-06-24 13:41:48 +02:00
2013-10-08 11:17:57 +02:00
// also because we want to restore the nodes back to their original state
2013-07-01 17:59:42 +02:00
//after a search is removed, do the check on _lastSearchText and _lastSearchMode.
2013-06-24 13:41:48 +02:00
2013-08-26 12:42:32 +02:00
if ( searchText . Length = = 0 & & _lastSearchText . Length = = 0 & & _lastSearchMode ! = NavigationPane . NavigationMode . SavedSearch )
2013-06-24 13:41:48 +02:00
{
2013-10-08 11:17:57 +02:00
var list = AssignList ( _lastSearchMode ) ;
2013-06-24 13:41:48 +02:00
list . Clear ( ) ;
2013-10-08 11:17:57 +02:00
foreach ( VirtualTreeNode node in _treeView . AllNodes . Where ( n = > n . Tag ! = null & & n . Parent ! = null & & n . IsExpanded ) )
2013-07-01 17:59:42 +02:00
list . Add ( node . GetPersistenceInfo ( ) ) ;
2013-06-24 13:41:48 +02:00
}
// persist the expansion state of the root node separately - it's a special case as its
// expansion state isn't persisted differently depending on whether it's in org mode or not.
_rootExpanded = _treeView . Nodes [ 0 ] . IsExpanded | | _treeView . Nodes [ 0 ] . Nodes . Count = = 0 ;
}
2013-08-26 12:42:32 +02:00
private void RestoreExpandedNodes ( string searchText , NavigationPane . NavigationMode searchMode )
2013-06-24 13:41:48 +02:00
{
2013-08-26 12:42:32 +02:00
if ( ( searchText ! = _lastSearchText & & searchText . Length > 0 ) | | ( searchMode = = NavigationPane . NavigationMode . SavedSearch & & _lastSearchMode ! = NavigationPane . NavigationMode . SavedSearch ) )
2013-06-24 13:41:48 +02:00
{
// expand all nodes if there's a search and the search has changed.
_treeView . ExpandAll ( ) ;
}
2013-08-26 12:42:32 +02:00
if ( searchText . Length = = 0 & & searchMode ! = NavigationPane . NavigationMode . SavedSearch )
2013-06-24 13:41:48 +02:00
{
// if there isn't a search persist the user's expanded nodes.
2013-10-08 11:17:57 +02:00
var list = AssignList ( searchMode ) ;
2013-06-24 13:41:48 +02:00
var allNodes = new List < VirtualTreeNode > ( _treeView . AllNodes ) ;
2013-10-08 11:17:57 +02:00
2013-06-24 13:41:48 +02:00
foreach ( VirtualTreeNode . PersistenceInfo info in list )
{
VirtualTreeNode match ;
// First, look for the object in the same position
if ( _treeView . TryExactMatch ( info . Path , out match ) > = info . Path . Count )
{
if ( ! match . IsExpanded )
match . Expand ( ) ;
2013-10-08 11:17:57 +02:00
2013-06-24 13:41:48 +02:00
allNodes . Remove ( match ) ;
continue ;
}
// Second, find the object in the maximal sub tree where it appeared only once
if ( _treeView . TryExactMatch ( info . PathToMaximalSubTree , out match ) > = info . PathToMaximalSubTree . Count )
{
match = _treeView . FindNodeIn ( match , info . Tag ) ;
if ( match ! = null )
{
if ( ! match . IsExpanded )
match . Expand ( ) ;
2013-10-08 11:17:57 +02:00
2013-06-24 13:41:48 +02:00
allNodes . Remove ( match ) ;
}
}
}
// collapse everything else
foreach ( VirtualTreeNode n in allNodes )
{
2013-10-08 11:17:57 +02:00
if ( n . Tag ! = null & & n . Parent ! = null & & n . IsExpanded )
2013-06-24 13:41:48 +02:00
n . Collapse ( ) ;
}
// special case for root node
if ( _rootExpanded )
_treeView . Nodes [ 0 ] . Expand ( ) ;
}
}
#region MainWindowTreeNodeGroupAcceptor class
2013-10-08 11:17:57 +02:00
public class MainWindowTreeNodeGroupAcceptor : IAcceptGroups
2013-06-24 13:41:48 +02:00
{
private readonly VirtualTreeNode _parent ;
private readonly Color _treeViewForeColor ;
private readonly Color _treeViewBackColor ;
private readonly object _highlightedDragTarget ;
private int _index ;
2013-10-08 11:17:57 +02:00
public MainWindowTreeNodeGroupAcceptor ( object highlightedDragTarget ,
Color treeViewForeColor , Color treeViewBackColor , VirtualTreeNode parent )
2013-06-24 13:41:48 +02:00
{
_parent = parent ;
_treeViewForeColor = treeViewForeColor ;
_treeViewBackColor = treeViewBackColor ;
_highlightedDragTarget = highlightedDragTarget ;
}
#region IAcceptGroups Members
public void FinishedInThisGroup ( bool defaultExpand )
{
}
public IAcceptGroups Add ( Grouping grouping , Object group , int indent )
{
2013-10-08 11:17:57 +02:00
if ( group = = null )
return null ;
2013-07-01 17:59:42 +02:00
2013-10-08 11:17:57 +02:00
VirtualTreeNode node ;
2013-06-24 13:41:48 +02:00
2013-10-08 11:17:57 +02:00
if ( group is Pool )
{
node = AddPoolNode ( ( Pool ) group ) ;
}
else if ( group is Host )
{
node = AddHostNode ( ( Host ) group ) ;
}
else if ( group is VM )
{
node = AddVMNode ( ( VM ) group ) ;
}
2015-02-04 10:48:32 +01:00
else if ( group is DockerContainer )
{
node = AddDockerContainerNode ( ( DockerContainer ) group ) ;
}
2013-10-08 11:17:57 +02:00
else if ( group is VM_appliance )
{
node = AddVmApplianceNode ( ( VM_appliance ) group ) ;
}
else if ( group is SR )
{
node = AddSRNode ( ( SR ) group ) ;
}
else if ( group is XenAPI . Network )
{
node = AddNetworkNode ( ( XenAPI . Network ) group ) ;
}
else if ( group is VDI )
{
node = AddVDINode ( ( VDI ) group ) ;
}
else if ( group is Folder )
{
node = AddFolderNode ( ( Folder ) group ) ;
}
else
{
node = AddNode ( grouping . GetGroupName ( group ) , grouping . GetGroupIcon ( group ) ,
false , new GroupingTag ( grouping , GetGroupingTagFromNode ( _parent ) , group ) ) ;
2013-06-24 13:41:48 +02:00
2013-10-08 11:17:57 +02:00
if ( group is DateTime )
Program . BeginInvoke ( Program . MainWindow , ( ) = > { node . Text = HelpersGUI . DateTimeToString ( ( DateTime ) group , Messages . DATEFORMAT_DMY_HMS , true ) ; } ) ; // annoying: has to be on the event thread because of CA-46983
2013-06-24 13:41:48 +02:00
}
2013-10-08 11:17:57 +02:00
return new MainWindowTreeNodeGroupAcceptor ( _highlightedDragTarget , _treeViewForeColor , _treeViewBackColor , node ) ;
2013-06-24 13:41:48 +02:00
}
#endregion
2013-10-08 11:17:57 +02:00
private static object GetGroupingTagFromNode ( VirtualTreeNode node )
2013-06-24 13:41:48 +02:00
{
2013-10-08 11:17:57 +02:00
if ( node = = null )
return null ;
GroupingTag gt = node . Tag as GroupingTag ;
if ( gt ! = null )
2013-06-24 13:41:48 +02:00
{
// gt.Grouping is OrganizationalView means that we're at the Tags/Types/Custom Fields level.
// Custom field keys are the next level down, and values are the one after that.
return gt . Grouping is OrganizationalView ? null : gt . Group ;
}
2013-10-08 11:17:57 +02:00
return node . Tag ;
2013-06-24 13:41:48 +02:00
}
2013-10-08 11:17:57 +02:00
private VirtualTreeNode AddPoolNode ( Pool pool )
2013-06-24 13:41:48 +02:00
{
2013-10-08 11:17:57 +02:00
return AddNode ( Helpers . GetName ( pool ) , Images . GetIconFor ( pool ) , false , pool ) ;
2013-06-24 13:41:48 +02:00
}
2013-10-08 11:17:57 +02:00
private VirtualTreeNode AddVMNode ( VM vm )
2013-06-24 13:41:48 +02:00
{
bool hidden = vm . IsHidden ;
string name = hidden ? String . Format ( Messages . X_HIDDEN , vm . Name ) : vm . Name ;
2014-12-05 11:11:17 +01:00
2015-02-04 10:48:32 +01:00
return AddNode ( name , Images . GetIconFor ( vm ) , hidden , vm ) ;
}
2014-12-05 11:11:17 +01:00
2015-02-04 10:48:32 +01:00
private VirtualTreeNode AddDockerContainerNode ( DockerContainer cont )
{
return AddNode ( cont . Name . Ellipsise ( 1000 ) , Images . GetIconFor ( cont ) , cont . IsHidden , cont ) ;
2013-06-24 13:41:48 +02:00
}
2013-10-08 11:17:57 +02:00
private VirtualTreeNode AddVmApplianceNode ( VM_appliance appliance )
2013-06-24 13:41:48 +02:00
{
2013-10-08 11:17:57 +02:00
return AddNode ( appliance . Name , Images . GetIconFor ( appliance ) , false , appliance ) ;
2013-06-24 13:41:48 +02:00
}
2013-10-08 11:17:57 +02:00
private VirtualTreeNode AddHostNode ( Host host )
2013-06-24 13:41:48 +02:00
{
2013-10-08 11:17:57 +02:00
return AddNode ( host . Name , Images . GetIconFor ( host ) , false , host ) ;
2013-06-24 13:41:48 +02:00
}
2013-10-08 11:17:57 +02:00
private VirtualTreeNode AddSRNode ( SR sr )
2013-06-24 13:41:48 +02:00
{
bool hidden = sr . IsHidden ;
String name = hidden ? String . Format ( Messages . X_HIDDEN , sr . NameWithoutHost ) : sr . NameWithoutHost ;
2013-10-08 11:17:57 +02:00
return AddNode ( name , Images . GetIconFor ( sr ) , hidden , sr ) ;
2013-06-24 13:41:48 +02:00
}
2013-10-08 11:17:57 +02:00
private VirtualTreeNode AddNetworkNode ( XenAPI . Network network )
2013-06-24 13:41:48 +02:00
{
bool hidden = network . IsHidden ;
bool slave = network . IsSlave ;
string rawName = network . Name ;
2013-10-08 11:17:57 +02:00
String name = slave
? String . Format ( Messages . NIC_SLAVE , rawName )
: hidden
? String . Format ( Messages . X_HIDDEN , rawName )
: rawName ;
return AddNode ( name , Images . GetIconFor ( network ) , slave | | hidden , network ) ;
2013-06-24 13:41:48 +02:00
}
2013-10-08 11:17:57 +02:00
private VirtualTreeNode AddVDINode ( VDI vdi )
2013-06-24 13:41:48 +02:00
{
String name = String . IsNullOrEmpty ( vdi . Name ) ? Messages . NO_NAME : vdi . Name ;
2013-10-08 11:17:57 +02:00
return AddNode ( name , Images . GetIconFor ( vdi ) , false , vdi ) ;
2013-06-24 13:41:48 +02:00
}
2013-10-08 11:17:57 +02:00
private VirtualTreeNode AddFolderNode ( Folder folder )
2013-06-24 13:41:48 +02:00
{
2013-10-08 11:17:57 +02:00
return AddNode ( folder . Name , Images . GetIconFor ( folder ) , false , folder ) ;
2013-06-24 13:41:48 +02:00
}
2013-10-08 11:17:57 +02:00
private VirtualTreeNode AddNode ( string name , Icons icon , bool grayed , object obj )
2013-06-24 13:41:48 +02:00
{
2013-10-08 11:17:57 +02:00
VirtualTreeNode result = new VirtualTreeNode ( name . Ellipsise ( 1000 ) )
{
Tag = obj ,
ImageIndex = ( int ) icon ,
SelectedImageIndex = ( int ) icon
} ;
_parent . Nodes . Insert ( _index , result ) ;
_index + + ;
2013-06-24 13:41:48 +02:00
IXenObject xenObject = obj as IXenObject ;
bool highlighted = _highlightedDragTarget ! = null & & obj ! = null & & _highlightedDragTarget . Equals ( obj ) ;
if ( highlighted )
{
result . BackColor = SystemColors . Highlight ;
result . ForeColor = SystemColors . HighlightText ;
}
else if ( grayed )
{
result . BackColor = _treeViewBackColor ;
result . ForeColor = SystemColors . GrayText ;
}
else
{
result . BackColor = _treeViewBackColor ;
result . ForeColor = _treeViewForeColor ;
}
return result ;
}
}
#endregion
}
}