/*******************************************************************************
* Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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:
* Exadel, Inc. and Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.common.editor;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.IProgressMonitor;
import org.jboss.tools.common.editor.form.RightFormContainer;
import org.jboss.tools.common.editor.form.SampleErrorForm;
import org.jboss.tools.common.editor.form.SampleTreeForm;
import org.jboss.tools.common.model.util.ModelFeatureFactory;
import org.jboss.tools.common.model.util.XModelTreeListenerSWTASync;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextOperationTarget;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IPropertyListener;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.jboss.tools.common.meta.action.XActionItem;
import org.jboss.tools.common.meta.action.XActionList;
import org.jboss.tools.common.model.XFilteredTreeConstraint;
import org.jboss.tools.common.model.XModel;
import org.jboss.tools.common.model.XModelObject;
import org.jboss.tools.common.model.event.XModelTreeEvent;
import org.jboss.tools.common.model.event.XModelTreeListener;
import org.jboss.tools.common.model.filesystems.FileSystemsHelper;
import org.jboss.tools.common.model.ui.ModelUIPlugin;
import org.jboss.tools.common.model.ui.forms.DefaultFormFactory;
import org.jboss.tools.common.model.ui.forms.FormFactory;
import org.jboss.tools.common.model.ui.forms.IFormFactory;
import org.jboss.tools.common.model.ui.forms.LayouredFormFactory;
import org.jboss.tools.common.model.ui.forms.XModelObjectFormFactory;
import org.jboss.tools.common.model.ui.forms.DefaultFormContainer;
import org.jboss.tools.common.model.ui.forms.DefaultFormPage;
import org.jboss.tools.common.model.ui.forms.IForm;
import org.jboss.tools.common.model.ui.forms.MementoDOM;
import org.jboss.tools.common.model.ui.forms.SplitFormContainer;
import org.jboss.tools.common.model.ui.resources.ResourceLayoutManager;
import org.jboss.tools.common.model.ui.texteditors.TextActionHelper;
import org.jboss.tools.common.model.ui.widgets.IWidgetSettings;
public class TreeFormPage extends DefaultFormPage implements ITextEditor, ITextOperationTarget, ISelectionChangedListener {
private SelectionNotifier selectionNotifier;
private XModelObject installedObject;
private XModel model;
private boolean errorMode;
private Map<String,IAction> actions = new HashMap<String,IAction>();
private ArrayList<String> actionMapping = new ArrayList<String>();
private IEditorSite site;
private IEditorInput input;
private DefaultFormContainer mainContainer;
private SplitFormContainer splitContainer;
private SampleTreeForm treeForm;
private SampleErrorForm errorForm;
private RightFormContainer rightFormContainer;
private XModelTreeListenerSWTASync modelListener = new XModelTreeListenerSWTASync(new XMTL());
public TreeFormPage() {
GridLayout layout = new GridLayout();
layout.horizontalSpacing = 0;
layout.verticalSpacing = 0;
layout.marginHeight = 10;
layout.marginWidth = 10;
selectionNotifier = new SelectionNotifier();
selectionNotifier.addSelectionChangedListener(this);
this.setSelectionProvider(selectionNotifier);
errorForm = new SampleErrorForm();
errorForm.setVisible(Boolean.FALSE.booleanValue());
errorForm.setLayout(layout);
treeForm = new SampleTreeForm(this);
treeForm.setSelectionNotifier(selectionNotifier);
rightFormContainer = new RightFormContainer();
rightFormContainer.setSelectionChangedListener(selectionNotifier);
layout = new GridLayout();
layout.horizontalSpacing = 0;
layout.verticalSpacing = 0;
layout.marginHeight = 5;
layout.marginWidth = 5;
splitContainer = new SplitFormContainer(treeForm, rightFormContainer);
splitContainer.setLayout(layout);
splitContainer.setLayoutData(new GridData(GridData.FILL_BOTH));
mainContainer = new DefaultFormContainer();
mainContainer.setLayoutData(new GridData(GridData.FILL_BOTH));
mainContainer.addForm(errorForm);
mainContainer.addForm(splitContainer);
this.form = mainContainer;
}
public void addErrorSelectionListener(ErrorSelectionListener listener) {
errorForm.addErrorSelectionListener(listener);
}
public void addFilter(XFilteredTreeConstraint filter) {
treeForm.addFilter(filter);
}
public void initialize(Object model) {
this.installedObject = (XModelObject)model;
this.model = installedObject.getModel();
treeForm.initialize(model);
// add model listener
}
public Control createFormControl(Composite parent, IWidgetSettings settings) {
final XModel m = model;
m.addModelTreeListener(modelListener);
Control c = super.createFormControl(parent, settings);
c.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
m.removeModelTreeListener(modelListener);
}
});
return c;
}
public void update() {
if(control == null || control.isDisposed()) return;
if (treeForm!=null) treeForm.update();
if (rightFormContainer!=null) rightFormContainer.update();
}
public ISelectionProvider getSelectionProvider() {
return selectionNotifier;
}
private void printActionList(String level, XActionList actionList) {
if(!ModelUIPlugin.getDefault().isDebugging()) return;
String actionListName = actionList.getName();
String actionListDisplayName = actionList.getDisplayName();
String actionListPath = actionList.getPath();
XActionItem[] items = actionList.getActionItems();
for (int i=0;i<items.length;++i) {
if (items[i] instanceof XActionList) {
printActionList(level+" ", (XActionList)items[i]); //$NON-NLS-1$
} else {
String actionItemName = items[i].getName();
String actionItemDisplayName = items[i].getDisplayName();
String actionItemPath = items[i].getPath();
}
}
}
private MementoDOM memento;
private XModelObject selection = null;
private XModelObject nextSelection = null;
boolean updateLater = true;
// ISelectionChangedListener
public void selectionChanged(SelectionChangedEvent event) {
if(event.getSelection() instanceof ITextSelection) return;
final XModelObject xmo = getModelObject(event.getSelection());
if(nextSelection == xmo) return;
nextSelection = xmo;
saveForm();
if(!updateLater) {
updateSelection(xmo);
} else {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
updateSelection(xmo);
}
});
}
}
void saveForm() {
// store form into memento
if (rightFormContainer.size()>0) {
if (memento!=null) {
Iterator i = rightFormContainer.iterator();
while (i.hasNext()) {
IForm iForm = (IForm)i.next();
IMemento formMemento = memento.getChild(iForm.getHeadingText());
if (formMemento==null) formMemento = memento.createChild(iForm.getHeadingText());
iForm.store(formMemento);
}
}
}
}
public void updateSelection(XModelObject xmo) {
if(xmo != nextSelection) return;
if(selection == nextSelection) return;
selection = nextSelection;
if (xmo!=null && xmo.getModelEntity()!=null) printActionList("", xmo.getModelEntity().getActionList()); //$NON-NLS-1$
IForm form = (xmo == null) ? null : getFormFactory(xmo).getForm();
rightFormContainer.clear();
if(form != null) {
form.initialize(xmo);
// load form from memento
if (memento!=null) {
IMemento formMementro = memento.getChild(form.getHeadingText());
if (formMementro==null) formMementro = memento.createChild(form.getHeadingText());
form.load(formMementro);
}
if(rightFormContainer.getControl() == null || rightFormContainer.getControl().isDisposed()) {
return;
}
rightFormContainer.addForm(form);
form.setParent(rightFormContainer);
if(checkFocus()) {
setFocus();
}
}
}
boolean checkFocus() {
Control c = Display.getDefault().getFocusControl();
if(c == null) {
return true;
}
return false;
}
private IFormFactory getFormFactory(XModelObject selected) {
if(selected == null) return null;
XModelObjectFormFactory formFactory = null;
String formFactoryClassName = selected.getModelEntity().getProperty("formFactory"); //$NON-NLS-1$
if(formFactoryClassName != null) {
if("%Default%".equals(formFactoryClassName)) { //$NON-NLS-1$
return new LayouredFormFactory(selected);
}
Class cls = ModelFeatureFactory.getInstance().getFeatureClass(formFactoryClassName);
if(cls == null) return new FormFactory(selected);
try {
Constructor c = cls.getConstructor(new Class[]{XModelObject.class});
formFactory = (XModelObjectFormFactory)c.newInstance(new Object[]{selected});
} catch (InstantiationException e) {
ModelUIPlugin.getPluginLog().logError(e);
} catch (SecurityException e) {
ModelUIPlugin.getPluginLog().logError(e);
} catch (NoSuchMethodException e) {
ModelUIPlugin.getPluginLog().logError(e);
} catch (IllegalArgumentException e) {
ModelUIPlugin.getPluginLog().logError(e);
} catch (IllegalAccessException e) {
ModelUIPlugin.getPluginLog().logError(e);
} catch (InvocationTargetException e) {
ModelUIPlugin.getPluginLog().logError(e);
}
return formFactory == null ? new FormFactory(selected) : formFactory;
} else {
formFactory = new DefaultFormFactory(selected);
}
return formFactory;
}
private XModelObject getModelObject(ISelection selection) {
if(!(selection instanceof IStructuredSelection) || selection.isEmpty()) return null;
IStructuredSelection s = (IStructuredSelection)selection;
Object o = s.getFirstElement();
return (o instanceof XModelObject) ? (XModelObject)o : null;
}
class XMTL implements XModelTreeListener {
public void nodeChanged(XModelTreeEvent event) {
XModelObject o = event.getModelObject();
String p1 = "" + installedObject.getPath() + "/"; //$NON-NLS-1$ //$NON-NLS-2$
String p2 = "" + o.getPath() + "/"; //$NON-NLS-1$ //$NON-NLS-2$
if(p2.startsWith(p1)) {
update();
}
}
public void structureChanged(XModelTreeEvent event) {
XModelObject o = event.getModelObject();
String p1 = "" + installedObject.getPath() + "/"; //$NON-NLS-1$ //$NON-NLS-2$
String p2 = "" + o.getPath() + "/"; //$NON-NLS-1$ //$NON-NLS-2$
if(p2.startsWith(p1)) {
update();
}
}
}
public boolean isErrorMode() {
return errorMode;
}
public void setErrorMode(boolean b) {
errorMode = b;
if (this.installedObject!=null) doErrorMode();
mainContainer.setEnabled(!b);
}
private void doErrorMode() {
if (isErrorMode()) {
// show error page
errorForm.initialize(getErrors());
errorForm.setVisible(Boolean.TRUE.booleanValue());
} else {
// hide error page
//errorForm.initialize(this.installedObject.get("errors"));
errorForm.setVisible(Boolean.FALSE.booleanValue());
}
}
private String getErrors() {
XModelObject f = FileSystemsHelper.getFile(installedObject);
if(f == null) {
f = installedObject;
}
return f.get("errors"); //$NON-NLS-1$
}
public IDocumentProvider getDocumentProvider() {
return null;
}
public void close(boolean save) {
store();
}
public boolean isEditable() {
return false;
}
public void doRevertToSaved() {
}
public void setAction(String actionID, IAction action) {
actions.put(actionID, action);
}
public IAction getAction(String id) {
return (IAction)actions.get(id);
}
public void setActionActivationCode(String actionId, char activationCharacter, int activationKeyCode, int activationStateMask) {
}
public void removeActionActivationCode(String actionId) {
}
public boolean showsHighlightRangeOnly() {
return false;
}
public void showHighlightRangeOnly(boolean showHighlightRangeOnly) {
}
public void setHighlightRange(int offset, int length, boolean moveCursor) {
}
public IRegion getHighlightRange() {
return null;
}
public void resetHighlightRange() {}
public void selectAndReveal(int offset, int length) {}
public IEditorInput getEditorInput() {
return input;
}
public IEditorSite getEditorSite() {
return site;
}
public void gotoMarker(IMarker marker) {
}
public void init(IEditorSite site, IEditorInput input) throws PartInitException {
this.site = site;
this.input = input;
if (input instanceof IFileEditorInput) {
memento = new MementoDOM(ResourceLayoutManager.getDefault().getLayoutElement(getFile(), "TreeFormPage")); //$NON-NLS-1$
}
}
public void addPropertyListener(IPropertyListener listener) {
}
public void createPartControl(Composite parent) {
super.createControl(parent);
createActions();
}
public IWorkbenchPartSite getSite() {
return site;
}
public Image getTitleImage() {
return null;
}
public String getTitleToolTip() {
return null;
}
public void removePropertyListener(IPropertyListener listener) {
}
public void setFocus() {
if(treeForm != null && treeForm.getControl() != null && !treeForm.getControl().isDisposed()) {
treeForm.setFocus();
} else {
if(control != null && !control.isDisposed()) control.setFocus();
}
}
public Object getAdapter(Class adapter) {
if (ITextOperationTarget.class.equals(adapter)) return this;
return null;
}
private IFile getFile() {
return (input instanceof IFileEditorInput) ? ((IFileEditorInput)input).getFile() : null;
}
private void store() {
IFile file = getFile();
if(file == null) return;
ResourceLayoutManager.getDefault().store(file);
}
public void doSave(IProgressMonitor monitor) {
store();
}
public void doSaveAs() {
store();
}
public boolean isDirty() {
return false;
}
public boolean isSaveAsAllowed() {
return false;
}
public boolean isSaveOnCloseNeeded() {
return false;
}
public boolean canDoOperation(int operation) {
// Collection actions = this.actions.values();
// Iterator i = actions.iterator();
// IAction action;
// while (i.hasNext()) {
// action = (IAction)i.next();
// }
return true;
}
public void doOperation(int operation) {
if (operation>actionMapping.size()) {
ModelUIPlugin.getPluginLog().logError(new IllegalArgumentException("Can not find global action with index: "+operation)); //$NON-NLS-1$
} else {
String globalAction = (String)actionMapping.get(operation);
this.doGlobalAction(globalAction);
}
}
protected void createActions() {
actionMapping.add(null);
actionMapping.add(ITextOperationTarget.UNDO, ActionFactory.UNDO.getId());
actionMapping.add(ITextOperationTarget.REDO, ActionFactory.REDO.getId());
actionMapping.add(ITextOperationTarget.CUT, ActionFactory.CUT.getId());
actionMapping.add(ITextOperationTarget.COPY, ActionFactory.COPY.getId());
actionMapping.add(ITextOperationTarget.PASTE, ActionFactory.PASTE.getId());
actionMapping.add(ITextOperationTarget.DELETE, ActionFactory.DELETE.getId());
actionMapping.add(ITextOperationTarget.SELECT_ALL, ActionFactory.SELECT_ALL.getId());
actionMapping.add(ITextOperationTarget.SHIFT_RIGHT, ITextEditorActionConstants.SHIFT_RIGHT);
actionMapping.add(ITextOperationTarget.SHIFT_LEFT, ITextEditorActionConstants.SHIFT_LEFT);
actionMapping.add(ITextOperationTarget.PRINT, ActionFactory.PRINT.getId());
TextActionHelper.addCutAction(this);
TextActionHelper.addCopyAction(this);
TextActionHelper.addPasteAction(this);
TextActionHelper.addDeleteAction(this);
}
public void doGlobalAction(String action) {
if(errorForm != null && errorForm.isVisible() && errorForm.doGlobalAction(action)) {
return;
}
if(treeForm.doGlobalAction(action)) {
return;
}
if(mainContainer.doGlobalAction(action)) {
// TODO
// refresh
}
}
}