/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.gui.workflow.editor;
import java.io.File;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.ui.palette.FlyoutPaletteComposite.FlyoutPreferences;
import org.eclipse.gef.ui.palette.PaletteViewer;
import org.eclipse.gef.ui.palette.PaletteViewerProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.internal.views.properties.tabbed.view.TabbedPropertyComposite;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.tabbed.ITabDescriptor;
import org.eclipse.ui.views.properties.tabbed.ITabSelectionListener;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
import de.rcenvironment.core.component.workflow.execution.api.WorkflowExecutionService;
import de.rcenvironment.core.component.workflow.execution.api.WorkflowFileException;
import de.rcenvironment.core.gui.workflow.GUIWorkflowDescriptionLoaderCallback;
import de.rcenvironment.core.gui.workflow.parts.ReadOnlyWorkflowEditorEditPartFactory;
/**
* WorkflowEditor operating in read-only mode.
* @author Martin Misiak
*/
public class ReadOnlyWorkflowEditor extends WorkflowEditor {
private static final Log LOGGER = LogFactory.getLog(ReadOnlyWorkflowEditor.class);
private TabbedPropertySheetPage tabbedPropertySheetPage;
public ReadOnlyWorkflowEditor() {
super();
}
@Override
public Object getAdapter(@SuppressWarnings("rawtypes") Class type) {
if (type == IPropertySheetPage.class) {
if (tabbedPropertySheetPage == null || tabbedPropertySheetPage.getControl() == null
|| tabbedPropertySheetPage.getControl().isDisposed()) {
tabbedPropertySheetPage = new ReadOnlyTabbedPropertySheetPage(this);
}
return tabbedPropertySheetPage;
} else {
return super.getAdapter(type);
}
}
/**
* ReadOnlyTabbedPropertySheetPage hooks the "disable property editing" functionality
* into a TabbedPropertySheetPage.
*/
private class ReadOnlyTabbedPropertySheetPage extends TabbedPropertySheetPage {
ReadOnlyTabbedPropertySheetPage(ITabbedPropertySheetPageContributor tabbedPropertySheetPageContributor) {
super(tabbedPropertySheetPageContributor);
super.addTabSelectionListener(new ITabSelectionListener(){
@Override
public void tabSelected(ITabDescriptor arg0) {
disableCurrentPropertySection(tabbedPropertySheetPage);
}
});
}
@Override
public void selectionChanged(IWorkbenchPart part, ISelection selection){
super.selectionChanged(part, selection);
disableCurrentPropertySection(tabbedPropertySheetPage);
}
}
@Override
protected void initializeGraphicalViewer() {
super.initializeGraphicalViewer();
GraphicalViewer viewer = super.getViewer();
viewer.setEditPartFactory(new ReadOnlyWorkflowEditorEditPartFactory());
viewer.setContents(super.getWorkflowDescription());
viewer.getControl().setBackground(Display.getDefault().getSystemColor(SWT.COLOR_GRAY));
int[] eventTypes = { SWT.MouseDoubleClick, SWT.DragDetect };
removeListeners(viewer.getControl(), eventTypes);
tabbedPropertySheetPage = new ReadOnlyTabbedPropertySheetPage(this);
}
/**
* Effectively disables hit-testing of the visual components of the tool palette.
*/
@Override
protected PaletteViewerProvider createPaletteViewerProvider() {
return new PaletteViewerProvider(getEditDomain()) {
@Override
public PaletteViewer createPaletteViewer(Composite parent){
PaletteViewer pv = super.createPaletteViewer(parent);
pv.getVisualPartMap().clear();
return pv;
}
};
}
/**
* Default palette-state is set to hidden.
*/
@Override
protected FlyoutPreferences getPalettePreferences() {
FlyoutPreferences prefs = super.getPalettePreferences();
prefs.setPaletteState(8);
return prefs;
}
@Override
protected void loadWorkflowFromFile(final File wfFile, final GUIWorkflowDescriptionLoaderCallback wfdc) {
if (wfFile != null) {
Job job = new Job(Messages.openWorkflow) {
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
monitor.beginTask(Messages.loadingComponents, 2);
monitor.worked(1);
WorkflowExecutionService workflowExecutionService =
serviceRegistryAccess.getService(WorkflowExecutionService.class);
workflowDescription = workflowExecutionService
.loadWorkflowDescriptionFromFileConsideringUpdates(wfFile, wfdc, true);
initializeWorkflowDescriptionListener();
monitor.worked(1);
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
if (getViewer().getControl() != null) {
getViewer().setContents(workflowDescription);
getGraphicalControl().setVisible(true);
if (getEditorSite() != null) {
setFocus();
}
firePropertyChange(PROP_FINAL_WORKFLOW_DESCRIPTION_SET);
}
}
});
} catch (final WorkflowFileException e) {
LogFactory.getLog(getClass()).error("Failed to open workflow: " + wfFile.getAbsolutePath(), e);
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
// do not use Display.getDefault().getActiveShell() as this might return
// the progress monitor dialog
closeEditorAndShowMessage("Failed to open workflow file in read-only: The workflow was probably executed"
+ " with a different version of RCE than the one in use.");
}
});
} finally {
monitor.done();
}
return Status.OK_STATUS;
};
};
job.setUser(true);
job.schedule();
}
String fileName = getPartName();
if (fileName != null) {
String fileNameRO = fileName + " - Read only";
setPartName(fileNameRO);
}
}
/**
* Identify towards the TabbedPropertySheetPage as a "WorkflowEditor" to receive
* all component properties, which are registered for this Editor.
* TODO : Find a better way, than a hard-coded string.
* @return The contributor ID of the WorkflowEditor.
*/
@Override
public String getContributorId() {
return "de.rcenvironment.rce.gui.workflow.editor.WorkflowEditor";
}
public boolean isSaveOnCloseNeeded(){
return false;
}
@Override
public boolean isSaveAsAllowed() {
return false;
}
@Override
public boolean isDirty() {
return false;
}
@Override
public void doSave(IProgressMonitor arg0) {}
/**
* Disables the controls in the currently selected tab of the TabbedPropertySheetPage,
* making the Properties of a selected Component non-editable.
* @param tpsp TabbedPropertySheetPage responsible for holding the properties
*/
private void disableCurrentPropertySection(TabbedPropertySheetPage tpsp){
if (tpsp instanceof TabbedPropertySheetPage){
Control swtControls = tpsp.getControl();
if (swtControls instanceof TabbedPropertyComposite){
TabbedPropertyComposite propComposite = (TabbedPropertyComposite) swtControls;
Composite tabComposite = propComposite.getTabComposite();
recursiveSetDisabled(tabComposite);
}
}
}
/**
* Recursively iterates an Composite until it reaches its leaf Controls, or it does not
* contain any more children, and sets them to disabled. Some Composites/Controls
* receive a special treatment( Labels, StyledText, Tree ) instead of being set to disabled.
* Special treatment is also applied for Object of different types than Composite/Control.
* @param ctrl Input Control/Composite
*/
private void recursiveSetDisabled(Object obj) {
if (obj instanceof Composite){
Composite comp = (Composite) obj;
for (Control c : comp.getChildren()){
recursiveSetDisabled(c);
}
// For composites which do not have children( Like CCombo, StyledText etc...)
if (comp.getChildren().length == 0){
comp.setEnabled(false);
}
// No composite, must be a Control leaf
} else if (obj instanceof Control){
Control ctrl = (Control) obj;
ctrl.setEnabled(false);
}
// Apply special treatment for specific Composites/Controls and different Objects
specialTreatment(obj);
return;
}
/**
* Provides special treatment of specific Composites/Controls
* for the Method recursiveSetDisabled(Control).
* @param ctrl Input Control/Composite
*/
private void specialTreatment(Object obj){
// Special Treatment of Composites
if (obj instanceof Composite){
Composite comp = (Composite) obj;
// Treatment: Tree
if (comp instanceof Tree){
Tree t = (Tree) comp;
int[] eventTypes = { SWT.DragDetect, SWT.Selection };
removeListeners(t, eventTypes);
// t.getItems()[0].
t.setEnabled(true);
}
// Treatment: StyledText
if (comp instanceof StyledText){
StyledText text = (StyledText) comp;
text.setEnabled(true);
text.setEditable(false);
}
// Treatment: CTabFolder
if (comp instanceof CTabFolder){
CTabFolder folder = (CTabFolder) comp;
CTabItem[] folderItems = folder.getItems();
for (CTabItem cItem : folderItems){
//Identify the "add new folder" button on the absence of SWT.CLOSE style
if (cItem.getStyle() != SWT.CLOSE){
cItem.dispose();
} else {
cItem.setShowClose(false);
}
}
}
// Special Treatment of Controls
} else if (obj instanceof Control){
Control ctrl = (Control) obj;
// Treatment: Label
if (ctrl instanceof Label){
ctrl.setEnabled(true);
int[] eventTypes = { SWT.MouseDown, SWT.MouseUp, SWT.MouseDoubleClick };
removeListeners(ctrl, eventTypes);
}
// Treatment Controls: ...add more here
}
return;
}
/**
* Removes all listeners of a SWT Widget which listen to specific eventTypes.
* @param ctrl Control who's listeners are to be removed
* @param eventTypes Listeners who listen to the events specified in this array get removed
*/
public static void removeListeners(Widget ctrl, int[] eventTypes) {
for (int eventType : eventTypes) {
Listener[] listeners = ctrl.getListeners(eventType);
for (Listener listener : listeners) {
ctrl.removeListener(eventType, listener);
}
}
}
}