/*
* 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.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.csstudio.sds.internal.runmode.RunModeBoxInput;
import org.csstudio.sds.ui.SdsUiPlugin;
import org.csstudio.sds.ui.internal.actions.OpenScreenshotAction;
import org.csstudio.sds.ui.runmode.RunModeService;
import org.csstudio.ui.util.CustomMediaFactory;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Platform;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.RootEditPart;
import org.eclipse.gef.editparts.ScalableFreeformRootEditPart;
import org.eclipse.gef.editparts.ZoomManager;
import org.eclipse.gef.ui.actions.ActionRegistry;
import org.eclipse.gef.ui.actions.ZoomInAction;
import org.eclipse.gef.ui.actions.ZoomOutAction;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseTrackListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IViewPart;
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, Kai Meyer, Christian Zoller
* @version $Revision: 1.26 $
*/
public final class ShellRunModeBox extends AbstractRunModeBox {
private static final Logger LOG = LoggerFactory.getLogger(ShellRunModeBox.class);
private static final String VIEW_TO_REGISTER_CONTEXT_MENU = "org.eclipse.ui.views.ResourceNavigator";
private static final int SHELL_BORDER = 40;
private static final int SCROLLBAR_MARGIN = 25;
private EditPartViewerProxy _editPartViewerProxy;
private RunModeContextMenuProvider _contextMenuProvider;
/**
* The shell.
*/
private Shell _shell;
private Point parentLocation;
/**
* Constructor.
*
* @param input
* the input
*/
public ShellRunModeBox(RunModeBoxInput input, Point parentLocation) {
super(input);
if (parentLocation != null) {
this.parentLocation = parentLocation;
} else {
this.parentLocation = new Point(0, 0);
}
}
/**
* {@inheritDoc}
*/
@Override
protected GraphicalViewer doOpen(final int x,
final int y,
final boolean openRelative,
final int width,
final int height,
final String title) {
List<RunModeBoxInput> predecessors = getPredecessors(getInput());
// create a shell
_shell = new Shell();
_shell.setText(title);
if (openRelative) {
_shell.setLocation(parentLocation.x + x, parentLocation.y + y);
} else {
_shell.setLocation(x, y);
}
_shell.setLayout(getFillLayout());
_shell.setImage(CustomMediaFactory.getInstance().getImageFromPlugin(SdsUiPlugin.PLUGIN_ID,
"icons/sds.gif"));
_shell.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
final ScrolledComposite scrollComposite = new ScrolledComposite(_shell, SWT.V_SCROLL
| SWT.H_SCROLL);
scrollComposite.setExpandHorizontal(true);
scrollComposite.setExpandVertical(true);
scrollComposite.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).indent(0, 0)
.create());
scrollComposite.setLayout(getFillLayout());
scrollComposite.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLUE));
// create a parent composite that fills the whole shell
GridLayout parentLayout = new GridLayout(1, false);
parentLayout.horizontalSpacing = 0;
parentLayout.marginWidth = 0;
parentLayout.marginHeight = 0;
parentLayout.verticalSpacing = 0;
final Composite parent = new Composite(scrollComposite, SWT.NONE);
parent.setLayout(parentLayout);
parent.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_YELLOW));
// create a composite for the graphical viewer
Composite c = new Composite(parent, SWT.NONE);
c.setLayout(getFillLayout());
c.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).indent(0, 0).create());
// create a composite for path and navigation information
int fullHeight = height;
int fullWidth = width;
if (predecessors.size() > 0) {
Composite navigation = new Composite(parent, SWT.NONE);
RowLayout rowLayout = new RowLayout();
navigation.setLayout(rowLayout);
navigation.setLayoutData(GridDataFactory.fillDefaults().align(SWT.FILL, SWT.BOTTOM)
.grab(true, false).create());
for (int i = 0; i < predecessors.size(); i++) {
new LinkLabel(navigation, predecessors.get(i));
if (i < predecessors.size() - 1) {
new SeparatorLabel(navigation);
}
}
//navigation.pack();
Point size = navigation.computeSize(width, SWT.DEFAULT);
fullHeight = fullHeight + size.y;
}
_shell.setSize(fullWidth + SCROLLBAR_MARGIN, fullHeight + SHELL_BORDER + SCROLLBAR_MARGIN);
// configure a graphical viewer
final GraphicalViewer graphicalViewer = createGraphicalViewer(c);
ActionRegistry actionRegistry = new ActionRegistry();
this.createActions(actionRegistry);
// provide a context menu, Note: We use an proxy for the EditpartViewer
// to ensure that the real EditPartViewer can get garbage collected
_editPartViewerProxy = new EditPartViewerProxy(graphicalViewer);
_contextMenuProvider = new RunModeContextMenuProvider(_editPartViewerProxy, actionRegistry);
_contextMenuProvider.setRemoveAllWhenShown(true);
graphicalViewer.setContextMenu(_contextMenuProvider);
IViewPart viewPart = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
.findView(VIEW_TO_REGISTER_CONTEXT_MENU);
if (viewPart != null) {
viewPart.getSite().registerContextMenu("org.csstudio.sds.ui.runmode",
_contextMenuProvider,
_editPartViewerProxy);
}
// provide a toolbar
createToolbar(_shell, graphicalViewer);
scrollComposite.setContent(parent);
// add dispose listener
_shell.addDisposeListener(new DisposeListener() {
/**
* {@inheritDoc}
*/
@Override
public void widgetDisposed(final DisposeEvent e) {
dispose();
}
});
// open the shell
_shell.open();
return graphicalViewer;
}
/**
* @return
*/
private FillLayout getFillLayout() {
FillLayout fillLayout = new FillLayout();
fillLayout.marginHeight = 0;
fillLayout.marginWidth = 0;
fillLayout.spacing = 0;
return fillLayout;
}
/**
* Recursive method which returns all predecessors of the current run mode
* box.
*
* @param input
* the current box�s input
* @return the input�s of all predecessor boxes
*/
private List<RunModeBoxInput> getPredecessors(RunModeBoxInput input) {
List<RunModeBoxInput> result = new ArrayList<RunModeBoxInput>();
RunModeBoxInput predecessor = input.getPredecessorBox();
if (predecessor != null) {
result.addAll(getPredecessors(predecessor));
result.add(predecessor);
}
return result;
}
/**
* Creates the actions for the shell.
*
* @param actionRegistry
* The {@link ActionRegistry} for the created actions
*/
private void createActions(final ActionRegistry actionRegistry) {
Action closeAction = new Action() {
@Override
public void run() {
Display.getCurrent().asyncExec(new Runnable() {
@Override
public void run() {
_shell.close();
}
});
}
};
closeAction.setText("Close Shell");
closeAction.setId(RunModeContextMenuProvider.CLOSE_ACTION_ID);
actionRegistry.registerAction(closeAction);
}
/**
* Disposes the shell.
*/
@Override
protected void doDispose() {
// close the shell
if (!_shell.isDisposed()) {
_shell.close();
_shell = null;
if (_contextMenuProvider != null) {
_contextMenuProvider.dispose();
_contextMenuProvider = null;
}
if (_editPartViewerProxy != null) {
_editPartViewerProxy.dispose();
_editPartViewerProxy = null;
}
}
}
/**
* Creates a toolbar for the graphical viewer.
*
* @param shell
* the shell
* @param graphicalViewer
* the graphical viewer
*/
@SuppressWarnings("deprecation")
protected void createToolbar(final Shell shell, final GraphicalViewer graphicalViewer) {
// menu bar
MenuManager menuManager = new MenuManager();
// configure zoom actions
RootEditPart rootEditPart = graphicalViewer.getRootEditPart();
if (rootEditPart instanceof ScalableFreeformRootEditPart) {
final ZoomManager zm = ((ScalableFreeformRootEditPart) rootEditPart).getZoomManager();
final List<String> zoomLevels = new ArrayList<String>(3);
zoomLevels.add(ZoomManager.FIT_ALL);
zoomLevels.add(ZoomManager.FIT_WIDTH);
zoomLevels.add(ZoomManager.FIT_HEIGHT);
zm.setZoomLevelContributions(zoomLevels);
if (zm != null) {
MenuManager zoomManager = new MenuManager("Zoom");
final IAction zoomIn = new ZoomInAction(zm);
final IAction zoomOut = new ZoomOutAction(zm);
zoomManager.add(zoomIn);
zoomManager.add(zoomOut);
menuManager.add(zoomManager);
}
MenuManager layerManager = new MenuManager("Layers");
layerManager.add(new ChangeLayerVisibilityAction(graphicalViewer));
menuManager.add(layerManager);
}
// Added by Markus Moeller, 2009-01-26
// Search for the screenshot plugin
IExtensionRegistry extReg = Platform.getExtensionRegistry();
IConfigurationElement[] confElements = extReg
.getConfigurationElementsFor("org.csstudio.utility.screenshot.ImageWorker");
if (confElements.length > 0) {
for (int i = 0; i < confElements.length; i++) {
if (confElements[i].getContributor().getName()
.compareToIgnoreCase("org.csstudio.utility.screenshot") == 0) {
MenuManager captureManager = new MenuManager("Screenshot");
captureManager.add(new OpenScreenshotAction());
menuManager.add(captureManager);
}
}
}
Menu menu = menuManager.createMenuBar(shell);
shell.setMenuBar(menu);
}
/**
* Sets the focus on this Shell.
*/
@Override
public void bringToTop() {
if (_shell != null && !_shell.isDisposed()) {
_shell.setMinimized(false);
_shell.setActive();
_shell.setFocus();
} else {
RunModeService.getInstance().closeRunModeBox(getInput());
}
}
/**
* {@inheritDoc}
*/
@Override
protected void handleWindowPositionChange(final int x,
final int y,
final int width,
final int height) {
_shell.setBounds(x, y, width, height);
}
/**
* {@inheritDoc}
*/
@Override
protected void finalize() throws Throwable {
LOG.debug("finalized()");
}
/**
* Helper class that represents a navigation separator.
*
* @author Sven Wende
*
*/
private static class SeparatorLabel {
public SeparatorLabel(Composite parent) {
Label label = new Label(parent, SWT.NONE);
label.setImage(CustomMediaFactory.getInstance()
.getImageFromPlugin(SdsUiPlugin.PLUGIN_ID, "icons/arrow_right.png"));
label.setText(" > ");
}
}
/**
* Helper class that represents a display navigation link.
*
* @author Sven Wende
*/
private static class LinkLabel extends MouseAdapter implements MouseTrackListener {
private Label _label;
private RunModeBoxInput _input;
public LinkLabel(Composite parent, RunModeBoxInput input) {
assert input != null;
_input = input;
_label = new Label(parent, SWT.NONE);
_label.setText(input.getFilePath().lastSegment());
_label.setForeground(CustomMediaFactory.getInstance().getColor(0, 0, 255));
_label.addMouseListener(this);
_label.addMouseTrackListener(this);
_label.setToolTipText(_input.calculateFullPath() + " ["
+ new SimpleDateFormat("hh:mm").format(new Date(input.getTimestamp())) + "]");
}
@Override
public void mouseUp(MouseEvent e) {
RunModeService.getInstance().openDisplayShellInRunMode(_input.getFilePath(),
_input.getAliases());
}
@Override
public void mouseEnter(MouseEvent e) {
_label.setForeground(CustomMediaFactory.getInstance().getColor(0, 255, 255));
}
@Override
public void mouseExit(MouseEvent e) {
_label.setForeground(CustomMediaFactory.getInstance().getColor(0, 0, 255));
}
@Override
public void mouseHover(MouseEvent e) {
}
}
@Override
public Point getCurrentLocation() {
return _shell.getLocation();
}
}