X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.scenegraph.swing%2Fsrc%2Forg%2Fsimantics%2Fscenegraph%2Fswing%2FMonitorNode.java;h=697983a63c61789d94bfa8a1432a3cfc3749b211;hb=cb2d456a2dd2d35f2acabcf1a2f4da154ba9edaf;hp=22ef3bab7294a05ac39e85828b45fec4c5ba4b88;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.scenegraph.swing/src/org/simantics/scenegraph/swing/MonitorNode.java b/bundles/org.simantics.scenegraph.swing/src/org/simantics/scenegraph/swing/MonitorNode.java index 22ef3bab7..697983a63 100644 --- a/bundles/org.simantics.scenegraph.swing/src/org/simantics/scenegraph/swing/MonitorNode.java +++ b/bundles/org.simantics.scenegraph.swing/src/org/simantics/scenegraph/swing/MonitorNode.java @@ -1,385 +1,385 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management - * in Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.scenegraph.swing; - -import java.awt.Color; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.FocusEvent; -import java.awt.event.FocusListener; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.awt.event.MouseEvent; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; - -import javax.swing.JTextField; -import javax.swing.border.Border; -import javax.swing.border.CompoundBorder; -import javax.swing.border.EmptyBorder; -import javax.swing.border.LineBorder; - -import org.simantics.scenegraph.ExportableWidget.InputWidget; -import org.simantics.scenegraph.ExportableWidget.OutputWidget; -import org.simantics.scenegraph.utils.DummyComponent; - -@OutputWidget("value") -@InputWidget("value") -public class MonitorNode extends ComponentNode implements ActionListener, FocusListener, PropertyChangeListener, KeyListener { - /** - * - */ - private static final long serialVersionUID = 7073028693751719102L; - - protected boolean editable = true; - protected String value = ""; - protected String tooltip = ""; - protected double borderWidth = 0; - - protected transient ActionListener actionListener = null; - - private boolean doResize = false; - - protected Font font = null; - protected Color color = null; - protected int halign = JTextField.LEFT; // See JTextField for value options - - static class TextField extends JTextField { - private static final int X_INSET = 5; - private static final int Y_INSET = -1; - private static final long serialVersionUID = -668522226693100386L; - private Border lineBorder; - private final MonitorNode node; - - public TextField(double borderWidth, MonitorNode node) { - if(borderWidth < 0.1) { - lineBorder = new EmptyBorder(Y_INSET, X_INSET, Y_INSET, X_INSET); - } else { - lineBorder = new CompoundBorder(LineBorder.createGrayLineBorder(), new EmptyBorder(Y_INSET, X_INSET, Y_INSET, X_INSET)); - } - this.node = node; - setHorizontalAlignment(JTextField.CENTER); - setAlignmentY(JTextField.CENTER_ALIGNMENT); - } - - // workaround for 4530952 - @Override - public void setText(String s) { - if (getText().equals(s)) { - return; - } - super.setText(s); - - } - - @Override - public void setBorder(Border border) { - super.setBorder(lineBorder); - } - - public void setBorder(double borderWidth) { - if(borderWidth < 0.1) { - lineBorder = new EmptyBorder(Y_INSET, X_INSET, Y_INSET, X_INSET); - } else { - lineBorder = new CompoundBorder(LineBorder.createGrayLineBorder(), new EmptyBorder(Y_INSET, X_INSET, Y_INSET, X_INSET)); - } - - super.setBorder(lineBorder); - } - - @Override - public Point getToolTipLocation(MouseEvent event) { - Point2D p2d = node.localToControl(event.getPoint()); - Point p = new Point((int)p2d.getX(),-20+(int)p2d.getY()); - return p; - } - } - - @Override - public String toString() { - return super.toString() + "[editable=" + editable + ", value=" + value + "]"; - } - - private void markResize() { - //System.out.println("MonitorNode.markResize()"); - doResize = true; - } - - @Override - public void init() { - component = new TextField(borderWidth,this); - component.setEditable(editable); - component.setEnabled(editable); - component.addActionListener(this); - component.addFocusListener(this); - component.addKeyListener(this); - super.init(); - } - - @SyncField("editable") - public void setEditable(boolean value) { - this.editable = value; - - if(component != null) { - component.setEditable(value); - component.setEnabled(value); - } - } - - @PropertySetter("Stroke Width") - @SyncField("borderWidth") - public void setBorderWidth(Float borderWidth) { - this.borderWidth = borderWidth; - if(component != null) { - ((TextField)component).setBorder(borderWidth); - } - } - - @SyncField("value") - public void setText(String value) { - this.value = value; - // RemoteViewer does not have component initialized - if (component != null) { - //System.out.println("MonitorNode.setText(" + value + ")"); - component.setText(value); - markResize(); - component.repaint(); - } - } - - @SyncField("tooltip") - public void setToolTipText(String tooltip) { - this.tooltip = tooltip; - if (component != null) { - component.setToolTipText(tooltip); - } - } - - - @PropertySetter("Font") - @SyncField("font") - public void setFont(Font font) { - this.font = font; - if (component != null) { - setComponentFont(font); - markResize(); - } - } - - @PropertySetter("Color") - @SyncField("color") - public void setColor(Color color) { - this.color = color; - if (component != null) { - component.setForeground(color); - markResize(); - } - } - - @SyncField("halign") - public void setHorizontalAlign(int halign) { - this.halign = halign; - } - - @Override - public void render(Graphics2D g2d) { - if (doResize) - recalculateSize(g2d); - doResize = false; - if (component != null) { - synchronized (component) { - if (component.getHorizontalAlignment() != halign) - component.setHorizontalAlignment(halign); - super.render(g2d); - } - } - } - - private void recalculateSize(Graphics2D g2d) { - //System.out.println("MonitorNode.recalculateSize(" + value + ")"); - if (component == null || value == null) - return; - - Font font = getComponentFont(); - if (font != null) { - String measuredValue = value; - //String measuredValue = value + "x"; - // If bounds are NOT set, calculate size.. - if (bounds == null) { - FontMetrics metrics = component.getFontMetrics(font); - Rectangle2D size = metrics.getStringBounds(measuredValue, g2d); - int xPadding = 15; - int yPadding = 2; -// setSize(xPadding + (int) Math.ceil(size.getWidth()), yPadding + (int) Math.ceil(size.getHeight())); - setBounds(new Rectangle2D.Double(0, 0, xPadding + (int) Math.ceil(size.getWidth()), yPadding + (int) Math.ceil(size.getHeight()))); - //component.setScrollOffset(0); - } else { - // ... If bounds are set, change font size to get the text fit - // into the bounds. Find the best fit through bisection. - - // min is assumed to fit within the bounds. It will not be searched - float min = 6; - - // First find an upper bound that no longer fits within the bounds. - // First guess is 62. - float max = 62; - final float upperLimit = 200; - while (max < upperLimit) { - font = font.deriveFont(max); - FontMetrics metrics = component.getFontMetrics(font); - Rectangle2D fbounds = metrics.getStringBounds(measuredValue, g2d); - if (!fits(bounds, fbounds)) - break; - max += 20; - } - if (max < upperLimit) { - // Bisect the largest font size in [min,max] that fits the bounds. - while (true) { - float half = (max + min) / 2; - float interval = max - min; - font = font.deriveFont(half); - FontMetrics metrics = component.getFontMetrics(font); - Rectangle2D fbounds = metrics.getStringBounds(measuredValue, g2d); - if (fits(bounds, fbounds)) { - // Fits within bounds, bisect [half, max] - if (interval <= 1) { - break; - } - min = half; - } else { - // Does not fit within bounds, bisect [min, half] - if (interval <= 1) { - font = font.deriveFont(min); - break; - } - max = half; - } - } - } - - setComponentFont(font); -// setSize((int)bounds.getWidth(), (int)bounds.getHeight()); - } - } - } - - private boolean fits(Rectangle2D parent, Rectangle2D child) { - return parent.getWidth() >= child.getWidth() && parent.getHeight() >= child.getHeight(); - } - - public String getText() { - return value; - } - - public Font getFont() { - return font; - } - - @Override - public void propertyChange(PropertyChangeEvent evt) { - if("value".equals(evt.getPropertyName()) && component != null) { - synchronized(component) { - component.setText((String)evt.getNewValue()); - markResize(); - component.repaint(); - } - } else if("editable".equals(evt.getPropertyName()) && component != null) { - synchronized(component) { - component.setEditable((Boolean)evt.getNewValue()); - component.setEnabled((Boolean)evt.getNewValue()); - } - } - } - - - public void setActionListener(ActionListener actionListener) { - this.actionListener = actionListener; - } - - @Override - public void actionPerformed(ActionEvent e) { -// performAction(e); - loseFocus(); - } - - void loseFocus() { - if (component != null) - if (component.isFocusOwner()) - if (container.getParent() != null) - container.getParent().requestFocusInWindow(); // Lose focus - } - - @Override - public void focusGained(FocusEvent arg0) { - if (component != null) { - component.selectAll(); - } - } - - @Override - public void focusLost(FocusEvent arg0) { - if (component != null) { - ActionEvent e = new ActionEvent(component, ActionEvent.ACTION_PERFORMED, component.getText()); - performAction(e); - } - } - - /** - * Wrapper method to send event to serverside - * - * @param e - */ - @ServerSide - public void performAction(ActionEvent e) { - if (actionListener != null) { - //System.out.println("MonitorNode.performAction(" + e + ")"); - actionListener.actionPerformed(e); - } - } - - @Override - public void keyPressed(KeyEvent e) { - } - - @Override - public void keyTyped(KeyEvent e) { - } - - @Override - public void keyReleased(KeyEvent e) { - if (e.getModifiers() == 0 && e.getKeyCode() == KeyEvent.VK_ESCAPE) { - // ESC without modifiers == CANCEL edit - // TODO: signal about cancellation - loseFocus(); - } - } - - public String widgetGet(String name) { - if("value".equals(name)) { - return ""+value; - } - return null; - } - - public void widgetSet(String name, String value) { - if("value".equals(name)) { - ActionEvent e = new ActionEvent(new DummyComponent(), ActionEvent.ACTION_PERFORMED, value); - performAction(e); - } - } -} +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.scenegraph.swing; + +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.JTextField; +import javax.swing.border.Border; +import javax.swing.border.CompoundBorder; +import javax.swing.border.EmptyBorder; +import javax.swing.border.LineBorder; + +import org.simantics.scenegraph.ExportableWidget.InputWidget; +import org.simantics.scenegraph.ExportableWidget.OutputWidget; +import org.simantics.scenegraph.utils.DummyComponent; + +@OutputWidget("value") +@InputWidget("value") +public class MonitorNode extends ComponentNode implements ActionListener, FocusListener, PropertyChangeListener, KeyListener { + /** + * + */ + private static final long serialVersionUID = 7073028693751719102L; + + protected boolean editable = true; + protected String value = ""; + protected String tooltip = ""; + protected double borderWidth = 0; + + protected transient ActionListener actionListener = null; + + private boolean doResize = false; + + protected Font font = null; + protected Color color = null; + protected int halign = JTextField.LEFT; // See JTextField for value options + + static class TextField extends JTextField { + private static final int X_INSET = 5; + private static final int Y_INSET = -1; + private static final long serialVersionUID = -668522226693100386L; + private Border lineBorder; + private final MonitorNode node; + + public TextField(double borderWidth, MonitorNode node) { + if(borderWidth < 0.1) { + lineBorder = new EmptyBorder(Y_INSET, X_INSET, Y_INSET, X_INSET); + } else { + lineBorder = new CompoundBorder(LineBorder.createGrayLineBorder(), new EmptyBorder(Y_INSET, X_INSET, Y_INSET, X_INSET)); + } + this.node = node; + setHorizontalAlignment(JTextField.CENTER); + setAlignmentY(JTextField.CENTER_ALIGNMENT); + } + + // workaround for 4530952 + @Override + public void setText(String s) { + if (getText().equals(s)) { + return; + } + super.setText(s); + + } + + @Override + public void setBorder(Border border) { + super.setBorder(lineBorder); + } + + public void setBorder(double borderWidth) { + if(borderWidth < 0.1) { + lineBorder = new EmptyBorder(Y_INSET, X_INSET, Y_INSET, X_INSET); + } else { + lineBorder = new CompoundBorder(LineBorder.createGrayLineBorder(), new EmptyBorder(Y_INSET, X_INSET, Y_INSET, X_INSET)); + } + + super.setBorder(lineBorder); + } + + @Override + public Point getToolTipLocation(MouseEvent event) { + Point2D p2d = node.localToControl(event.getPoint()); + Point p = new Point((int)p2d.getX(),-20+(int)p2d.getY()); + return p; + } + } + + @Override + public String toString() { + return super.toString() + "[editable=" + editable + ", value=" + value + "]"; + } + + private void markResize() { + //System.out.println("MonitorNode.markResize()"); + doResize = true; + } + + @Override + public void init() { + component = new TextField(borderWidth,this); + component.setEditable(editable); + component.setEnabled(editable); + component.addActionListener(this); + component.addFocusListener(this); + component.addKeyListener(this); + super.init(); + } + + @SyncField("editable") + public void setEditable(boolean value) { + this.editable = value; + + if(component != null) { + component.setEditable(value); + component.setEnabled(value); + } + } + + @PropertySetter("Stroke Width") + @SyncField("borderWidth") + public void setBorderWidth(Float borderWidth) { + this.borderWidth = borderWidth; + if(component != null) { + ((TextField)component).setBorder(borderWidth); + } + } + + @SyncField("value") + public void setText(String value) { + this.value = value; + // RemoteViewer does not have component initialized + if (component != null) { + //System.out.println("MonitorNode.setText(" + value + ")"); + component.setText(value); + markResize(); + component.repaint(); + } + } + + @SyncField("tooltip") + public void setToolTipText(String tooltip) { + this.tooltip = tooltip; + if (component != null) { + component.setToolTipText(tooltip); + } + } + + + @PropertySetter("Font") + @SyncField("font") + public void setFont(Font font) { + this.font = font; + if (component != null) { + setComponentFont(font); + markResize(); + } + } + + @PropertySetter("Color") + @SyncField("color") + public void setColor(Color color) { + this.color = color; + if (component != null) { + component.setForeground(color); + markResize(); + } + } + + @SyncField("halign") + public void setHorizontalAlign(int halign) { + this.halign = halign; + } + + @Override + public void render(Graphics2D g2d) { + if (doResize) + recalculateSize(g2d); + doResize = false; + if (component != null) { + synchronized (component) { + if (component.getHorizontalAlignment() != halign) + component.setHorizontalAlignment(halign); + super.render(g2d); + } + } + } + + private void recalculateSize(Graphics2D g2d) { + //System.out.println("MonitorNode.recalculateSize(" + value + ")"); + if (component == null || value == null) + return; + + Font font = getComponentFont(); + if (font != null) { + String measuredValue = value; + //String measuredValue = value + "x"; + // If bounds are NOT set, calculate size.. + if (bounds == null) { + FontMetrics metrics = component.getFontMetrics(font); + Rectangle2D size = metrics.getStringBounds(measuredValue, g2d); + int xPadding = 15; + int yPadding = 2; +// setSize(xPadding + (int) Math.ceil(size.getWidth()), yPadding + (int) Math.ceil(size.getHeight())); + setBounds(new Rectangle2D.Double(0, 0, xPadding + (int) Math.ceil(size.getWidth()), yPadding + (int) Math.ceil(size.getHeight()))); + //component.setScrollOffset(0); + } else { + // ... If bounds are set, change font size to get the text fit + // into the bounds. Find the best fit through bisection. + + // min is assumed to fit within the bounds. It will not be searched + float min = 6; + + // First find an upper bound that no longer fits within the bounds. + // First guess is 62. + float max = 62; + final float upperLimit = 200; + while (max < upperLimit) { + font = font.deriveFont(max); + FontMetrics metrics = component.getFontMetrics(font); + Rectangle2D fbounds = metrics.getStringBounds(measuredValue, g2d); + if (!fits(bounds, fbounds)) + break; + max += 20; + } + if (max < upperLimit) { + // Bisect the largest font size in [min,max] that fits the bounds. + while (true) { + float half = (max + min) / 2; + float interval = max - min; + font = font.deriveFont(half); + FontMetrics metrics = component.getFontMetrics(font); + Rectangle2D fbounds = metrics.getStringBounds(measuredValue, g2d); + if (fits(bounds, fbounds)) { + // Fits within bounds, bisect [half, max] + if (interval <= 1) { + break; + } + min = half; + } else { + // Does not fit within bounds, bisect [min, half] + if (interval <= 1) { + font = font.deriveFont(min); + break; + } + max = half; + } + } + } + + setComponentFont(font); +// setSize((int)bounds.getWidth(), (int)bounds.getHeight()); + } + } + } + + private boolean fits(Rectangle2D parent, Rectangle2D child) { + return parent.getWidth() >= child.getWidth() && parent.getHeight() >= child.getHeight(); + } + + public String getText() { + return value; + } + + public Font getFont() { + return font; + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if("value".equals(evt.getPropertyName()) && component != null) { + synchronized(component) { + component.setText((String)evt.getNewValue()); + markResize(); + component.repaint(); + } + } else if("editable".equals(evt.getPropertyName()) && component != null) { + synchronized(component) { + component.setEditable((Boolean)evt.getNewValue()); + component.setEnabled((Boolean)evt.getNewValue()); + } + } + } + + + public void setActionListener(ActionListener actionListener) { + this.actionListener = actionListener; + } + + @Override + public void actionPerformed(ActionEvent e) { +// performAction(e); + loseFocus(); + } + + void loseFocus() { + if (component != null) + if (component.isFocusOwner()) + if (container.getParent() != null) + container.getParent().requestFocusInWindow(); // Lose focus + } + + @Override + public void focusGained(FocusEvent arg0) { + if (component != null) { + component.selectAll(); + } + } + + @Override + public void focusLost(FocusEvent arg0) { + if (component != null) { + ActionEvent e = new ActionEvent(component, ActionEvent.ACTION_PERFORMED, component.getText()); + performAction(e); + } + } + + /** + * Wrapper method to send event to serverside + * + * @param e + */ + @ServerSide + public void performAction(ActionEvent e) { + if (actionListener != null) { + //System.out.println("MonitorNode.performAction(" + e + ")"); + actionListener.actionPerformed(e); + } + } + + @Override + public void keyPressed(KeyEvent e) { + } + + @Override + public void keyTyped(KeyEvent e) { + } + + @Override + public void keyReleased(KeyEvent e) { + if (e.getModifiers() == 0 && e.getKeyCode() == KeyEvent.VK_ESCAPE) { + // ESC without modifiers == CANCEL edit + // TODO: signal about cancellation + loseFocus(); + } + } + + public String widgetGet(String name) { + if("value".equals(name)) { + return ""+value; + } + return null; + } + + public void widgetSet(String name, String value) { + if("value".equals(name)) { + ActionEvent e = new ActionEvent(new DummyComponent(), ActionEvent.ACTION_PERFORMED, value); + performAction(e); + } + } +}