package org.csstudio.swt.xygraph.toolbar;
import java.util.List;
import org.csstudio.swt.xygraph.figures.XYGraph;
import org.csstudio.swt.xygraph.figures.XYGraphFlags;
import org.csstudio.swt.xygraph.undo.AddAnnotationCommand;
import org.csstudio.swt.xygraph.undo.IOperationsManagerListener;
import org.csstudio.swt.xygraph.undo.OperationsManager;
import org.csstudio.swt.xygraph.undo.RemoveAnnotationCommand;
import org.csstudio.swt.xygraph.undo.ZoomType;
import org.csstudio.swt.xygraph.util.XYGraphMediaFactory;
import org.eclipse.draw2d.ActionEvent;
import org.eclipse.draw2d.ActionListener;
import org.eclipse.draw2d.Button;
import org.eclipse.draw2d.ButtonGroup;
import org.eclipse.draw2d.ButtonModel;
import org.eclipse.draw2d.ChangeEvent;
import org.eclipse.draw2d.ChangeListener;
import org.eclipse.draw2d.Clickable;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.ImageFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.ToggleButton;
import org.eclipse.draw2d.ToggleModel;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.window.Window;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.printing.PrintDialog;
import org.eclipse.swt.printing.Printer;
import org.eclipse.swt.printing.PrinterData;
import org.eclipse.swt.widgets.Display;
/**The toolbar for an xy-graph.
* @author Xihui Chen
* @author Kay Kasemir (some zoom operations)
*/
public class XYGraphToolbar extends Figure {
private final static int BUTTON_SIZE = 25;
final protected XYGraph xyGraph;
final protected ButtonGroup zoomGroup;
public XYGraphToolbar(final XYGraph xyGraph) {
this(xyGraph, XYGraphFlags.COMBINED_ZOOM);
}
/** Initialize
* @param xyGraph XYGraph on which this toolbar operates
* @param flags Bitwise 'or' of flags
* @see XYGraphFlags#COMBINED_ZOOM
* @see XYGraphFlags#SEPARATE_ZOOM
*/
public XYGraphToolbar(final XYGraph xyGraph, final int flags) {
this.xyGraph = xyGraph;
setLayoutManager(new WrappableToolbarLayout());
final Button configButton = new Button(createImage("icons/Configure.png"));
configButton.setToolTip(new Label("Configure Settings..."));
addButton(configButton);
configButton.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent event) {
openConfigurationDialog();
}
});
final ToggleButton showLegend = new ToggleButton("", createImage("icons/ShowLegend.png"));
showLegend.setToolTip(new Label("Show Legend"));
addButton(showLegend);
showLegend.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent event) {
xyGraph.setShowLegend(!xyGraph.isShowLegend());
}
});
showLegend.setSelected(xyGraph.isShowLegend());
addSeparator("org.csstudio.swt.xygraph.toolbar.showLegend");
final Button addAnnotationButton = new Button(createImage("icons/Add_Annotation.png"));
addAnnotationButton.setToolTip(new Label("Add Annotation..."));
addButton(addAnnotationButton);
addAnnotationButton.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent event) {
AddAnnotationDialog dialog = new AddAnnotationDialog(
Display.getCurrent().getActiveShell(), xyGraph);
if(dialog.open() == Window.OK){
xyGraph.addAnnotation(dialog.getAnnotation());
xyGraph.getOperationsManager().addCommand(
new AddAnnotationCommand(xyGraph, dialog.getAnnotation()));
}
}
});
final Button delAnnotationButton = new Button(createImage("icons/Del_Annotation.png"));
delAnnotationButton.setToolTip(new Label("Remove Annotation..."));
addButton(delAnnotationButton);
delAnnotationButton.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent event) {
RemoveAnnotationDialog dialog = new RemoveAnnotationDialog(
Display.getCurrent().getActiveShell(), xyGraph);
if(dialog.open() == Window.OK && dialog.getAnnotation() != null){
xyGraph.removeAnnotation(dialog.getAnnotation());
xyGraph.getOperationsManager().addCommand(
new RemoveAnnotationCommand(xyGraph, dialog.getAnnotation()));
}
}
});
addSeparator("org.csstudio.swt.xygraph.toolbar.annotation");
addSeparator("org.csstudio.swt.xygraph.toolbar.extra");
if ((flags & XYGraphFlags.STAGGER) > 0)
{ //stagger axes button
final Button staggerButton = new Button(createImage("icons/stagger.png"));
staggerButton.setToolTip(new Label("Stagger axes so they don't overlap"));
addButton(staggerButton);
staggerButton.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent event) {
xyGraph.performStagger();
}
});
}
else
{ //auto scale button
final Button autoScaleButton = new Button(createImage("icons/AutoScale.png"));
autoScaleButton.setToolTip(new Label("Perform Auto Scale"));
addButton(autoScaleButton);
autoScaleButton.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent event) {
xyGraph.performAutoScale();
}
});
}
//zoom buttons
zoomGroup = new ButtonGroup();
createZoomButtons(flags);
addSeparator("org.csstudio.swt.xygraph.toolbar.undoredo");
addUndoRedoButtons();
addSeparator("org.csstudio.swt.xygraph.toolbar.snapshot");
addSnapshotButton();
}
protected static Image createImage(String path) {
Image image = XYGraphMediaFactory.getInstance().getImage(path);
return image;
}
protected void addSnapshotButton() {
Button snapShotButton = new Button(createImage("icons/camera.gif"));
snapShotButton.setToolTip(new Label("Print scaled image to printer"));
addButton(snapShotButton);
snapShotButton.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent event) {
// Show the Choose Printer dialog
PrintDialog dialog = new PrintDialog(Display.getCurrent().getActiveShell(), SWT.NULL);
PrinterData printerData = dialog.open();
printerData.orientation = PrinterData.LANDSCAPE; // force landscape
if (printerData != null) {
// Create the printer object
Printer printer = new Printer(printerData);
// Calculate the scale factor between the screen resolution and printer
// resolution in order to correctly size the image for the printer
Point screenDPI = Display.getCurrent().getDPI();
Point printerDPI = printer.getDPI();
int scaleFactorX = printerDPI.x / screenDPI.x;
// Determine the bounds of the entire area of the printer
Rectangle size = printer.getClientArea();
Rectangle trim = printer.computeTrim(0, 0, 0, 0);
Rectangle imageSize = new Rectangle(size.x/scaleFactorX, size.y/scaleFactorX,
size.width/scaleFactorX, size.height/scaleFactorX);
if (printer.startJob("Print Plot")) {
if (printer.startPage()) {
GC gc = new GC(printer);
Image xyImage = xyGraph.getImage(imageSize);
Image printerImage = new Image(printer, xyImage.getImageData());
xyImage.dispose();
// Draw the image
gc.drawImage(printerImage, imageSize.x, imageSize.y,
imageSize.width,
imageSize.height,
-trim.x, -trim.y,
size.width-trim.width,
size.height-trim.height);
// Clean up
printerImage.dispose();
gc.dispose();
printer.endPage();
}
}
// End the job and dispose the printer
printer.endJob();
printer.dispose();
}
}
});
}
private void addUndoRedoButtons() {
//undo button
final GrayableButton undoButton = new GrayableButton(createImage("icons/Undo.png"));
undoButton.setToolTip(new Label("Undo"));
undoButton.setEnabled(false);
addButton(undoButton);
undoButton.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent event) {
xyGraph.getOperationsManager().undo();
}
});
xyGraph.getOperationsManager().addListener(new IOperationsManagerListener(){
@Override
public void operationsHistoryChanged(OperationsManager manager) {
if(manager.getUndoCommandsSize() > 0){
undoButton.setEnabled(true);
final String cmd_name = manager.getUndoCommands()[
manager.getUndoCommandsSize() -1].toString();
undoButton.setToolTip(new Label(NLS.bind("Undo {0}", cmd_name)));
}else{
undoButton.setEnabled(false);
undoButton.setToolTip(new Label("Undo"));
}
}
});
// redo button
final GrayableButton redoButton = new GrayableButton(createImage("icons/Redo.png"));
redoButton.setToolTip(new Label("Redo"));
redoButton.setEnabled(false);
addButton(redoButton);
redoButton.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent event) {
xyGraph.getOperationsManager().redo();
}
});
xyGraph.getOperationsManager().addListener(new IOperationsManagerListener(){
@Override
public void operationsHistoryChanged(OperationsManager manager) {
if(manager.getRedoCommandsSize() > 0){
redoButton.setEnabled(true);
final String cmd_name = manager.getRedoCommands()[
manager.getRedoCommandsSize() -1].toString();
redoButton.setToolTip(new Label(NLS.bind("Redo {0}", cmd_name)));
}else{
redoButton.setEnabled(false);
redoButton.setToolTip(new Label("Redo"));
}
}
});
}
/** Create buttons enumerated in <code>ZoomType</code>
* @param flags Bitwise 'or' of flags
* @see XYGraphFlags#COMBINED_ZOOM
* @see XYGraphFlags#SEPARATE_ZOOM
*/
protected void createZoomButtons(final int flags) {
for(final ZoomType zoomType : ZoomType.values()){
if (! zoomType.useWithFlags(flags)) continue;
final ImageFigure imageFigure = new ImageFigure(zoomType.getIconImage());
final Label tip = new Label(zoomType.getDescription());
final ToggleButton button = new ToggleButton(imageFigure);
button.setBackgroundColor(ColorConstants.button);
button.setOpaque(true);
final ToggleModel model = new ToggleModel();
model.addChangeListener(new ChangeListener(){
@Override
public void handleStateChanged(ChangeEvent event) {
if(event.getPropertyName().equals("selected") &&
button.isSelected()){
xyGraph.setZoomType(zoomType);
}
}
});
button.setModel(model);
button.setToolTip(tip);
addButton(button);
zoomGroup.add(model);
if(zoomType == ZoomType.NONE)
zoomGroup.setDefault(model);
}
}
protected void openConfigurationDialog() {
XYGraphConfigDialog dialog = new XYGraphConfigDialog(
Display.getCurrent().getActiveShell(), xyGraph);
dialog.open();
}
public void addButton(Clickable button){
button.setPreferredSize(BUTTON_SIZE, BUTTON_SIZE);
add(button);
}
public void addSeparator(final String id) {
ToolbarSeparator separator = new ToolbarSeparator(id);
separator.setPreferredSize(BUTTON_SIZE/2, BUTTON_SIZE);
add(separator);
}
protected static final class ToolbarSeparator extends Figure{
protected String id;
ToolbarSeparator(String id) {
this.id = id;
}
private final Color GRAY_COLOR = XYGraphMediaFactory.getInstance().getColor(
new RGB(130, 130, 130));
@Override
protected void paintClientArea(Graphics graphics) {
super.paintClientArea(graphics);
graphics.setForegroundColor(GRAY_COLOR);
graphics.setLineWidth(1);
graphics.drawLine(bounds.x + bounds.width/2, bounds.y,
bounds.x + bounds.width/2, bounds.y + bounds.height);
}
public String getId() {
return id;
}
}
/**
* Bodges up a normal toolbar from the Figure toolbar.
* @param xyGraph
* @param man
*/
public void createGraphActions(final IContributionManager tool, final IContributionManager men) {
final CheckableActionGroup zoomG = new CheckableActionGroup();
for (Object child : getChildren()) {
if (!(child instanceof Figure)) continue;
final Figure c = (Figure)child;
if (c instanceof Clickable) {
final Clickable button = (Clickable)c;
final int flag = button instanceof ToggleButton
? IAction.AS_CHECK_BOX
: IAction.AS_PUSH_BUTTON;
final String text = ((Label)button.getToolTip()).getText();
final Object cont = button.getChildren().get(0);
final Image image = cont instanceof ImageFigure
? ((ImageFigure)cont).getImage()
: ((Label)cont).getIcon();
final Action action = new Action(text, flag) {
@Override
public void run() {
if (button.getModel() instanceof ToggleModel) {
((ToggleModel)button.getModel()).fireActionPerformed();
} else {
button.doClick();
}
}
};
if (flag == IAction.AS_CHECK_BOX) {
final boolean isSel = button.isSelected();
action.setChecked(isSel);
}
if (button instanceof GrayableButton) {
final GrayableButton gb = (GrayableButton)button;
gb.addChangeListener(new ChangeListener() {
@Override
public void handleStateChanged(ChangeEvent event) {
if (event.getPropertyName().equals(ButtonModel.ENABLED_PROPERTY)) {
action.setEnabled(gb.isEnabled());
}
}
});
}
action.setImageDescriptor(new ImageDescriptor() {
@Override
public ImageData getImageData() {
return image.getImageData();
}
});
tool.add(action);
men.add(action);
final List models = zoomGroup.getElements();
if (models.contains(button.getModel())) {
zoomG.add(action);
}
} else if (c instanceof ToolbarSeparator) {
tool.add(new Separator(((ToolbarSeparator)c).getId()));
men.add(new Separator(((ToolbarSeparator)c).getId()));
}
}
}
}