/*******************************************************************************
* Copyright (c) 2009, 2010 Innovation Gate 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:
* Innovation Gate GmbH - initial API and implementation
******************************************************************************/
package de.innovationgate.eclipse.editors.design;
import java.io.IOException;
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.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.editor.FormEditor;
import org.eclipse.ui.forms.editor.IFormPage;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.menus.IMenuService;
import de.innovationgate.eclipse.editors.Plugin;
import de.innovationgate.eclipse.editors.ResourceIDs;
import de.innovationgate.eclipse.editors.actions.RunValidation;
import de.innovationgate.eclipse.editors.design.pages.ACLRolesConfigurationPage;
import de.innovationgate.eclipse.editors.design.pages.AdvancedConfigurationPage;
import de.innovationgate.eclipse.editors.design.pages.DirectAccessibleModulesPage;
import de.innovationgate.eclipse.editors.design.pages.GeneralConfigurationPage;
import de.innovationgate.eclipse.editors.design.pages.JobDefinitionsConfigurationPage;
import de.innovationgate.eclipse.editors.design.pages.MappingsConfigurationPage;
import de.innovationgate.eclipse.editors.design.pages.PluginConfigurationPage;
import de.innovationgate.eclipse.editors.design.pages.SchemaConfigurationPage;
import de.innovationgate.eclipse.editors.design.pages.ShortcutsConfigurationPage;
import de.innovationgate.eclipse.editors.tml.markers.TMLFileValidator;
import de.innovationgate.eclipse.utils.WorkbenchUtils;
import de.innovationgate.eclipse.utils.ui.GenesisBoundFormPage;
import de.innovationgate.eclipse.utils.ui.model.WGADesignConfigurationModelWrapper;
import de.innovationgate.eclipse.utils.ui.model.WGASchemaDefinitionModel;
import de.innovationgate.eclipse.utils.wga.WGADesignStructureHelper;
import de.innovationgate.wga.model.Encoding;
import de.innovationgate.wga.model.ModelListener;
import de.innovationgate.wga.model.ValidationError;
import de.innovationgate.wga.model.VersionCompliance;
import de.innovationgate.wga.model.WGADesignConfigurationModel;
/**
* editor for an WGADesign
*
*
* this editor monitors changes of its editor input
* if editor file has been changed external for e.g. by an plugin export
* the editor will be automatically refreshed
* NOTE: external functions changing the editors input should check about dirty state before
* changing editor resources
*
*
*
*
*/
public class WGADesignEditor extends FormEditor implements ModelListener, IResourceChangeListener {
public static final String ID = "de.innovationgate.eclipse.ids.editors.WGADesignEditor";
private WGADesignConfigurationModel _model;
private boolean _dirty;
private Map<String, GenesisBoundFormPage> _pages = new HashMap<String, GenesisBoundFormPage>();
private VersionCompliance _persistedVersionComliance;
private Encoding _persistedDesignEncoding;
//private ShortcutsConfigurationPage _shortcutsPage;
private static final int SHORTCUTS_PAGE_INDEX = 4;
private static final int SCHEMADEFINITION_PAGE_INDEX = 5;
private static final String EXPORT_TYPE_LOCAL = "LOCAL_EXPORT";
private static final String EXPORT_TYPE_REMOTE = "REMOTE_EXPORT";
public WGADesignEditor() {
ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE);
}
@Override
protected void addPages() {
try {
GeneralConfigurationPage general = new GeneralConfigurationPage(this);
general.setModel(_model);
addPage(general);
MappingsConfigurationPage mappingsConfig = new MappingsConfigurationPage(this);
mappingsConfig.setModel(_model);
addPage(mappingsConfig);
//RemoteActionsConfigurationPage remoteActions = new RemoteActionsConfigurationPage(this);
//remoteActions.setModel(_model);
//addPage(remoteActions);
ACLRolesConfigurationPage aclRoles = new ACLRolesConfigurationPage(this);
aclRoles.setModel(_model);
addPage(aclRoles);
JobDefinitionsConfigurationPage jobDefs = new JobDefinitionsConfigurationPage(this);
jobDefs.setModel(_model);
addPage(jobDefs);
// dynamic page
if (_model.isFeatureSupported(WGADesignConfigurationModel.FEATURE_SHORTCUTS)) {
ShortcutsConfigurationPage shortcutsPage = new ShortcutsConfigurationPage(this);
shortcutsPage.setModel(_model);
addPage(SHORTCUTS_PAGE_INDEX, shortcutsPage);
}
AdvancedConfigurationPage advancedPage = new AdvancedConfigurationPage(this);
advancedPage.setModel(_model);
addPage(advancedPage);
DirectAccessibleModulesPage directAccessibleModulePage = new DirectAccessibleModulesPage(this);
directAccessibleModulePage.setModel(_model);
addPage(directAccessibleModulePage);
PluginConfigurationPage pluginConfig = new PluginConfigurationPage(this);
pluginConfig.setModel(_model);
addPage(pluginConfig);
if (_model.isFeatureSupported(WGASchemaDefinitionModel.FEATURE_SCHEMADEFINITION) && _model instanceof WGASchemaDefinitionModel) {
SchemaConfigurationPage schemaPage = new SchemaConfigurationPage(this);
schemaPage.setModel((WGASchemaDefinitionModel)_model);
addPage(SCHEMADEFINITION_PAGE_INDEX, schemaPage);
}
} catch (PartInitException e) {
Plugin.getDefault().logError("Unable to init design editor pages.", e);
}
}
@Override
public void init(IEditorSite site, IEditorInput input)
throws PartInitException {
super.init(site, input);
IFile syncInfoFile = ((IFileEditorInput)input).getFile();
try {
if (getSite().getShell().isVisible()) {
// check if design is compatible
if (syncInfoFile != null) {
if (!WGADesignStructureHelper.isWGAVersionComplianceCompatible(syncInfoFile)) {
MessageDialog.openWarning(getSite().getShell(), "Incompatible design version", "This design uses an incompatible compliance level. Please upgrade to the latest WDS version to work on this design with full feature support.");
}
}
}
_model =new WGADesignConfigurationModelWrapper(syncInfoFile);
_model.addListener(this);
_persistedVersionComliance = _model.getVersionCompliance();
_persistedDesignEncoding = _model.getDesignEncoding();
setPartName("Design (" + syncInfoFile.getParent().getName() + ")");
try {
// model might have create default files, so refresh project
((IFileEditorInput)input).getFile().getProject().refreshLocal(IResource.DEPTH_INFINITE, null);
} catch (CoreException e) {
Plugin.getDefault().logError("Unable to refresh project.", e);
}
} catch (IOException e) {
throw new PartInitException(e.getMessage(), e);
}
}
@Override
public void doSave(IProgressMonitor monitor) {
try {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
if (validateModel()) {
boolean askForValidation = false;
if (_persistedVersionComliance != null && !_persistedVersionComliance.equals(_model.getVersionCompliance())) {
askForValidation = true;
}
//boolean askForReopenEditors = false;
if (_persistedDesignEncoding == null && !(_persistedDesignEncoding == _model.getDesignEncoding())) {
//askForReopenEditors = true;
askForValidation = true;
} else if (_persistedDesignEncoding != null && !_persistedDesignEncoding.equals(_model.getDesignEncoding())) {
//askForReopenEditors = true;
askForValidation = true;
}
_model.saveChanges();
_persistedVersionComliance = _model.getVersionCompliance();
_persistedDesignEncoding = _model.getDesignEncoding();
resetValidationMessages();
_dirty = false;
ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE);
firePropertyChange(IEditorPart.PROP_DIRTY);
if (askForValidation) {
boolean result = MessageDialog.openQuestion(getSite().getShell(), "Validation requested", "Validation dependent properties of this design has changed. A revalidation of the design resources is recommended. Perform validation now?");
if (result) {
RunValidation.call(((IFileEditorInput)getEditorInput()).getFile().getParent(), getSite().getShell());
}
}
/*
* not necessary anymore bc. editors use filedocumentprovider now which can handle these automatical
if (askForReopenEditors) {
handleReOpenDesignResourceEditors();
}*/
} else {
monitor.setCanceled(true);
}
} catch (IOException e) {
WorkbenchUtils.showErrorDialog(getSite().getShell(), "Error", "Unable to save changes.", e);
}
}
private void handleReOpenDesignResourceEditors() {
// collect tml/ tmlscript editor which are editing a resource of the current design
IContainer designRoot = ((IFileEditorInput)getEditorInput()).getFile().getParent();
List<IEditorPart> editorsToReopen = WorkbenchUtils.findOpenEditors(Plugin.getDefault().getWorkbench(), ResourceIDs.EDITOR_TML, designRoot);
editorsToReopen.addAll(WorkbenchUtils.findOpenEditors(Plugin.getDefault().getWorkbench(), ResourceIDs.EDITOR_TMLSCRIPT, designRoot));
if (editorsToReopen.isEmpty()) {
return;
}
boolean result = MessageDialog.openQuestion(getSite().getShell(), "Reopen editors", "The design encoding has changed. Reopening corresponding design resource editors is recommended. Continue?");
if (result) {
// close editors
List<IFile> filesToOpen = new ArrayList<IFile>();
for (IEditorPart editor : editorsToReopen) {
filesToOpen.add(((IFileEditorInput)editor.getEditorInput()).getFile());
getSite().getPage().closeEditor(editor, true);
}
// reopen editors
for (IFile file : filesToOpen) {
if (file.getFileExtension().equalsIgnoreCase("tml")) {
try {
WorkbenchUtils.openEditor(Plugin.getDefault().getWorkbench(), file, ResourceIDs.EDITOR_TML);
} catch (PartInitException e) {
Plugin.getDefault().logError("Unable to open editor", e);
}
TMLFileValidator.validateTMLFile(file);
} else if (file.getFileExtension().equalsIgnoreCase("tmlscript")) {
try {
WorkbenchUtils.openEditor(Plugin.getDefault().getWorkbench(), file, ResourceIDs.EDITOR_TMLSCRIPT);
} catch (PartInitException e) {
Plugin.getDefault().logError("Unable to open editor", e);
}
}
}
}
getSite().getPage().activate(this);
}
private void resetValidationMessages() {
Iterator<GenesisBoundFormPage> pages = _pages.values().iterator();
while (pages.hasNext()) {
GenesisBoundFormPage page = pages.next();
page.resetValidationMessages();
setPageImage(page.getIndex(), null);
}
}
private boolean validateModel() {
List<ValidationError> errors = _model.validate();
resetValidationMessages();
// notify active page
//Page activePage = (Page)getActivePageInstance();
//activePage.handleValidationErrors(errors);
Iterator<GenesisBoundFormPage> pages = _pages.values().iterator();
while (pages.hasNext()) {
GenesisBoundFormPage page = pages.next();
page.handleValidationErrors(errors);
if (page.hasError()) {
setPageImage(page.getIndex(), PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_ERROR_TSK));
} else {
setPageImage(page.getIndex(), null);
}
}
if (errors != null && !errors.isEmpty()) {
return false;
} else {
return true;
}
}
@Override
public boolean isSaveAsAllowed() {
return false;
}
public void modelChanged() {
_dirty = true;
firePropertyChange(IEditorPart.PROP_DIRTY);
validateModel();
// dynamic page handling
IFormPage page = findPage(ShortcutsConfigurationPage.ID);
if (_model.isFeatureSupported(WGADesignConfigurationModel.FEATURE_SHORTCUTS)) {
if (page == null) {
try {
page =new ShortcutsConfigurationPage(this);
((ShortcutsConfigurationPage)page).setModel(_model);
addPage(SHORTCUTS_PAGE_INDEX, page);
} catch (PartInitException e) {
}
}
} else if (page != null) {
removePage(page.getIndex());
}
page = findPage(SchemaConfigurationPage.ID);
if (_model.isFeatureSupported(WGASchemaDefinitionModel.FEATURE_SCHEMADEFINITION)) {
if (page == null) {
try {
page = new SchemaConfigurationPage(this);
((SchemaConfigurationPage)page).setModel(_model);
addPage(SCHEMADEFINITION_PAGE_INDEX, page);
} catch (PartInitException e) {
}
}
} else if (page != null) {
removePage(page.getIndex());
}
}
@Override
public boolean isDirty() {
return _dirty;
}
@Override
public void doSaveAs() {
}
@Override
public int addPage(IFormPage page) throws PartInitException {
if (page instanceof GenesisBoundFormPage) {
_pages.put(page.getId(), (GenesisBoundFormPage)page);
}
return super.addPage(page);
}
@Override
public void addPage(int index, IFormPage page) throws PartInitException {
if (page instanceof GenesisBoundFormPage) {
_pages.put(page.getId(), (GenesisBoundFormPage)page);
}
super.addPage(index, page);
}
@Override
public void removePage(int pageIndex) {
Iterator<GenesisBoundFormPage> pages = _pages.values().iterator();
while (pages.hasNext()) {
GenesisBoundFormPage page = pages.next();
if (page.getIndex() == pageIndex) {
pages.remove();
}
}
super.removePage(pageIndex);
}
/*
@Override
public boolean isSaveOnCloseNeeded() {
boolean saveOnClose = super.isSaveOnCloseNeeded();
if (saveOnClose) {
List<ValidationError> errors = _model.validate();
if (errors != null && !errors.isEmpty()) {
// model has errors - no save on close
return saveOnClose = false;
}
}
return saveOnClose;
}*/
public void createPageToolbar(Form form) {
ToolBarManager toolbarManager = (ToolBarManager)form.getToolBarManager();
IMenuService ms = (IMenuService)getSite().getService(IMenuService.class);
ms.populateContributionManager(toolbarManager, "toolbar:" + ID);
toolbarManager.update(true);
/*
form.getToolBarManager().add(new Action("Export WGA Design", IAction.AS_DROP_DOWN_MENU) {
@Override
public ImageDescriptor getImageDescriptor() {
return WGADesignerPlugin.getDefault().getImageRegistry().getDescriptor(WGADesignerPlugin.IMAGE_EXPORT_WGA_DESIGN);
}
@Override
public IMenuCreator getMenuCreator() {
return new IMenuCreator() {
private Menu _menu = null;
public void dispose() {
if (_menu != null) {
_menu.dispose();
}
}
public Menu getMenu(Control parent) {
if (_menu != null) {
_menu.dispose();
}
_menu = new Menu(parent);
MenuItem itemLocal = new MenuItem(_menu, SWT.None);
itemLocal.setText("Export design to local filesystem");
itemLocal.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
// store last action in prefs
WGADesignerPlugin.getDefault().getPreferenceStore().putValue(PreferenceConstants.PLUGIN_EXPORT_TYPE + "_" + _model.getDesignKey(), EXPORT_TYPE_LOCAL);
// start local export wizard
openWizardOnCurrentInput(ExportWGADesignLocal.ID);
}
});
MenuItem itemRemote = new MenuItem(_menu, SWT.None);
itemRemote.setText("Export design to remote server");
itemRemote.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
// store last action in prefs
WGADesignerPlugin.getDefault().getPreferenceStore().putValue(PreferenceConstants.PLUGIN_EXPORT_TYPE + "_" + _model.getDesignKey(), EXPORT_TYPE_REMOTE);
// start remote export wizard
openWizardOnCurrentInput(ExportWGADesignRemote.ID);
}
});
return _menu;
}
public Menu getMenu(Menu parent) {
return null;
}
};
}
@Override
public void run() {
String lastExportType = WGADesignerPlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.PLUGIN_EXPORT_TYPE + "_" + _model.getDesignKey());
if (lastExportType != null && lastExportType.equals(EXPORT_TYPE_LOCAL)) {
openWizardOnCurrentInput(ExportWGADesignLocal.ID);
} else if (lastExportType != null && lastExportType.equals(EXPORT_TYPE_REMOTE)) {
openWizardOnCurrentInput(ExportWGADesignRemote.ID);
}
}
});
form.getToolBarManager().update(true);
*/
}
public void resourceChanged(IResourceChangeEvent event) {
try {
final IFile fSyncInfo = ((IFileEditorInput)getEditorInput()).getFile();
final IFile fCsConfig = new WGADesignStructureHelper(fSyncInfo).getCsConfig();
IFile schema = null;
if (fSyncInfo != null && fSyncInfo.exists()) {
schema = fSyncInfo.getParent().getFolder(new Path("files").append("system")).getFile("schema.xml");
}
final IFile fSchema = schema;
event.getDelta().accept(new IResourceDeltaVisitor() {
public boolean visit(IResourceDelta delta) throws CoreException {
// check if editor files (syninfo.xml/csconfig.xml) has been changed external for e.g. by an plugin export
// in this case we can refresh the editor
// external functions changing the editors input should check about dirty state before
// changing resources
if (delta.getResource().equals(fSyncInfo)) {
if (delta.getResource().exists()) {
refresh();
return false;
} else {
// design has been deleted
close(false);
}
} else if (delta.getResource().equals(fCsConfig)) {
refresh();
return false;
} else if (delta.getResource().equals(fSchema)) {
refresh();
return false;
}
return true;
}
});
} catch (CoreException e) {
Plugin.getDefault().logError("Unable to handle resource change event.", e);
}
}
/**
* refresh the editor and all pages with the model state in the filesystem
*/
public void refresh() {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
Iterator<GenesisBoundFormPage> pages = _pages.values().iterator();
while (pages.hasNext()) {
GenesisBoundFormPage page = pages.next();
try {
page.refresh();
} catch (IOException e) {
Plugin.getDefault().logError("Unable to refresh editor page '" + page.getId() + "'.", e);
}
}
_dirty = false;
firePropertyChange(IEditorPart.PROP_DIRTY);
_persistedVersionComliance = _model.getVersionCompliance();
_persistedDesignEncoding = _model.getDesignEncoding();
}
});
}
@Override
public void dispose() {
super.dispose();
ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
}
/*
protected void openRemoteExportWizard() {
ExportWGADesignRemote wizard = new ExportWGADesignRemote();
wizard.init(WGADesignerPlugin.getDefault().getWorkbench(),
new SingleStructuredSelection(((FileEditorInput)getEditorInput()).getFile().getParent()));
WizardDialog dialog = new WizardDialog(WGADesignerPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getShell(), wizard);
dialog.open();
}*/
}