Xcos: fix NPE on dynamic palette
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / palette / PaletteCtrl.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2015 - Marcos CARDINOT
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.Dimension;
16 import java.awt.datatransfer.Transferable;
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.logging.Level;
20 import java.util.logging.Logger;
21
22 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement.InterpreterException;
23 import org.scilab.modules.xcos.JavaController;
24 import org.scilab.modules.xcos.Kind;
25 import org.scilab.modules.xcos.block.BasicBlock;
26 import org.scilab.modules.xcos.graph.XcosDiagram;
27 import org.scilab.modules.xcos.graph.model.XcosCellFactory;
28 import org.scilab.modules.xcos.palette.listener.PaletteMouseListener;
29 import org.scilab.modules.xcos.palette.view.PaletteManagerView;
30 import org.scilab.modules.xcos.palette.view.PaletteView;
31 import org.scilab.modules.xcos.utils.BlockPositioning;
32 import org.scilab.modules.xcos.utils.XcosConstants;
33 import org.scilab.modules.xcos.utils.XcosMessages;
34
35 import com.mxgraph.swing.handler.mxGraphTransferHandler;
36 import com.mxgraph.swing.util.mxGraphTransferable;
37
38 /**
39  * All the operations which are used to render, load and put
40  * the selected blocks on a diagram.
41  * @author Marcos Cardinot <mcardinot@gmail.com>
42  */
43 public final class PaletteCtrl {
44     /**
45      * Internal graph used to render the selected blocks.
46      */
47     private static XcosDiagram internalGraph;
48     static {
49         JavaController controller = new JavaController();
50         internalGraph = new XcosDiagram(controller, controller.createObject(Kind.DIAGRAM), Kind.DIAGRAM, "");
51         internalGraph.installListeners();
52     }
53
54     private static final PaletteMouseListener MOUSE_LISTENER = new PaletteMouseListener();
55     private static final Logger LOG = Logger.getLogger(PaletteBlockCtrl.class.getName());
56
57     private static final int BLOCKS_BY_ROW = 5;
58     private static final Dimension BLOCK_POSITION = XcosConstants.PaletteBlockSize.NORMAL.getBlockDimension();
59
60     private static final List<PaletteBlockCtrl> BLOCKS = new ArrayList<PaletteBlockCtrl>();
61     private final PaletteView view;
62
63     /**
64      * Default constructor
65      */
66     public PaletteCtrl() {
67         this.view = new PaletteView();
68
69         // install listeners
70         this.view.addMouseListener(MOUSE_LISTENER);
71         this.view.addMouseMotionListener(MOUSE_LISTENER);
72     }
73
74     /**
75      * @return the view
76      */
77     public PaletteView getView() {
78         return view;
79     }
80
81     /**
82      * Clear the view
83      */
84     public void clear() {
85         BLOCKS.clear();
86         view.removeAll();
87     }
88
89     /**
90      * Deselects all blocks
91      */
92     public static void clearSelections() {
93         for (PaletteBlockCtrl block : BLOCKS) {
94             block.setSelected(false);
95         }
96     }
97
98     /**
99      * Adds a block to the view.
100      * @param ctrl PaletteBlockCtrl
101      */
102     public void addBlock(PaletteBlockCtrl ctrl) {
103         BLOCKS.add(ctrl);
104         view.add(ctrl.getView());
105     }
106
107     /**
108      * Get the selected palette blocks
109      * @return blocks that have been added to the XcosDiagram
110      */
111     public Object[] getSelectedBlocks() {
112         int row = 0;
113         int column = 0;
114         List<BasicBlock> basicBlocks = new ArrayList<BasicBlock>();
115         for (PaletteBlockCtrl blockCtrl : BLOCKS) {
116             if (!blockCtrl.isSelected()) {
117                 continue;
118             }
119
120             BasicBlock basicBlock = null;
121             try {
122                 basicBlock = XcosCellFactory.createBlock(blockCtrl.getModel().getName());
123             } catch (InterpreterException e) {
124             }
125
126             if (basicBlock == null) {
127                 if (LOG.isLoggable(Level.FINEST)) {
128                     LOG.finest(String.format(XcosMessages.UNABLE_TO_LOAD_BLOCK,
129                                              blockCtrl.getModel().getData().getEvaluatedPath()));
130                 }
131                 getView().setEnabled(false);
132                 continue;
133             }
134
135             // add to the 'recently used blocks' panel
136             PaletteManagerView pmv = PaletteManagerView.get();
137             if (pmv != null) {
138                 pmv.getPanel().addRecentltyUsedBlock(blockCtrl.getModel());
139             }
140
141             // render and export it
142             final double margin = 15.0;
143             basicBlock.getGeometry().setX(margin + BLOCK_POSITION.width * column);
144             basicBlock.getGeometry().setY(margin + BLOCK_POSITION.height * row);
145             ++column;
146
147             if (column >= BLOCKS_BY_ROW) {
148                 column = 0;
149                 ++row;
150             }
151
152             basicBlocks.add(basicBlock);
153         }
154
155         int size = basicBlocks.size();
156         if (size == 0) {
157             return null;
158         }
159
160         // convert to Object[]
161         Object[] ret = new Object[size];
162         for (int i = 0; i < size; i++) {
163             ret[i] = basicBlocks.get(i);
164         }
165         return ret;
166     }
167
168     /**
169      * This function is used to get all selected blocks.
170      * @return the transferable object
171      */
172     public Transferable getTransferable() {
173         Transferable transfer = null;
174         Object[] cells = getSelectedBlocks();
175         if (cells == null) {
176             return null;
177         }
178
179         BlockPositioning.updatePortsPosition(internalGraph, cells);
180         internalGraph.addCells(cells);
181
182         mxGraphTransferHandler handler = (mxGraphTransferHandler) internalGraph.getAsComponent().getTransferHandler();
183         transfer = new mxGraphTransferable(cells, internalGraph.getPaintBounds(cells),
184                                            handler.createTransferableImage(internalGraph.getAsComponent(), cells));
185
186         return transfer;
187     }
188 }