/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.ui.editors;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.commands.ActionHandler;
import org.eclipse.ui.IEditorActionBarContributor;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.handlers.IHandlerActivation;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.part.MultiPageEditorActionBarContributor;
import org.eclipse.ui.texteditor.StatusLineContributionItem;
import org.teiid.designer.core.workspace.ModelUtil;
import org.teiid.designer.ui.UiConstants;
import org.teiid.designer.ui.UiPlugin;
import org.teiid.designer.ui.actions.IModelerActionConstants;
import org.teiid.designer.ui.actions.ModelerGlobalActionsMap;
import org.teiid.designer.ui.common.actions.ActionService;
import org.teiid.designer.ui.common.actions.GlobalActionsMap;
import org.teiid.designer.ui.common.util.UiUtil;
/**
* Manages the installation/deinstallation of global actions for multi-page editors. Responsible for the redirection of global
* actions to the active editor. Multi-page contributor replaces the contributors for the individual editors in the multi-page
* editor.
*
* @since 8.0
*/
public class ModelEditorActionContributor extends MultiPageEditorActionBarContributor
implements IModelerActionConstants, UiConstants {
/** Map of default global actions. */
private static ModelerGlobalActionsMap defaultActionsMap;
/** StatusBar field for Read Only/Writable state of the model file. */
private StatusLineContributionItem fileStateItem;
/** The editor input. Will always be a model file. */
private IFileEditorInput input;
/**
* A collection of editor page action contributors. These page contributors should NOT be disposed from this class. It is
* their ModelEditorPage that is responsible for their disposing.
*/
private Map partContributorMap;
/** Listener to clean up the partContributorMap. */
private IPartListener partListener;
/**
* Keep track of the global action handlers. When we activate them through the IHandlerService, if their is already a handler
* for that action, Eclipse logs a warning message but the activation still works. This map is being used so that we can
* deactivate existing handlers before activating the new one (which gets rid of the warning message).
*/
private Map<String, IHandlerActivation> actionHandlerMap;
static {
defaultActionsMap = new ModelerGlobalActionsMap();
}
/**
*
*/
public ModelEditorActionContributor() {
this.actionHandlerMap = new HashMap<String, IHandlerActivation>(ModelerGlobalActionsMap.ALL_GLOBAL_ACTIONS.length);
}
/**
* @param thePart the editor part
* @param theContributor the action bar contributor
*/
public void addContributor( IEditorPart thePart,
IEditorActionBarContributor theContributor ) {
if (partContributorMap == null) {
partContributorMap = new HashMap();
}
partContributorMap.put(thePart, theContributor);
// if not done previously, create listener for part closed events
if (this.partListener == null) {
this.partListener = new EditorPartListener();
getPage().addPartListener(this.partListener);
}
theContributor.init(getActionBars(), getPage());
}
/**
* @see org.eclipse.ui.part.EditorActionBarContributor#contributeToStatusLine(org.eclipse.jface.action.IStatusLineManager)
*/
@Override
public void contributeToStatusLine( IStatusLineManager theStatusLineManager ) {
super.contributeToStatusLine(theStatusLineManager);
fileStateItem = new StatusLineContributionItem(IModelerActionConstants.StatusBar.MODEL_EDITOR_FILE_STATE);
theStatusLineManager.add(fileStateItem);
}
/**
* @see org.eclipse.ui.part.EditorActionBarContributor#dispose()
* @since 5.0
*/
@Override
public void dispose() {
if (this.partListener != null) {
getPage().removePartListener(this.partListener);
}
super.dispose();
}
/**
* Gets the action bar contributor for the given page editor.
*
* @param thePart the page editor whose contributor is being requested
* @return the contributor or <code>null</code> if not found
*/
private AbstractModelEditorPageActionBarContributor getActionContributor( IEditorPart thePart ) {
// get the contributor from the map
AbstractModelEditorPageActionBarContributor result = null;
if (partContributorMap != null) {
result = (AbstractModelEditorPageActionBarContributor)partContributorMap.get(thePart);
}
return result;
}
/**
* Handler for part closed events. Used to clean up the part contributor map.
*
* @param thePart the part that was closed
* @since 5.0
*/
void handlePartClosed( IWorkbenchPart thePart ) {
if (thePart instanceof ModelEditor) {
// just remove editor pages
List editors = ((ModelEditor)thePart).getAllEditors();
for (int size = editors.size(), i = 0; i < size; ++i) {
// could have checked first to see if contained in but remove also does that
this.partContributorMap.remove(editors.get(i));
}
}
}
/**
* @see org.eclipse.ui.IEditorActionBarContributor#setActiveEditor(org.eclipse.ui.IEditorPart)
*/
@Override
public void setActiveEditor( IEditorPart thePart ) {
final IEditorPart thisPart = thePart;
Runnable runnable = new Runnable() {
@Override
public void run() {
setActivePage(thisPart);
}
};
UiUtil.runInSwtThread(runnable, true);
}
/* (non-JavaDoc)
* Method declared in AbstractMultiPageEditorActionBarContributor.
*/
@Override
public void setActivePage( IEditorPart thePart ) {
// redirect to the pages contributor
AbstractModelEditorPageActionBarContributor contributor = null;
IEditorPart part = thePart;
// when first starting eclipse with a ModelEditor as the active editor, and when switching
// from another editor to the ModelEditor, the part passed in is the editor itself.
// so find the current page and use it's contributor
if (thePart instanceof ModelEditor) {
part = ((ModelEditor)thePart).getCurrentPage();
}
if( part == null || part.getSite() == null) return;
//
// deactivate other page contributors by setting the active editor. if not their editor they will deactivate.
//
if (this.partContributorMap != null) {
Iterator itrContributor = this.partContributorMap.values().iterator();
while (itrContributor.hasNext()) {
IEditorActionBarContributor pageContributor = (IEditorActionBarContributor)itrContributor.next();
if (pageContributor != null) {
pageContributor.setActiveEditor(part);
}
}
}
//
// activate current page contributor
//
// even if activeEditor is the part we still need to setActiveEditor on the contributor
// to let the contributor re-contribute. if we don't and user selects off of the editor
// and on to a view and back to the editor the contribution state may not be valid
contributor = getActionContributor(part);
// editor parts don't have to have a contributor
if (contributor != null) {
contributor.setActiveEditor(part);
}
//
// install global actions
// (ModelerGlobalActionsMap)
ModelerGlobalActionsMap globalActions = (contributor == null) ? (ModelerGlobalActionsMap)defaultActionsMap : (ModelerGlobalActionsMap)contributor.getGlobalActions();
// if contributor does not return a map then use all default actions
if (globalActions == null) {
globalActions = new ModelerGlobalActionsMap();
}
IWorkbenchWindow window = getPage().getWorkbenchWindow();
ActionService actionService = (contributor == null) ? UiPlugin.getDefault().getActionService(window.getActivePage()) : contributor.getActionService();
IHandlerService svc = (IHandlerService)part.getSite().getService(IHandlerService.class);
Iterator itr = globalActions.entrySet().iterator();
while (itr.hasNext()) {
Map.Entry entry = (Map.Entry)itr.next();
String actionId = (String)entry.getKey();
// if the actions map indicates that a default action should be used, the map will not contain that
// action. need to get it from the service
IAction action = null;
if( globalActions.isDefaultAction(actionId) && actionService != null ) {
action = actionService.getDefaultAction(actionId);
} else {
action = (IAction)entry.getValue();
}
if (action == null) {
action = GlobalActionsMap.UNSUPPORTED_ACTION;
}
// must deactive if already one activated in order to get rid of an Eclipse warning message
if (this.actionHandlerMap.containsKey(actionId)) {
IHandlerActivation activation = this.actionHandlerMap.get(actionId);
if( activation.getHandlerService() != null ) {
activation.getHandlerService().deactivateHandler(activation);
}
}
getActionBars().setGlobalActionHandler(actionId, action);
this.actionHandlerMap.put(actionId, svc.activateHandler(actionId, new ActionHandler(action)));
}
// must call this if action bars have been changed
getActionBars().updateActionBars();
}
/**
* Sets the model file being edited by the <code>ModelEditor</code>. Updates the status bar with the readonly state of the
* file.
*
* @param theInput the model file
*/
public void setEditorInput( IFileEditorInput theInput ) {
input = theInput;
setReadOnlyState();
}
/** Sets the Read-only/Writable state of the editor resource into the status bar. */
public void setReadOnlyState() {
if (input != null && fileStateItem != null) {
// update status bar file state field
fileStateItem.setText(getReadOnlyState() ? Util.getString("ModelerEditorActionContributor.modelIsReadOnly") //$NON-NLS-1$
: Util.getString("ModelerEditorActionContributor.modelIsWritable")); //$NON-NLS-1$
}
}
/**
* @return true if model is read-only
*/
public boolean getReadOnlyState() {
if (input != null) {
return ModelUtil.isIResourceReadOnly(input.getFile());
}
return true;
}
/**
* Listener to clean up the part contributor map.
*
* @since 5.0
*/
class EditorPartListener implements IPartListener {
@Override
public void partActivated( IWorkbenchPart thePart ) {
}
@Override
public void partBroughtToTop( IWorkbenchPart thePart ) {
}
@Override
public void partDeactivated( IWorkbenchPart thePart ) {
}
@Override
public void partOpened( IWorkbenchPart thePart ) {
}
@Override
public void partClosed( IWorkbenchPart thePart ) {
handlePartClosed(thePart);
}
}
}