Xcos palette: add xcosPalGenerateAllIcon utility
[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  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 package org.scilab.modules.xcos.palette;
14
15 import static org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement.asynchronousScilabExec;
16 import static org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement.buildCall;
17 import static org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement.synchronousScilabExec;
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.ActionEvent;
27 import java.awt.event.ActionListener;
28 import java.awt.event.MouseListener;
29 import java.lang.ref.WeakReference;
30 import java.util.logging.Level;
31 import java.util.logging.Logger;
32
33 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement.InterpreterException;
34 import org.scilab.modules.gui.messagebox.ScilabModalDialog;
35 import org.scilab.modules.gui.messagebox.ScilabModalDialog.IconType;
36 import org.scilab.modules.localization.Messages;
37 import org.scilab.modules.xcos.block.BasicBlock;
38 import org.scilab.modules.xcos.block.BlockFactory;
39 import org.scilab.modules.xcos.block.BlockFactory.BlockInterFunction;
40 import org.scilab.modules.xcos.graph.XcosDiagram;
41 import org.scilab.modules.xcos.io.scicos.ScicosFormatException;
42 import org.scilab.modules.xcos.io.scicos.ScilabDirectHandler;
43 import org.scilab.modules.xcos.palette.listener.PaletteBlockMouseListener;
44 import org.scilab.modules.xcos.palette.model.PaletteBlock;
45 import org.scilab.modules.xcos.palette.view.PaletteBlockView;
46 import org.scilab.modules.xcos.palette.view.PaletteManagerView;
47 import org.scilab.modules.xcos.utils.BlockPositioning;
48 import org.scilab.modules.xcos.utils.XcosMessages;
49
50 import com.mxgraph.swing.handler.mxGraphTransferHandler;
51 import com.mxgraph.swing.util.mxGraphTransferable;
52
53 /**
54  * A palette block is the representation of the block in the palette. All the
55  * operations there are used to render, load and put (on a diagram) a block.
56  */
57 public final class PaletteBlockCtrl {
58     /**
59      * Internal graph used to render each block.
60      */
61     public static final XcosDiagram INTERNAL_GRAPH;
62     static {
63         INTERNAL_GRAPH = new XcosDiagram();
64         INTERNAL_GRAPH.installListeners();
65     }
66
67     private static final double BLOCK_DEFAULT_POSITION = 10.0;
68     private static final MouseListener MOUSE_LISTENER = new PaletteBlockMouseListener();
69     private static final Logger LOG = Logger.getLogger(PaletteBlockCtrl.class.getName());
70
71     private static final String UNABLE_TO_LOAD_BLOCK = Messages.gettext("Unable to load block from %s .");
72     private static final String LOADING_THE_BLOCK = Messages.gettext("Loading the block") + XcosMessages.DOTS;
73
74     private static PaletteBlockCtrl previouslySelected;
75
76     private final PaletteBlock model;
77     private final PaletteBlockView view;
78
79     private transient WeakReference<Transferable> transferable = new WeakReference<Transferable>(null);
80
81     /**
82      * Default constructor
83      *
84      * @param model
85      *            the block data
86      */
87     public PaletteBlockCtrl(PaletteBlock model) {
88         this.model = model;
89         this.view = new PaletteBlockView(this);
90         installListeners(this.view);
91     }
92
93     /**
94      * @param view
95      *            The view to setup
96      */
97     private void installListeners(PaletteBlockView view) {
98         view.addMouseListener(MOUSE_LISTENER);
99         installDnd();
100     }
101
102     /**
103      * @return the view
104      */
105     public PaletteBlockView getView() {
106         return view;
107     }
108
109     /**
110      * @return the model
111      */
112     public PaletteBlock getModel() {
113         return model;
114     }
115
116     /**
117      * This function is the only access to get the block.
118      *
119      * @return the transferable object
120      * @throws ScicosFormatException
121      *             on decoding error
122      */
123     public synchronized Transferable getTransferable() throws ScicosFormatException {
124         Transferable transfer = transferable.get();
125         if (transfer == null) {
126             /* Load the block from the H5 file */
127             BasicBlock block;
128             try {
129                 block = loadBlock();
130             } catch (ScicosFormatException ex) {
131                 getView().setEnabled(false);
132                 throw ex;
133             }
134             if (block == null) {
135                 if (LOG.isLoggable(Level.FINEST)) {
136                     LOG.finest(String.format(UNABLE_TO_LOAD_BLOCK, getModel().getData().getEvaluatedPath()));
137                 }
138                 getView().setEnabled(false);
139                 throw new InvalidDnDOperationException();
140             }
141             getView().setEnabled(true);
142
143             /* Render it and export it */
144             block.getGeometry().setX(BLOCK_DEFAULT_POSITION);
145             block.getGeometry().setY(BLOCK_DEFAULT_POSITION);
146
147             INTERNAL_GRAPH.addCell(block);
148             INTERNAL_GRAPH.selectAll();
149
150             BlockPositioning.updateBlockView(block);
151
152             mxGraphTransferHandler handler = ((mxGraphTransferHandler) INTERNAL_GRAPH.getAsComponent().getTransferHandler());
153             transfer = handler.createTransferable(INTERNAL_GRAPH.getAsComponent());
154             transferable = new WeakReference<Transferable>(transfer);
155
156             INTERNAL_GRAPH.removeCells();
157         }
158         return transfer;
159     }
160
161     /**
162      * @return the loaded block.
163      * @throws ScicosFormatException
164      *             on error
165      */
166     private BasicBlock loadBlock() throws ScicosFormatException {
167         BasicBlock block;
168         if (model.getName().compareTo("TEXT_f") != 0) {
169
170             // Load the block with a reference instance
171             final ScilabDirectHandler handler = ScilabDirectHandler.acquire();
172             if (handler == null) {
173                 return null;
174             }
175
176             try {
177                 synchronousScilabExec(ScilabDirectHandler.BLK + " = " + buildCall(model.getName(), "define"));
178                 block = handler.readBlock();
179             } catch (InterpreterException e1) {
180                 LOG.severe(e1.toString());
181                 block = null;
182             } finally {
183                 handler.release();
184             }
185
186             // invalid block case
187             if (block == null) {
188                 return null;
189             }
190
191             if (block.getStyle().compareTo("") == 0) {
192                 block.setStyle(block.getInterfaceFunctionName());
193             }
194         } else {
195             block = BlockFactory.createBlock(BlockInterFunction.TEXT_f);
196         }
197         return block;
198     }
199
200     /**
201      * @param callback
202      *            called after the block loading
203      */
204     protected void loadBlock(final ActionListener callback) {
205         if (model.getName().compareTo("TEXT_f") != 0) {
206
207             // Load the block with a reference instance
208             final ScilabDirectHandler handler = ScilabDirectHandler.acquire();
209             if (handler == null) {
210                 return;
211             }
212
213             final ActionListener internalCallback = new ActionListener() {
214                 @Override
215                 public void actionPerformed(ActionEvent e) {
216                     try {
217                         final BasicBlock block = handler.readBlock();
218
219                         // invalid block case
220                         if (block == null) {
221                             return;
222                         }
223
224                         // update style
225                         if (block.getStyle().compareTo("") == 0) {
226                             block.setStyle(block.getInterfaceFunctionName());
227                         }
228
229                         callback.actionPerformed(new ActionEvent(block, 0, "loaded"));
230                     } catch (ScicosFormatException e1) {
231                         e1.printStackTrace();
232                     } finally {
233                         handler.release();
234                     }
235                 }
236             };
237
238             try {
239                 asynchronousScilabExec(internalCallback, ScilabDirectHandler.BLK + " = " + buildCall(model.getName(), "define"));
240             } catch (InterpreterException e1) {
241                 LOG.severe(e1.toString());
242             } finally {
243                 handler.release();
244             }
245         } else {
246             final BasicBlock block = BlockFactory.createBlock(BlockInterFunction.TEXT_f);
247             callback.actionPerformed(new ActionEvent(block, 0, "loaded"));
248         }
249     }
250
251     /**
252      * This function load the block and render it on the hidden diagram. This
253      * can be time-consuming and each block should be cached on the caller when
254      * possible.
255      *
256      * @return a rendered block
257      */
258     public BasicBlock getBlock() {
259         try {
260             return (BasicBlock) ((mxGraphTransferable) getTransferable()).getCells()[0];
261         } catch (ScicosFormatException e) {
262             LOG.severe(e.toString());
263             return null;
264         }
265     }
266
267     /**
268      * @return true if it is selected, false otherwise
269      */
270     public boolean isSelected() {
271         return this == previouslySelected;
272     }
273
274     /**
275      * @param selected
276      *            the selected state to set
277      */
278     public void setSelected(boolean selected) {
279         if (selected) {
280             if (previouslySelected != null) {
281                 previouslySelected.setSelected(false);
282             }
283             previouslySelected = this;
284         }
285         getView().setSelectedUI(selected);
286     }
287
288     /**
289      * Install the Drag'n'Drop on this instance.
290      */
291     public void installDnd() {
292         // Install the handler for dragging nodes into a graph
293         DragGestureListener dragGestureListener = new DragGestureListener() {
294             @Override
295             public void dragGestureRecognized(DragGestureEvent e) {
296                 if (PaletteManagerView.get() == null) {
297                     PaletteManagerView.restore(null);
298                 }
299                 final PaletteManagerView winView = PaletteManagerView.get();
300                 final DragGestureEvent event = e;
301                 final String msg = String.format(UNABLE_TO_LOAD_BLOCK, getModel().getName());
302
303                 winView.setInfo(LOADING_THE_BLOCK);
304                 try {
305                     Transferable transfer = getTransferable();
306
307                     if (transfer != null) {
308                         event.startDrag(null, null, new Point(), transfer, null);
309                     } else {
310                         throw new InvalidDnDOperationException();
311                     }
312                 } catch (InvalidDnDOperationException exception) {
313                     ScilabModalDialog.show(winView, msg, XcosMessages.XCOS_ERROR, IconType.ERROR_ICON);
314                 } catch (ScicosFormatException ex) {
315                     ScilabModalDialog.show(winView, ex.getMessage(), XcosMessages.XCOS_ERROR, IconType.ERROR_ICON);
316                 } finally {
317                     winView.setInfo(XcosMessages.EMPTY_INFO);
318                 }
319             }
320
321         };
322
323         DragSource dragSource = DragSource.getDefaultDragSource();
324         dragSource.createDefaultDragGestureRecognizer(this.getView(), DnDConstants.ACTION_COPY, dragGestureListener);
325     }
326 }