2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2012 - Pedro Arthur dos S. Souza
4 * Copyright (C) 2012 - Caio Lucas dos S. Souza
6 * This file must be used under the terms of the CeCILL.
7 * This source file is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at
10 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
14 package org.scilab.modules.gui.editor;
17 import java.awt.event.ActionListener;
18 import java.awt.event.ActionEvent;
19 import java.awt.event.MouseEvent;
20 import java.awt.event.KeyEvent;
21 import java.awt.Component;
22 import javax.swing.JOptionPane;
23 import javax.swing.JMenu;
24 import javax.swing.JMenuItem;
25 import javax.swing.JPopupMenu;
27 import org.scilab.modules.gui.datatip.DatatipManager;
28 import org.scilab.modules.gui.editor.ScilabClipboard;
29 import org.scilab.modules.gui.editor.SystemClipboard;
30 import org.scilab.modules.gui.editor.PolylineHandler;
31 import org.scilab.modules.gui.editor.GEDPicker;
32 import org.scilab.modules.gui.editor.LabelHandler;
33 import org.scilab.modules.gui.editor.LegendHandler;
34 import org.scilab.modules.gui.editor.action.EditorHistory;
35 import org.scilab.modules.gui.editor.action.ActionDelete;
36 import org.scilab.modules.gui.editor.action.ActionLegend;
37 import org.scilab.modules.gui.editor.action.ActionMove;
38 import org.scilab.modules.gui.editor.action.ActionPaste;
39 import org.scilab.modules.gui.editor.action.ActionTextEdit;
40 import org.scilab.modules.gui.editor.action.ActionPasteStyle;
41 import org.scilab.modules.gui.editor.action.ActionHide;
42 import org.scilab.modules.gui.ged.Inspector;
43 import org.scilab.modules.gui.ged.StartGED;
44 import org.scilab.modules.gui.ged.SwapObject;
45 import org.scilab.modules.localization.Messages;
46 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement;
50 * Point and click figure editor.
52 * Provides polyline selection by mouse click,
53 * copy, cut, paste, delete, hide, unhide polylines
54 * by popup menus and keyboard shortcuts.
56 * @author Caio Souza <caioc2bolado@gmail.com>
57 * @author Pedro Souza <bygrandao@gmail.com>
65 JMenuItem copy, copyStyle, cut, paste, pasteStyle, delete, clear, hide, unhide, clipboardCopy, labelX, labelY, labelZ, insert, remove, ged, editdata, undo, redo;
66 JMenu labels, legends;
68 EntityPicker.LegendInfo selectedLegend = null;
69 Integer selected = null;
70 Integer figureUid = null;
72 Integer[] lastClick = { 0, 0 };
73 Integer[] dragClick = { 0, 0 };
74 EntityPicker entityPicker;
75 DataEditor dataEditor;
76 boolean dataModifyEnabled = false;
77 boolean dataEditEnabled = false;
78 boolean updateDrag = true;
79 EditorHistory editorHistory;
81 Component dialogComponent;
83 enum SelectionType {POLYLINE, LEGEND, SURFACE};
84 SelectionType selectedType;
90 editorHistory = new EditorHistory();
91 entityPicker = new EntityPicker();
92 dataEditor = new DataEditor();
93 dataEditor.setLeaveAction(new ActionListener() {
94 public void actionPerformed(ActionEvent actionEvent) {
101 * Enable / disable data modify.
102 * @param b true to enable, false to disable.
104 public void setDataModifyEnabled(boolean b) {
105 dataModifyEnabled = b;
106 if (!dataModifyEnabled) {
108 } else if (getSelected() != null) {
114 * Returns if the data modify is enabled or not.
115 * @return True if enabled, false otherwise.
117 public boolean isDataModifyEnabled() {
118 return dataModifyEnabled;
121 public void setUpdateDrag(boolean state) {
126 * On right mouse click, set popup menu visible.
127 * @param event MouseEvent to retrieve click positon in figure.
129 public void onRightMouseClick(MouseEvent event) {
131 if (!dataEditEnabled) {
132 lastClick[0] = event.getX();
133 lastClick[1] = event.getY();
134 boolean b = ScilabClipboard.getInstance().canPaste();
137 boolean notBlank = AxesHandler.isAxesNotBlank(figureUid);
138 clipboardCopy.setEnabled(notBlank);
140 pasteStyle.setEnabled(ScilabClipboard.getInstance().canPasteStyle());
141 undo.setEnabled(editorHistory.isUndoEnabled());
142 redo.setEnabled(editorHistory.isRedoEnabled());
144 menu.show(event.getComponent(), event.getX(), event.getY());
145 dialogComponent = event.getComponent();
147 dataEditor.onRightClick(event);
152 * Handles left mouse clicks.
154 * @param event the mouse event.
156 public void onLeftMouseDown(MouseEvent event) {
158 lastClick[0] = event.getX();
159 lastClick[1] = event.getY();
161 if (!dataEditEnabled) {
162 switch (event.getClickCount()) {
164 setSelected(tryPickAnyObject(lastClick));
167 /*there is a polyline selected? if yes start dataEditor*/
168 if (selected != null && selectedType == SelectionType.POLYLINE && dataModifyEnabled) {
171 /*on double click over a legend or label open dialog*/
172 else if (selectedLegend != null) {
173 onClickInsert(selectedLegend.polyline);
175 /*try pick a label and open the dialog*/
176 onClickLabel(entityPicker.pickLabel(figureUid, lastClick));
182 } else { /*data editor is enabled, pass event to it*/
183 switch (event.getClickCount()) {
185 dataEditor.onLeftMouseDown(event);
188 dataEditor.onLeftDoubleClick(event);
194 dragClick[0] = lastClick[0];
195 dragClick[1] = lastClick[1];
198 public void onLeftMouseRelease(MouseEvent event) {
200 Integer object = getSelected();
201 if (dataModifyEnabled && !dataEditEnabled && object != null) {
202 editorHistory.addAction(new ActionMove(object, lastClick, dragClick, (selectedType == SelectionType.LEGEND)));
204 dataEditor.onLeftMouseRelease(event);
209 * On drag move the selected object, if dataEditor
210 * is enabled pass event to it.
211 * @param event The mouse event.
213 public void onMouseDragged(MouseEvent event) {
214 Integer[] newClick = { event.getX(), event.getY() };
215 if (dataModifyEnabled) {
216 if (!dataEditEnabled) {
217 Integer objUID = getSelected();
218 if (objUID != null) {
219 if (selectedType == SelectionType.LEGEND) {
220 LegendHandler.dragLegend(objUID, dragClick, newClick);
221 } else if (selectedType == SelectionType.POLYLINE) {
222 PolylineHandler.getInstance().dragPolyline(objUID, dragClick, newClick);
225 LabelHandler.dragLabel(figureUid, dragClick, newClick, updateDrag);
228 dataEditor.onDrag(dragClick, newClick);
231 dragClick[0] = newClick[0];
232 dragClick[1] = newClick[1];
236 * Handles keyboard input
237 * @param event The Key event.
239 void onKeyPressed(KeyEvent event) {
241 if (event.isControlDown()) {
242 switch (event.getKeyCode()) {
244 if (getSelected() != null) {
249 if (ScilabClipboard.getInstance().canPaste()) {
257 if (editorHistory.isUndoEnabled()) {
263 ScilabInterpreterManagement.asynchronousScilabExec(null, "scf();");
264 } catch (Exception e) {
265 System.err.println(e);
272 switch (event.getKeyCode()) {
273 case KeyEvent.VK_DELETE:
274 if (!dataEditEnabled) {
278 case KeyEvent.VK_ESCAPE:
288 * Initializes the popup menu.
290 * Create the popup menu and all popup menu items
291 * and set the properly action for each menu item.
294 menu = new JPopupMenu();
295 labels = new JMenu(Messages.gettext("Label"));
296 legends = new JMenu(Messages.gettext("Legend"));
298 copy = new JMenuItem(Messages.gettext("Copy"));
299 copy.setToolTipText(Messages.gettext("Copy selected object"));
300 cut = new JMenuItem(Messages.gettext("Cut"));
301 cut.setToolTipText(Messages.gettext("Cut selected object"));
302 paste = new JMenuItem(Messages.gettext("Paste"));
303 paste.setToolTipText(Messages.gettext("Paste copied object on this figure"));
304 delete = new JMenuItem(Messages.gettext("Delete"));
305 delete.setToolTipText(Messages.gettext("Delete selected object"));
306 clear = new JMenuItem(Messages.gettext("Clear"));
307 clear.setToolTipText(Messages.gettext("Clears the figure"));
308 hide = new JMenuItem(Messages.gettext("Hide"));
309 hide.setToolTipText(Messages.gettext("Hide selected object"));
310 unhide = new JMenuItem(Messages.gettext("Unhide all"));
311 unhide.setToolTipText(Messages.gettext("Unhide all objects"));
312 clipboardCopy = new JMenuItem(Messages.gettext("Copy to Clipboard"));
313 clipboardCopy.setToolTipText(Messages.gettext("Copy figure to system clipboard"));
314 labelX = new JMenuItem(Messages.gettext("Label X"));
315 labelX.setToolTipText(Messages.gettext("Insert a label in X axis"));
316 labelY = new JMenuItem(Messages.gettext("Label Y"));
317 labelY.setToolTipText(Messages.gettext("Insert a label in Y axis"));
318 labelZ = new JMenuItem(Messages.gettext("Label Z"));
319 labelZ.setToolTipText(Messages.gettext("Insert a label in Z axis"));
320 insert = new JMenuItem(Messages.gettext("Insert"));
321 insert.setToolTipText(Messages.gettext("Insert a legend into the selected curve"));
322 remove = new JMenuItem(Messages.gettext("Remove"));
323 remove.setToolTipText(Messages.gettext("Remove the legend from the selected curve"));
324 ged = new JMenuItem(Messages.gettext("Open Quick Editor"));
325 ged.setToolTipText(Messages.gettext("Initialize the graphics editor"));
326 editdata = new JMenuItem(Messages.gettext("Edit curve data"));
327 editdata.setToolTipText(Messages.gettext("Enables curve data modification"));
328 undo = new JMenuItem(Messages.gettext("Undo"));
329 undo.setToolTipText(Messages.gettext("Undo last action"));
330 redo = new JMenuItem(Messages.gettext("Redo"));
331 redo.setToolTipText(Messages.gettext("Redo last undo action"));
332 copyStyle = new JMenuItem(Messages.gettext("Copy style"));
333 copyStyle.setToolTipText(Messages.gettext("Copy the style of the axes"));
334 pasteStyle = new JMenuItem(Messages.gettext("Paste style"));
335 pasteStyle.setToolTipText(Messages.gettext("Paste the copied style on these axes"));
337 copy.addActionListener(new ActionListener() {
338 public void actionPerformed(ActionEvent actionEvent) {
343 cut.addActionListener(new ActionListener() {
344 public void actionPerformed(ActionEvent actionEvent) {
349 paste.addActionListener(new ActionListener() {
350 public void actionPerformed(ActionEvent actionEvent) {
355 delete.addActionListener(new ActionListener() {
356 public void actionPerformed(ActionEvent actionEvent) {
361 clear.addActionListener(new ActionListener() {
362 public void actionPerformed(ActionEvent actionEvent) {
367 hide.addActionListener(new ActionListener() {
368 public void actionPerformed(ActionEvent actionEvent) {
373 unhide.addActionListener(new ActionListener() {
374 public void actionPerformed(ActionEvent actionEvent) {
379 clipboardCopy.addActionListener(new ActionListener() {
380 public void actionPerformed(ActionEvent actionEvent) {
385 labelX.addActionListener(new ActionListener() {
386 public void actionPerformed(ActionEvent actionEvent) {
387 onClickLabel(AxesHandler.axisTo.__X__);
391 labelY.addActionListener(new ActionListener() {
392 public void actionPerformed(ActionEvent actionEvent) {
393 onClickLabel(AxesHandler.axisTo.__Y__);
397 labelZ.addActionListener(new ActionListener() {
398 public void actionPerformed(ActionEvent actionEvent) {
399 onClickLabel(AxesHandler.axisTo.__Z__);
403 insert.addActionListener(new ActionListener() {
404 public void actionPerformed(ActionEvent actionEvent) {
405 onClickInsert(getSelected());
409 remove.addActionListener(new ActionListener() {
410 public void actionPerformed(ActionEvent actionEvent) {
415 ged.addActionListener(new ActionListener() {
416 public void actionPerformed(ActionEvent actionEvent) {
421 editdata.addActionListener(new ActionListener() {
422 public void actionPerformed(ActionEvent actionEvent) {
423 setDataModifyEnabled(true);
427 undo.addActionListener(new ActionListener() {
428 public void actionPerformed(ActionEvent actionEvent) {
433 redo.addActionListener(new ActionListener() {
434 public void actionPerformed(ActionEvent actionEvent) {
439 copyStyle.addActionListener(new ActionListener() {
440 public void actionPerformed(ActionEvent actionEvent) {
445 pasteStyle.addActionListener(new ActionListener() {
446 public void actionPerformed(ActionEvent actionEvent) {
461 menu.add(pasteStyle);
471 menu.add(clipboardCopy);
476 if (StartGED.enableNewGed) {
484 * Set the current selected object, change its color,
485 * if there is a previous selected object restores its color,
486 * enable/disable popup menu items if there is/isn't
489 * @param uid object unique identifier. Null uid unselect previous selection.
491 public void setSelected(Integer uid) {
493 if (CommonHandler.objectExists(selected)) {
494 CommonHandler.setColor(selected, oriColor);
499 if (selected != null) {
500 oriColor = CommonHandler.setColor(selected, -3);
502 boolean spl = (selectedType == SelectionType.SURFACE || selectedType == SelectionType.POLYLINE || selectedType == SelectionType.LEGEND);
504 boolean sp = (selectedType == SelectionType.SURFACE || selectedType == SelectionType.POLYLINE);
506 boolean p = selectedType == SelectionType.POLYLINE;
507 /* Enable delete if object is surface or polyline or legend*/
508 delete.setEnabled(true && spl);
509 /* Enable copy, cut, hide if object is surface or polyline*/
510 copy.setEnabled(true && sp);
511 cut.setEnabled(true && sp);
512 hide.setEnabled(true && sp);
513 /* Enable editdata, add legend if object is polyline*/
514 legends.setEnabled(true && p);
515 editdata.setEnabled(true && p);
517 copy.setEnabled(false);
518 cut.setEnabled(false);
519 delete.setEnabled(false);
520 hide.setEnabled(false);
521 legends.setEnabled(false);
522 editdata.setEnabled(false);
527 * Get current color of the object line/mark.
529 * @return Returns the current color of the object.
531 public Integer getOriColor() {
536 * Set current color of the object line/mark.
538 * @param newScilabColor Color selected by user.
540 public void setOriColor(Integer newScilabColor) {
541 oriColor = newScilabColor;
546 * Returns selected object unique identifier.
547 * @return selected object uid or null if there isn't any selected.
549 public Integer getSelected() {
550 if (CommonHandler.objectExists(selected)) {
559 * Set the figure uid wich the editor belongs.
560 * @param uid Figure unique identifier.
562 public void setFigure(Integer uid) {
567 * Get the figure uid wich the editor belongs.
568 * @return figure uid.
570 public Integer getFigureUid() {
575 * Implements copy menu item action(Callback).
577 public void onClickCopy() {
578 if (selectedType != SelectionType.LEGEND) {
579 ScilabClipboard.getInstance().copy(getSelected());
580 ScilabClipboard.getInstance().setCopiedColor(oriColor);
585 * Implements paste menu item action(Callback).
587 public void onClickPaste() {
589 Integer currentObject, newObject, currentParent, newParent;
590 boolean isDuplicated = false;
592 currentObject = ScilabClipboard.getInstance().getCurrentObject();
593 currentParent = CommonHandler.getParent(currentObject);
594 Integer oldFigure = CommonHandler.getParentFigure(currentObject);
595 if (!CommonHandler.cmpColorMap(figureUid, oldFigure)) {
596 String msg = "The colormap from source figure seems to be different from the destination figure." +
597 "\nThis may influence the final appearance from the object." +
598 "\nDo you want copy the color map too?";
599 int i = JOptionPane.showConfirmDialog(dialogComponent, Messages.gettext(msg), Messages.gettext("Warning"), JOptionPane.YES_NO_OPTION);
601 if (i == JOptionPane.YES_OPTION) {
602 CommonHandler.cloneColorMap(oldFigure, figureUid);
606 AxesHandler.pasteRotationAngles(currentObject, figureUid, lastClick);
608 newObject = ScilabClipboard.getInstance().paste(figureUid, lastClick);
609 newParent = CommonHandler.getParent(newObject);
610 if (newObject == currentObject) {
611 isDuplicated = false;
613 editorHistory.addAction(new ActionPaste(newObject, currentParent, newParent, isDuplicated));
617 * Implements cut menu item action
619 public void onClickCut() {
620 Integer s = getSelected();
621 if (s != null && selectedType != SelectionType.LEGEND) {
623 ScilabClipboard.getInstance().cut(s);
624 ScilabClipboard.getInstance().setCopiedColor(oriColor);
629 * Implements delete menu item action(Callback).
631 public void onClickDelete() {
632 Integer toDelete = getSelected();
633 if (toDelete != null) {
635 editorHistory.addAction(new ActionDelete(toDelete, CommonHandler.getParent(toDelete)));
636 CommonHandler.cut(toDelete);
641 * Implements clear menu item action(Callback).
643 public void onClickClear() {
645 Integer axesTo = AxesHandler.clickedAxes(figureUid, lastClick);
646 if (axesTo != null) {
647 PolylineHandler.getInstance().deleteAll(axesTo);
652 * Implements hide menu item action(Callback).
654 public void onClickHide() {
655 if (getSelected() != null) {
656 CommonHandler.setVisible(selected, false);
657 editorHistory.addAction(new ActionHide(selected));
663 * Implements unhide menu item action(Callback).
665 public void onClickUnhide() {
666 CommonHandler.unhideAll(figureUid);
670 * Implements clipboard copy menu item action(Callback).
672 public void onClickCCopy() {
673 SystemClipboard.copyToSysClipboard(figureUid);
677 * Implements label insert action(Callback).
678 * @param axis axis number.
680 public void onClickLabel(AxesHandler.axisTo axis) {
682 Integer axes = AxesHandler.clickedAxes(figureUid, lastClick);
683 if (axes != null && axis != null) {
684 String text = LabelHandler.getLabelText(axes, axis);
685 String s = (String)JOptionPane.showInputDialog(
687 Messages.gettext("Enter the text"),
688 Messages.gettext("Set label text"),
689 JOptionPane.PLAIN_MESSAGE,
695 String[] oldText = {text};
696 Integer label = LabelHandler.setLabel(axes, tmp, axis);
697 editorHistory.addAction(new ActionTextEdit(label, oldText, tmp));
703 * Implements legend insert action(Callback).
704 * @param polyline Polyline to be inserted in the legend.
706 public void onClickInsert(Integer polyline) {
708 Integer axes = AxesHandler.clickedAxes(figureUid, lastClick);
710 String text = LegendHandler.getLegendText(axes, polyline);
711 String s = (String)JOptionPane.showInputDialog(
713 Messages.gettext("Enter the text"),
714 Messages.gettext("Set legend text"),
715 JOptionPane.PLAIN_MESSAGE,
720 Integer legend = LegendHandler.searchLegend(axes);
721 Integer[] links = LegendHandler.getLinks(legend);
722 String[] texts = LegendHandler.getText(legend);
723 Double[] position = LegendHandler.getPosition(legend);
724 LegendHandler.setLegend(axes, polyline, s);
725 editorHistory.addAction(new ActionLegend(axes, links, texts, position));
731 * Implements legend remove action(Callback).
733 public void onClickRemove() {
735 Integer axesTo = AxesHandler.clickedAxes(figureUid, lastClick);
736 Integer legend = LegendHandler.searchLegend(axesTo);
737 Integer[] links = LegendHandler.getLinks(legend);
738 String[] text = LegendHandler.getText(legend);
739 Double[] position = LegendHandler.getPosition(legend);
740 LegendHandler.removeLegend(axesTo, selected);
741 editorHistory.addAction(new ActionLegend(axesTo, links, text, position));
745 * Enter data editor mode.
747 public void enterDataEditor() {
748 if (!dataEditEnabled && selectedType == SelectionType.POLYLINE) {
749 dataEditor.beginEdit(selected);
750 dataEditEnabled = true;
755 * Leave data editor mode.
757 public void leaveDataEditor() {
758 if (dataEditEnabled) {
759 dataEditor.endEdit();
760 dataEditEnabled = false;
765 * Starts the GED with the property selected by user.
767 public void onClickGED() {
768 if (DatatipManager.getFromUid(figureUid).pickAndHighlight(lastClick[0], lastClick[1])) {
769 Inspector.getInspector(DatatipManager.getFromUid(figureUid).getSelectedTip());
771 Integer[] objects = (new GEDPicker()).pick(figureUid, lastClick);
772 Inspector.getInspector(objects[objects.length - 1]);
777 * Implements Undo action(callBAck)
779 public void onClickUndo() {
780 editorHistory.undo();
784 * Implements Redo action(callBack)
786 public void onClickRedo() {
787 editorHistory.redo();
791 * Implementes copyStyle action(callback)
793 public void onClickCopyStyle() {
795 Integer axes = AxesHandler.clickedAxes(figureUid, lastClick);
796 ScilabClipboard.getInstance().copyStyle(axes);
800 * Implementes pasteStyle action(callback)
802 public void onClickPasteStyle() {
804 Integer axes = AxesHandler.clickedAxes(figureUid, lastClick);
805 if (!AxesHandler.isAxesEmpty(axes)) {
806 String msg = "The axes which the style was copied is not in CubeView" +
807 "\nIf you don't copy the data bounds the view angles can appear different" +
808 "\nDo you want copy the data bounds too?(it can shrink/stretch the current view)";
809 int i = JOptionPane.showConfirmDialog(dialogComponent, Messages.gettext(msg), Messages.gettext("Warning"), JOptionPane.YES_NO_OPTION);
811 if (i == JOptionPane.NO_OPTION) {
816 Double[] oldColorMap = CommonHandler.getColorMap(figureUid);
817 Integer backgroundColor = CommonHandler.getBackground(figureUid);
818 Integer oldAxes = AxesHandler.clickedAxes(figureUid, lastClick);
819 Integer newAxes = ScilabClipboard.getInstance().pasteStyle(oldAxes, flag);
820 editorHistory.addAction(new ActionPasteStyle(newAxes, oldAxes, oldColorMap, backgroundColor));
824 * Test if the mouse position (pos)
825 * is over a polyline, legend or plot3d
826 * and return the selected object uid or null.
827 * @param pos Vector with position (x, y).
828 * @return The picked object uid or null otherwise.
830 private Integer tryPickAnyObject(Integer[] pos) {
831 /*try pick a legend*/
832 selectedLegend = entityPicker.pickLegend(figureUid, pos);
833 if (selectedLegend != null) {
834 selectedType = SelectionType.LEGEND;
835 return selectedLegend.legend;
837 /*try pick a polyline*/
838 Integer picked = entityPicker.pick(figureUid, pos[0], pos[1]);
839 if (picked != null) {
840 selectedType = SelectionType.POLYLINE;
843 picked = entityPicker.pickSurface(figureUid, pos);
844 if (picked != null) {
845 selectedType = SelectionType.SURFACE;