Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.plugin / org.gvsig.app / org.gvsig.app.mainplugin / src / main / java / org / gvsig / app / project / documents / view / toc / gui / TOC.java @ 43955

History | View | Annotate | Download (40.3 KB)

1 40558 jjdelcerro
/**
2
 * gvSIG. Desktop Geographic Information System.
3 40435 jjdelcerro
 *
4 40558 jjdelcerro
 * Copyright (C) 2007-2013 gvSIG Association.
5 40435 jjdelcerro
 *
6 43100 jjdelcerro
 * This program is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License as published by the Free Software
8
 * Foundation; either version 3 of the License, or (at your option) any later
9
 * version.
10 40435 jjdelcerro
 *
11 43100 jjdelcerro
 * This program is distributed in the hope that it will be useful, but WITHOUT
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14
 * details.
15 40435 jjdelcerro
 *
16 43100 jjdelcerro
 * You should have received a copy of the GNU General Public License along with
17
 * this program; if not, write to the Free Software Foundation, Inc., 51
18
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 40435 jjdelcerro
 *
20 43100 jjdelcerro
 * For any additional information, do not hesitate to contact us at info AT
21
 * gvsig.com, or visit our website www.gvsig.com.
22 40435 jjdelcerro
 */
23
package org.gvsig.app.project.documents.view.toc.gui;
24
25
import java.awt.BorderLayout;
26
import java.awt.Dimension;
27
import java.awt.Font;
28
import java.awt.FontMetrics;
29
import java.awt.Image;
30
import java.awt.Point;
31
import java.awt.Rectangle;
32
import java.awt.event.ComponentEvent;
33
import java.awt.event.ComponentListener;
34
import java.awt.event.InputEvent;
35
import java.awt.event.MouseAdapter;
36
import java.awt.event.MouseEvent;
37
import java.text.MessageFormat;
38
import java.util.ArrayList;
39
import java.util.Enumeration;
40
import java.util.HashMap;
41 43278 fdiaz
import java.util.List;
42 40435 jjdelcerro
import java.util.Map;
43 43278 fdiaz
44 40435 jjdelcerro
import javax.swing.BorderFactory;
45
import javax.swing.JColorChooser;
46
import javax.swing.JComponent;
47
import javax.swing.JDialog;
48
import javax.swing.JScrollPane;
49
import javax.swing.JTree;
50
import javax.swing.SwingUtilities;
51
import javax.swing.event.TreeExpansionEvent;
52
import javax.swing.event.TreeExpansionListener;
53
import javax.swing.tree.DefaultMutableTreeNode;
54
import javax.swing.tree.DefaultTreeModel;
55 43100 jjdelcerro
import javax.swing.tree.TreeNode;
56 40435 jjdelcerro
import javax.swing.tree.TreePath;
57
import javax.swing.tree.TreeSelectionModel;
58 43278 fdiaz
59 43100 jjdelcerro
import org.apache.commons.lang.BooleanUtils;
60 43278 fdiaz
import org.slf4j.Logger;
61
import org.slf4j.LoggerFactory;
62
63 40435 jjdelcerro
import org.gvsig.andami.PluginServices;
64
import org.gvsig.andami.messages.NotificationManager;
65 42548 dmartinezizquierdo
import org.gvsig.app.ApplicationLocator;
66 43094 jjdelcerro
import org.gvsig.app.project.ProjectPreferences;
67 40435 jjdelcerro
import org.gvsig.app.project.documents.view.IContextMenuAction;
68
import org.gvsig.app.project.documents.view.toc.DnDJTree;
69
import org.gvsig.app.project.documents.view.toc.ITocItem;
70
import org.gvsig.app.project.documents.view.toc.ITocOrderListener;
71
import org.gvsig.app.project.documents.view.toc.TocItemBranch;
72
import org.gvsig.app.project.documents.view.toc.TocItemLeaf;
73
import org.gvsig.fmap.mapcontext.MapContext;
74
import org.gvsig.fmap.mapcontext.events.AtomicEvent;
75
import org.gvsig.fmap.mapcontext.events.listeners.AtomicEventListener;
76
import org.gvsig.fmap.mapcontext.layers.FLayer;
77
import org.gvsig.fmap.mapcontext.layers.FLayers;
78
import org.gvsig.fmap.mapcontext.layers.LayerCollectionEvent;
79
import org.gvsig.fmap.mapcontext.layers.operations.Classifiable;
80
import org.gvsig.fmap.mapcontext.layers.operations.IHasImageLegend;
81
import org.gvsig.fmap.mapcontext.layers.operations.LayerCollection;
82
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
83
import org.gvsig.fmap.mapcontext.rendering.legend.IClassifiedLegend;
84
import org.gvsig.fmap.mapcontext.rendering.legend.ILegend;
85
import org.gvsig.fmap.mapcontext.rendering.legend.ISingleSymbolLegend;
86
import org.gvsig.fmap.mapcontext.rendering.legend.events.LegendChangedEvent;
87
import org.gvsig.fmap.mapcontext.rendering.legend.events.listeners.LegendListener;
88
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
89
90
/**
91 42548 dmartinezizquierdo
 *
92 40435 jjdelcerro
 * @author fjp
93
 */
