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