/// /// Copyright © 2003-2008 JetBrains s.r.o. /// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder). /// using System; using System.Collections; using System.Drawing; using System.Windows.Forms; using JetBrains.Omea.GUIControls; using JetBrains.Omea.OpenAPI; using JetBrains.Omea.ResourceTools; namespace JetBrains.Omea.Workspaces { /// /// The tree-based selector of resources visible in a workspace. /// internal class WorkspaceTreeSelector: UserControl, IResourceChildProvider, IWorkspaceSelector { /// /// Required designer variable. /// private System.ComponentModel.Container components = null; private string[] _resourceTypes; private Button _btnAdd; private Button _btnAddWithChildren; private Button _btnRemove; private Label _lblAvailable; private Label _lblInWorkspace; private Label _lblProcessing; private ResourceTreeView _tvAvailable; private ResourceTreeView _tvInWorkspace; private IResource _rootResource; private int _parentProperty; private IResourceNodeFilter _availTreeFilter; private IResourceNodeFilter _inWorkspaceTreeFilter; private WorkspaceManager _workspaceManager; private IResource _currentWorkspace; private bool _operationInProgress; private bool _needRebuildTree; public WorkspaceTreeSelector( string[] resTypes, IResource rootResource, int parentProperty, IResourceNodeFilter availTreeFilter, IResourceNodeFilter inWorkspaceTreeFilter ) { // This call is required by the Windows.Forms Form Designer. InitializeComponent(); _resourceTypes = resTypes; _rootResource = rootResource; _parentProperty = parentProperty; _availTreeFilter = availTreeFilter; _inWorkspaceTreeFilter = inWorkspaceTreeFilter; _workspaceManager = Core.WorkspaceManager as WorkspaceManager; } /// /// Clean up any resources being used. /// protected override void Dispose( bool disposing ) { if( disposing ) { if(components != null) { components.Dispose(); } } base.Dispose( disposing ); } #region Component Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { components = new System.ComponentModel.Container(); } #endregion public Control GetControl() { return this; } public void SetWorkspace( IResource workspace ) { _currentWorkspace = workspace; _tvInWorkspace.RootResource = workspace; _tvInWorkspace.ExpandAll(); if ( workspace != null ) { _lblInWorkspace.Text = "In Workspace '" + workspace.DisplayName + "':"; } else { _lblInWorkspace.Text = "In Workspace:"; } } public void CreateComponents() { _lblAvailable = new Label(); _lblAvailable.Text = "Available:"; _lblAvailable.FlatStyle = FlatStyle.System; _lblAvailable.AutoSize = true; _lblInWorkspace = new Label(); _lblInWorkspace.FlatStyle = FlatStyle.System; _lblInWorkspace.AutoSize = true; _lblProcessing = new Label(); _lblProcessing.FlatStyle = FlatStyle.System; _lblProcessing.AutoSize = true; _lblProcessing.Visible = false; _lblProcessing.Text = "Processing..."; _btnAdd = CreateTabButton( "Add", OnAddTreeClick ); _btnAddWithChildren = CreateTabButton( "Add Subtree", OnAddTreeRecursiveClick ); _btnRemove = CreateTabButton( "Remove", OnRemoveTreeClick ); _tvAvailable = new ResourceTreeView(); _tvAvailable.AddNodeFilter( new HideAllWorkspacesResourcesFilter() ); if ( _availTreeFilter != null ) { _tvAvailable.AddNodeFilter( _availTreeFilter ); } _tvAvailable.RootResource = _rootResource; if ( _parentProperty > 0 ) { _tvAvailable.ParentProperty = _parentProperty; } else { _tvAvailable.ParentProperty = Core.Props.Parent; } _tvAvailable.MultiSelect = true; _tvAvailable.HideSelection = false; _tvAvailable.ExecuteDoubleClickAction = false; _tvAvailable.ShowContextMenu = false; _tvAvailable.AllowDrop = false; _tvAvailable.DoubleClick += OnAvailableTreeDoubleClick; _tvAvailable.AfterSelect += OnAvailableTreeSelectionChanged; _tvAvailable.TreeUpdated += OnTreeUpdated; _tvInWorkspace = new ResourceTreeView(); _tvInWorkspace.ResourceChildProvider = this; _tvInWorkspace.MultiSelect = true; _tvInWorkspace.HideSelection = false; _tvInWorkspace.ParentProperty = _workspaceManager.GetRecurseLinkPropId( _resourceTypes [0] ); _tvInWorkspace.ExecuteDoubleClickAction = false; _tvInWorkspace.ShowContextMenu = false; _tvInWorkspace.AllowDrop = false; _tvInWorkspace.DoubleClick += OnRemoveTreeClick; _tvInWorkspace.AfterSelect += OnWorkspaceTreeSelectionChanged; _tvInWorkspace.TreeUpdated += OnTreeUpdated; if ( _inWorkspaceTreeFilter != null ) { _tvInWorkspace.AddNodeFilter( _inWorkspaceTreeFilter ); } UpdateAvailableTreeSelection(); UpdateWorkspaceTreeSelection(); Controls.AddRange( new Control[] { _lblAvailable, _tvAvailable, _btnAdd, _btnAddWithChildren, _btnRemove, _lblProcessing, _lblInWorkspace, _tvInWorkspace } ); } private void OnAvailableTreeSelectionChanged( object sender, TreeViewEventArgs e ) { UpdateAvailableTreeSelection(); } private void UpdateAvailableTreeSelection() { bool allFolders = true; foreach ( IResource selResource in _tvAvailable.SelectedResources ) { WorkspaceResourceType wrType = _workspaceManager.GetWorkspaceResourceType( selResource.Type ); if (wrType != WorkspaceResourceType.Folder ) { allFolders = false; } } _btnAdd.Enabled = !allFolders; _btnAddWithChildren.Enabled = (_tvAvailable.SelectedResources.Count > 0); } private void OnAvailableTreeDoubleClick( object sender, EventArgs e ) { if ( _btnAdd.Enabled ) { BeginWorkspaceOperation(); Core.ResourceAP.QueueJob( JobPriority.Immediate, new ResourceListDelegate( DoAdd ), _tvAvailable.SelectedResources ); } else if ( _btnAddWithChildren.Enabled ) { BeginWorkspaceOperation(); Core.ResourceAP.QueueJob( JobPriority.Immediate, new ResourceListDelegate( DoAddRecursive ), _tvAvailable.SelectedResources ); } } private void BeginWorkspaceOperation() { _lblProcessing.Visible = true; _btnAdd.Enabled = false; _btnAddWithChildren.Enabled = false; _btnRemove.Enabled = false; _operationInProgress = true; } private void OnAddTreeClick( object sender, EventArgs e ) { BeginWorkspaceOperation(); Core.ResourceAP.QueueJob( JobPriority.Immediate, new ResourceListDelegate( DoAdd ), _tvAvailable.SelectedResources ); } private void DoAdd( IResourceList resList ) { ArrayList skippedResources = new ArrayList(); foreach( IResource res in resList ) { if ( _workspaceManager.IsInWorkspaceRecursive( _currentWorkspace, res ) ) { skippedResources.Add( res ); } else { _workspaceManager.AddResourceToWorkspace( _currentWorkspace, res ); } } Core.UIManager.QueueUIJob( new UpdateDelegate( UpdateTree ), resList, skippedResources ); } private void OnAddTreeRecursiveClick( object sender, EventArgs e ) { BeginWorkspaceOperation(); Core.ResourceAP.QueueJob( JobPriority.Immediate, new ResourceListDelegate( DoAddRecursive ), _tvAvailable.SelectedResources ); } private void DoAddRecursive( IResourceList selResourceList ) { ArrayList skippedResources = new ArrayList(); // if any of the resources were added non-recursively, we need to do a full // tree rebuild in order for second-level children to be updated correctly (#5554) foreach( IResource res in selResourceList ) { if ( _workspaceManager.IsInWorkspaceRecursive( _currentWorkspace, res ) ) { skippedResources.Add( res ); } else { if ( res.HasLink( "InWorkspace", _currentWorkspace ) ) { _needRebuildTree = true; } _workspaceManager.AddResourceToWorkspaceRecursive( _currentWorkspace, res ); } } Core.UIManager.QueueUIJob( new UpdateDelegate( UpdateTree ), selResourceList, skippedResources ); } private void UpdateTree( IResourceList selResourceList, ArrayList skippedResources ) { if ( _tvInWorkspace.IsDisposed ) { return; } if ( _needRebuildTree ) { _tvInWorkspace.UpdateNodeFilter( true ); } _tvInWorkspace.ExpandAll(); _tvInWorkspace.SelectResourceNodes( selResourceList ); AddToWorkspaceAction.ReportSkippedResources( FindForm(), skippedResources ); } private delegate void UpdateDelegate( IResourceList selResourceList, ArrayList skippedResources ); private void OnTreeUpdated( object sender, EventArgs e ) { if ( _operationInProgress ) { _lblProcessing.Visible = false; UpdateAvailableTreeSelection(); UpdateWorkspaceTreeSelection(); } } private void OnWorkspaceTreeSelectionChanged( object sender, TreeViewEventArgs e ) { UpdateWorkspaceTreeSelection(); } private void UpdateWorkspaceTreeSelection() { _btnRemove.Enabled = _tvInWorkspace.SelectedResources.Count > 0; } private void OnRemoveTreeClick( object sender, EventArgs e ) { BeginWorkspaceOperation(); Core.ResourceAP.QueueJob( JobPriority.Immediate, new ResourceListDelegate( DoRemove ), _tvAvailable.SelectedResources ); } private void DoRemove( IResourceList selResourceList ) { _workspaceManager.RemoveResourcesFromWorkspace( _currentWorkspace, _tvInWorkspace.SelectedResources ); } public IResourceList GetChildResources( ResourceTreeView resourceTree, IResource parent ) { IResourceList result = null; if ( parent.Type == "Workspace" ) { result = parent.GetLinksToLive( null, "InWorkspace" ).Union( parent.GetLinksToLive( null, "InWorkspaceRecursive" ) ); result.Sort( new SortSettings( Core.Props.Name, true ) ); } else { // if any of our parents has been added recursively, return our children // as the child list IResource nextParent = parent; while( nextParent != null ) { if ( nextParent.HasLink( "InWorkspaceRecursive", _currentWorkspace ) ) { IResourceList excludedResources = _currentWorkspace.GetLinksOfTypeLive( null, "ExcludeFromWorkspace" ); result = parent.GetLinksToLive( null, _tvInWorkspace.ParentProperty ).Minus( excludedResources ); string sortProps = Core.ResourceTreeManager.GetResourceNodeSort( parent ); if ( sortProps != null ) { result.Sort( sortProps ); } break; } nextParent = nextParent.GetLinkProp( _tvInWorkspace.ParentProperty ); } } if ( result != null ) { IResourceList filterList = null; foreach( string resType in _resourceTypes ) { if ( _workspaceManager.GetWorkspaceResourceType( resType ) != WorkspaceResourceType.None ) { filterList = Core.ResourceStore.GetAllResourcesLive( resType ).Union( filterList, true ); } } result = result.Intersect( filterList, true ); return result; } return Core.ResourceStore.EmptyResourceList; } private static Button CreateTabButton( string name, EventHandler clickHandler ) { Button btnAdd = new Button(); btnAdd.Text = name; btnAdd.FlatStyle = FlatStyle.System; btnAdd.Size = new Size( 72, 24 ); btnAdd.Click += clickHandler; return btnAdd; } protected override void OnSizeChanged( EventArgs e ) { base.OnSizeChanged( e ); int middleSpaceX = (int) (48 * Core.ScaleFactor.Width); _lblAvailable.Location = new Point( 0, 0 ); _lblInWorkspace.Location = new Point( Width / 2 + middleSpaceX, 0 ); _tvAvailable.Location = new Point( 0, 20 ); _tvAvailable.Size = new Size( Width / 2 - middleSpaceX, Height-20 ); _tvInWorkspace.Location = new Point( Width / 2 + middleSpaceX, 20 ); _tvInWorkspace.Size = _tvAvailable.Size; Size btnSize = new Size( (int) (72 * Core.ScaleFactor.Width), (int) (24 * Core.ScaleFactor.Height) ); int btnX = (int) (Width / 2 - (36 * Core.ScaleFactor.Width )); _btnAdd.Location = new Point( btnX, 24 ); _btnAdd.Size = btnSize; _btnAddWithChildren.Location = new Point( btnX, 56 ); _btnAddWithChildren.Size = btnSize; _btnRemove.Location = new Point( btnX, 88 ); _btnRemove.Size = btnSize; _lblProcessing.Location = new Point( btnX, 120 ); } private class HideAllWorkspacesResourcesFilter: IResourceNodeFilter { public bool AcceptNode( IResource res, int level ) { return !res.HasProp( "VisibleInAllWorkspaces" ); } } } }