/*-
* Copyright © 2009 Diamond Light Source Ltd.
*
* This file is part of GDA.
*
* GDA is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License version 3 as published by the Free
* Software Foundation.
*
* GDA is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along
* with GDA. If not, see <http://www.gnu.org/licenses/>.
*/
package uk.ac.gda.dal.csswidgets.editparts;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import org.csstudio.sds.components.model.RectangleModel;
import org.csstudio.sds.internal.persistence.PersistenceUtil;
import org.csstudio.sds.model.AbstractWidgetModel;
import org.csstudio.sds.model.ContainerModel;
import org.csstudio.sds.model.DisplayModel;
import org.csstudio.sds.ui.editparts.AbstractContainerEditPart;
import org.csstudio.sds.ui.editparts.IWidgetPropertyChangeHandler;
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.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.MouseEvent;
import org.eclipse.draw2d.MouseListener;
import org.eclipse.draw2d.MouseMotionListener;
import org.eclipse.draw2d.RectangleFigure;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editpolicies.XYLayoutEditPolicy;
import org.eclipse.gef.requests.CreateRequest;
import org.eclipse.swt.graphics.Color;
import org.eclipse.ui.progress.IJobRunnable;
import uk.ac.gda.dal.csswidgets.figures.MoveableWindowFigure;
import uk.ac.gda.dal.csswidgets.model.MoveableTitleBarModel;
import uk.ac.gda.dal.csswidgets.model.MoveableWindowModel;
/**
* A widget that can contain multiple movable linking containers.
*/
public class MoveableWindowEditPart extends AbstractContainerEditPart {
private IProgressMonitor _runningMonitor;
private int delta_x = 0;
private int delta_y = 0;
private String title;
private ContainerLoadJob job;
private Point clickedAt;
private MoveableTitleBarModel rect;
private MoveableTitleBarModel overRect;
private MoveableWindow win;
private Point lastLocation;
public MoveableWindowEditPart() {
lastLocation = new Point();
}
@Override
public IFigure getContentPane() {
return ((MoveableWindowFigure) getFigure()).getContentsPane();
}
@Override
protected IFigure doCreateFigure() {
MoveableWindowModel widget = (MoveableWindowModel) getContainerModel();
MoveableWindowFigure moveableWindowFigure = new MoveableWindowFigure();
moveableWindowFigure.setAutoFit(widget.isAutoZoom());
if (widget.isLive()) {
moveableWindowFigure.addMouseListener(new MouseListener.Stub() {
@Override
public void mousePressed(MouseEvent me) {
me.consume();
}
});
}
return moveableWindowFigure;
}
@Override
protected void registerPropertyChangeHandlers() {
final HashMap<String, MoveableWindow> moveableWindows = new HashMap<String, MoveableWindow>();
IWidgetPropertyChangeHandler handler = new IWidgetPropertyChangeHandler() {
@Override
public boolean handleChange(final Object oldValue, final Object newValue, final IFigure figure) {
if (!moveableWindows.containsKey(newValue.toString())) {
InputStream icon = getClass().getResourceAsStream("/icons/close.png");
InputStream overIcon = getClass().getResourceAsStream("/icons/close_over.png");
if (_runningMonitor != null)
_runningMonitor.setCanceled(true);
_runningMonitor = new NullProgressMonitor();
job = new ContainerLoadJob((MoveableWindowModel) getContainerModel(), (IPath) newValue, (MoveableWindowFigure) figure);
job.run(_runningMonitor);
title = newValue.toString();
System.out.println(title);
int beginIndex = title.lastIndexOf('/') + 1;
int endIndex = title.indexOf('.');
title = title.substring(beginIndex, endIndex).toUpperCase();
final RectangleFigure invisibleRectangle = new RectangleFigure();
invisibleRectangle.setSize(0, 24);
invisibleRectangle.setLocation(new Point(0, 0));
invisibleRectangle.setForegroundColor(new Color(null, 0, 0, 0));
invisibleRectangle.setFill(false);
invisibleRectangle.setOutline(false);
win = new MoveableWindow();
win.setName(newValue.toString());
win.setRectangle(invisibleRectangle);
final RectangleFigure invisibleButton = new RectangleFigure();
invisibleButton.setSize(19, 19);
invisibleButton.setFill(false);
invisibleButton.setOutline(false);
rect = new MoveableTitleBarModel(title, icon);
rect.setLocation(0, 0);
rect.setSize(0, 24);
rect.setVisible(true);
win.setTitleBarModel(rect);
overRect = new MoveableTitleBarModel(title, overIcon);
overRect.setLocation(0, 0);
overRect.setSize(0, 24);
overRect.setVisible(false);
win.setOverTitleBarModel(overRect);
job.widgets.add(rect);
job.widgets.add(overRect);
win.setBox(job.widgets);
final List<AbstractWidgetModel> widgets = win.getBox();
final int[] xPositions = new int[widgets.size()];
final int[] yPositions = new int[widgets.size()];
int boxWidth = 0;
int boxHeight = 0;
for (int i = 0; i < widgets.size(); i++) {
if (widgets.get(i).getWidth() > boxWidth)
boxWidth = (widgets.get(i).getWidth());
if (widgets.get(i).getHeight() > boxHeight)
boxHeight = (widgets.get(i).getHeight());
xPositions[i] = widgets.get(i).getX();
if (!widgets.get(i).getClass().isInstance(rect))
yPositions[i] = widgets.get(i).getY() + 23;
else
yPositions[i] = widgets.get(i).getY();
}
Dimension boxSize = new Dimension(boxWidth, boxHeight);
win.setBoxSize(boxSize);
invisibleRectangle.setSize(boxSize.width, 24);
invisibleButton.setLocation(new Point(boxSize.width - 21, 3));
rect.setWidth(boxSize.width);
overRect.setWidth(boxSize.width);
win.setButton(invisibleButton);
AbstractWidgetModel widget;
for (int i = 0; i < widgets.size(); i++) {
widget = widgets.get(i);
widget.setX(xPositions[i]);
widget.setY(yPositions[i]);
}
overRect.setVisible(false);
rect.setVisible(true);
MouseMotionListener mml = new MouseMotionListener.Stub() {
@Override
public void mouseDragged(MouseEvent arg0) {
if(Math.abs(arg0.getLocation().x-lastLocation.x)>5 || Math.abs(arg0.getLocation().y-lastLocation.y)>5){
lastLocation = arg0.getLocation();
AbstractWidgetModel widget;
int newX = arg0.x - delta_x;
int newY = arg0.y - delta_y;
for (int i = 0; i < widgets.size(); i++) {
widget = widgets.get(i);
Iterator<Entry<String, MoveableWindow>> it = moveableWindows.entrySet().iterator();
while (it.hasNext()) {
Entry<String, MoveableWindow> pairs = it.next();
MoveableWindow mw = (pairs.getValue());
final List<AbstractWidgetModel> widgets = mw.getBox();
for (int j = 0; j < widgets.size(); j++){
if(!(widgets.get(j) instanceof MoveableTitleBarModel))
if(widgets.get(j) instanceof RectangleModel){
if(widgets.get(j).getWidth()<200)
widgets.get(j).setVisible(false);
}
else
widgets.get(j).setVisible(false);
}
}
if (newX >= 0)
widget.setX(newX + xPositions[i]);
else
widget.setX(xPositions[i]);
if (newY >= 0)
widget.setY(newY + yPositions[i]);
else
widget.setY(yPositions[i]);
}
int titleBarX = invisibleRectangle.getLocation().x;
int titleBarY = invisibleRectangle.getLocation().y - rect.getHeight();
int buttonX = invisibleButton.getLocation().x;
int buttonY = invisibleButton.getLocation().y;
int boxWidth = 0;
int boxHeight = 0;
for (int i = 0; i < widgets.size(); i++) {
if (widgets.get(i).getWidth() > boxWidth)
boxWidth = (widgets.get(i).getWidth());
if (widgets.get(i).getHeight() > boxHeight)
boxHeight = (widgets.get(i).getHeight());
}
if (newX >= 0) {
titleBarX = newX;
buttonX = titleBarX + boxWidth - 21;
}
else {
titleBarX = 0;
buttonX = titleBarX + boxWidth - 21;
}
if (newY >= 0) {
titleBarY = newY;
buttonY = titleBarY + 3;
}
else {
titleBarY = 0;
buttonY = titleBarY + 3;
}
invisibleRectangle.setLocation(new Point(titleBarX, titleBarY));
invisibleButton.setLocation(new Point(buttonX, buttonY));
}
}
};
invisibleRectangle.addMouseMotionListener(mml);
win.setMouseMotionListener(mml);
MouseListener ml = new MouseListener.Stub() {
@Override
public void mousePressed(MouseEvent arg0) {
arg0.consume();// required for mouseDragged to work
clickedAt = new Point(arg0.x, arg0.y);
delta_x = clickedAt.x - moveableWindows.get(newValue.toString()).getRectangle().getLocation().x;
delta_y = clickedAt.y - moveableWindows.get(newValue.toString()).getRectangle().getLocation().y;
List<AbstractWidgetModel> newWidgets = widgets;
job._container.removeWidgets(moveableWindows.get(newValue.toString()).getBox());
job._container.addWidgets(newWidgets);
}
@Override
public void mouseReleased(MouseEvent me) {
Iterator<Entry<String, MoveableWindow>> it = moveableWindows.entrySet().iterator();
while (it.hasNext()) {
Entry<String, MoveableWindow> pairs = it.next();
MoveableWindow mw = (pairs.getValue());
final List<AbstractWidgetModel> widgets = mw.getBox();
for (int j = 0; j < widgets.size(); j++)
widgets.get(j).setVisible(true);
}
}
};
MouseMotionListener cbhl = new MouseMotionListener.Stub() {
@Override
public void mouseEntered(MouseEvent arg0) {
moveableWindows.get(newValue.toString()).getTitleBarModel().setVisible(false);
moveableWindows.get(newValue.toString()).getOverTitleBarModel().setVisible(true);
}
@Override
public void mouseExited(MouseEvent arg0) {
moveableWindows.get(newValue.toString()).getOverTitleBarModel().setVisible(false);
moveableWindows.get(newValue.toString()).getTitleBarModel().setVisible(true);
}
};
invisibleButton.addMouseMotionListener(cbhl);
win.setCloseButtonHoverListener(cbhl);
invisibleRectangle.addMouseListener(ml);
win.setMouseListener(ml);
MouseListener cl = new MouseListener.Stub() {
@Override
public void mousePressed(MouseEvent arg0) {
job._container.removeWidgets(moveableWindows.get(newValue.toString()).getBox());
job._figure.getContentsPane().remove(moveableWindows.get(newValue.toString()).getRectangle());
job._figure.getContentsPane().remove(moveableWindows.get(newValue.toString()).getButton());
moveableWindows.remove(newValue.toString());
}
};
invisibleButton.addMouseListener(cl);
win.setCloseListener(cl);
job._figure.getContentsPane().add(invisibleRectangle);
job._figure.getContentsPane().add(invisibleButton);
job._container.addWidgets(widgets);
moveableWindows.put(newValue.toString(), win);
}
return true;
}
};
setPropertyChangeHandler(MoveableWindowModel.PROP_RESOURCE, handler);
}
@Override
protected void refreshChildren() {
super.refreshChildren();
((MoveableWindowFigure) getFigure()).updateZoom();
}
@Override
protected void createEditPolicies() {
super.createEditPolicies();
installEditPolicy(EditPolicy.CONTAINER_ROLE, null);
installEditPolicy(EditPolicy.LAYOUT_ROLE, new XYLayoutEditPolicy() {
@Override
protected Command createChangeConstraintCommand(final EditPart child, final Object constraint) {
return null;
}
@Override
protected Command getCreateCommand(final CreateRequest request) {
return null;
}
});
installEditPolicy(EditPolicy.LAYOUT_ROLE, null);
}
private static class ContainerLoadJob implements IJobRunnable {
MoveableWindowModel _container;
IPath _path;
MoveableWindowFigure _figure;
DisplayModel tempModel;
List<AbstractWidgetModel> widgets;
public ContainerLoadJob(MoveableWindowModel container, IPath path, MoveableWindowFigure figure) {
assert container != null;
assert path != null;
assert figure != null;
_container = container;
_path = path;
_figure = figure;
}
@Override
public IStatus run(IProgressMonitor progressMonitor) {
IStatus status = Status.OK_STATUS;
if (_path != null && !_path.isEmpty()) {
if (!progressMonitor.isCanceled()) {
if (!progressMonitor.isCanceled())
load();
else
status = Status.CANCEL_STATUS;
} else
status = Status.CANCEL_STATUS;
}
return status;
}
/**
* Initialises the {@link ContainerModel} from the specified path.
*/
protected void load() {
InputStream input = getInputStream(_path);
if (input != null) {
tempModel = new DisplayModel();
PersistenceUtil.syncFillModel(tempModel, input);
// add new widgets
widgets = tempModel.getWidgets();
tempModel.removeWidgets(widgets);
_container.setPrimarPv(tempModel.getPrimaryPV());
}
}
/**
* Return the {@link InputStream} of the file that is available on the specified path.
*
* @param path
* The {@link IPath} to the file
* @return The corresponding {@link InputStream} or null
*/
private static 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) {
}
}
if (result == null) {
// try from local file system
try {
result = new FileInputStream(path.toFile());
} catch (FileNotFoundException e) {
}
}
return result;
}
}
@Override
protected boolean determineChildrenSelectability() {
return true;
}
}