2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2007-2008 - INRIA - Vincent Couvert
4 * Copyright (C) 2007 - INRIA - Marouane BEN JELLOUL
5 * Copyright (C) 2011 - DIGITEO - Vincent COUVERT
7 * This file must be used under the terms of the CeCILL.
8 * This source file is licensed as described in the file COPYING, which
9 * you should have received as part of this distribution. The terms
10 * are also available at
11 * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
15 package org.scilab.modules.gui.bridge.editbox;
17 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_BACKGROUNDCOLOR__;
18 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_MAX__;
19 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_MIN__;
20 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_SCROLLABLE__;
21 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_STRING__;
23 import java.awt.BorderLayout;
24 import java.awt.Color;
26 import java.awt.KeyboardFocusManager;
27 import java.awt.event.ActionEvent;
28 import java.awt.event.FocusEvent;
29 import java.awt.event.FocusListener;
30 import java.awt.event.KeyEvent;
31 import java.util.ArrayList;
33 import javax.swing.AbstractAction;
34 import javax.swing.InputMap;
35 import javax.swing.JPanel;
36 import javax.swing.JScrollPane;
37 import javax.swing.JTextPane;
38 import javax.swing.KeyStroke;
39 import javax.swing.ScrollPaneConstants;
40 import javax.swing.UIManager;
41 import javax.swing.border.Border;
42 import javax.swing.text.AbstractDocument;
43 import javax.swing.text.BoxView;
44 import javax.swing.text.ComponentView;
45 import javax.swing.text.Element;
46 import javax.swing.text.IconView;
47 import javax.swing.text.LabelView;
48 import javax.swing.text.ParagraphView;
49 import javax.swing.text.SimpleAttributeSet;
50 import javax.swing.text.StyleConstants;
51 import javax.swing.text.StyledDocument;
52 import javax.swing.text.StyledEditorKit;
53 import javax.swing.text.View;
54 import javax.swing.text.ViewFactory;
56 import org.scilab.modules.graphic_objects.console.Console;
57 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
58 import org.scilab.modules.gui.SwingView;
59 import org.scilab.modules.gui.SwingViewObject;
60 import org.scilab.modules.gui.SwingViewWidget;
61 import org.scilab.modules.gui.events.callback.CommonCallBack;
62 import org.scilab.modules.gui.menubar.MenuBar;
63 import org.scilab.modules.gui.textbox.TextBox;
64 import org.scilab.modules.gui.toolbar.ToolBar;
65 import org.scilab.modules.gui.utils.Position;
66 import org.scilab.modules.gui.utils.PositionConverter;
67 import org.scilab.modules.gui.utils.ScilabRelief;
68 import org.scilab.modules.gui.utils.ScilabSwingUtilities;
69 import org.scilab.modules.gui.utils.Size;
70 import org.scilab.modules.gui.widget.Widget;
73 * Swing implementation for Scilab EditBox in GUIs
74 * @author Vincent COUVERT
76 public class SwingScilabEditBox extends JScrollPane implements SwingViewObject, Widget {
78 private static final long serialVersionUID = 2048261239598753717L;
82 private CommonCallBack callback;
84 private FocusListener focusListener;
86 private Border defaultBorder = null;
88 private StyledDocument doc;
89 private SimpleAttributeSet docAttributes = new SimpleAttributeSet();
91 private JTextPane textPane = new JTextPane();
92 //use to disable wordwarp
93 private JPanel noWrapPanel = new JPanel(new BorderLayout());
94 private boolean scrollable = false;
95 private boolean isMultiLine = false;
97 private Object enterKeyAction;
98 private Object tabKeyAction;
99 private Object shiftTabKeyAction;
102 private class EditBoxView extends BoxView {
103 public EditBoxView(Element elem, int axis) {
107 protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
108 super.layoutMajorAxis(targetSpan, axis, offsets, spans);
109 int textBlockHeight = 0;
112 if (textPane.getAlignmentY() == BOTTOM_ALIGNMENT) {
113 for (int i = 0; i < spans.length; i++) {
114 textBlockHeight += spans[i];
116 offset = (targetSpan - textBlockHeight);
117 for (int i = 0; i < offsets.length; i++) {
118 offsets[i] += offset;
120 } else if (textPane.getAlignmentY() == CENTER_ALIGNMENT) {
121 for (int i = 0; i < spans.length; i++) {
122 textBlockHeight += spans[i];
124 offset = (targetSpan - textBlockHeight) / 2;
125 for (int i = 0; i < offsets.length; i++) {
126 offsets[i] += offset;
129 // TOP_ALIGNEMENT or other
130 // default behaviour : do nothing special
135 private class EditBoxEditorKit extends StyledEditorKit {
136 private static final long serialVersionUID = -3293325523458217074L;
138 public ViewFactory getViewFactory() {
139 return new ViewFactory() {
140 public View create(Element elem) {
141 String kind = elem.getName();
143 if (kind.equals(AbstractDocument.ContentElementName)) {
144 return new LabelView(elem);
145 } else if (kind.equals(AbstractDocument.ParagraphElementName)) {
146 return new ParagraphView(elem);
147 } else if (kind.equals(AbstractDocument.SectionElementName)) {
148 return new EditBoxView(elem, View.Y_AXIS);
149 } else if (kind.equals(StyleConstants.ComponentElementName)) {
150 return new ComponentView(elem);
151 } else if (kind.equals(StyleConstants.IconElementName)) {
152 return new IconView(elem);
155 return new LabelView(elem);
164 public SwingScilabEditBox() {
165 super(new JPanel(new BorderLayout()));
166 noWrapPanel = (JPanel) getViewport().getView();
167 textPane = new JTextPane();
168 noWrapPanel.add(textPane, BorderLayout.CENTER);
170 setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
171 setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
173 textPane.setEditorKit(new EditBoxEditorKit());
174 doc = (StyledDocument) textPane.getDocument();
176 // Create a focus listener to call the callback action
177 focusListener = new FocusListener() {
178 public void focusGained(FocusEvent arg0) {
182 public void focusLost(FocusEvent arg0) {
186 textPane.addFocusListener(focusListener);
187 KeyStroke enterKey = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
188 KeyStroke tabKey = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);
189 KeyStroke shiftTabKey = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, KeyEvent.SHIFT_DOWN_MASK);
190 InputMap map = textPane.getInputMap();
191 enterKeyAction = map.get(enterKey);
192 tabKeyAction = map.get(tabKey);
193 shiftTabKeyAction = map.get(shiftTabKey);
195 if (Console.getConsole().getUseDeprecatedLF() == false) {
196 setEditFont(getFont());
201 * Validate UserInput and call Scilab Callback if needed
203 private void validateUserInput() {
204 // Validates user input
205 if (getParent() != null) { // To avoid to execute the callback when then parent figure is destroyed
207 String[] stringProperty = getText().split("\n");
208 GraphicController.getController().setProperty(uid, __GO_UI_STRING__, stringProperty);
210 if (SwingView.getFromId(uid) != null && callback != null) {
211 callback.actionPerformed(null);
217 * Draws a swing Scilab EditBox
218 * @see org.scilab.modules.gui.uielement.UIElement#draw()
221 this.setVisible(true);
226 * Gets the dimensions (width and height) of a swing Scilab EditBox
227 * @return the dimensions of the EditBox
228 * @see org.scilab.modules.gui.uielement.UIElement#getDims()
230 public Size getDims() {
231 return new Size(this.getSize().width, this.getSize().height);
235 * Gets the position (X-coordinate and Y-coordinate) of a swing Scilab
237 * @return the position of the EditBox
238 * @see org.scilab.modules.gui.uielement.UIElement#getPosition()
240 public Position getPosition() {
241 return PositionConverter.javaToScilab(getLocation(), getSize(), getParent());
245 * Sets the dimensions (width and height) of a swing Scilab EditBox
246 * @param newSize the dimensions we want to set to the EditBox
247 * @see org.scilab.modules.gui.uielement.UIElement#setDims(org.scilab.modules.gui.utils.Size)
249 public void setDims(Size newSize) {
250 this.setSize(newSize.getWidth(), newSize.getHeight());
254 * Sets the position (X-coordinate and Y-coordinate) of a swing Scilab
256 * @param newPosition the position we want to set to the EditBox
257 * @see org.scilab.modules.gui.uielement.UIElement#setPosition(org.scilab.modules.gui.utils.Position)
259 public void setPosition(Position newPosition) {
260 Position javaPosition = PositionConverter.scilabToJava(newPosition, getDims(), getParent());
261 setLocation(javaPosition.getX(), javaPosition.getY());
265 * Add a callback to the EditBox
266 * @param cb the callback to set.
268 public void setCallback(CommonCallBack cb) {
272 public void setText(String[] texts) {
273 if (texts.length == 0) {
275 textPane.setText(null);
276 doc.setParagraphAttributes(0, doc.getLength() - 1, docAttributes, true);
277 } catch (Exception e) {
281 StringBuffer newText = new StringBuffer(texts[0]);
283 for (int i = 1; i < texts.length; ++i) {
284 newText.append("\n" + texts[i]);
288 textPane.setText(newText.toString());
289 doc.setParagraphAttributes(0, doc.getLength() - 1, docAttributes, true);
290 } catch (Exception e) {
296 public void setText(String text) {
298 textPane.setText(text);
299 doc.setParagraphAttributes(0, doc.getLength() - 1, docAttributes, true);
300 } catch (Exception e) {
305 public void setEmptyText() {
306 textPane.setText(null);
307 doc.setParagraphAttributes(0, doc.getLength() - 1, docAttributes, true);
311 * Set if the EditBox is enabled or not
312 * @param status true if the EditBox is enabled
314 public void setEnabled(boolean status) {
315 if (status == isEnabled()) {
319 super.setEnabled(status);
320 textPane.setEnabled(status);
322 //force background to gray
324 SwingViewWidget.update(this, __GO_UI_BACKGROUNDCOLOR__, GraphicController.getController().getProperty(uid, __GO_UI_BACKGROUNDCOLOR__));
326 Color gray = new Color(0.9f, 0.9f, 0.9f);
331 /* (Des)Activate the callback */
332 if (callback != null) {
334 removeFocusListener(focusListener); /*
335 * To be sure the callback
336 * is not added two times
338 //removeActionListener(actionListener); /* To be sure the callback is not added two times */
339 addFocusListener(focusListener);
340 //addActionListener(actionListener);
342 removeFocusListener(focusListener);
343 //removeActionListener(actionListener);
350 * @param menuBarToAdd the MenuBar associated to the Tab.
352 public void addMenuBar(MenuBar menuBarToAdd) {
353 /* Unimplemented for EditBoxes */
354 throw new UnsupportedOperationException();
359 * @param toolBarToAdd the ToolBar associated to the Tab.
361 public void addToolBar(ToolBar toolBarToAdd) {
362 /* Unimplemented for EditBoxes */
363 throw new UnsupportedOperationException();
368 * @return MenuBar: the MenuBar associated to the Tab.
370 public MenuBar getMenuBar() {
371 /* Unimplemented for EditBoxes */
372 throw new UnsupportedOperationException();
377 * @return ToolBar: the ToolBar associated to the Tab.
379 public ToolBar getToolBar() {
380 /* Unimplemented for EditBoxes */
381 throw new UnsupportedOperationException();
385 * Set the horizontal alignment for the EditBox text
386 * @param alignment the value for the alignment (See ScilabAlignment.java)
388 public void setHorizontalAlignment(String alignment) {
389 if (alignment.equals("") == false) {
390 int alignConstant = StyleConstants.ALIGN_LEFT;
391 if (alignment.equals("right")) {
392 alignConstant = StyleConstants.ALIGN_RIGHT;
393 } else if (alignment.equals("center")) {
394 alignConstant = StyleConstants.ALIGN_CENTER;
397 StyleConstants.setAlignment(docAttributes, alignConstant);
398 doc.setParagraphAttributes(0, doc.getLength(), docAttributes, true);
403 * Set the vertical alignment for the EditBox text
404 * @param alignment the value for the alignment (See ScilabAlignment.java)
406 public void setVerticalAlignment(String alignment) {
407 if (alignment.equals("") == false) {
408 if (alignment.equals("bottom")) {
409 textPane.setAlignmentY(BOTTOM_ALIGNMENT);
410 } else if (alignment.equals("top")) {
411 textPane.setAlignmentY(TOP_ALIGNMENT);
412 } else if (alignment.equals("middle")) {
413 textPane.setAlignmentY(CENTER_ALIGNMENT);
415 // Force text update to render
421 * Set the Relief of the EditBox
422 * @param reliefType the type of the relief to set (See ScilabRelief.java)
424 public void setRelief(String reliefType) {
425 if (defaultBorder == null) {
426 defaultBorder = textPane.getBorder();
428 textPane.setBorder(ScilabRelief.getBorderFromRelief(reliefType, defaultBorder));
432 * Destroy the EditBox
434 public void destroy() {
435 ScilabSwingUtilities.removeFromParent(this);
440 * @param infoBarToAdd the InfoBar associated to the EditBox.
442 public void addInfoBar(TextBox infoBarToAdd) {
443 /* Unimplemented for EditBoxes */
444 throw new UnsupportedOperationException();
449 * @return the InfoBar associated to the EditBox.
451 public TextBox getInfoBar() {
452 /* Unimplemented for EditBoxes */
453 throw new UnsupportedOperationException();
460 public void setId(Integer id) {
468 public Integer getId() {
472 public void setBackground(Color bg) {
473 super.setBackground(bg);
474 if (docAttributes != null && textPane != null) {
475 textPane.setBackground(bg);
476 StyleConstants.setBackground(docAttributes, bg);
480 public void setEditFont(Font font) {
482 if (textPane != null) {
483 textPane.setFont(font);
484 StyleConstants.setFontFamily(docAttributes, font.getFamily());
485 StyleConstants.setFontSize(docAttributes, font.getSize());
486 StyleConstants.setBold(docAttributes, font.isBold());
487 StyleConstants.setItalic(docAttributes, font.isItalic());
488 doc.setParagraphAttributes(0, doc.getLength() - 1, docAttributes, true);
492 public void setFont(Font font) {
497 * Generic update method
498 * @param property property name
499 * @param value property value
501 public void update(int property, Object value) {
502 GraphicController controller = GraphicController.getController();
505 case __GO_UI_MAX__: {
506 double min = ((Double) controller.getProperty(uid, __GO_UI_MIN__));
507 double max = ((Double) controller.getProperty(uid, __GO_UI_MAX__));
508 if (max - min > 1.0) {
509 setMultiLineText(true);
511 setMultiLineText(false);
514 //refresh scrollable state
515 setScrollable(scrollable);
516 // Force String update
517 update(__GO_UI_STRING__, GraphicController.getController().getProperty(uid, __GO_UI_STRING__));
520 case __GO_UI_MIN__: {
521 Double min = ((Double) value);
522 Double max = ((Double) controller.getProperty(uid, __GO_UI_MAX__));
523 if (max - min > 1.0) {
524 setMultiLineText(true);
526 setMultiLineText(false);
529 //refresh scrollable state
530 setScrollable(scrollable);
531 // Force String update
532 update(__GO_UI_STRING__, GraphicController.getController().getProperty(uid, __GO_UI_STRING__));
535 case __GO_UI_STRING__: {
536 String[] str = (String[])value;
538 double min = ((Double) controller.getProperty(uid, __GO_UI_MIN__));
539 double max = ((Double) controller.getProperty(uid, __GO_UI_MAX__));
541 //if str.length > 1 automactly switch to multiline
542 if (str.length > 1 && max - min <= 1.0 ) {
543 //update max in model that recall setText
544 controller.setProperty(uid, __GO_UI_MAX__, min + 2);
548 ArrayList<String> lst = new ArrayList<String>();
549 for (int i = 0 ; i < str.length ; i++) {
553 while ((index = s.indexOf('\n', lastIndex)) != -1) {
554 lst.add(s.substring(lastIndex, index));
555 lastIndex = index + 1;
557 if (lastIndex <= s.length()) {
558 lst.add(s.substring(lastIndex));
562 if (lst.size() != str.length) {
563 String[] newStr = new String[lst.size()];
565 controller.setProperty(uid, __GO_UI_STRING__, newStr);
569 if (max - min > 1.0) {
571 setMultiLineText(true);
573 if (str.length == 0) {
578 setMultiLineText(false);
582 case __GO_UI_SCROLLABLE__ : {
583 setScrollable((Boolean)value);
587 SwingViewWidget.update(this, property, value);
592 setMinimumSize(textPane.getMinimumSize());
595 public void setScrollable(Boolean scrollable) {
596 this.scrollable = scrollable;
608 setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
619 setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
623 private void setWordWrap(boolean wordWrap) {
625 setViewportView(textPane);
627 setViewportView(noWrapPanel);
628 noWrapPanel.add(textPane);
632 public String getText() {
633 return textPane.getText();
636 public void setMultiLineText(boolean enable) {
637 isMultiLine = enable;
638 KeyStroke enterKey = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
639 KeyStroke tabKey = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);
640 KeyStroke shiftTabKey = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, KeyEvent.SHIFT_DOWN_MASK);
642 setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
643 textPane.getInputMap().remove(enterKey);
644 textPane.getInputMap().remove(tabKey);
645 textPane.getInputMap().remove(shiftTabKey);
646 textPane.getInputMap().put(enterKey, enterKeyAction);
647 textPane.getInputMap().put(tabKey, tabKeyAction);
648 textPane.getInputMap().put(tabKey, shiftTabKeyAction);
650 setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
651 AbstractAction focusNextComponent = new AbstractAction() {
652 private static final long serialVersionUID = -5286137769378297783L;
654 public void actionPerformed(ActionEvent e) {
655 KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
656 manager.focusNextComponent();
660 AbstractAction validateUserInput = new AbstractAction() {
661 private static final long serialVersionUID = -5286137769378297783L;
663 public void actionPerformed(ActionEvent e) {
668 AbstractAction focusPreviousComponent = new AbstractAction() {
669 private static final long serialVersionUID = -5286137769378297783L;
671 public void actionPerformed(ActionEvent e) {
672 KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
673 manager.focusPreviousComponent();
676 textPane.getInputMap().remove(enterKey);
677 textPane.getInputMap().remove(tabKey);
678 textPane.getInputMap().remove(shiftTabKey);
679 textPane.getInputMap().put(enterKey, validateUserInput);
680 textPane.getInputMap().put(tabKey, focusNextComponent); // input validation will be performed by focusLost
681 textPane.getInputMap().put(shiftTabKey, focusPreviousComponent); // input validation will be performed by focusLost
685 public void resetBackground() {
686 Color color = (Color) UIManager.getLookAndFeelDefaults().get("TextField.background");
688 setBackground(color);
692 public void resetForeground() {
693 Color color = (Color)UIManager.getLookAndFeelDefaults().get("TextField.foreground");
695 setForeground(color);