/*
* Copyright (c) 2008 Stiftung Deutsches Elektronen-Synchrotron,
* Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
*
* THIS SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "../AS IS" BASIS.
* WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. SHOULD THE SOFTWARE PROVE DEFECTIVE
* IN ANY RESPECT, THE USER ASSUMES THE COST OF ANY NECESSARY SERVICING, REPAIR OR
* CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
* NO USE OF ANY SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
* DESY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
* OR MODIFICATIONS.
* THE FULL LICENSE SPECIFYING FOR THE SOFTWARE THE REDISTRIBUTION, MODIFICATION,
* USAGE AND OTHER RIGHTS AND OBLIGATIONS IS INCLUDED WITH THE DISTRIBUTION OF THIS
* PROJECT IN THE FILE LICENSE.HTML. IF THE LICENSE IS NOT INCLUDED YOU MAY FIND A COPY
* AT HTTP://WWW.DESY.DE/LEGAL/LICENSE.HTM
*/
package org.csstudio.sds.ui.internal.runmode;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
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.csstudio.dal.CssApplicationContext;
import org.csstudio.dal.simple.SimpleDALBroker;
import org.csstudio.sds.internal.persistence.DisplayModelLoadAdapter;
import org.csstudio.sds.internal.persistence.PersistenceUtil;
import org.csstudio.sds.internal.runmode.RunModeBoxInput;
import org.csstudio.sds.model.AbstractWidgetModel;
import org.csstudio.sds.model.DisplayModel;
import org.csstudio.sds.model.IPropertyChangeListener;
import org.csstudio.sds.model.RuntimeContext;
import org.csstudio.sds.model.WidgetProperty;
import org.csstudio.sds.ui.SdsUiPlugin;
import org.csstudio.sds.ui.editparts.ExecutionMode;
import org.csstudio.sds.ui.internal.editor.dnd.ProcessVariableDragSourceListener;
import org.csstudio.sds.ui.internal.editor.dnd.ProcessVariablesDragSourceListener;
import org.csstudio.sds.ui.internal.editparts.WidgetEditPartFactory;
import org.csstudio.sds.ui.internal.viewer.PatchedGraphicalViewer;
import org.csstudio.sds.ui.runmode.IDisplayLoadedCallback;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.gef.EditDomain;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.editparts.ScalableFreeformRootEditPart;
import org.eclipse.gef.tools.SelectionTool;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.PlatformUI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A box that manages a shell, which uses a GEF graphical viewer to display SDS
* displays.
*
* @author Sven Wende, Alexander Will
* @version $Revision: 1.30 $
*/
public abstract class AbstractRunModeBox {
private static final Logger LOG = LoggerFactory.getLogger(AbstractRunModeBox.class);
private boolean _disposed;
/**
* The viewer that displays the model.
*/
private GraphicalViewer _graphicalViewer;
/**
* A List of DisposeListener.
*/
private List<IRunModeDisposeListener> _disposeListeners;
/**
* An input stream for the display xml data.
*/
private InputStream _inputStream;
/**
* The display model which should be shown.
*/
private DisplayModel _displayModel;
/**
* The input for this box.
*/
private final RunModeBoxInput _input;
/**
* Contains all property change listeners that will be added to the display
* model or widgets.
*/
private HashMap<WidgetProperty, IPropertyChangeListener> _propertyListeners;
private IDisplayLoadedCallback callback;
/**
* Constructor.
*
* @param input
* the {@link RunModeBoxInput} for the model file that should be displayed
*/
public AbstractRunModeBox(final RunModeBoxInput input)
throws IllegalArgumentException {
assert input != null;
_input = input;
_inputStream = getInputStream(input.getFilePath());
_disposed = false;
if (_inputStream == null) {
throw new IllegalArgumentException("Cannot open display "
+ input.getFilePath().toPortableString());
}
_disposeListeners = new ArrayList<IRunModeDisposeListener>();
_propertyListeners = new HashMap<WidgetProperty, IPropertyChangeListener>();
}
/**
* Open!
*/
public void openRunMode(final Runnable runAfterOpen, final IDisplayLoadedCallback callback) {
// Open the run mode representation
this.callback = callback;
// initialize model
_displayModel = new DisplayModel();
_displayModel.setLive(true);
// load and connect the model
PersistenceUtil.asyncFillModel(_displayModel, _inputStream,
new DisplayModelLoadAdapter() {
@Override
public void onDisplayModelLoaded() {
}
@Override
public void onDisplayPropertiesLoaded() {
// expose runtime information to the model
RuntimeContext runtimeContext = new RuntimeContext(
_input.getFilePath(), _input.getAliases());
runtimeContext.setRunModeBoxInput(_input);
// .. we create a separate broker instance for each running display
runtimeContext.setBroker(SimpleDALBroker.newInstance(new CssApplicationContext("CSS")));
LOG.info("SimpleDALBroker instance created");
_displayModel.setRuntimeContext(runtimeContext);
final int x = _displayModel.getX();
final int y = _displayModel.getY();
final boolean openRelative = _displayModel.getOpenRelative();
final int width = _displayModel.getWidth();
final int height = _displayModel.getHeight();
PlatformUI.getWorkbench().getDisplay().syncExec(
new Runnable() {
@Override
public void run() {
Map<String, String> aliases = _input
.getAliases();
// create and open the viewer
StringBuffer title = new StringBuffer();
// title
title.append(_input.getFilePath()
.makeRelative()
.toPortableString());
if ((aliases != null)
&& !aliases.isEmpty()) {
title.append("?");
Iterator<String> it = aliases
.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
String val = aliases.get(key);
title.append(key);
title.append("=");
title.append(val);
title.append(it.hasNext() ? "&"
: "");
}
}
_graphicalViewer = doOpen(x, y, openRelative, width,
height, title.toString());
// configure the viewer
_graphicalViewer
.setContents(_displayModel);
String bgColor = _displayModel.getColor(AbstractWidgetModel.PROP_COLOR_BACKGROUND);
_graphicalViewer
.getControl()
.setBackground(SdsUiPlugin.getDefault().getColorAndFontService().getColor(bgColor));
// execute the runnable
if (runAfterOpen != null) {
runAfterOpen.run();
}
callback.displayLoaded();
}
});
}
});
}
/**
* Subclasses should open the necessary workbench elements (usually views or
* shells), which should display a synoptic display using a GEF
* {@link GraphicalViewer}.
*
* Subclasses should also take care for a clean shutdown handling, by adding
* the necessary listeners to the created workbench parts which call
* {@link #dispose()} on this box, in case the part is closed by the user.
*
* @param x
* x position hint
* @param y
* y position hin
* @param openRelative
* To be opened relative to predecessor displays
* @param width
* width hint
* @param height
* height hint
* @param title
* a title
* @return the {@link GraphicalViewer} which is used to display the model
*/
protected abstract GraphicalViewer doOpen(int x, int y, boolean openRelative, int width,
int height, String title);
/**
* Adds the given IRunModeDisposeListener to the internal List of
* DisposeListeners.
*
* @param listener
* The IRunModeDisposeListener, which should be added
*/
public void addDisposeListener(final IRunModeDisposeListener listener) {
if (!_disposeListeners.contains(listener)) {
_disposeListeners.add(listener);
}
}
/**
* Removes the given IRunModeDisposeListener from the internal List of
* DisposeListeners.
*
* @param listener
* The IRunModeDisposeListener, which should be removed
*/
public void removeDisposeListener(final IRunModeDisposeListener listener) {
if (_disposeListeners.contains(listener)) {
_disposeListeners.remove(listener);
}
}
/**
* Notifies all registered IRunModeDisposeListener, that this RunModeBox is
* disposed.
*/
private void fireDispose() {
if (_disposeListeners != null) {
for (IRunModeDisposeListener l : _disposeListeners) {
l.dispose();
}
}
}
/**
* Disposes the shell.
*/
public final synchronized void dispose() {
if(!_disposed) {
_disposed = true;
// remove all change listeners
for (WidgetProperty p : _propertyListeners.keySet()) {
p.removePropertyChangeListener(_propertyListeners.get(p));
}
// let subclasses do their job
doDispose();
// inform listeners that this box has been disposed
fireDispose();
// kill broker
RuntimeContext context = _displayModel.getRuntimeContext();
if(context!=null) {
SimpleDALBroker broker = context.getBroker();
broker.releaseAll();
context.setBroker(null);
LOG.info("SimpleDALBroker instance released.");
callback.displayClosed();
}
// forget all referenced objects
_graphicalViewer = null;
_displayModel = null;
_disposeListeners = null;
_inputStream = null;
_propertyListeners = null;
_disposed = true;
}
}
protected RunModeBoxInput getInput() {
return _input;
}
protected abstract void doDispose();
protected abstract void handleWindowPositionChange(int x, int y, int width,
int height);
/**
* Sets the focus on this Shell.
*/
public abstract void bringToTop();
/**
* Creates a graphical viewer that can be used to display SDS models.
*
* @param parent
* the parent composite
*
* @return a graphical viewer that can be used to display SDS models
*/
static GraphicalViewer createGraphicalViewer(final Composite parent) {
final PatchedGraphicalViewer viewer = new PatchedGraphicalViewer();
viewer.createControl(parent);
viewer.setEditPartFactory(new WidgetEditPartFactory(
ExecutionMode.RUN_MODE));
final ScalableFreeformRootEditPart root = new ScalableFreeformRootEditPart();
viewer.setRootEditPart(root);
EditDomain editDomain = new EditDomain();
final SelectionTool tool = new SelectionTool();
tool.setUnloadWhenFinished(false);
editDomain.setDefaultTool(tool);
editDomain.addViewer(viewer);
// initialize drag support (order matters!)
viewer.addDragSourceListener(new ProcessVariableDragSourceListener(viewer));
viewer.addDragSourceListener(new ProcessVariablesDragSourceListener(viewer));
// viewer.addDragSourceListener(new ProcessVariableDragSourceListener(viewer));
// viewer.addDragSourceListener(new TextTransferDragSourceListener(viewer));
return viewer;
}
/**
* Return the {@link InputStream} from the given path.
*
* @param path
* The {@link IPath} to the file
* @return The corresponding {@link InputStream}
*/
private InputStream getInputStream(final IPath path) {
InputStream result = null;
// try workspace
IResource r = ResourcesPlugin.getWorkspace().getRoot().findMember(path,
false);
if (r instanceof IFile) {
try {
result = ((IFile) r).getContents();
} catch (CoreException e) {
result = null;
}
}
if (result == null) {
// try from local file system
try {
result = new FileInputStream(path.toFile());
} catch (FileNotFoundException e) {
result = null;
}
}
return result;
}
public abstract Point getCurrentLocation();
public DisplayModel getDisplayModel() {
return _displayModel;
}
}