/*******************************************************************************
* Copyright (c) 2004, 2010 BREDEX GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BREDEX GmbH - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.jubula.client.ui.rcp.editors;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.persistence.EntityManager;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.DecoratingLabelProvider;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jubula.client.core.businessprocess.IWritableComponentNameCache;
import org.eclipse.jubula.client.core.events.DataEventDispatcher;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.IPropertyChangedListener;
import org.eclipse.jubula.client.core.model.INodePO;
import org.eclipse.jubula.client.core.model.IPersistentObject;
import org.eclipse.jubula.client.core.persistence.PMException;
import org.eclipse.jubula.client.ui.rcp.Plugin;
import org.eclipse.jubula.client.ui.rcp.businessprocess.UINodeBP;
import org.eclipse.jubula.client.ui.rcp.controllers.AbstractPartListener;
import org.eclipse.jubula.client.ui.rcp.events.GuiEventDispatcher;
import org.eclipse.jubula.client.ui.rcp.propertytester.EditorPartPropertyTester;
import org.eclipse.jubula.client.ui.rcp.provider.labelprovider.GeneralLabelProvider;
import org.eclipse.jubula.client.ui.rcp.utils.UIIdentitiyElementComparer;
import org.eclipse.jubula.client.ui.utils.CommandHelper;
import org.eclipse.jubula.client.ui.utils.LayoutUtil;
import org.eclipse.jubula.client.ui.views.IJBPart;
import org.eclipse.jubula.client.ui.views.ITreeViewerContainer;
import org.eclipse.jubula.tools.internal.constants.StringConstants;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartConstants;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.services.IEvaluationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author BREDEX GmbH
* @created Mar 17, 2010
*/
public abstract class AbstractJBEditor extends EditorPart implements IJBEditor,
ISelectionProvider, ITreeViewerContainer, IJBPart,
IPropertyChangedListener {
/** Add-Submenu ID */
public static final String ADD_ID = PlatformUI.PLUGIN_ID + ".AddSubMenu"; //$NON-NLS-1$
/** Refactor-menu ID */
public static final String REFACTOR_ID = PlatformUI.PLUGIN_ID
+ ".RefactorSubMenu"; //$NON-NLS-1$
/** <code>BLANK</code> */
public static final String BLANK = " "; //$NON-NLS-1$
/** postfix for add-action id */
protected static final String ADD = "_ADD"; //$NON-NLS-1$
/** the logger */
protected static final Logger LOG = LoggerFactory
.getLogger(AbstractJBEditor.class);
/** List of ISelectionChangedListener */
private List<ISelectionChangedListener> m_selectionChangedListenerList =
new ArrayList<ISelectionChangedListener>();
/** TreeViewer for specification */
private TreeViewer m_mainTreeViewer;
/** the parent composite of this workbench part */
private Composite m_parentComposite;
/** the helper that assists this editor */
private JBEditorHelper m_editorHelper;
/** The parent Control. */
private Control m_control;
/** PartListener of this WokbenchPart */
private PartListener m_partListener = new PartListener();
/**
* @author BREDEX GmbH
* @created 20.09.2006
*/
private class PartListener extends AbstractPartListener {
/**
* {@inheritDoc}
*/
public void partActivated(IWorkbenchPart part) {
if (part == AbstractJBEditor.this) {
setActionHandlers();
}
super.partActivated(part);
}
}
/**
* Creates the specification part of the editor
*
* @param parent
* Composite.
*/
protected void createMainPart(Composite parent) {
setMainTreeViewer(new TreeViewer(parent));
DecoratingLabelProvider lp = new DecoratingLabelProvider(
new GeneralLabelProvider(), Plugin.getDefault().getWorkbench()
.getDecoratorManager().getLabelDecorator());
getMainTreeViewer().setLabelProvider(lp);
getMainTreeViewer().setUseHashlookup(true);
getMainTreeViewer().setComparer(new UIIdentitiyElementComparer());
getSite().setSelectionProvider(this);
firePropertyChange(IWorkbenchPartConstants.PROP_INPUT);
}
/**
* The SelectionChangedListener for this editor.
*
* @author BREDEX GmbH
* @created 04.04.2005
*/
private class EditorSelectionChangedListener implements
ISelectionChangedListener {
/**
* {@inheritDoc}
*/
public void selectionChanged(SelectionChangedEvent event) {
Iterator<ISelectionChangedListener> iter =
getSelectionChangedListenerList()
.iterator();
SelectionChangedEvent selChangedEvent = new SelectionChangedEvent(
AbstractJBEditor.this, event.getSelection());
while (iter.hasNext()) {
ISelectionChangedListener listener = iter.next();
listener.selectionChanged(selChangedEvent);
}
}
}
/**
* {@inheritDoc}
* @param adapter the adapter to get
* @return this TestCaseEditor instance if the adaper matches.
*/
public Object getAdapter(Class adapter) {
if (adapter == this.getClass()) {
return this;
} else if (adapter == NodeEditorInput.class) {
return getEditorInput();
}
Object superAdapter = super.getAdapter(adapter);
if (superAdapter != null) {
return superAdapter;
}
return getEditorHelper().getAdapter(adapter);
}
/**
* @param parentComposite
* the parentComposite to set
*/
protected void setParentComposite(Composite parentComposite) {
m_parentComposite = parentComposite;
}
/**
* @return the parentComposite
*/
public Composite getParentComposite() {
return m_parentComposite;
}
/**
* {@inheritDoc}
*/
public void addSelectionChangedListener(
ISelectionChangedListener listener) {
if (!getSelectionChangedListenerList().contains(listener)) {
getSelectionChangedListenerList().add(listener);
}
}
/**
* {@inheritDoc}
*/
public ISelection getSelection() {
if (getMainTreeViewer() == null) {
return StructuredSelection.EMPTY;
}
return getMainTreeViewer().getSelection();
}
/**
* {@inheritDoc}
*/
public void removeSelectionChangedListener(
ISelectionChangedListener listener) {
getSelectionChangedListenerList().remove(listener);
}
/** {@inheritDoc} */
public void setSelection(ISelection selection) {
ISelection newSelection = getMainTreeViewer().getSelection();
INodePO child = null;
if (selection instanceof StructuredSelection) {
Object firstElement = ((StructuredSelection) selection)
.getFirstElement();
if (firstElement instanceof INodePO) {
final IPersistentObject editorRoot = getWorkVersion();
INodePO node = (INodePO) firstElement;
if (editorRoot.getId().equals(node.getId())) {
newSelection = new StructuredSelection(editorRoot);
} else {
Iterator<? extends INodePO> nodeListIterator =
((INodePO) editorRoot).getAllNodeIter();
while (nodeListIterator.hasNext()) {
child = nodeListIterator.next();
if (node.getGuid().equals(child.getGuid())) {
newSelection = new StructuredSelection(child);
break;
}
}
}
}
}
setSelectionImpl(newSelection);
if (child != null) {
getMainTreeViewer().setExpandedState(child, true);
}
}
/**
* @return the work version to use for this editor
*/
protected IPersistentObject getWorkVersion() {
return getEditorHelper().getEditSupport().getWorkVersion();
}
/**
* Sets the current selection for this selection provider.
*
* @param selection the new selection
*/
protected void setSelectionImpl(ISelection selection) {
UINodeBP.setFocusAndSelection(selection, getMainTreeViewer());
}
/**
* @param mainTreeViewer
* the mainTreeViewer to set
*/
protected void setMainTreeViewer(TreeViewer mainTreeViewer) {
m_mainTreeViewer = mainTreeViewer;
}
/**
* @return the topTreeViewer
*/
protected TreeViewer getMainTreeViewer() {
return m_mainTreeViewer;
}
/**
* @param selectionChangedListenerList
* the selectionChangedListenerList to set
*/
protected void setSelectionChangedListenerList(
List<ISelectionChangedListener> selectionChangedListenerList) {
m_selectionChangedListenerList = selectionChangedListenerList;
}
/**
* @return the selectionChangedListenerList
*/
protected List<ISelectionChangedListener>
getSelectionChangedListenerList() {
return m_selectionChangedListenerList;
}
/**
* {@inheritDoc}
*/
public TreeViewer getTreeViewer() {
return getMainTreeViewer();
}
/**
* {@inheritDoc}
*/
public void handlePropertyChanged(boolean isCompNameChanged) {
createPartName();
Plugin.getDisplay().syncExec(new Runnable() {
public void run() {
getTreeViewer().refresh();
}
});
}
/**
* creates and sets the partName
*/
protected void createPartName() {
String nodeName = getWorkVersion().getName();
if (nodeName == null) {
nodeName = StringConstants.EMPTY;
}
setPartName(getEditorPrefix() + nodeName);
}
/**
* Sets the help to the HelpSystem.
* @param parent the parent composite to set the help id to
*/
protected abstract void setHelp(Composite parent);
/**
* {@inheritDoc}
*/
public final void createPartControl(Composite parent) {
if (getEditorHelper() == null) {
setEditorHelper(new JBEditorHelper(this));
}
checkMasterSessionUpToDate();
createPartName();
GridLayout layout = new GridLayout();
layout.numColumns = 1;
layout.verticalSpacing = 3;
layout.marginWidth = LayoutUtil.MARGIN_WIDTH;
layout.marginHeight = LayoutUtil.MARGIN_HEIGHT;
parent.setLayout(layout);
getEditorSite().getPage().addPartListener(m_partListener);
setHelp(parent);
createPartControlImpl(parent);
createContextMenu();
addInternalSelectionListeners(new EditorSelectionChangedListener());
}
/**
* Called by {@link #createPartControl(Composite)}. Warning: Do <b>not</b>
* call {@link #createPartControl(Composite)} from this method, as this will
* cause an infinite loop.
*
* @param parent The parent component.
*/
protected abstract void createPartControlImpl(Composite parent);
/**
* Adds the given listener to all controls in the editor that should provide
* a selection. The default implementation adds the listener to the main
* tree viewer. Subclasses may extend, but not override.
*
* @param editorSelectionChangedListener
* The listener that forwards control selection events to
* workbench selection listeners.
*/
protected void addInternalSelectionListeners(
ISelectionChangedListener editorSelectionChangedListener) {
getMainTreeViewer().addSelectionChangedListener(
editorSelectionChangedListener);
}
/**
* {@inheritDoc}
*/
public void init(IEditorSite site, IEditorInput input)
throws PartInitException {
if (getEditorHelper() == null) {
setEditorHelper(new JBEditorHelper(this));
}
getEditorHelper().init(site, input);
}
/**
* Reopens the Editor with the changed node
* @param node the changed node of this editor.
* @throws PMException if the node can not be loaded
*/
public void reOpenEditor(IPersistentObject node) throws PMException {
ISelection previousSelection = getSelection();
getEditorHelper().setDirty(false);
getEditorHelper().getEditSupport().reloadEditSession();
((PersistableEditorInput)getEditorInput()).refreshNode();
try {
init(getEditorSite(), getEditorInput());
setInitialInput();
setSelection(previousSelection);
} catch (PartInitException e) {
getSite().getPage().closeEditor(this, false);
}
}
/**
* set the initial input
*/
protected abstract void setInitialInput();
/**
* @return false
*/
public boolean isSaveAsAllowed() {
return false;
}
/**
* {@inheritDoc}
*/
public void initTextAndInput(IEditorSite site, IEditorInput input) {
setSite(site);
setInput(input);
createPartName();
getEditorSite().getActionBars().getMenuManager();
}
/**
* {@inheritDoc}
*/
public void fireDirtyProperty(boolean isDirty) {
// fire property for change of dirty state
firePropertyChange(PROP_DIRTY);
if (!isDirty) {
firePropertyChange(PROP_INPUT);
}
}
/**
* Show the status line.
*/
public void setFocus() {
getTreeViewer().getTree().setFocus();
Plugin.showStatusLine(this);
}
/**
* Does nothing.
*/
public void doSaveAs() {
// do nothing
}
/**
* {@inheritDoc}
*/
public boolean isDirty() {
return getEditorHelper().isDirty();
}
/**
* fill the context menu
* @param mgr IMenuManager
*/
protected abstract void fillContextMenu(IMenuManager mgr);
/**
* Create context menu.
* @return the menu
*/
protected Menu createContextMenu() {
// Create menu manager.
MenuManager menuMgr = new MenuManager();
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager mgr) {
fillContextMenu(mgr);
}
});
// Create menu.
Menu menu = menuMgr.createContextMenu(getControl());
getControl().setMenu(menu);
getMainTreeViewer().getControl().setMenu(menu);
// Register menu for extension.
getSite().registerContextMenu(menuMgr, this);
return menu;
}
/**
* {@inheritDoc}
*/
public void dispose() {
try {
DataEventDispatcher ded = DataEventDispatcher.getInstance();
ded.removePropertyChangedListener(this);
if (getEditorSite() != null && getEditorSite().getPage() != null) {
GuiEventDispatcher.getInstance()
.removeEditorDirtyStateListener(this);
}
if (getSite() != null) {
getSite().setSelectionProvider(null);
}
if (getEditorSite() != null && getEditorSite().getPage() != null) {
getEditorSite().getPage().removePartListener(m_partListener);
}
if (getEditorHelper() != null) {
getEditorHelper().dispose();
}
} finally {
super.dispose();
}
}
/**
* Checks if the MasterSession is up to date.
*/
protected void checkMasterSessionUpToDate() {
// nothing here
}
/**
* Adds DoubleClickListener to the given tree viewer.
*
* @param commandId
* the command to execute on double click event
* @param viewer
* the viewer to register the listener for
*/
protected void addDoubleClickListener(final String commandId,
StructuredViewer viewer) {
viewer.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
CommandHelper.executeCommand(commandId, getSite());
}
});
}
/**
* @param editorHelper the editorHelper to set
*/
protected void setEditorHelper(JBEditorHelper editorHelper) {
m_editorHelper = editorHelper;
}
/**
* @return the editorHelper
*/
public JBEditorHelper getEditorHelper() {
return m_editorHelper;
}
/**
* @param control the control to set
*/
protected void setControl(Control control) {
m_control = control;
}
/**
* @return the control
*/
private Control getControl() {
return m_control;
}
/**
* Sets all necessary global action handlers for this editor. This
* ensures that the editor's actions control the enablement of the
* corresponding actions in the main menu.
*/
protected void setActionHandlers() {
getSite().setSelectionProvider(this);
getEditorSite().getActionBars().updateActionBars();
}
/**
* {@inheritDoc}
*/
public void handleEditorDirtyStateChanged(
IJBEditor gdEditor, boolean isDirty) {
if (gdEditor == this) {
IEvaluationService service = getSite().getService(
IEvaluationService.class);
service.requestEvaluation(EditorPartPropertyTester.FQN_IS_DIRTY);
}
}
/** {@inheritDoc} */
public EntityManager getEntityManager() {
return getEditorHelper().getEditSupport().getSession();
}
/**
* Refreshes the editors viewer
*/
public void refresh() {
Plugin.getDisplay().syncExec(new Runnable() {
public void run() {
getTreeViewer().refresh(true);
}
});
}
/** {@inheritDoc} */
public IWritableComponentNameCache getCompNameCache() {
return m_editorHelper.getEditSupport().getCache();
}
}