///
/// 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.Generic;
using System.Diagnostics;
using System.Text;
using System.Windows.Forms;
using JetBrains.JetListViewLibrary;
using JetBrains.Omea.Base;
using JetBrains.Omea.FiltersManagement;
using JetBrains.Omea.OpenAPI;
namespace JetBrains.Omea.GUIControls
{
///
/// The "Views and Categories" pane.
///
public class ViewsCategoriesPane: ResourceTreePaneBase
{
private WorkspaceCategoryFilter _workspaceCategoryFilter;
private ViewsCategoriesChildProvider _vcChildProvider;
private IResource _lastActiveWorkspace = null;
private readonly CategoryTotalCountDecorator _totalCountDecorator = new CategoryTotalCountDecorator();
public ViewsCategoriesPane()
{
AddNodeDecorator( new TextQueryViewDecorator() );
AddNodeDecorator( _totalCountDecorator );
}
public void AddContentTypes( string[] types )
{
_totalCountDecorator.AddContentTypes( types );
}
public bool ShowWorkspaceOtherView
{
get
{
return _dataProvider.ResourceChildProvider != null;
}
set
{
if ( _rootResource == Core.ResourceTreeManager.ResourceTreeRoot )
{
if ( value )
{
if ( _vcChildProvider == null )
{
_vcChildProvider = new ViewsCategoriesChildProvider();
}
_dataProvider.ResourceChildProvider = _vcChildProvider;
}
else
{
_dataProvider.ResourceChildProvider = null;
}
}
}
}
public override void SetActiveWorkspace( IResource workspace )
{
if ( _lastActiveWorkspace == workspace )
{
return;
}
_lastActiveWorkspace = workspace;
if ( _resourceTree.Filters.Contains( _workspaceCategoryFilter ) )
{
_resourceTree.Filters.Remove( _workspaceCategoryFilter );
_workspaceCategoryFilter.Dispose();
}
if ( workspace != null )
{
IResourceList workspaceCategories = Core.WorkspaceManager.GetWorkspaceResourcesLive( workspace,
"Category" ).Union( Core.WorkspaceManager.GetWorkspaceResourcesLive( workspace, "ResourceTreeRoot" ) );
_workspaceCategoryFilter = new WorkspaceCategoryFilter( workspace, workspaceCategories );
_resourceTree.Filters.Add( _workspaceCategoryFilter );
}
if ( ShowWorkspaceOtherView )
{
_dataProvider.RebuildTree();
}
AsyncUpdateSelection();
}
}
///
/// The filter which accepts categories only if they, or their children, are linked
/// to the specified workspace.
///
internal class WorkspaceCategoryFilter: IJetListViewNodeFilter, IDisposable
{
private readonly IResource _workspace;
private readonly IResourceList _workspaceCategories;
private readonly List _workspaceCategoryList = new List();
internal WorkspaceCategoryFilter( IResource workspace, IResourceList workspaceCategories )
{
_workspace = workspace;
_workspaceCategories = workspaceCategories;
_workspaceCategories.ResourceAdded += OnWorkspaceCategoryAdded;
_workspaceCategories.ResourceDeleting += OnWorkspaceCategoryDeleting;
UpdateFilterList( null );
}
public void Dispose()
{
_workspaceCategories.ResourceAdded -= OnWorkspaceCategoryAdded;
_workspaceCategories.ResourceDeleting -= OnWorkspaceCategoryDeleting;
}
/**
* Builds the list of categories added to the workspace and their parents.
*/
private void UpdateFilterList( IResource removedCategory )
{
_workspaceCategoryList.Clear();
foreach( IResource res in _workspaceCategories )
{
if ( res == removedCategory )
continue;
IResource parentRes = res;
while( parentRes != null && IsCategoryOrRoot( parentRes ) )
{
if ( _workspaceCategoryList.IndexOf( parentRes.Id ) < 0 )
{
_workspaceCategoryList.Add( parentRes.Id );
}
parentRes = parentRes.GetLinkProp( Core.Props.Parent );
}
}
if ( FilterChanged != null )
{
FilterChanged( this, EventArgs.Empty );
}
}
private static bool IsCategoryOrRoot( IResource parentRes )
{
if ( parentRes.Type == "Category" )
{
return true;
}
if ( parentRes.Type == "ResourceTreeRoot" )
{
return parentRes.GetPropText( "RootResourceType" ).StartsWith( "Category" );
}
return false;
}
/**
* Updates the filter list when categories are added or removed from the workspace.
*/
private void OnWorkspaceCategoryAdded( object sender, ResourceIndexEventArgs e )
{
UpdateFilterList( null );
}
private void OnWorkspaceCategoryDeleting( object sender, ResourceIndexEventArgs e )
{
UpdateFilterList( e.Resource );
}
public bool AcceptNode( JetListViewNode node )
{
IResource res = (IResource) node.Data;
if ( IsCategoryOrRoot( res ) )
{
if ( _workspaceCategoryList.IndexOf( res.Id ) >= 0 )
{
return true;
}
IResource parent = res.GetLinkProp( "Parent" );
while( parent != null && IsCategoryOrRoot( parent ) )
{
if ( parent.HasLink( "InWorkspaceRecursive", _workspace ) )
{
return true;
}
parent = parent.GetLinkProp( Core.Props.Parent );
}
return false;
}
return true;
}
public event EventHandler FilterChanged;
}
///
/// The provider which allows showing the "Other" workspace view in the
/// Views and Categories pane when it is not possible to show that view
/// in any other pane.
///
internal class ViewsCategoriesChildProvider: IJetResourceChildProvider
{
public IResourceList GetChildResources( IResource parent )
{
if ( parent == Core.ResourceTreeManager.ResourceTreeRoot )
{
IResource ws = Core.WorkspaceManager.ActiveWorkspace;
if ( ws != null )
{
IResourceList children = parent.GetLinksToLive( null, Core.Props.Parent );
IResourceList otherView = ws.GetLinksOfType( "WorkspaceOtherView", "InWorkspace" );
Debug.Assert( otherView.Count == 1 );
children = children.Union( otherView );
string nodeSort = Core.ResourceTreeManager.GetResourceNodeSort( parent );
if ( nodeSort != null )
{
children.Sort( nodeSort );
}
return children;
}
}
return null;
}
}
#region ViewsCategoriesRootDragDropHandler Class
///
/// Drag'n'Drop handler for the root of the “Views and Categories” sidebar pane.
///
public class ViewsCategoriesRootDragDropHandler : IResourceDragDropHandler
{
#region IResourceDragDropHandler Members
public void Drop( IResource targetResource, IDataObject data, DragDropEffects allowedEffect, int keyState )
{
if( data.GetDataPresent( typeof(IResourceList) ) )
{
// The resources we're dragging
IResourceList dragResources = (IResourceList)data.GetData( typeof(IResourceList) );
// Mount the items
foreach( IResource res in dragResources )
new ResourceProxy( res, JobPriority.Immediate ).SetPropAsync( Core.Props.Parent, targetResource );
}
}
public DragDropEffects DragOver( IResource targetResource, IDataObject data, DragDropEffects allowedEffect, int keyState )
{
if( data.GetDataPresent( typeof(IResourceList) ) )
{
// The resources we're dragging
IResourceList dragResources = (IResourceList)data.GetData( typeof(IResourceList) );
// Check if really dropping over our resource (resource tree root for Views'n'Cats)
if( !(targetResource == Core.ResourceTreeManager.ResourceTreeRoot) )
return DragDropEffects.None;
// Collect all the direct and indirect parents of the droptarget; then we'll check to avoid dropping parent on its children
List parentList = new List();
IResource parent = targetResource;
while( parent != null )
{
parentList.Add( parent.Id );
parent = parent.GetLinkProp( Core.Props.Parent );
}
// Check
foreach( IResource res in dragResources )
{
// Dropping parent over its child?
if( parentList.IndexOf( res.Id ) >= 0 )
return DragDropEffects.None;
// Can drop only views, view-folders, and category-tree-roots on the views'n'cats tree root
if( !(
(FilterRegistry.IsViewOrFolder( res ))
|| ((res.Type == "ResourceTreeRoot") && (res.HasProp( "RootResourceType" )) && (res.GetStringProp( "RootResourceType" ).StartsWith( "Category" )))
) )
return DragDropEffects.None;
}
return DragDropEffects.Move;
}
return DragDropEffects.None;
}
public void AddResourceDragData( IResourceList dragResources, IDataObject dataObject )
{
if( !dataObject.GetDataPresent( typeof(string) ) )
{
StringBuilder sb = StringBuilderPool.Alloc();
try
{
foreach( IResource resource in dragResources )
{
if( sb.Length != 0 )
sb.Append( ", " );
string text = resource.DisplayName;
if( text.IndexOf( ' ' ) > 0 )
sb.Append( "“" + text + "”" );
else
sb.Append( text );
}
dataObject.SetData( sb.ToString() );
}
finally
{
StringBuilderPool.Dispose( sb );
}
}
}
#endregion
}
#endregion
}