306d533566d970b58b0a211674c7bd65e308fb8a
[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.buildCall;
16 import static org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement.synchronousScilabExec;
17
18 import java.awt.Point;
19 import java.awt.datatransfer.Transferable;
20 import java.awt.dnd.DnDConstants;
21 import java.awt.dnd.DragGestureEvent;
22 import java.awt.dnd.DragGestureListener;
23 import java.awt.dnd.DragSource;
24 import java.awt.dnd.InvalidDnDOperationException;
25 import java.awt.event.MouseListener;
26 import java.lang.ref.WeakReference;
27 import java.util.logging.Level;
28 import java.util.logging.Logger;
29
30 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement.InterpreterException;
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.block.BasicBlock;
35 import org.scilab.modules.xcos.block.BlockFactory;
36 import org.scilab.modules.xcos.block.BlockFactory.BlockInterFunction;
37 import org.scilab.modules.xcos.graph.XcosDiagram;
38 import org.scilab.modules.xcos.io.scicos.ScicosFormatException;
39 import org.scilab.modules.xcos.io.scicos.ScilabDirectHandler;
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
50 /**
51  * A palette block is the representation of the block in the palette. All the
52  * operations there are used to render, load and put (on a diagram) a block.
53  */
54 public final class PaletteBlockCtrl {
55     /**
56      * Internal graph used to render each block.
57      */
58     public static final XcosDiagram INTERNAL_GRAPH;
59     static {
60         INTERNAL_GRAPH = new XcosDiagram();
61         INTERNAL_GRAPH.installListeners();
62     }
63
64     private static final double BLOCK_DEFAULT_POSITION = 10.0;
65     private static final MouseListener MOUSE_LISTENER = new PaletteBlockMouseListener();
66     private static final Logger LOG = Logger.getLogger(PaletteBlockCtrl.class.getName());
67
68     private static final String UNABLE_TO_LOAD_BLOCK = Messages.gettext("Unable to load block from %s .");
69     private static final String LOADING_THE_BLOCK = Messages.gettext("Loading the block") + XcosMessages.DOTS;
70
71     private static PaletteBlockCtrl previouslySelected;
72
73     private final PaletteBlock model;
74     private final PaletteBlockView view;
75
76     private transient WeakReference<Transferable> transferable = new WeakReference<Transferable>(null);
77
78     /**
79      * Default constructor
80      *
81      * @param model
82      *            the block data
83      */
84     public PaletteBlockCtrl(PaletteBlock model) {
85         this.model = model;
86         this.view = new PaletteBlockView(this);
87         installListeners(this.view);
88     }
89
90     /**
91      * @param view
92      *            The view to setup
93      */
94     private void installListeners(PaletteBlockView view) {
95         view.addMouseListener(MOUSE_LISTENER);
96         installDnd();
97     }
98
99     /**
100      * @return the view
101      */
102     public PaletteBlockView getView() {
103         return view;
104     }
105
106     /**
107      * @return the model
108      */
109     public PaletteBlock getModel() {
110         return model;
111     }
112
113     /**
114      * This function is the only access to get the block.
115      *
116      * @return the transferable object
117      * @throws ScicosFormatException
118      *             on decoding error
119      */
120     public synchronized Transferable getTransferable() throws ScicosFormatException {
121         Transferable transfer = transferable.get();
122         if (transfer == null) {
123             /* Load the block from the H5 file */
124             BasicBlock block;
125             try {
126                 block = loadBlock();
127             } catch (ScicosFormatException ex) {
128                 getView().setEnabled(false);
129                 throw ex;
130             }
131             if (block == null) {
132                 if (LOG.isLoggable(Level.FINEST)) {
133                     LOG.finest(String.format(UNABLE_TO_LOAD_BLOCK, getModel().getData().getEvaluatedPath()));
134                 }
135                 getView().setEnabled(false);
136                 throw new InvalidDnDOperationException();
137             }
138             getView().setEnabled(true);
139
140             /* Render it and export it */
141             block.getGeometry().setX(BLOCK_DEFAULT_POSITION);
142             block.getGeometry().setY(BLOCK_DEFAULT_POSITION);
143
144             INTERNAL_GRAPH.addCell(block);
145             INTERNAL_GRAPH.selectAll();
146
147             BlockPositioning.updateBlockView(block);
148
149             mxGraphTransferHandler handler = ((mxGraphTransferHandler) INTERNAL_GRAPH.getAsComponent().getTransferHandler());
150             transfer = handler.createTransferable(INTERNAL_GRAPH.getAsComponent());
151             transferable = new WeakReference<Transferable>(transfer);
152
153             INTERNAL_GRAPH.removeCells();
154         }
155         return transfer;
156     }
157
158     /**
159      * @return the loaded block.
160      * @throws ScicosFormatException
161      *             on error
162      */
163     protected BasicBlock loadBlock() throws ScicosFormatException {
164         BasicBlock block;
165         if (model.getName().compareTo("TEXT_f") != 0) {
166
167             // Load the block with a reference instance
168             final ScilabDirectHandler handler = ScilabDirectHandler.acquire();
169             if (handler == null) {
170                 return null;
171             }
172
173             try {
174                 synchronousScilabExec(ScilabDirectHandler.BLK + " = " + buildCall(model.getName(), "define"));
175                 block = handler.readBlock();
176             } catch (InterpreterException e1) {
177                 LOG.severe(e1.toString());
178                 block = null;
179             } finally {
180                 handler.release();
181             }
182
183             // invalid block case
184             if (block == null) {
185                 return null;
186             }
187
188             if (block.getStyle().compareTo("") == 0) {
189                 block.setStyle(block.getInterfaceFunctionName());
190             }
191         } else {
192             block = BlockFactory.createBlock(BlockInterFunction.TEXT_f);
193         }
194         return block;
195     }
196
197     /**
198      * This function load the block and render it on the hidden diagram. This
199      * can be time-consuming and each block should be cached on the caller when
200      * possible.
201      *
202      * @return a rendered block
203      */
204     public BasicBlock getBlock() {
205         try {
206             return (BasicBlock) ((mxGraphTransferable) getTransferable()).getCells()[0];
207         } catch (ScicosFormatException e) {
208             LOG.severe(e.toString());
209             return null;
210         }
211     }
212
213     /**
214      * @return true if it is selected, false otherwise
215      */
216     public boolean isSelected() {
217         return this == previouslySelected;
218     }
219
220     /**
221      * @param selected
222      *            the selected state to set
223      */
224     public void setSelected(boolean selected) {
225         if (selected) {
226             if (previouslySelected != null) {
227                 previouslySelected.setSelected(false);
228             }
229             previouslySelected = this;
230         }
231         getView().setSelectedUI(selected);
232     }
233
234     /**
235      * Install the Drag'n'Drop on this instance.
236      */
237     public void installDnd() {
238         // Install the handler for dragging nodes into a graph
239         DragGestureListener dragGestureListener = new DragGestureListener() {
240             @Override
241             public void dragGestureRecognized(DragGestureEvent e) {
242                 if (PaletteManagerView.get() == null) {
243                     PaletteManagerView.restore(null);
244                 }
245                 final PaletteManagerView winView = PaletteManagerView.get();
246                 final DragGestureEvent event = e;
247                 final String msg = String.format(UNABLE_TO_LOAD_BLOCK, getModel().getName());
248
249                 winView.setInfo(LOADING_THE_BLOCK);
250                 try {
251                     Transferable transfer = getTransferable();
252
253                     if (transfer != null) {
254                         event.startDrag(null, null, new Point(), transfer, null);
255                     } else {
256                         throw new InvalidDnDOperationException();
257                     }
258                 } catch (InvalidDnDOperationException exception) {
259                     ScilabModalDialog.show(winView, msg, XcosMessages.XCOS_ERROR, IconType.ERROR_ICON);
260                 } catch (ScicosFormatException ex) {
261                     ScilabModalDialog.show(winView, ex.getMessage(), XcosMessages.XCOS_ERROR, IconType.ERROR_ICON);
262                 } finally {
263                     winView.setInfo(XcosMessages.EMPTY_INFO);
264                 }
265             }
266
267         };
268
269         DragSource dragSource = DragSource.getDefaultDragSource();
270         dragSource.createDefaultDragGestureRecognizer(this.getView(), DnDConstants.ACTION_COPY, dragGestureListener);
271     }
272 }