2f1e991665fdd3a244311106976ca5e6787caaa5
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / palette / PaletteBlockCtrl.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009 - DIGITEO - Clement DAVID
4  * Copyright (C) 2011-2015 - Scilab Enterprises - Clement DAVID
5  *
6  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
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.
14  *
15  */
16
17 package org.scilab.modules.xcos.palette;
18
19 import java.awt.Point;
20 import java.awt.datatransfer.Transferable;
21 import java.awt.dnd.DnDConstants;
22 import java.awt.dnd.DragGestureEvent;
23 import java.awt.dnd.DragGestureListener;
24 import java.awt.dnd.DragSource;
25 import java.awt.dnd.InvalidDnDOperationException;
26 import java.awt.event.MouseListener;
27 import java.lang.ref.WeakReference;
28 import java.util.logging.Level;
29 import java.util.logging.Logger;
30
31 import org.scilab.modules.gui.messagebox.ScilabModalDialog;
32 import org.scilab.modules.gui.messagebox.ScilabModalDialog.IconType;
33 import org.scilab.modules.localization.Messages;
34 import org.scilab.modules.xcos.JavaController;
35 import org.scilab.modules.xcos.Kind;
36 import org.scilab.modules.xcos.block.BasicBlock;
37 import org.scilab.modules.xcos.graph.XcosDiagram;
38 import org.scilab.modules.xcos.graph.model.XcosCellFactory;
39 import org.scilab.modules.xcos.io.scicos.ScicosFormatException;
40 import org.scilab.modules.xcos.palette.listener.PaletteBlockMouseListener;
41 import org.scilab.modules.xcos.palette.model.PaletteBlock;
42 import org.scilab.modules.xcos.palette.view.PaletteBlockView;
43 import org.scilab.modules.xcos.palette.view.PaletteManagerView;
44 import org.scilab.modules.xcos.utils.BlockPositioning;
45 import org.scilab.modules.xcos.utils.XcosMessages;
46
47 import com.mxgraph.swing.handler.mxGraphTransferHandler;
48 import com.mxgraph.swing.util.mxGraphTransferable;
49 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement;
50
51 /**
52  * A palette block is the representation of the block in the palette. All the
53  * operations there are used to render, load and put (on a diagram) a block.
54  */
55 public final class PaletteBlockCtrl {
56     /**
57      * Internal graph used to render each block.
58      */
59     public static final XcosDiagram INTERNAL_GRAPH;
60     static {
61         JavaController controller = new JavaController();
62         INTERNAL_GRAPH = new XcosDiagram(controller, controller.createObject(Kind.DIAGRAM), Kind.DIAGRAM, "");
63         INTERNAL_GRAPH.installListeners();
64     }
65
66     private static final double BLOCK_DEFAULT_POSITION = 10.0;
67     private static final MouseListener MOUSE_LISTENER = new PaletteBlockMouseListener();
68     private static final Logger LOG = Logger.getLogger(PaletteBlockCtrl.class.getName());
69
70     private static final String UNABLE_TO_LOAD_BLOCK = Messages.gettext("Unable to load block from %s .");
71     private static final String LOADING_THE_BLOCK = Messages.gettext("Loading the block") + XcosMessages.DOTS;
72
73     private static PaletteBlockCtrl previouslySelected;
74
75     private final PaletteBlock model;
76     private final PaletteBlockView view;
77
78     private transient WeakReference<Transferable> transferable = new WeakReference<Transferable>(null);
79
80     /**
81      * Default constructor
82      *
83      * @param model
84      *            the block data
85      */
86     public PaletteBlockCtrl(PaletteBlock model) {
87         this.model = model;
88         this.view = new PaletteBlockView(this);
89         installListeners(this.view);
90     }
91
92     /**
93      * @param view
94      *            The view to setup
95      */
96     private void installListeners(PaletteBlockView view) {
97         view.addMouseListener(MOUSE_LISTENER);
98         installDnd();
99     }
100
101     /**
102      * @return the view
103      */
104     public PaletteBlockView getView() {
105         return view;
106     }
107
108     /**
109      * @return the model
110      */
111     public PaletteBlock getModel() {
112         return model;
113     }
114
115     /**
116      * This function is the only access to get the block.
117      *
118      * @return the transferable object
119      * @throws ScicosFormatException
120      *             on decoding error
121      */
122     public synchronized Transferable getTransferable() throws ScicosFormatException {
123         Transferable transfer = transferable.get();
124         if (transfer == null) {
125             BasicBlock block;
126             try {
127                 block = XcosCellFactory.createBlock(model.getName());
128             } catch (ScilabInterpreterManagement.InterpreterException ex) {
129                 LOG.finest(String.format(UNABLE_TO_LOAD_BLOCK, model.getName()));
130                 getView().setEnabled(false);
131                 throw new InvalidDnDOperationException();
132             }
133             getView().setEnabled(true);
134
135             /* Render it and export it */
136             block.getGeometry().setX(BLOCK_DEFAULT_POSITION);
137             block.getGeometry().setY(BLOCK_DEFAULT_POSITION);
138
139             INTERNAL_GRAPH.addCell(block);
140             INTERNAL_GRAPH.selectAll();
141
142             BlockPositioning.updateBlockView(INTERNAL_GRAPH, block);
143
144             mxGraphTransferHandler handler = ((mxGraphTransferHandler) INTERNAL_GRAPH.getAsComponent().getTransferHandler());
145             Object[] cells = new Object[] {block};
146             transfer = new mxGraphTransferable(cells, INTERNAL_GRAPH.getPaintBounds(cells), handler.createTransferableImage(INTERNAL_GRAPH.getAsComponent(), cells));
147             transferable = new WeakReference<Transferable>(transfer);
148
149             INTERNAL_GRAPH.removeCells();
150         }
151         return transfer;
152     }
153
154     /**
155      * This function load the block and render it on the hidden diagram. This
156      * can be time-consuming and each block should be cached on the caller when
157      * possible.
158      *
159      * @return a rendered block
160      */
161     public BasicBlock getBlock() {
162         try {
163             return (BasicBlock) ((mxGraphTransferable) getTransferable()).getCells()[0];
164         } catch (ScicosFormatException e) {
165             LOG.severe(e.toString());
166             return null;
167         }
168     }
169
170     /**
171      * @return true if it is selected, false otherwise
172      */
173     public boolean isSelected() {
174         return this == previouslySelected;
175     }
176
177     /**
178      * @param selected
179      *            the selected state to set
180      */
181     public void setSelected(boolean selected) {
182         if (selected) {
183             if (previouslySelected != null) {
184                 previouslySelected.setSelected(false);
185             }
186             previouslySelected = this;
187         }
188         getView().setSelectedUI(selected);
189     }
190
191     /**
192      * Install the Drag'n'Drop on this instance.
193      */
194     public void installDnd() {
195         // Install the handler for dragging nodes into a graph
196         DragGestureListener dragGestureListener = new DragGestureListener() {
197             @Override
198             public void dragGestureRecognized(DragGestureEvent e) {
199                 if (PaletteManagerView.get() == null) {
200                     PaletteManagerView.restore(null);
201                 }
202                 final PaletteManagerView winView = PaletteManagerView.get();
203                 final DragGestureEvent event = e;
204                 final String msg = String.format(UNABLE_TO_LOAD_BLOCK, getModel().getName());
205
206                 winView.setInfo(LOADING_THE_BLOCK);
207                 try {
208                     Transferable transfer = getTransferable();
209
210                     if (transfer != null) {
211                         event.startDrag(null, null, new Point(), transfer, null);
212                     } else {
213                         throw new InvalidDnDOperationException();
214                     }
215                 } catch (InvalidDnDOperationException exception) {
216                     ScilabModalDialog.show(winView, msg, XcosMessages.XCOS_ERROR, IconType.ERROR_ICON);
217                 } catch (ScicosFormatException ex) {
218                     ScilabModalDialog.show(winView, ex.getMessage(), XcosMessages.XCOS_ERROR, IconType.ERROR_ICON);
219                 } finally {
220                     winView.setInfo(XcosMessages.EMPTY_INFO);
221                 }
222             }
223
224         };
225
226         DragSource dragSource = DragSource.getDefaultDragSource();
227         dragSource.createDefaultDragGestureRecognizer(this.getView(), DnDConstants.ACTION_COPY, dragGestureListener);
228     }
229 }