94 43278 fdiaz
public class TOC extends JComponent {
95 40435 jjdelcerro
96
    /**
97 42548 dmartinezizquierdo
     *
98 40435 jjdelcerro
     */
99
    private static final long serialVersionUID = 5689047685537359038L;
100
101 43100 jjdelcerro
    private static final Logger logger = LoggerFactory.getLogger(TOC.class);
102 40435 jjdelcerro
103 43100 jjdelcerro
    private static class ItemsExpandeds {
104 40435 jjdelcerro
105 43100 jjdelcerro
        private final Map<Object, Boolean> itemsExpanded = new HashMap<>();
106
        private boolean expandingNodes = false;
107 40435 jjdelcerro
108 43100 jjdelcerro
        public boolean isMarked(ITocItem item) {
109
            Object key = item.getLabel();
110
            boolean isItemExpanded = BooleanUtils.isTrue(this.itemsExpanded.get(key));
111
            return isItemExpanded;
112
        }
113 40435 jjdelcerro
114 43100 jjdelcerro
        public void setMark(ITocItem item, boolean expanded) {
115
            Object key = item.getLabel();
116
            this.itemsExpanded.put(key, expanded);
117
        }
118 40435 jjdelcerro
119 43100 jjdelcerro
        public void removeLayer(FLayer layer) {
120
            Object key = layer.getName();
121
            this.itemsExpanded.remove(key);
122
        }
123 40435 jjdelcerro
124 43100 jjdelcerro
        public void update(JTree tree, TreeNode node) {
125
            if (expandingNodes) {
126
                return;
127
            }
128
            try {
129
                expandingNodes = true;
130
                DefaultTreeModel treeModel = (DefaultTreeModel) tree.getModel();
131 43955 jjdelcerro
                Enumeration<TreeNode> nodes = (Enumeration<TreeNode>)(node.children());
132 43100 jjdelcerro
                while (nodes.hasMoreElements()) {
133 43161 jjdelcerro
                    DefaultMutableTreeNode curNode = (DefaultMutableTreeNode) nodes.nextElement();
134 43100 jjdelcerro
                    if (curNode.getChildCount() > 0) {
135
                        update(tree, curNode);
136
                    }
137
                    TreePath path = new TreePath(treeModel.getPathToRoot(curNode));
138
                    ITocItem item = (ITocItem) curNode.getUserObject();
139
                    if (this.isMarked(item)) {
140
                        tree.expandPath(path);
141
                    } else {
142
                        tree.collapsePath(path);
143
                    }
144
                }
145
            } finally {
146
                expandingNodes = false;
147
            }
148 40435 jjdelcerro
149 43100 jjdelcerro
        }
150
    }
151 40435 jjdelcerro
152 43100 jjdelcerro
    private MapContext mapContext;
153
154
    private final DnDJTree m_Tree;
155
    private final DefaultTreeModel m_TreeModel;
156
    private final DefaultMutableTreeNode m_Root;
157
    private final TOCRenderer m_TocRenderer;
158
    private final JScrollPane m_Scroller;
159
160
    private final ItemsExpandeds itemsExpandeds = new ItemsExpandeds();
161
162 40435 jjdelcerro
    private NodeSelectionListener nodeSelectionListener = null;
163
164
    /**
165
     * Crea un nuevo TOC.
166
     */
167
    public TOC() {
168
        this.setName("TOC");
169
        this.setLayout(new BorderLayout());
170
        this.setMinimumSize(new Dimension(100, 80));
171
        this.setPreferredSize(new Dimension(100, 80));
172
173
        m_Root = new DefaultMutableTreeNode(java.lang.Object.class);
174
        m_TreeModel = new DefaultTreeModel(m_Root);
175
        m_Tree = new DnDJTree(m_TreeModel);
176
177
        m_TocRenderer = new TOCRenderer(m_Tree.getBackground());
178
        m_Tree.setCellRenderer(m_TocRenderer);
179
        m_Tree.setRootVisible(false);
180
        m_Tree.setShowsRootHandles(true);
181 43278 fdiaz
        m_Tree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
182 40435 jjdelcerro
        nodeSelectionListener = new NodeSelectionListener(m_Tree);
183
        m_Tree.addMouseListener(nodeSelectionListener);
184
185 43100 jjdelcerro
        this.addComponentListener(new ComponentListener() {
186 40435 jjdelcerro
187 43100 jjdelcerro
            @Override
188
            public void componentResized(ComponentEvent e) {
189
                tocResized();
190
            }
191 40435 jjdelcerro
192 43100 jjdelcerro
            @Override
193
            public void componentMoved(ComponentEvent e) {
194
            }
195 40435 jjdelcerro
196 43100 jjdelcerro
            @Override
197
            public void componentShown(ComponentEvent e) {
198
            }
199
200
            @Override
201
            public void componentHidden(ComponentEvent e) {
202
            }
203
        });
204
205
        m_Tree.addOrderListener(new ITocOrderListener() {
206 43278 fdiaz
207 43100 jjdelcerro
            @Override
208
            public void orderChanged(int oldPos, int newPos, FLayers layers) {
209
                try {
210
                    layers.moveTo(oldPos, newPos);
211
                } catch (Exception e) {
212
                    logger.warn("Can't change order of layers in TOC", e);
213
                }
214
                mapContext.invalidate();
215
            }
216
217
            @Override
218
            public void parentChanged(FLayers source, FLayers targer, FLayer layer) {
219
                try {
220
                    source.move(layer, targer);
221
                } catch (Exception e) {
222
                    logger.warn("Can't move layers in TOC", e);
223
                }
224
                mapContext.invalidate();
225
            }
226
        });
227
228
        m_Tree.addTreeExpansionListener(new TreeExpansionListener() {
229 43278 fdiaz
230 43100 jjdelcerro
            @Override
231
            public void treeCollapsed(TreeExpansionEvent event) {
232
                TreePath path = event.getPath();
233
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
234
                if (node.getUserObject() instanceof ITocItem) {
235
                    itemsExpandeds.setMark((ITocItem) node.getUserObject(), false);
236
                }
237
            }
238
239
            @Override
240
            public void treeExpanded(TreeExpansionEvent event) {
241
                TreePath path = event.getPath();
242
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
243
                if (node.getUserObject() instanceof ITocItem) {
244
                    itemsExpandeds.setMark((ITocItem) node.getUserObject(), true);
245
                }
246
            }
247
        });
248
249 40435 jjdelcerro
        m_Tree.setRowHeight(0); // Para que lo determine el renderer
250
251
        m_Scroller = new JScrollPane(m_Tree);
252
        m_Scroller.setBorder(BorderFactory.createEmptyBorder());
253
254 43100 jjdelcerro
        add(m_Scroller);
255 40435 jjdelcerro
256
    }
257
258
    /**
259
     * Elimina los listeners que actuan sobre el TOC, lo ?nico que deja hacer es
260
     * desplegar la leyenda de las capas.
261
     */
262
    public void removeListeners() {
263
        m_Tree.removeMouseListener(nodeSelectionListener);
264
        m_Tree.invalidateListeners();
265
    }
266
267 43278 fdiaz
    /**
268
     * @param mc
269
     */
270 40435 jjdelcerro
    public void setMapContext(MapContext mc) {
271 43100 jjdelcerro
        this.mapContext = mc;
272
        this.mapContext.addAtomicEventListener(new AtomicEventListener() {
273 40435 jjdelcerro
274 43100 jjdelcerro
            @Override
275 40435 jjdelcerro
            public void atomicEvent(final AtomicEvent e) {
276
                if (!SwingUtilities.isEventDispatchThread()) {
277
                    SwingUtilities.invokeLater(new Runnable() {
278
279 43100 jjdelcerro
                        @Override
280 40435 jjdelcerro
                        public void run() {
281
                            atomicEvent(e);
282
                        }
283
                    });
284
                    return;
285
                }
286
287 43278 fdiaz
                if ((e.getLayerCollectionEvents().length > 0) || (e.getLegendEvents().length > 0)) {
288 43100 jjdelcerro
                    reloadLayers();
289 40435 jjdelcerro
                }
290
291
                if (e.getLayerEvents().length > 0) {
292
                    repaint();
293
                }
294
295
                if (e.getExtentEvents().length > 0) {
296
                    repaint();
297
                }
298
                LayerCollectionEvent[] events = e.getLayerCollectionEvents();
299 43100 jjdelcerro
                for (int i = 0; i < events.length; i++) {
300
                    if (events[i].getEventType() == LayerCollectionEvent.LAYER_ADDED) {
301
                        if (PluginServices.getMainFrame() != null) {
302
                            PluginServices.getMainFrame().enableControls();
303
                        }
304
                    }
305
                    // ===================================================
306
                    // Change visibility of layer before adding, according to app preferences
307
                    if (events[i].getEventType() == LayerCollectionEvent.LAYER_ADDING) {
308
                        if (haveToAddNewLayersInInvisibleMode()) {
309
                            events[i].getAffectedLayer().setVisible(false);
310
                        }
311
                    }
312 40435 jjdelcerro
                }
313
            }
314
        });
315 43278 fdiaz
316 43100 jjdelcerro
        this.mapContext.getLayers().addLegendListener(new LegendListener() {
317 40435 jjdelcerro
318 43100 jjdelcerro
            @Override
319
            public void legendChanged(LegendChangedEvent e) {
320
                reloadLayers();
321 40435 jjdelcerro
            }
322 43100 jjdelcerro
        });
323 43278 fdiaz
324 43100 jjdelcerro
        reloadLayers();
325 40435 jjdelcerro
    }
326
327 43278 fdiaz
    /**
328
     *
329
     */
330 40435 jjdelcerro
    public void refresh() {
331 43100 jjdelcerro
        reloadLayers();
332
    }
333 43278 fdiaz
334
    /**
335
     *
336
     */
337 43100 jjdelcerro
    public void reloadLayers() {
338 40435 jjdelcerro
        if (!SwingUtilities.isEventDispatchThread()) {
339
            SwingUtilities.invokeLater(new Runnable() {
340
341 43100 jjdelcerro
                @Override
342 40435 jjdelcerro
                public void run() {
343 43100 jjdelcerro
                    reloadLayers();
344 40435 jjdelcerro
                }
345
            });
346
            return;
347
        }
348
        LayerCollection theLayers = mapContext.getLayers();
349
        m_Root.removeAllChildren();
350
        m_Root.setAllowsChildren(true);
351 43100 jjdelcerro
        reloadLayers(theLayers, m_Root);
352 40435 jjdelcerro
353
        m_TreeModel.reload();
354
355 43100 jjdelcerro
        itemsExpandeds.update(m_Tree, m_Root);
356 40435 jjdelcerro
    }
357
358 43278 fdiaz
    private void reloadLayers(LayerCollection theLayers, DefaultMutableTreeNode parentNode) {
359 43100 jjdelcerro
360 40435 jjdelcerro
        int width = m_Tree.getWidth();
361
        if (width == 0) {
362
            width = 300;
363
        }
364 43100 jjdelcerro
365 40435 jjdelcerro
        // Get the tree font height
366
        Font font = m_Tree.getFont();
367
        FontMetrics metrics = this.getFontMetrics(font);
368
        Dimension sizeBranch = new Dimension(width, metrics.getHeight() + 4);
369
370
        for (int i = theLayers.getLayersCount() - 1; i >= 0; i--) {
371
            FLayer lyr = theLayers.getLayer(i);
372
            if (!lyr.isInTOC()) {
373
                continue;
374
            }
375
            TocItemBranch elTema = new TocItemBranch(lyr);
376
            elTema.setSize(sizeBranch);
377
378 43100 jjdelcerro
            DefaultMutableTreeNode nodeLayer = new DefaultMutableTreeNode(elTema);
379 40435 jjdelcerro
380 43278 fdiaz
            m_TreeModel.insertNodeInto(nodeLayer, parentNode, parentNode.getChildCount());
381 40435 jjdelcerro
            if (lyr instanceof LayerCollection) {
382
                LayerCollection group = (LayerCollection) lyr;
383 43100 jjdelcerro
                reloadLayers(group, nodeLayer);
384 40435 jjdelcerro
385 43100 jjdelcerro
            } else if (haveToShowLeyendOfLayer(lyr)) {
386
                this.addLegend(nodeLayer, lyr);
387
            }
388
        }
389
    }
390 40435 jjdelcerro
391 43100 jjdelcerro
    private void addLegend(final DefaultMutableTreeNode nodeLayer, FLayer lyr) {
392
        int width = m_Tree.getWidth();
393
        if (width == 0) {
394
            width = 300;
395
        }
396
        Dimension sizeLeaf = new Dimension(width, 15);
397 40435 jjdelcerro
398 43100 jjdelcerro
        if (lyr instanceof Classifiable) {
399
            Classifiable classifiable = (Classifiable) lyr;
400
            ILegend legendInfo = classifiable.getLegend();
401
402
            try {
403
                if (legendInfo instanceof IClassifiedLegend) {
404 43278 fdiaz
                    IClassifiedLegend cl = (IClassifiedLegend) legendInfo;
405 43100 jjdelcerro
                    String[] descriptions = cl.getDescriptions();
406
                    ISymbol[] symbols = cl.getSymbols();
407
408
                    for (int j = 0; j < descriptions.length; j++) {
409
                        TocItemLeaf itemLeaf;
410 43278 fdiaz
                        itemLeaf = new TocItemLeaf(symbols[j], descriptions[j], classifiable.getShapeType());
411 43100 jjdelcerro
                        itemLeaf.setSize(sizeLeaf);
412 40435 jjdelcerro
413 43278 fdiaz
                        DefaultMutableTreeNode nodeValue = new DefaultMutableTreeNode(itemLeaf);
414
                        m_TreeModel.insertNodeInto(nodeValue, nodeLayer, nodeLayer.getChildCount());
415 40435 jjdelcerro
416 43100 jjdelcerro
                    }
417
                }
418 40435 jjdelcerro
419 43278 fdiaz
                if (legendInfo instanceof ISingleSymbolLegend && (legendInfo.getDefaultSymbol() != null)) {
420 43100 jjdelcerro
                    TocItemLeaf itemLeaf;
421 43278 fdiaz
                    itemLeaf =
422
                        new TocItemLeaf(legendInfo.getDefaultSymbol(), legendInfo.getDefaultSymbol().getDescription(),
423
                            classifiable.getShapeType());
424 43100 jjdelcerro
                    itemLeaf.setSize(sizeLeaf);
425 40435 jjdelcerro
426 43278 fdiaz
                    DefaultMutableTreeNode nodeValue = new DefaultMutableTreeNode(itemLeaf);
427
                    m_TreeModel.insertNodeInto(nodeValue, nodeLayer, nodeLayer.getChildCount());
428 43100 jjdelcerro
                }
429 42548 dmartinezizquierdo
430 43100 jjdelcerro
                if (legendInfo instanceof IHasImageLegend) {
431
                    final IHasImageLegend imageLegend = (IHasImageLegend) legendInfo;
432 43278 fdiaz
                    // Las imagenes de la leyenda que vienen de servicios
433
                    // remotos pueden
434
                    // ser lentas de pintar y relentizan todo gvSIG, asi que
435
                    // mejor si
436 43100 jjdelcerro
                    // podemos hacerlo en segundo plano.
437
                    Thread thread = new Thread(new Runnable() {
438 42548 dmartinezizquierdo
439 43100 jjdelcerro
                        @Override
440
                        public void run() {
441
                            final Image image = imageLegend.getImageLegend();
442 43278 fdiaz
                            // Una vez obtenida la imagen, la actualizacion del
443
                            // ToC
444
                            // la hacemos en el thread de Swing para evitar
445
                            // problemas.
446 43100 jjdelcerro
                            SwingUtilities.invokeLater(new Runnable() {
447 42548 dmartinezizquierdo
448 43100 jjdelcerro
                                @Override
449
                                public void run() {
450
                                    int w = 0;
451
                                    int h = 0;
452 42548 dmartinezizquierdo
453 43100 jjdelcerro
                                    if (image != null) {
454
                                        w = image.getWidth(null);
455
                                        h = image.getHeight(null);
456
                                    }
457 40435 jjdelcerro
458 43100 jjdelcerro
                                    if (image != null && w > 0 && h > 0) {
459
                                        TocItemLeaf itemLeaf = new TocItemLeaf();
460
                                        itemLeaf.setImageLegend(image, "", new Dimension(w, h));
461
                                        DefaultMutableTreeNode nodeValue = new DefaultMutableTreeNode(itemLeaf);
462 43278 fdiaz
                                        m_TreeModel.insertNodeInto(nodeValue, nodeLayer, nodeLayer.getChildCount());
463 43100 jjdelcerro
                                    }
464 43278 fdiaz
                                    // Aqui habria que forzar a refrescar el
465
                                    // nodo nodeLayer
466 43100 jjdelcerro
                                }
467
                            });
468 40435 jjdelcerro
                        }
469 43100 jjdelcerro
                    }, "ToCImageLegendUpdate");
470
                    thread.start();
471 42548 dmartinezizquierdo
                }
472 43100 jjdelcerro
            } catch (Throwable e) {
473 43278 fdiaz
                logger.warn(MessageFormat.format("Can't add leyend of layer {0} to the TOC.", lyr), e);
474 43100 jjdelcerro
            }
475 40435 jjdelcerro
        }
476
477
    }
478
479 43100 jjdelcerro
    private void tocResized() {
480 40435 jjdelcerro
        DefaultMutableTreeNode n;
481 43161 jjdelcerro
        Enumeration<TreeNode> enumeration = m_Root.children();
482 40435 jjdelcerro
483
        while (enumeration.hasMoreElements()) {
484
            n = (DefaultMutableTreeNode) enumeration.nextElement();
485
486
            if (n.getUserObject() instanceof TocItemBranch) {
487
                ITocItem item = (ITocItem) n.getUserObject();
488
                Dimension szAnt = item.getSize();
489
                item.setSize(new Dimension(this.getWidth() - 40, szAnt.height));
490
            }
491
492
        }
493
    }
494
495
    /**
496
     * Obtiene el JScrollPane que contiene el TOC
497 42548 dmartinezizquierdo
     *
498 40435 jjdelcerro
     * @return JScrollPane que contiene el TOC
499
     */
500
    public JScrollPane getJScrollPane() {
501
        return this.m_Scroller;
502
    }
503
504 43278 fdiaz
    /**
505
     * @return
506
     */
507 40435 jjdelcerro
    public DnDJTree getTree() {
508
        return m_Tree;
509
    }
510
511
    /**
512
     * Clase Listener que reacciona al pulsar sobre el checkbox de un nodo y
513
     * crea un popupmenu al pulsar el bot?n derecho.
514
     */
515 43278 fdiaz
    class NodeSelectionListener extends MouseAdapter { // implements
516 40435 jjdelcerro
517 43278 fdiaz
                                                       // ActionListener {
518
519 40435 jjdelcerro
        JTree tree;
520
        JDialog dlg;
521
        JColorChooser colorChooser;
522
        FPopupMenu popmenu = null;
523
        DefaultMutableTreeNode node;
524
525
        /**
526
         * Crea un nuevo NodeSelectionListener.
527 42548 dmartinezizquierdo
         *
528 43278 fdiaz
         * @param tree
529
         *            !
530 40435 jjdelcerro
         */
531
        NodeSelectionListener(JTree tree) {
532
            this.tree = tree;
533
        }
534
535 43100 jjdelcerro
        @Override
536 40435 jjdelcerro
        public void mouseClicked(MouseEvent e) {
537
            int x = e.getX();
538
            int y = e.getY();
539
            int row = tree.getRowForLocation(x, y);
540
            TreePath path = tree.getPathForRow(row);
541 43278 fdiaz
            final FLayers layers = mapContext.getLayers();
542
            List<FLayer> plainListLayers = toPlainList(layers);
543
            plainListLayers.remove(plainListLayers.size() - 1);
544
            int countDeepActiveLayers = countDeepActiveLayers(plainListLayers);
545 40435 jjdelcerro
546
            if (path != null) {
547
                if (e.getClickCount() == 1) {
548
                    // this fixes a bug when double-clicking. JTree by default
549
                    // expands the tree when double-clicking, so we capture a
550
                    // different node in the second click than in the first
551
                    node = (DefaultMutableTreeNode) path.getLastPathComponent();
552
                }
553
554 43278 fdiaz
                if (node != null && node.getUserObject() instanceof TocItemBranch) {
555 40435 jjdelcerro
                    // double click with left button ON A BRANCH/NODE (layer)
556 43278 fdiaz
                    if (e.getClickCount() >= 2 && e.getButton() == MouseEvent.BUTTON1) {
557 40435 jjdelcerro
                        e.consume();
558
                        PluginServices.getMDIManager().setWaitCursor();
559
                        try {
560 43100 jjdelcerro
                            TocItemBranch leaf = (TocItemBranch) node.getUserObject();
561
                            IContextMenuAction action = leaf.getDoubleClickAction();
562 40435 jjdelcerro
                            if (action != null) {
563
                                /*
564
                                 * if there is an action associated with the
565
                                 * double-clicked element it will be fired for
566
                                 * it and FOR ALL OTHER COMPATIBLES THAT HAVE
567
                                 * BEEN ACTIVATED.
568
                                 */
569 43100 jjdelcerro
                                ArrayList<FLayer> targetLayers = new ArrayList<>();
570 40435 jjdelcerro
571 43100 jjdelcerro
                                TocItemBranch owner = (TocItemBranch) node.getUserObject();
572 40435 jjdelcerro
573
                                FLayer masterLayer = owner.getLayer();
574
                                targetLayers.add(masterLayer);
575 43100 jjdelcerro
                                FLayer[] actives = mapContext.getLayers().getActives();
576 40435 jjdelcerro
                                for (int i = 0; i < actives.length; i++) {
577 43278 fdiaz
                                    if (actives[i].getClass().equals(masterLayer.getClass())) {
578 40435 jjdelcerro
                                        if (actives[i] instanceof FLyrVect) {
579 43100 jjdelcerro
                                            FLyrVect vectorLayer = (FLyrVect) actives[i];
580
                                            FLyrVect vectorMaster = (FLyrVect) masterLayer;
581 43278 fdiaz
                                            if (vectorLayer.getShapeType() == vectorMaster.getShapeType()) {
582 40435 jjdelcerro
                                                targetLayers.add(vectorLayer);
583 43339 fdiaz
                                                vectorLayer.setActive(true);
584 40435 jjdelcerro
                                            } else {
585
                                                vectorLayer.setActive(false);
586
                                            }
587
                                        }
588
                                        // TODO for the rest of layer types
589
                                        // (i.e. FLyrRaster)
590
                                    } else {
591
                                        actives[i].setActive(false);
592
                                    }
593
                                }
594 42548 dmartinezizquierdo
595 41128 jldominguez
                                // Do nothing if there is a non-available layer
596 43100 jjdelcerro
                                for (int k = 0; k < targetLayers.size(); k++) {
597 41128 jldominguez
                                    if (!targetLayers.get(k).isAvailable()) {
598
                                        return;
599
                                    }
600 43339 fdiaz
                                    targetLayers.get(k).setActive(true);
601 41128 jldominguez
                                }
602 42548 dmartinezizquierdo
603 43100 jjdelcerro
                                action.execute(leaf, targetLayers.toArray(new FLayer[0]));
604 40435 jjdelcerro
                            }
605
                        } catch (Exception ex) {
606
                            NotificationManager.addError(ex);
607
                        } finally {
608
                            PluginServices.getMDIManager().restoreCursor();
609
                        }
610
                        return;
611
                    }
612
613
                    TocItemBranch elTema = (TocItemBranch) node.getUserObject();
614
                    FLayer lyr = elTema.getLayer();
615 43375 jjdelcerro
                    if( lyr.isAvailable() ) {
616
                        lyr.getMapContext().beginAtomicEvent();
617
                    }
618 40435 jjdelcerro
619 43278 fdiaz
                    // Si est? pulsado SHIFT
620 40435 jjdelcerro
                    if (((e.getModifiers() & InputEvent.SHIFT_MASK) != 0)
621 43278 fdiaz
                        && (e.getButton() == MouseEvent.BUTTON1 || e.getButton() == MouseEvent.BUTTON3)) {
622
                        if (countDeepActiveLayers > 0) {
623
                            selectInterval(plainListLayers, lyr);
624 40435 jjdelcerro
                        } else {
625 43278 fdiaz
                            lyr.setActive(!lyr.isActive());
626 40435 jjdelcerro
                        }
627
628 43278 fdiaz
                    } else { // Si no est? pulsado SHIFT
629
                        // Si no est? pulsado CTRL
630
                        if (!((e.getModifiers() & InputEvent.CTRL_MASK) != 0)) {
631
                            if (e.getButton() == MouseEvent.BUTTON1) {
632
                                if (countDeepActiveLayers > 1) {
633
                                    layers.setAllActives(false);
634
                                    lyr.setActive(true);
635
                                } else {
636
                                    boolean active = lyr.isActive();
637
                                    layers.setAllActives(false);
638
                                    lyr.setActive(!active);
639
                                }
640
                            }
641
                            if (e.getButton() == MouseEvent.BUTTON3) {
642
                                if (lyr.isActive()) {
643
                                    // No modificamos la selecci?n porque lo que
644
                                    // se va a hacer m?s abajo es abrir el men?
645
                                    // contextual
646
                                } else {
647
                                    boolean active = lyr.isActive();
648
                                    layers.setAllActives(false);
649
                                    lyr.setActive(!active);
650
                                }
651
                            }
652
                        } else { // Si s? est? pulsado CTRL
653
                            if (e.getButton() == MouseEvent.BUTTON1) {
654
                                // BUTTON1 cambiamos la activaci?n de la lyr
655
                                // seleccionada
656
                                lyr.setActive(!lyr.isActive());
657
                            }
658
                            if (e.getButton() == MouseEvent.BUTTON3) {
659
                                if (lyr.isActive()) {
660
                                    // No modificamos la selecci?n porque lo que
661
                                    // se va a hacer m?s abajo es abrir el men?
662
                                    // contextual
663
                                } else {
664
                                    lyr.setActive(true);
665
                                }
666
                            }
667 40435 jjdelcerro
                        }
668
                    }
669
670 43278 fdiaz
                    Point layerNodeLocation = tree.getUI().getPathBounds(tree, path).getLocation();
671 40435 jjdelcerro
672
                    // Rect?ngulo que representa el checkbox
673 43278 fdiaz
                    Rectangle checkBoxBounds = m_TocRenderer.getCheckBoxBounds();
674
                    checkBoxBounds.translate((int) layerNodeLocation.getX(), (int) layerNodeLocation.getY());
675 40435 jjdelcerro
676
                    if (checkBoxBounds.contains(e.getPoint())) {
677
                        updateVisible(lyr);
678 43100 jjdelcerro
                        // si node no tiene leyenda llamar a addLegend
679 40435 jjdelcerro
                    }
680
681
                    if (e.getButton() == MouseEvent.BUTTON3) {
682
                        popmenu = new FPopupMenu(mapContext, node);
683
                        tree.add(popmenu);
684
                        popmenu.show(e.getComponent(), e.getX(), e.getY());
685
                    }
686 43375 jjdelcerro
                    if( lyr.isAvailable() ) {
687
                        lyr.getMapContext().endAtomicEvent();
688
                    }
689 40435 jjdelcerro
                }
690
691
                if (node != null && node.getUserObject() instanceof TocItemLeaf) {
692 43278 fdiaz
                    TocItemBranch owner = (TocItemBranch) ((DefaultMutableTreeNode) node.getParent()).getUserObject();
693 42822 dmartinezizquierdo
694
                    FLayer masterLayer = owner.getLayer();
695
696 40435 jjdelcerro
                    // double click with left button ON A LEAF (ISymbol)
697 43278 fdiaz
                    if (e.getClickCount() >= 2 && e.getButton() == MouseEvent.BUTTON1) {
698 40435 jjdelcerro
                        e.consume();
699
700
                        PluginServices.getMDIManager().setWaitCursor();
701
                        try {
702 43100 jjdelcerro
                            TocItemLeaf leaf = (TocItemLeaf) node.getUserObject();
703
                            IContextMenuAction action = leaf.getDoubleClickAction();
704 40435 jjdelcerro
                            if (action != null) {
705
                                /*
706
                                 * if there is an action associated with the
707
                                 * double-clicked element it will be fired for
708
                                 * it and FOR ALL OTHER COMPATIBLES THAT HAVE
709
                                 * BEEN ACTIVATED.
710
                                 */
711 42822 dmartinezizquierdo
                                /*
712 43278 fdiaz
                                 * #3035: Symbology is applied to active layers
713
                                 * too
714
                                 * Now it will be done only on the
715
                                 * double-clicked one
716 42822 dmartinezizquierdo
                                 */
717 43278 fdiaz
                                action.execute(leaf, new FLayer[] { masterLayer });
718 40435 jjdelcerro
                            }
719
                        } catch (Exception ex) {
720 43100 jjdelcerro
                            logger.warn("Problems executing action in the ToC.", ex);
721 40435 jjdelcerro
                        } finally {
722
                            PluginServices.getMDIManager().restoreCursor();
723
                        }
724
                        return;
725
                    }
726
                }
727
728
                ((DefaultTreeModel) tree.getModel()).nodeChanged(node);
729
730
                if (row == 0) {
731
                    tree.revalidate();
732
                    tree.repaint();
733
                }
734
735 43278 fdiaz
                // FIXME Is it really necessary?
736 40435 jjdelcerro
                if (PluginServices.getMainFrame() != null) {
737
                    PluginServices.getMainFrame().enableControls();
738
                }
739
            } else {
740
                if (e.getButton() == MouseEvent.BUTTON3) {
741
                    popmenu = new FPopupMenu(mapContext, null);
742
                    tree.add(popmenu);
743
                    popmenu.show(e.getComponent(), e.getX(), e.getY());
744
                }
745
746
            }
747
        }
748
749 43278 fdiaz
        private void selectInterval(List<FLayer> layers, FLayer lyr) {
750
            // FLayer[] activeLayers = layers.getActives();
751
            int firstActive = Integer.MAX_VALUE;
752
            int lastActive = -1;
753
            int myLayer = -1;
754
755
            for (int j = 0; j < layers.size(); j++) {
756
                FLayer layerAux = layers.get(j);
757
758
                if (layerAux.isActive()) {
759
                    if (firstActive > j) {
760
                        firstActive = j;
761
                    }
762
                    if (lastActive < j) {
763
                        lastActive = j;
764
                    }
765
                    if (layerAux.equals(lyr)) {
766
                        myLayer = j;
767
                    }
768
                }
769
                if (myLayer < 0 && layerAux.equals(lyr)) {
770
                    myLayer = j;
771
                }
772
            }
773
774
            if (firstActive < Integer.MAX_VALUE && myLayer >= 0) {
775
                for (int pasada = 0; pasada < 2; pasada++) {
776
                    if (myLayer < firstActive) {
777
                        for (int j = 0; j < myLayer; j++) {
778
                            FLayer layerAux = layers.get(j);
779
                            if (pasada == 0) {
780
                                if (layerAux instanceof FLayers) {
781
                                    layerAux.setActive(false);
782
                                }
783
                            } else {
784
                                if (!(layerAux instanceof FLayers)) {
785
                                    layerAux.setActive(false);
786
                                }
787 40435 jjdelcerro
                            }
788
                        }
789 43278 fdiaz
                        for (int j = myLayer; j <= lastActive; j++) {
790
                            FLayer layerAux = layers.get(j);
791
                            if (pasada == 0) {
792
                                if (layerAux instanceof FLayers) {
793
                                    layerAux.setActive(true);
794
                                }
795
                            } else {
796
                                if (!(layerAux instanceof FLayers)) {
797
                                    layerAux.setActive(true);
798
                                }
799 40435 jjdelcerro
                            }
800
                        }
801 43278 fdiaz
                        for (int j = lastActive + 1; j < layers.size(); j++) {
802
                            FLayer layerAux = layers.get(j);
803
                            if (pasada == 0) {
804
                                if (layerAux instanceof FLayers) {
805
                                    layerAux.setActive(false);
806
                                }
807
                            } else {
808
                                if (!(layerAux instanceof FLayers)) {
809
                                    layerAux.setActive(false);
810
                                }
811
                            }
812
                        }
813
                    } else {
814
                        if (myLayer > lastActive) {
815
                            for (int j = 0; j < firstActive; j++) {
816
                                FLayer layerAux = layers.get(j);
817
                                if (pasada == 0) {
818
                                    if (layerAux instanceof FLayers) {
819
                                        layerAux.setActive(false);
820
                                    }
821
                                } else {
822
                                    if (!(layerAux instanceof FLayers)) {
823
                                        layerAux.setActive(false);
824
                                    }
825
                                }
826
                            }
827
                            for (int j = firstActive; j <= myLayer; j++) {
828
                                FLayer layerAux = layers.get(j);
829
                                if (pasada == 0) {
830
                                    if (layerAux instanceof FLayers) {
831
                                        layerAux.setActive(true);
832
                                    }
833
                                } else {
834
                                    if (!(layerAux instanceof FLayers)) {
835
                                        layerAux.setActive(true);
836
                                    }
837
                                }
838
                            }
839
                            for (int j = myLayer + 1; j < layers.size(); j++) {
840
                                FLayer layerAux = layers.get(j);
841
                                if (pasada == 0) {
842
                                    if (layerAux instanceof FLayers) {
843
                                        layerAux.setActive(false);
844
                                    }
845
                                } else {
846
                                    if (!(layerAux instanceof FLayers)) {
847
                                        layerAux.setActive(false);
848
                                    }
849
                                }
850
                            }
851
                        } else { // Si myLayer est? entre firstActive y lastActive
852
                                 // seleccionamos desde myLayer hasta lastLayer
853
                            for (int j = 0; j < myLayer; j++) {
854
                                FLayer layerAux = layers.get(j);
855
                                if (pasada == 0) {
856
                                    if (layerAux instanceof FLayers) {
857
                                        layerAux.setActive(false);
858
                                    }
859
                                } else {
860
                                    if (!(layerAux instanceof FLayers)) {
861
                                        layerAux.setActive(false);
862
                                    }
863
                                }
864
                            }
865
                            for (int j = myLayer; j <= lastActive; j++) {
866
                                FLayer layerAux = layers.get(j);
867
                                if (pasada == 0) {
868
                                    if (layerAux instanceof FLayers) {
869
                                        layerAux.setActive(true);
870
                                    }
871
                                } else {
872
                                    if (!(layerAux instanceof FLayers)) {
873
                                        layerAux.setActive(true);
874
                                    }
875
                                }
876
                            }
877
                            for (int j = lastActive + 1; j < layers.size(); j++) {
878
                                FLayer layerAux = layers.get(j);
879
                                if (pasada == 0) {
880
                                    if (layerAux instanceof FLayers) {
881
                                        layerAux.setActive(false);
882
                                    }
883
                                } else {
884
                                    if (!(layerAux instanceof FLayers)) {
885
                                        layerAux.setActive(false);
886
                                    }
887
                                }
888
                            }
889
                        }
890 40435 jjdelcerro
                    }
891 43100 jjdelcerro
                }
892 40435 jjdelcerro
            }
893 43278 fdiaz
        }
894 40435 jjdelcerro
895 43278 fdiaz
        private List<FLayer> toPlainList(FLayer layer) {
896
            return toPlainList(layer, new ArrayList<FLayer>());
897 40435 jjdelcerro
        }
898
899 43278 fdiaz
        private List<FLayer> toPlainList(FLayer layer, List<FLayer> result) {
900
            if (layer instanceof FLayers) {
901
                FLayers layerGroup = (FLayers) layer;
902
                for (int i = 0; i < layerGroup.getLayersCount(); i++) {
903
                    toPlainList(layerGroup.getLayer(i), result);
904
                }
905
            }
906
            result.add(layer);
907
            return result;
908 40435 jjdelcerro
        }
909
910 43278 fdiaz
        private int countDeepActiveLayers(List<FLayer> layers) {
911
            int count = 0;
912
            for (FLayer fLayer : layers) {
913
                if (fLayer.isActive()) {
914
                    count++;
915 40435 jjdelcerro
                }
916
            }
917 43278 fdiaz
            return count;
918 40435 jjdelcerro
        }
919
920
        /**
921
         * Actualiza la visibilidad de la capas.
922 42548 dmartinezizquierdo
         *
923 43278 fdiaz
         * @param lyr
924
         *            Capa sobre la que se est? clickando.
925 40435 jjdelcerro
         */
926
        private void updateVisible(FLayer lyr) {
927
            if (lyr.isAvailable()) {
928
                lyr.setVisible(!lyr.visibleRequired());
929
                updateVisibleChild(lyr);
930
                updateVisibleParent(lyr);
931 43278 fdiaz
                if (node != null && !(lyr instanceof FLayers)) {
932
                    if (haveToShowLeyendOfLayer(lyr)) {
933
                        if (node.getChildCount() == 0) {
934 43100 jjdelcerro
                            addLegend(node, lyr);
935
                        }
936
                    } else {
937
                        this.node.removeAllChildren();
938
                        m_TreeModel.reload(node);
939
                    }
940
                }
941 40435 jjdelcerro
            }
942
        }
943
944
        /**
945
         * Actualiza de forma recursiva la visibilidad de los hijos de la capa
946
         * que se pasa como par?metro.
947 42548 dmartinezizquierdo
         *
948 43278 fdiaz
         * @param lyr
949
         *            Capa a actualizar.
950 40435 jjdelcerro
         */
951
        private void updateVisibleChild(FLayer lyr) {
952
            if (lyr instanceof FLayers) { // Es la raiz de una rama o
953 43100 jjdelcerro
                // cualquier nodo intermedio.
954 40435 jjdelcerro
955
                FLayers layergroup = (FLayers) lyr;
956
957
                for (int i = 0; i < layergroup.getLayersCount(); i++) {
958
                    layergroup.getLayer(i).setVisible(lyr.visibleRequired());
959
                    updateVisibleChild(layergroup.getLayer(i));
960
                }
961
            }
962
        }
963
964
        /**
965
         * Actualiza de forma recursiva la visibilidad del padre de la capa que
966
         * se pasa como par?metro.
967 42548 dmartinezizquierdo
         *
968 43278 fdiaz
         * @param lyr
969
         *            Capa a actualizar.
970 40435 jjdelcerro
         */
971
        private void updateVisibleParent(FLayer lyr) {
972
            FLayers parent = lyr.getParentLayer();
973
974
            if (parent != null) {
975
                boolean parentVisible = false;
976
977
                for (int i = 0; i < parent.getLayersCount(); i++) {
978
                    if (parent.getLayer(i).visibleRequired()) {
979
                        parentVisible = true;
980
                    }
981
                }
982
983
                parent.setVisible(parentVisible);
984
                updateVisibleParent(parent);
985
            }
986
        }
987
988 43100 jjdelcerro
        @Override
989 40435 jjdelcerro
        public void mouseReleased(MouseEvent arg0) {
990
            super.mouseReleased(arg0);
991
        }
992
993 43100 jjdelcerro
        @Override
994 40435 jjdelcerro
        public void mouseEntered(MouseEvent arg0) {
995
            super.mouseEntered(arg0);
996
        }
997
    }
998 42548 dmartinezizquierdo
999 43100 jjdelcerro
    private boolean haveToAddNewLayersInInvisibleMode() {
1000
        ProjectPreferences projectPreferences = ApplicationLocator.getProjectManager().getProjectPreferences();
1001
1002 43094 jjdelcerro
        return projectPreferences.getAddNewLayersInInvisibleMode();
1003 40435 jjdelcerro
    }
1004
1005 43100 jjdelcerro
    private boolean haveToShowLeyendOfLayer(FLayer layer) {
1006
        ProjectPreferences projectPreferences = ApplicationLocator.getProjectManager().getProjectPreferences();
1007
        return !(!layer.isVisible() && projectPreferences.getHideLegendInToCOfNonVisibleLayers());
1008
1009
    }
1010
1011 40435 jjdelcerro
}