/*******************************************************************************
* Copyright (c) 2008 Olivier Moises
*
* 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:
* Olivier Moises- initial API and implementation
*******************************************************************************/
package org.eclipse.wazaabi.ide.ui.editors;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.domain.IEditingDomainProvider;
import org.eclipse.emf.edit.ui.util.EditUIUtil;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gef.ContextMenuProvider;
import org.eclipse.gef.EditDomain;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.gef.commands.CommandStackEvent;
import org.eclipse.gef.commands.CommandStackEventListener;
import org.eclipse.gef.editparts.RootTreeEditPart;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.ui.actions.ActionRegistry;
import org.eclipse.gef.ui.actions.DeleteAction;
import org.eclipse.gef.ui.actions.PrintAction;
import org.eclipse.gef.ui.actions.RedoAction;
import org.eclipse.gef.ui.actions.SaveAction;
import org.eclipse.gef.ui.actions.SelectAllAction;
import org.eclipse.gef.ui.actions.UndoAction;
import org.eclipse.gef.ui.actions.UpdateAction;
import org.eclipse.gef.ui.palette.PaletteViewer;
import org.eclipse.gef.ui.parts.SelectionSynchronizer;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
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.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.dialogs.SaveAsDialog;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor;
import org.eclipse.wazaabi.ide.mapping.rules.MappingRuleManager;
import org.eclipse.wazaabi.ide.ui.PaletteContribution;
import org.eclipse.wazaabi.ide.ui.editors.actions.ChangeMappingAction;
import org.eclipse.wazaabi.ide.ui.editors.actions.HideLayoutInfoAction;
import org.eclipse.wazaabi.ide.ui.editors.actions.InsertECoreElementAction;
import org.eclipse.wazaabi.ide.ui.editors.actions.RunInSeparateWindow;
import org.eclipse.wazaabi.ide.ui.editors.viewer.ExtendedTreeViewer;
import org.eclipse.wazaabi.ide.ui.editors.viewer.bindingrules.OnContainerMappingRules;
import org.eclipse.wazaabi.ide.ui.editors.viewer.bindingrules.OnJDTElementsMappingRules;
import org.eclipse.wazaabi.ide.ui.editors.viewer.bindingrules.OnTextComponentMapping;
import org.eclipse.wazaabi.ide.ui.editparts.TreePartFactory;
import org.eclipse.wazaabi.ide.ui.outline.AbstractOutlinePage;
import org.eclipse.wazaabi.ide.ui.outline.OutlinePage;
import org.eclipse.wazaabi.ide.ui.palette.ComponentsDrawerPaletteContribution;
import org.eclipse.wazaabi.ide.ui.palette.ControlGroupPaletteContribution;
import org.eclipse.wazaabi.ide.ui.palette.LayoutsDrawerPaletteContribution;
import org.eclipse.wazaabi.ide.ui.propertysheets.eventhandlers.AbstractStyleRuleAction;
import org.eclipse.wazaabi.mm.core.widgets.AbstractComponent;
import org.eclipse.wazaabi.ui.runtime.parts.TabbedPropertySheetPage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class WazaabiTreeEditor extends EditorPart implements
IEditingDomainProvider, ISelectionProvider, IMenuListener,
CommandStackEventListener, ISelectionListener,
ITabbedPropertySheetPageContributor {
private static final int PALETTE_SIZE = 125;
final static Logger logger = LoggerFactory
.getLogger(WazaabiTreeEditor.class);
private TransactionalEditingDomain editingDomain;
private EditDomain editDomain;
private ExtendedTreeViewer viewer;
private PaletteViewer paletteViewer;
private PaletteRoot root;
private AbstractOutlinePage outlinePage;
private ActionRegistry actionRegistry;
private List<String> stackActions = new ArrayList<String>();
private List<String> selectionActions = new ArrayList<String>();
private List<String> propertyActions = new ArrayList<String>();
private SelectionSynchronizer synchronizer;
private MappingRuleManager mappingRuleManager = null;
public WazaabiTreeEditor() {
super();
setEditDomain(new EditDomain());
initializeEditingDomain();
}
@Override
public void doSave(IProgressMonitor monitor) {
// Save only resources that have actually changed.
//
final Map<Object, Object> saveOptions = new HashMap<Object, Object>();
saveOptions.put(Resource.OPTION_SAVE_ONLY_IF_CHANGED,
Resource.OPTION_SAVE_ONLY_IF_CHANGED_MEMORY_BUFFER);
// Do the work within an operation because this is a long running
// activity that modifies the workbench.
//
WorkspaceModifyOperation operation = new WorkspaceModifyOperation() {
// This is the method that gets invoked when the operation runs.
//
@Override
public void execute(IProgressMonitor monitor) {
// Save the resources to the file system.
//
boolean first = true;
for (Resource resource : editingDomain.getResourceSet()
.getResources()) {
if ((first || !resource.getContents().isEmpty() || isPersisted(resource))
&& !editingDomain.isReadOnly(resource)) {
try {
// long timeStamp = resource.getTimeStamp();
resource.save(saveOptions);
// if (resource.getTimeStamp() != timeStamp) {
// savedResources.add(resource);
// }
} catch (Exception exception) {
exception.printStackTrace();
// resourceToDiagnosticMap
// .put(resource,
// analyzeResourceProblems(resource,
// exception));
}
first = false;
}
}
}
};
// updateProblemIndication = false;
try {
// This runs the options, and shows progress.
//
new ProgressMonitorDialog(getSite().getShell()).run(true, false,
operation);
// Refresh the necessary state.
//
getCommandStack().markSaveLocation();
firePropertyChange(IEditorPart.PROP_DIRTY);
} catch (Exception exception) {
// Something went wrong that shouldn't.
//
// MyEditorPlugin.INSTANCE.log(exception);
}
// updateProblemIndication = true;
// updateProblemIndication();
}
protected boolean isPersisted(Resource resource) {
boolean result = false;
try {
InputStream stream = editingDomain.getResourceSet()
.getURIConverter().createInputStream(resource.getURI());
if (stream != null) {
result = true;
stream.close();
}
} catch (IOException e) {
// Ignore
}
return result;
}
@Override
public void doSaveAs() {
SaveAsDialog saveAsDialog = new SaveAsDialog(getSite().getShell());
saveAsDialog.open();
IPath path = saveAsDialog.getResult();
if (path != null) {
IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
if (file != null) {
doSaveAs(URI.createPlatformResourceURI(file.getFullPath()
.toString(), true), new FileEditorInput(file));
}
}
}
protected void doSaveAs(URI uri, IEditorInput editorInput) {
(editingDomain.getResourceSet().getResources().get(0)).setURI(uri);
setInputWithNotify(editorInput);
setPartName(editorInput.getName());
IProgressMonitor progressMonitor = new NullProgressMonitor();
doSave(progressMonitor);
}
@Override
public void init(IEditorSite site, IEditorInput input)
throws PartInitException {
setSite(site);
setInputWithNotify(input);
getCommandStack().addCommandStackEventListener(this);
setPartName(input.getName());
site.setSelectionProvider(this);
getSite().getWorkbenchWindow().getSelectionService()
.addSelectionListener(this);
// site.getPage().addPartListener(partListener);
// ResourcesPlugin.getWorkspace().addResourceChangeListener(resourceChangeListener,
// IResourceChangeEvent.POST_CHANGE);
initializeActionRegistry();
}
protected void initializeActionRegistry() {
createActions();
updateActions(propertyActions);
updateActions(stackActions);
}
protected void createActions() {
ActionRegistry registry = getActionRegistry();
IAction action;
action = new HideLayoutInfoAction(this, Action.AS_CHECK_BOX);
registry.registerAction(action);
action = new UndoAction(this);
registry.registerAction(action);
getStackActions().add(action.getId());
action = new RedoAction(this);
registry.registerAction(action);
getStackActions().add(action.getId());
action = new SelectAllAction(this);
registry.registerAction(action);
action = new DeleteAction((IWorkbenchPart) this);
registry.registerAction(action);
getSelectionActions().add(action.getId());
action = new SaveAction(this);
registry.registerAction(action);
getPropertyActions().add(action.getId());
action = new InsertECoreElementAction((IWorkbenchPart) this);
registry.registerAction(action);
getSelectionActions().add(action.getId());
action = new ChangeMappingAction((IWorkbenchPart) this);
registry.registerAction(action);
getSelectionActions().add(action.getId());
action = new RunInSeparateWindow(this);
registry.registerAction(action);
getSelectionActions().add(action.getId());
registry.registerAction(new PrintAction(this));
}
protected List<String> getStackActions() {
return stackActions;
}
protected List<String> getSelectionActions() {
return selectionActions;
}
protected List<String> getPropertyActions() {
return propertyActions;
}
/**
* This is for implementing {@link IEditorPart} and simply tests the command
* stack. <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public boolean isDirty() {
return getCommandStack().isDirty();
}
@Override
public boolean isSaveAsAllowed() {
return true;
}
@Override
public void createPartControl(Composite parent) {
Resource resource = createOrGetResource();
Composite splitter = createEditorSplitter(parent);
createPaletteViewer(splitter);
initializeEditorSplitter(splitter);
viewer = new ExtendedTreeViewer();
viewer.setMappingRuleManager(getMappingRuleManager());
initializeViewer(splitter);
getViewer().setContents(resource);
registContextMenu();
hookGraphicalViewer();
// viewer.setKeyHandler(new GraphicalViewerKeyHandler(viewer)
// .setParent(getCommonKeyHandler()));
}
/**
*
* create splitter for the editor.
*
* @param parent
* @return
*/
protected Composite createEditorSplitter(Composite parent) {
return new Splitter(parent, SWT.HORIZONTAL);
}
/**
*
* create splitter for the editor.
*
* @param parent
* @return
*/
protected void initializeEditorSplitter(Composite splitter) {
if (splitter instanceof Splitter) {
((Splitter) splitter).maintainSize(getPaletteViewer().getControl());
((Splitter) splitter).setFixedSize(getInitialPaletteSize());
((Splitter) splitter)
.addFixedSizeChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
handlePaletteResized(((Splitter) evt.getSource())
.getFixedSize());
}
});
}
}
/**
*
* regist ContextMenu
*/
protected void registContextMenu() {
// CONFIGURE VIEWER
ContextMenuProvider provider = new WazaabiTreeEditorContextMenuProvider(
viewer, getActionRegistry());
viewer.setContextMenu(provider);
getSite().registerContextMenu(this.getClass() + ".contextmenu", //$NON-NLS-1$
provider, viewer);
}
protected void initializeViewer(Composite parent) {
getViewer().setRootEditPart(new RootTreeEditPart());
getViewer().createControl(parent);
getViewer().setEditDomain(editDomain);
getViewer().setEditPartFactory(new TreePartFactory());
}
@Override
public void setFocus() {
// TODO Auto-generated method stub
}
public Resource createOrGetResource() {
URI resourceURI = EditUIUtil.getURI(getEditorInput());
editingDomain.setID(resourceURI.toString());
TransactionalEditingDomain.Registry.INSTANCE.add(editingDomain.getID(),
editingDomain);
Resource resource = null;
/*
* Exception exception = null; Resource resource = null;
*/
try {
// Load the resource through the editing domain.
//
resource = editingDomain.getResourceSet().getResource(resourceURI,
true);
} catch (Exception e) {
// exception = e;
resource = editingDomain.getResourceSet().getResource(resourceURI,
false);
logger.error("{}\n{}", e.getMessage(), e.getCause());
}
// Diagnostic diagnostic = analyzeResourceProblems(resource, exception);
// if (diagnostic.getSeverity() != Diagnostic.OK) {
// resourceToDiagnosticMap.put(resource,
// analyzeResourceProblems(resource, exception));
// }
// editingDomain.getResourceSet().eAdapters()
// .add(problemIndicationAdapter);
return resource;
}
public void menuAboutToShow(IMenuManager manager) {
// TODO Auto-generated method stub
}
public void addSelectionChangedListener(ISelectionChangedListener listener) {
// TODO Auto-generated method stub
}
public ISelection getSelection() {
// TODO Auto-generated method stub
return null;
}
public void removeSelectionChangedListener(
ISelectionChangedListener listener) {
// TODO Auto-generated method stub
}
public void setSelection(ISelection selection) {
// TODO Auto-generated method stub
}
public EditingDomain getEditingDomain() {
return editingDomain;
}
protected void initializeEditingDomain() {
editingDomain = TransactionalEditingDomain.Factory.INSTANCE
.createEditingDomain();
// TODO : is it not a better way for this ?
editingDomain.getResourceSet().getResourceFactoryRegistry()
.getExtensionToFactoryMap()
.put("ui", new XMIResourceFactoryImpl());
// editingDomain.getCommandStack().addCommandStackListener(
// new CommandStackListener() {
// public void commandStackChanged(final EventObject event) {
// getSite().getShell().getDisplay()
// .asyncExec(new Runnable() {
// public void run() {
// firePropertyChange(IEditorPart.PROP_DIRTY);
//
// // we do not call getOutlinePage()
// // because we don't want to instantiate
// // a new outline page at this point
// if (WazaabiTreeEditor.this.outlinePage != null)
// WazaabiTreeEditor.this.outlinePage
// .refreshSelection();
//
// // if (propertySheetPage != null
// // && !propertySheetPage.getControl()
// // .isDisposed()) {
// // propertySheetPage.refresh();
// // }
// }
// });
// }
// });
}
public ExtendedTreeViewer getViewer() {
return viewer;
}
protected void createPaletteViewer(Composite parent) {
PaletteViewer viewer = new PaletteViewer();
setPaletteViewer(viewer);
viewer.createControl(parent);
configurePaletteViewer();
hookPaletteViewer();
initializePaletteViewer();
}
protected void setPaletteViewer(PaletteViewer paletteViewer) {
this.paletteViewer = paletteViewer;
}
protected void configurePaletteViewer() {
}
protected void hookPaletteViewer() {
getEditDomain().setPaletteViewer(paletteViewer);
}
protected void initializePaletteViewer() {
}
public EditDomain getEditDomain() {
return editDomain;
}
protected PaletteViewer getPaletteViewer() {
return paletteViewer;
}
protected int getInitialPaletteSize() {
return PALETTE_SIZE;
}
protected void handlePaletteResized(int newSize) {
}
protected void setEditDomain(EditDomain ed) {
this.editDomain = ed;
getEditDomain().setPaletteRoot(getPaletteRoot());
}
protected PaletteRoot getPaletteRoot() {
if (root == null) {
root = new PaletteRoot();
root.setId(ContributionBasedPaletteFactory.PALETTE_ROOT_ID);
ContributionBasedPaletteFactory paletteFactory = new ContributionBasedPaletteFactory();
initializePalette(paletteFactory);
paletteFactory.createChildren(root);
}
return root;
}
/**
* This methods set the content of the Palette with a PaletteContribution
* not provided by OSGI DS.
*/
protected void initializePalette(
ContributionBasedPaletteFactory paletteFactory) {
ContributionBasedPaletteFactory.addPaletteContributionsToContainer(
root, new PaletteContribution[] {
new ComponentsDrawerPaletteContribution(),
new ControlGroupPaletteContribution(),
new LayoutsDrawerPaletteContribution() });
}
@SuppressWarnings("rawtypes")
@Override
public Object getAdapter(Class type) {
if (type.equals(IContentOutlinePage.class))
return getOutlinePage();
if (type.equals(ActionRegistry.class))
return getActionRegistry();
if (type.equals(CommandStack.class))
return getCommandStack();
if (type.equals(IPropertySheetPage.class))
return getPropertySheetPage();
return super.getAdapter(type);
}
protected ActionRegistry getActionRegistry() {
if (actionRegistry == null)
actionRegistry = new ActionRegistry();
return actionRegistry;
}
public void stackChanged(CommandStackEvent event) {
getSite().getShell().getDisplay().asyncExec(new Runnable() {
public void run() {
firePropertyChange(IEditorPart.PROP_DIRTY);
// we do not call getOutlinePage()
// because we don't want to instantiate
// a new outline page at this point
if (WazaabiTreeEditor.this.outlinePage != null)
WazaabiTreeEditor.this.outlinePage.refreshSelection();
}
});
updateActions(stackActions);
}
protected void updateActions(List<String> actionIds) {
ActionRegistry registry = getActionRegistry();
Iterator<String> iter = actionIds.iterator();
while (iter.hasNext()) {
IAction action = registry.getAction(iter.next());
if (action instanceof UpdateAction)
((UpdateAction) action).update();
}
}
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
// If not the active editor, ignore selection changed.
if (this.equals(getSite().getPage().getActiveEditor())) {
updateActions(selectionActions);
if (getOutlinePage() != null) {
getOutlinePage().selectionChanged(
new SelectionChangedEvent(this, selection));
}
}
}
protected void firePropertyChange(int property) {
super.firePropertyChange(property);
updateActions(propertyActions);
}
public void dispose() {
// if (getActionBarContributor().getActiveEditor() == this) {
// getActionBarContributor().setActiveEditor(null);
// }
if (outlinePage != null) {
outlinePage.dispose();
}
getCommandStack().removeCommandStackEventListener(this);
getSite().getWorkbenchWindow().getSelectionService()
.removeSelectionListener(this);
getEditDomain().setActiveTool(null);
getActionRegistry().dispose();
super.dispose();
}
protected CommandStack getCommandStack() {
return getEditDomain().getCommandStack();
}
protected SelectionSynchronizer getSelectionSynchronizer() {
if (synchronizer == null)
synchronizer = new SelectionSynchronizer();
return synchronizer;
}
protected void hookGraphicalViewer() {
getSelectionSynchronizer().addViewer(getViewer());
getSite().setSelectionProvider(getViewer());
}
protected IPropertySheetPage propertySheetPage;
public IPropertySheetPage getPropertySheetPage() {
if (propertySheetPage == null) {
propertySheetPage = new TabbedPropertySheetPage(
"platform:/plugin/org.eclipse.wazaabi.ide.ui/UIs/propertypage.ui") {
@Override
protected void doSetInput(AbstractComponent component,
Object input) {
component.set(AbstractStyleRuleAction.EDIT_DOMAIN_KEY,
WazaabiTreeEditor.this.getEditDomain());
super.doSetInput(component, input);
}
@Override
protected void createViewer(Composite parent) {
super.createViewer(parent);
getViewer().setPointersEvaluator(
new EditDomainPointerEvaluator(
WazaabiTreeEditor.this.getEditDomain())); //$NON-NLS-1$
}
};
}
return propertySheetPage;
}
// TODO : the line above have been commented because we need another kind of
// property sheets
// TODO : we will, ASAP, implements a better mechanism which will allows
// both extension and basic mechanism
public IPropertySheetPage getPropertySheetPage1() {
if (propertySheetPage == null) {
propertySheetPage = new org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage(
this);
}
return propertySheetPage;
}
public String getContributorId() {
// TODO : for temporary use only
return "org.eclipse.wazaabi.ide.ui.editors.WazaabiTreeEditor.contributor"; //$NON-NLS-1$
}
protected AbstractOutlinePage getOutlinePage() {
if (this.outlinePage == null)
this.outlinePage = new OutlinePage(this);
return this.outlinePage;
}
protected void initializeMappingRuleManager() {
mappingRuleManager
.registerContainingInstance(new OnContainerMappingRules(
mappingRuleManager));
mappingRuleManager
.registerContainingInstance(new OnTextComponentMapping());
mappingRuleManager
.registerContainingInstance(new OnJDTElementsMappingRules());
}
public MappingRuleManager getMappingRuleManager() {
if (mappingRuleManager == null) {
mappingRuleManager = new MappingRuleManager();
initializeMappingRuleManager();
}
return mappingRuleManager;
}
}