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 * Copyright (C) 2012 - 2016 - Scilab Enterprises
8 * This file is hereby licensed under the terms of the GNU GPL v2.0,
9 * pursuant to article 5.3.4 of the CeCILL v.2.1.
10 * This file was originally licensed under the terms of the CeCILL v2.1,
11 * and continues to be available under such terms.
12 * For more information, see the COPYING file which you should have received
13 * along with this program.
17 package org.scilab.modules.gui.editor;
20 import org.scilab.modules.renderer.utils.CommonHandler;
21 import org.scilab.modules.renderer.utils.EntityPicker;
22 import org.scilab.modules.renderer.utils.AxesHandler;
23 import java.awt.event.ActionListener;
24 import java.awt.event.ActionEvent;
25 import java.awt.event.MouseEvent;
26 import java.awt.event.KeyEvent;
27 import java.awt.Component;
28 import javax.swing.JOptionPane;
29 import javax.swing.JMenu;
30 import javax.swing.JMenuItem;
31 import javax.swing.JPopupMenu;
33 import org.scilab.modules.gui.datatip.DatatipManager;
34 import org.scilab.modules.gui.editor.ScilabClipboard;
35 import org.scilab.modules.gui.editor.SystemClipboard;
36 import org.scilab.modules.renderer.utils.PolylineHandler;
37 import org.scilab.modules.gui.editor.GEDPicker;
38 import org.scilab.modules.gui.editor.LabelHandler;
39 import org.scilab.modules.renderer.utils.LegendHandler;
40 import org.scilab.modules.gui.editor.action.EditorHistory;
41 import org.scilab.modules.gui.editor.action.ActionDelete;
42 import org.scilab.modules.gui.editor.action.ActionLegend;
43 import org.scilab.modules.gui.editor.action.ActionMove;
44 import org.scilab.modules.gui.editor.action.ActionPaste;
45 import org.scilab.modules.gui.editor.action.ActionTextEdit;
46 import org.scilab.modules.gui.editor.action.ActionPasteStyle;
47 import org.scilab.modules.gui.editor.action.ActionHide;
48 import org.scilab.modules.gui.ged.Inspector;
49 import org.scilab.modules.gui.ged.StartGED;
50 import org.scilab.modules.gui.ged.SwapObject;
51 import org.scilab.modules.localization.Messages;
52 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement;
56 * Point and click figure editor.
58 * Provides polyline selection by mouse click,
59 * copy, cut, paste, delete, hide, unhide polylines
60 * by popup menus and keyboard shortcuts.
62 * @author Caio Souza <caioc2bolado@gmail.com>
63 * @author Pedro Souza <bygrandao@gmail.com>
71 JMenuItem copy, copyStyle, cut, paste, pasteStyle, delete, clear, hide, unhide, clipboardCopy, labelX, labelY, labelZ, title, insert, remove, ged, editdata, undo, redo;
72 JMenu labels, legends;
74 EntityPicker.LegendInfo selectedLegend = null;
75 EntityPicker.SurfaceInfo selectedSurface = null;
76 Integer selected = null;
77 Integer figureUid = null;
78 Integer[] lastClick = { 0, 0 };
79 Integer[] dragClick = { 0, 0 };
80 EntityPicker entityPicker;
81 DataEditor dataEditor;
82 boolean dataModifyEnabled = false;
83 boolean dataEditEnabled = false;
84 boolean updateDrag = true;
85 EditorHistory editorHistory;
87 Component dialogComponent;
89 enum SelectionType {POLYLINE, LEGEND, SURFACE};
90 SelectionType selectedType;
96 editorHistory = new EditorHistory();
97 entityPicker = new EntityPicker();
98 dataEditor = new DataEditor();
99 dataEditor.setLeaveAction(new ActionListener() {
100 public void actionPerformed(ActionEvent actionEvent) {
107 * Enable / disable data modify.
108 * @param b true to enable, false to disable.
110 public void setDataModifyEnabled(boolean b) {
111 dataModifyEnabled = b;
112 if (!dataModifyEnabled) {
114 } else if (getSelected() != null) {
120 * Returns if the data modify is enabled or not.
121 * @return True if enabled, false otherwise.
123 public boolean isDataModifyEnabled() {
124 return dataModifyEnabled;
127 public void setUpdateDrag(boolean state) {
132 * On right mouse click, set popup menu visible.
133 * @param event MouseEvent to retrieve click positon in figure.
135 public void onRightMouseClick(MouseEvent event) {
136 if (!dataEditEnabled) {
137 lastClick[0] = event.getX();
138 lastClick[1] = event.getY();
139 boolean b = ScilabClipboard.getInstance().canPaste();
142 boolean notBlank = AxesHandler.isAxesNotBlank(figureUid);
143 clipboardCopy.setEnabled(notBlank);
145 pasteStyle.setEnabled(ScilabClipboard.getInstance().canPasteStyle());
146 undo.setEnabled(editorHistory.isUndoEnabled());
147 redo.setEnabled(editorHistory.isRedoEnabled());
149 menu.show(event.getComponent(), event.getX(), event.getY());
150 dialogComponent = event.getComponent();
152 dataEditor.onRightClick(event);
157 * Handles left mouse clicks.
159 * @param event the mouse event.
161 public void onLeftMouseDown(MouseEvent event) {
163 lastClick[0] = event.getX();
164 lastClick[1] = event.getY();
166 if (!dataEditEnabled) {
167 switch (event.getClickCount()) {
169 setSelected(tryPickAnyObject(lastClick));
172 /*there is a polyline selected? if yes start dataEditor*/
173 if (selected != null && selectedType == SelectionType.POLYLINE && dataModifyEnabled) {
176 /*on double click over a legend or label open dialog*/
177 else if (selectedLegend != null) {
178 onClickInsert(selectedLegend.polyline);
180 /*try pick a label and open the dialog*/
181 onClickLabel(EntityPicker.pickLabel(figureUid, lastClick));
187 } else { /*data editor is enabled, pass event to it*/
188 switch (event.getClickCount()) {
190 dataEditor.onLeftMouseDown(event);
193 dataEditor.onLeftDoubleClick(event);
199 dragClick[0] = lastClick[0];
200 dragClick[1] = lastClick[1];
203 public void onLeftMouseRelease(MouseEvent event) {
205 Integer object = getSelected();
206 if (dataModifyEnabled && !dataEditEnabled && object != null) {
207 editorHistory.addAction(new ActionMove(object, lastClick, dragClick, (selectedType == SelectionType.LEGEND)));
209 dataEditor.onLeftMouseRelease(event);
214 * On drag move the selected object, if dataEditor
215 * is enabled pass event to it.
216 * @param event The mouse event.
218 public void onMouseDragged(MouseEvent event) {
219 Integer[] newClick = { event.getX(), event.getY() };
220 if (dataModifyEnabled) {
221 if (!dataEditEnabled) {
222 Integer objUID = getSelected();
223 if (objUID != null) {
224 if (selectedType == SelectionType.LEGEND) {
225 LegendHandler.dragLegend(objUID, dragClick, newClick);
226 } else if (selectedType == SelectionType.POLYLINE) {
227 PolylineHandler.getInstance().dragPolyline(objUID, dragClick, newClick);
230 LabelHandler.dragLabel(figureUid, dragClick, newClick, updateDrag);
233 dataEditor.onDrag(dragClick, newClick);
236 dragClick[0] = newClick[0];
237 dragClick[1] = newClick[1];
241 * Handles keyboard input
242 * @param event The Key event.
244 void onKeyPressed(KeyEvent event) {
246 if (event.isControlDown()) {
247 switch (event.getKeyCode()) {
249 if (getSelected() != null) {
254 if (ScilabClipboard.getInstance().canPaste()) {
262 if (editorHistory.isUndoEnabled()) {
268 ScilabInterpreterManagement.asynchronousScilabExec(null, "scf();");
269 } catch (Exception e) {
270 System.err.println(e);
277 switch (event.getKeyCode()) {
278 case KeyEvent.VK_DELETE:
279 if (!dataEditEnabled) {
283 case KeyEvent.VK_ESCAPE:
293 * Initializes the popup menu.
295 * Create the popup menu and all popup menu items
296 * and set the properly action for each menu item.
299 menu = new JPopupMenu();
300 labels = new JMenu(Messages.gettext("Label"));
301 legends = new JMenu(Messages.gettext("Legend"));
303 copy = new JMenuItem(Messages.gettext("Copy"));
304 copy.setToolTipText(Messages.gettext("Copy selected object"));
305 cut = new JMenuItem(Messages.gettext("Cut"));
306 cut.setToolTipText(Messages.gettext("Cut selected object"));
307 paste = new JMenuItem(Messages.gettext("Paste"));
308 paste.setToolTipText(Messages.gettext("Paste copied object on this figure"));
309 delete = new JMenuItem(Messages.gettext("Delete"));
310 delete.setToolTipText(Messages.gettext("Delete selected object"));
311 clear = new JMenuItem(Messages.gettext("Clear"));
312 clear.setToolTipText(Messages.gettext("Clears the figure"));
313 hide = new JMenuItem(Messages.gettext("Hide"));
314 hide.setToolTipText(Messages.gettext("Hide selected object"));
315 unhide = new JMenuItem(Messages.gettext("Unhide all"));
316 unhide.setToolTipText(Messages.gettext("Unhide all objects"));
317 clipboardCopy = new JMenuItem(Messages.gettext("Copy to Clipboard"));
318 clipboardCopy.setToolTipText(Messages.gettext("Copy figure to system clipboard"));
319 title = new JMenuItem(Messages.gettext("Title"));
320 title.setToolTipText(Messages.gettext("Insert a title"));
321 labelX = new JMenuItem(Messages.gettext("Label X"));
322 labelX.setToolTipText(Messages.gettext("Insert a label in X axis"));
323 labelY = new JMenuItem(Messages.gettext("Label Y"));
324 labelY.setToolTipText(Messages.gettext("Insert a label in Y axis"));
325 labelZ = new JMenuItem(Messages.gettext("Label Z"));
326 labelZ.setToolTipText(Messages.gettext("Insert a label in Z axis"));
327 insert = new JMenuItem(Messages.gettext("Insert"));
328 insert.setToolTipText(Messages.gettext("Insert a legend into the selected curve"));
329 remove = new JMenuItem(Messages.gettext("Remove"));
330 remove.setToolTipText(Messages.gettext("Remove the legend from the selected curve"));
331 ged = new JMenuItem(Messages.gettext("Open Quick Editor"));
332 ged.setToolTipText(Messages.gettext("Initialize the graphics editor"));
333 editdata = new JMenuItem(Messages.gettext("Edit curve data"));
334 editdata.setToolTipText(Messages.gettext("Enables curve data modification"));
335 undo = new JMenuItem(Messages.gettext("Undo"));
336 undo.setToolTipText(Messages.gettext("Undo last action"));
337 redo = new JMenuItem(Messages.gettext("Redo"));
338 redo.setToolTipText(Messages.gettext("Redo last undo action"));
339 copyStyle = new JMenuItem(Messages.gettext("Copy style"));
340 copyStyle.setToolTipText(Messages.gettext("Copy the style of the axes"));
341 pasteStyle = new JMenuItem(Messages.gettext("Paste style"));
342 pasteStyle.setToolTipText(Messages.gettext("Paste the copied style on these axes"));
344 copy.addActionListener(new ActionListener() {
345 public void actionPerformed(ActionEvent actionEvent) {
350 cut.addActionListener(new ActionListener() {
351 public void actionPerformed(ActionEvent actionEvent) {
356 paste.addActionListener(new ActionListener() {
357 public void actionPerformed(ActionEvent actionEvent) {
362 delete.addActionListener(new ActionListener() {
363 public void actionPerformed(ActionEvent actionEvent) {
368 clear.addActionListener(new ActionListener() {
369 public void actionPerformed(ActionEvent actionEvent) {
374 hide.addActionListener(new ActionListener() {
375 public void actionPerformed(ActionEvent actionEvent) {
380 unhide.addActionListener(new ActionListener() {
381 public void actionPerformed(ActionEvent actionEvent) {
386 clipboardCopy.addActionListener(new ActionListener() {
387 public void actionPerformed(ActionEvent actionEvent) {
392 labelX.addActionListener(new ActionListener() {
393 public void actionPerformed(ActionEvent actionEvent) {
394 onClickLabel(AxesHandler.axisTo.__X__);
398 labelY.addActionListener(new ActionListener() {
399 public void actionPerformed(ActionEvent actionEvent) {
400 onClickLabel(AxesHandler.axisTo.__Y__);
404 labelZ.addActionListener(new ActionListener() {
405 public void actionPerformed(ActionEvent actionEvent) {
406 onClickLabel(AxesHandler.axisTo.__Z__);
409 title.addActionListener(new ActionListener() {
410 public void actionPerformed(ActionEvent actionEvent) {
411 onClickLabel(AxesHandler.axisTo.__TITLE__);
415 insert.addActionListener(new ActionListener() {
416 public void actionPerformed(ActionEvent actionEvent) {
417 onClickInsert(getSelected());
421 remove.addActionListener(new ActionListener() {
422 public void actionPerformed(ActionEvent actionEvent) {
427 ged.addActionListener(new ActionListener() {
428 public void actionPerformed(ActionEvent actionEvent) {
433 editdata.addActionListener(new ActionListener() {
434 public void actionPerformed(ActionEvent actionEvent) {
435 setDataModifyEnabled(true);
439 undo.addActionListener(new ActionListener() {
440 public void actionPerformed(ActionEvent actionEvent) {
445 redo.addActionListener(new ActionListener() {
446 public void actionPerformed(ActionEvent actionEvent) {
451 copyStyle.addActionListener(new ActionListener() {
452 public void actionPerformed(ActionEvent actionEvent) {
457 pasteStyle.addActionListener(new ActionListener() {
458 public void actionPerformed(ActionEvent actionEvent) {
474 menu.add(pasteStyle);
484 menu.add(clipboardCopy);
489 if (StartGED.enableNewGed) {
497 * Set the current selected object, change its color,
498 * if there is a previous selected object restores its color,
499 * enable/disable popup menu items if there is/isn't
502 * @param uid object unique identifier. Null uid unselect previous selection.
504 public void setSelected(Integer uid) {
505 if (CommonHandler.objectExists(selected)) {
506 CommonHandler.setSelected(selected, false);
511 if (selected != null) {
512 CommonHandler.setSelected(selected, true);
514 boolean spl = (selectedType == SelectionType.SURFACE || selectedType == SelectionType.POLYLINE || selectedType == SelectionType.LEGEND);
516 boolean sp = (selectedType == SelectionType.SURFACE || selectedType == SelectionType.POLYLINE);
518 boolean p = selectedType == SelectionType.POLYLINE;
519 /* Enable delete if object is surface or polyline or legend*/
520 delete.setEnabled(true && spl);
521 /* Enable copy, cut, hide if object is surface or polyline*/
522 copy.setEnabled(true && sp);
523 cut.setEnabled(true && sp);
524 hide.setEnabled(true && sp);
525 /* Enable editdata, add legend if object is polyline*/
526 legends.setEnabled(true && p);
527 editdata.setEnabled(true && p);
529 copy.setEnabled(false);
530 cut.setEnabled(false);
531 delete.setEnabled(false);
532 hide.setEnabled(false);
533 legends.setEnabled(false);
534 editdata.setEnabled(false);
539 * Returns selected object unique identifier.
540 * @return selected object uid or null if there isn't any selected.
542 public Integer getSelected() {
543 if (CommonHandler.objectExists(selected)) {
552 * Set the figure uid wich the editor belongs.
553 * @param uid Figure unique identifier.
555 public void setFigure(Integer uid) {
560 * Get the figure uid wich the editor belongs.
561 * @return figure uid.
563 public Integer getFigureUid() {
568 * Implements copy menu item action(Callback).
570 public void onClickCopy() {
571 if (selectedType != SelectionType.LEGEND) {
572 ScilabClipboard.getInstance().copy(getSelected());
577 * Implements paste menu item action(Callback).
579 public void onClickPaste() {
580 Integer currentObject, newObject, currentParent, newParent;
581 boolean isDuplicated = false;
583 currentObject = ScilabClipboard.getInstance().getCurrentObject();
584 currentParent = CommonHandler.getParent(currentObject);
585 Integer oldFigure = CommonHandler.getParentFigure(currentObject);
586 if (!CommonHandler.cmpColorMap(figureUid, oldFigure)) {
587 String msg = "The colormap from source figure seems to be different from the destination figure." +
588 "\nThis may influence the final appearance from the object." +
589 "\nDo you want copy the color map too?";
590 int i = JOptionPane.showConfirmDialog(dialogComponent, Messages.gettext(msg), Messages.gettext("Warning"), JOptionPane.YES_NO_OPTION);
592 if (i == JOptionPane.YES_OPTION) {
593 CommonHandler.cloneColorMap(oldFigure, figureUid);
597 AxesHandler.pasteRotationAngles(currentObject, figureUid, lastClick);
599 newObject = ScilabClipboard.getInstance().paste(figureUid, lastClick);
600 newParent = CommonHandler.getParent(newObject);
601 if (newObject == currentObject) {
602 isDuplicated = false;
604 editorHistory.addAction(new ActionPaste(newObject, currentParent, newParent, isDuplicated));
608 * Implements cut menu item action
610 public void onClickCut() {
611 Integer s = getSelected();
612 if (s != null && selectedType != SelectionType.LEGEND) {
614 ScilabClipboard.getInstance().cut(s);
619 * Implements delete menu item action(Callback).
621 public void onClickDelete() {
622 Integer toDelete = getSelected();
623 if (toDelete != null) {
625 editorHistory.addAction(new ActionDelete(toDelete, CommonHandler.getParent(toDelete)));
626 CommonHandler.cut(toDelete);
631 * Implements clear menu item action(Callback).
633 public void onClickClear() {
635 Integer axesTo = AxesHandler.clickedAxes(figureUid, lastClick);
636 if (axesTo != null) {
637 PolylineHandler.getInstance().deleteAll(axesTo);
642 * Implements hide menu item action(Callback).
644 public void onClickHide() {
645 if (getSelected() != null) {
646 CommonHandler.setVisible(selected, false);
647 editorHistory.addAction(new ActionHide(selected));
653 * Implements unhide menu item action(Callback).
655 public void onClickUnhide() {
656 CommonHandler.unhideAll(figureUid);
660 * Implements clipboard copy menu item action(Callback).
662 public void onClickCCopy() {
663 SystemClipboard.copyToSysClipboard(figureUid);
667 * Implements label insert action(Callback).
668 * @param axis axis number.
670 public void onClickLabel(AxesHandler.axisTo axis) {
671 Integer axes = AxesHandler.clickedAxes(figureUid, lastClick);
672 if (axes != null && axis != null) {
673 String text = LabelHandler.getLabelText(axes, axis);
674 String s = (String)JOptionPane.showInputDialog(
676 Messages.gettext("Enter the text"),
677 Messages.gettext("Set label text"),
678 JOptionPane.PLAIN_MESSAGE,
684 String[] oldText = {text};
685 Integer label = LabelHandler.setLabel(axes, tmp, axis);
686 editorHistory.addAction(new ActionTextEdit(label, oldText, tmp));
692 * Implements legend insert action(Callback).
693 * @param polyline Polyline to be inserted in the legend.
695 public void onClickInsert(Integer polyline) {
696 Integer axes = AxesHandler.clickedAxes(figureUid, lastClick);
698 String text = LegendHandler.getLegendText(axes, polyline);
699 String s = (String)JOptionPane.showInputDialog(
701 Messages.gettext("Enter the text"),
702 Messages.gettext("Set legend text"),
703 JOptionPane.PLAIN_MESSAGE,
707 if (s != null && !s.equals(text)) {
708 Integer legend = LegendHandler.searchLegend(axes);
709 Integer[] links = LegendHandler.getLinks(legend);
710 String[] texts = LegendHandler.getText(legend);
711 Double[] position = LegendHandler.getPosition(legend);
712 LegendHandler.setLegend(legend, axes, polyline, s);
713 editorHistory.addAction(new ActionLegend(axes, links, texts, position));
719 * Implements legend remove action(Callback).
721 public void onClickRemove() {
722 Integer axesTo = AxesHandler.clickedAxes(figureUid, lastClick);
723 Integer legend = LegendHandler.searchLegend(axesTo);
724 Integer[] links = LegendHandler.getLinks(legend);
725 String[] text = LegendHandler.getText(legend);
726 Double[] position = LegendHandler.getPosition(legend);
727 LegendHandler.removeLegend(axesTo, selected);
728 editorHistory.addAction(new ActionLegend(axesTo, links, text, position));
732 * Enter data editor mode.
734 public void enterDataEditor() {
735 if (!dataEditEnabled && selectedType == SelectionType.POLYLINE) {
736 dataEditor.beginEdit(selected);
737 dataEditEnabled = true;
742 * Leave data editor mode.
744 public void leaveDataEditor() {
745 if (dataEditEnabled) {
746 dataEditor.endEdit();
747 dataEditEnabled = false;
752 * Starts the GED with the property selected by user.
754 public void onClickGED() {
755 if (DatatipManager.getFromUid(figureUid).pickAndHighlight(lastClick[0], lastClick[1])) {
756 Inspector.getInspector(DatatipManager.getFromUid(figureUid).getSelectedTip());
758 Integer[] objects = (new GEDPicker()).pick(figureUid, lastClick);
759 Inspector.getInspector(objects[objects.length - 1]);
764 * Implements Undo action(callBAck)
766 public void onClickUndo() {
767 editorHistory.undo();
771 * Implements Redo action(callBack)
773 public void onClickRedo() {
774 editorHistory.redo();
778 * Implementes copyStyle action(callback)
780 public void onClickCopyStyle() {
782 Integer axes = AxesHandler.clickedAxes(figureUid, lastClick);
783 ScilabClipboard.getInstance().copyStyle(axes);
787 * Implementes pasteStyle action(callback)
789 public void onClickPasteStyle() {
791 Integer axes = AxesHandler.clickedAxes(figureUid, lastClick);
792 if (!AxesHandler.isAxesEmpty(axes)) {
793 String msg = "The axes which the style was copied is not in CubeView" +
794 "\nIf you don't copy the data bounds the view angles can appear different" +
795 "\nDo you want copy the data bounds too?(it can shrink/stretch the current view)";
796 int i = JOptionPane.showConfirmDialog(dialogComponent, Messages.gettext(msg), Messages.gettext("Warning"), JOptionPane.YES_NO_OPTION);
798 if (i == JOptionPane.NO_OPTION) {
803 Double[] oldColorMap = CommonHandler.getColorMap(figureUid);
804 Integer backgroundColor = CommonHandler.getBackground(figureUid);
805 Integer oldAxes = AxesHandler.clickedAxes(figureUid, lastClick);
806 Integer newAxes = ScilabClipboard.getInstance().pasteStyle(oldAxes, flag);
807 editorHistory.addAction(new ActionPasteStyle(newAxes, oldAxes, oldColorMap, backgroundColor));
811 * Test if the mouse position (pos)
812 * is over a polyline, legend or plot3d
813 * and return the selected object uid or null.
814 * @param pos Vector with position (x, y).
815 * @return The picked object uid or null otherwise.
817 private Integer tryPickAnyObject(Integer[] pos) {
818 /*try pick a legend*/
819 selectedLegend = entityPicker.pickLegend(figureUid, pos);
820 if (selectedLegend != null) {
821 selectedType = SelectionType.LEGEND;
822 return selectedLegend.legend;
824 /*try pick a polyline*/
825 Integer picked = entityPicker.pick(figureUid, pos[0], pos[1]);
826 if (picked != null) {
827 selectedType = SelectionType.POLYLINE;
830 selectedSurface = entityPicker.pickSurface(figureUid, pos);
831 if (selectedSurface.surface != null) {
832 selectedType = SelectionType.SURFACE;
834 return selectedSurface.surface;