///
/// 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 JetBrains.Omea.GUIControls;
using JetBrains.Omea.OpenAPI;
using System.Collections;
namespace JetBrains.Omea
{
/**
* An action which is composed of multiple actions contributed by different
* plugins, and invokes the registered actions in order until one of them
* matches the current context.
*/
public class CompositeAction: IAction
{
private class ActionComponent
{
public string ResourceType;
public IAction Action;
public IActionStateFilter[] Filters;
internal ActionComponent( string resourceType, IAction action, IActionStateFilter[] filters )
{
ResourceType = resourceType;
Action = action;
Filters = filters;
}
}
private string _id;
private ArrayList _components = new ArrayList();
public CompositeAction( string id )
{
_id = id;
ActionManager actionManager = ICore.Instance.ActionManager as ActionManager;
if ( actionManager != null )
{
actionManager.RegisterCompositeAction( id, this );
}
}
/**
* Adds a component to the composite action.
*/
internal void AddComponent( string resType, IAction action, IActionStateFilter[] filters )
{
_components.Add( new ActionComponent( resType, action, filters ) );
}
/**
* Polls the components of the action until the enabled one is found and executes it.
*/
public void Execute( IActionContext context )
{
if ( !ExecuteActionComponents( context ) )
{
SplitExecute( context );
}
}
/**
* Polls the components of the action and determines the aggregate state of the
* action.
*/
public void Update( IActionContext context, ref ActionPresentation presentation )
{
string[] resTypes = null;
if ( _components.Count == 0 )
{
presentation.Visible = false;
return;
}
bool isVisible = false;
bool isDisabled = false;
bool tabMatched = false;
UpdateActionComponents( context, ref presentation, ref resTypes, ref isVisible, ref isDisabled,
ref tabMatched );
if ( isVisible )
return;
// if the resource types were never checked, none of the components are
// resource type dependent
if ( resTypes != null && resTypes.Length > 1 )
{
SplitUpdate( resTypes, context, ref presentation, ref tabMatched );
if ( presentation.Visible && presentation.Enabled )
return;
}
if ( context.Kind == ActionContextKind.Toolbar && !tabMatched )
{
presentation.Visible = false;
}
else if ( isDisabled || context.Kind == ActionContextKind.MainMenu ||
context.Kind == ActionContextKind.Toolbar )
{
presentation.Visible = true;
presentation.Enabled = false;
}
else
{
presentation.Visible = false;
}
}
private bool ExecuteActionComponents( IActionContext context )
{
string[] resTypes = null;
ActionPresentation presentation = new ActionPresentation();
foreach( ActionComponent component in _components )
{
bool tabMatched = false;
UpdateComponentPresentation( component, context, ref presentation, ref resTypes, ref tabMatched );
if ( presentation.Visible && presentation.Enabled )
{
component.Action.Execute( context );
return true;
}
}
return false;
}
private void UpdateActionComponents( IActionContext context, ref ActionPresentation presentation,
ref string[] resTypes, ref bool isVisible, ref bool isDisabled, ref bool tabMatched )
{
foreach( ActionComponent component in _components )
{
UpdateComponentPresentation( component, context, ref presentation, ref resTypes, ref tabMatched );
if ( presentation.Visible && presentation.Enabled )
{
isVisible = true;
return;
}
if ( !presentation.Enabled )
isDisabled = true;
}
}
///
/// Splits the resource list in multiple resource lists, each of which has only a
/// single type, and tries to enable the action components with the split lists
///
private void SplitUpdate( string[] resTypes, IActionContext context, ref ActionPresentation presentation,
ref bool tabMatched )
{
IResourceList[] resLists = SplitResourceList( resTypes, context.SelectedResources );
for( int i=0; i 1 )
{
IResourceList[] resLists = SplitResourceList( resTypes, context.SelectedResources );
for( int i=0; i