Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.library / org.gvsig.symbology / org.gvsig.symbology.swing / org.gvsig.symbology.swing.api / src / main / java / org / gvsig / app / gui / styling / SymbolEditor.java @ 47476

History | View | Annotate | Download (20.3 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.app.gui.styling;
25

    
26
import java.awt.BorderLayout;
27
import java.awt.Dimension;
28
import java.awt.FlowLayout;
29
import java.awt.event.ActionEvent;
30
import java.awt.event.ActionListener;
31
import java.lang.reflect.Constructor;
32
import java.util.Comparator;
33
import java.util.List;
34
import java.util.TreeSet;
35
import javax.swing.BorderFactory;
36
import javax.swing.JComboBox;
37
import javax.swing.JLabel;
38
import javax.swing.JPanel;
39
import javax.swing.JTabbedPane;
40
import org.apache.commons.lang3.mutable.MutableObject;
41
import org.gvsig.andami.PluginServices;
42
import org.gvsig.andami.messages.NotificationManager;
43
import org.gvsig.andami.ui.mdiManager.IWindow;
44
import org.gvsig.andami.ui.mdiManager.WindowInfo;
45
import org.gvsig.app.gui.JComboBoxUnits;
46
import org.gvsig.fmap.dal.feature.Feature;
47
import org.gvsig.fmap.dal.feature.FeatureStore;
48
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
49
import org.gvsig.fmap.geom.GeometryLocator;
50
import org.gvsig.fmap.geom.GeometryManager;
51
import org.gvsig.fmap.geom.type.GeometryType;
52
import org.gvsig.fmap.mapcontext.MapContextLocator;
53
import org.gvsig.fmap.mapcontext.MapContextManager;
54
import org.gvsig.fmap.mapcontext.rendering.symbols.CartographicSupport;
55
import org.gvsig.fmap.mapcontext.rendering.symbols.IMultiLayerSymbol;
56
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
57
import org.gvsig.gui.beans.AcceptCancelPanel;
58
import org.gvsig.i18n.Messages;
59
import org.gvsig.symbology.swing.SymbologySwingLocator;
60
import org.gvsig.symbology.swing.SymbologySwingManager;
61
import org.slf4j.Logger;
62
import org.slf4j.LoggerFactory;
63

    
64
/**
65
 * Creates the panel that is used to control the properties of a symbol in order
66
 * to modify or check them and to create a new one.
67
 *
68
 * @author jaume dominguez faus - jaume.dominguez@iver.es
69
 *
70
 */
71
public class SymbolEditor extends JPanel implements IWindow {
72

    
73
    private static final long serialVersionUID = 9209260593958625497L;
74

    
75
    private static final GeometryManager GEOMETRY_MANAGER
76
            = GeometryLocator.getGeometryManager();
77

    
78
    private static final Logger LOG
79
            = LoggerFactory.getLogger(SymbolEditor.class);
80

    
81
    private WindowInfo wi;
82
    private JPanel pnlWest = null;
83
    private JPanel pnlCenter = null;
84
    private JPanel pnlPreview = null;
85
    private JPanel pnlLayers = null;
86
    private AcceptCancelPanel okCancelPanel;
87
    private ISymbol symbol;
88
    private SymbolPreviewer symbolPreview = null;
89
    private JPanel pnlTypeAndUnits = null;
90
    private JComboBox cmbType;
91
    private JComboBoxUnits cmbUnits;
92
    private JTabbedPane tabbedPane = null;
93
    private GeometryType shapeType;
94
    private ActionListener cmbTypeActionListener;
95

    
96
    private AbstractTypeSymbolEditor[] tabs;
97
    private SymbolLayerManager layerManager;
98
    private boolean replacing = false;
99
    private JComboBoxUnitsReferenceSystem cmbUnitsReferenceSystem;
100

    
101
    private ISymbol oldSymbol;
102

    
103
    private MapContextManager mapContextManager = MapContextLocator
104
            .getMapContextManager();
105
    private transient FeatureStore featureStore;
106
    private transient MutableObject<Feature> sampleFeature;
107

    
108
    public SymbolEditor(ISymbol symbol, GeometryType geometryType) {
109
        super();
110
        initialize(symbol, geometryType);
111
    }
112

    
113
    public SymbolEditor(ISymbol symbol, int shapeType) {
114
        super();
115
        try {
116
            GeometryType geometryType = GEOMETRY_MANAGER.getGeometryType(shapeType, SUBTYPES.GEOM2D);
117
            initialize(symbol, geometryType);
118
        } catch (Exception e1) {
119
            LOG.error("Impossible to get the geometry type", e1);
120
        }
121
    }
122

    
123
    /**
124
     * Constructor method
125
     *
126
     * @param symbol ISymbol
127
     * @param shapeType int
128
     */
129
    private void initialize(ISymbol symbol, GeometryType shapeType) {
130
        if (!(symbol instanceof IMultiLayerSymbol)) {
131
            // this is a simple symbol (or null one); it will be
132
            // converted to a multilayer one to accept layer addition
133
            IMultiLayerSymbol nSym
134
                    = mapContextManager.getSymbolManager()
135
                            .createMultiLayerSymbol(shapeType.getType());
136
            nSym.addLayer(symbol);
137

    
138
            if (symbol instanceof CartographicSupport) {
139
                CartographicSupport cs = (CartographicSupport) symbol;
140
                CartographicSupport nCs = (CartographicSupport) nSym;
141
                nCs.setReferenceSystem(cs.getReferenceSystem());
142
                nCs.setUnit(cs.getUnit());
143
            }
144

    
145
            this.symbol = nSym;
146
        } else {
147
            this.symbol = symbol;
148
        }
149

    
150
        // apply units and reference system to comboboxes
151
        if (this.symbol instanceof CartographicSupport) {
152
            CartographicSupport cs = (CartographicSupport) this.symbol;
153
            getCmbUnits().setSelectedUnitIndex(cs.getUnit());
154
            getCmbUnitsReferenceSystem().
155
                    setSelectedIndex(cs.getReferenceSystem());
156

    
157
        }
158

    
159
        try {
160
            this.oldSymbol = (ISymbol) this.symbol.clone();
161
        } catch (CloneNotSupportedException e) {
162
            NotificationManager.addWarning("Symbol layer", e);
163
        }
164
        this.shapeType = shapeType;
165
        initialize();
166
    }
167

    
168
    /**
169
     * This method initializes this
170
     *
171
     */
172
    private void initialize() {
173
        SymbologySwingManager symbologySwingManager = SymbologySwingLocator.getSwingManager();
174
        cmbTypeActionListener = new ActionListener() {
175
            int prevIndex = -2;
176

    
177
            @Override
178
            public void actionPerformed(ActionEvent e) {
179
                int index = getCmbType().getSelectedIndex();
180
                if (prevIndex != index) {
181
                    // needs to refresh
182
                    prevIndex = index;
183

    
184
                    AbstractTypeSymbolEditor options = (AbstractTypeSymbolEditor) getCmbType()
185
                            .getSelectedItem();
186

    
187
                    if (layerManager != null) {
188
                        ISymbol l = layerManager.getSelectedLayer();
189

    
190
                        // if the symbol is not null and is it managed by the "options" class
191
                        // refresh the controls
192
                        if (l != null && options.canManageSymbol(l)) {
193
                            if (l instanceof CartographicSupport) {
194
                                CartographicSupport cs = (CartographicSupport) l;
195
                                getCmbUnits().setSelectedUnitIndex(cs.getUnit());
196
                                getCmbUnitsReferenceSystem().setSelectedIndex(cs.getReferenceSystem());
197
                            }
198
                            options.refreshControls(l);
199
                        }
200

    
201
                        replaceOptions(options);
202
                        options.refreshControls(l);
203
                    } else {
204
                        replaceOptions(options);
205
                    }
206
                }
207
            }
208
        };
209

    
210
        Comparator tabComparator = (Comparator) (Object o1, Object o2) -> {
211
            AbstractTypeSymbolEditor pnl1 = (AbstractTypeSymbolEditor) o1;
212
            AbstractTypeSymbolEditor pnl2 = (AbstractTypeSymbolEditor) o2;
213
            int result = pnl1.getName().compareTo(pnl2.getName());
214
            return result;
215
        };
216

    
217
        TreeSet set = new TreeSet(tabComparator);
218
        List editors = symbologySwingManager.getSymbolEditorClassesByGeometryType(shapeType);
219
        Class[] constrLocator = new Class[]{SymbolEditor.class};
220
        Object[] constrInitargs = new Object[]{this};
221
        for (int i = 0; i < editors.size(); i++) {
222
            Class editorClass = (Class) editors.get(i);
223
            try {
224
                Constructor c = editorClass.getConstructor(constrLocator);
225
                AbstractTypeSymbolEditor instance = (AbstractTypeSymbolEditor) c.newInstance(constrInitargs);
226
                instance.setFeatureStore(featureStore);
227
                set.add(instance);
228
            } catch (Exception e) {
229
                NotificationManager.addError(Messages.getText("failed_installing_symbol_editor") + " "
230
                        + editorClass.getName(), e);
231
            }
232
        }
233
        tabs = (AbstractTypeSymbolEditor[]) set
234
                .toArray(new AbstractTypeSymbolEditor[0]);
235

    
236
        this.setLayout(new BorderLayout());
237
        this.add(getPnlWest(), BorderLayout.WEST);
238
        this.add(getPnlCenter(), BorderLayout.CENTER);
239
        this.add(getOkCancelPanel(), BorderLayout.SOUTH);
240

    
241
        cmbTypeActionListener.actionPerformed(null);
242
        refresh();
243
    }
244

    
245
    /**
246
     * Returns an array of tabs. The value of this array will depend on the
247
     * symbol selected. For example, if the symbol is composed by lines this
248
     * method will return tha tabs that allow the user to modify a simple line
249
     * symbol(in this case simple line and arrow decorator tabs)
250
     *
251
     * @param sym
252
     * @return tabs[] AbstractTypeSymbolEditor[]
253
     */
254
    private AbstractTypeSymbolEditor getOptionsForSymbol(ISymbol sym) {
255
        if (sym == null) {
256
            return tabs[0];
257
        }
258
        for (AbstractTypeSymbolEditor tab : tabs) {
259
            if (tab.canManageSymbol(sym)) {
260
                return tab;
261
            }
262
        }
263
        return tabs[0];
264
    }
265

    
266
    /**
267
     * Initializes the OkCancel panel where the accept and cancel buttons will
268
     * be placed
269
     *
270
     * @return okCancelPanel AcceptCancelPanel
271
     */
272
    private AcceptCancelPanel getOkCancelPanel() {
273
        if (okCancelPanel == null) {
274
            ActionListener action = (ActionEvent e) -> {
275
                if ("CANCEL".equals(e.getActionCommand())) {
276
                    symbol = oldSymbol;
277
                }
278
                PluginServices.getMDIManager().closeWindow(
279
                        SymbolEditor.this);
280
            };
281
            okCancelPanel = new AcceptCancelPanel(action, action);
282
        }
283
        return okCancelPanel;
284
    }
285

    
286
    @Override
287
    public WindowInfo getWindowInfo() {
288
        if (wi == null) {
289
            wi = new WindowInfo(WindowInfo.MODALDIALOG | WindowInfo.RESIZABLE);
290
            wi.setWidth(750);
291
            wi.setHeight(500);
292
            wi.setTitle(Messages.getText("symbol_property_editor"));
293
        }
294
        return wi;
295
    }
296

    
297
    public ISymbol getSymbol() {
298
        if (symbol instanceof CartographicSupport) {
299
            CartographicSupport cs = (CartographicSupport) symbol;
300
            cs.setUnit(getUnit());
301
            cs.setReferenceSystem(getReferenceSystem());
302
        }
303
        return symbol;
304
    }
305

    
306
    /**
307
     * Initializes the west panel
308
     *
309
     * @return
310
     */
311
    private JPanel getPnlWest() {
312
        if (pnlWest == null) {
313
            pnlWest = new JPanel();
314
            pnlWest.setLayout(new BorderLayout());
315
            pnlWest.add(getPnlPreview(), java.awt.BorderLayout.NORTH);
316
            if (symbol instanceof IMultiLayerSymbol) {
317
                pnlWest.add(getPnlLayers(), java.awt.BorderLayout.SOUTH);
318
            } // otherwise, no layer manager needed
319
        }
320
        return pnlWest;
321
    }
322

    
323
    /**
324
     * Initializes the center panel that shows the properties of a symbol.
325
     *
326
     * @return pnlCenter JPanel
327
     */
328
    private JPanel getPnlCenter() {
329
        if (pnlCenter == null) {
330
            pnlCenter = new JPanel(new BorderLayout());
331
            pnlCenter.setBorder(BorderFactory.createTitledBorder(null,
332
                    Messages.getText("properties")));
333
            pnlCenter.add(getPnlTypeAndUnits(), java.awt.BorderLayout.NORTH);
334
        }
335
        return pnlCenter;
336
    }
337

    
338
    /**
339
     * Initializes the preview panel that allows the user to see a
340
     * previsualization of the final symbol
341
     *
342
     * @return pnlPreview JPanel
343
     */
344
    private JPanel getPnlPreview() {
345
        if (pnlPreview == null) {
346
            pnlPreview = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 5));
347
            pnlPreview.setBorder(BorderFactory.createTitledBorder(null,
348
                    Messages.getText("preview")));
349
            pnlPreview.add(getSymbolPreviewer());
350
        }
351
        return pnlPreview;
352
    }
353

    
354
    /**
355
     * Initializes the Layers panel that shows the different layers created that
356
     * compose a symbol.
357
     *
358
     * @return pnlLayers JPanel
359
     */
360
    private JPanel getPnlLayers() {
361
        if (pnlLayers == null) {
362
            pnlLayers = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 5));
363
            pnlLayers.setBorder(BorderFactory.createTitledBorder(null,
364
                    Messages.getText("layers")));
365
            pnlLayers.add(getLayerManager());
366
        }
367
        return pnlLayers;
368
    }
369

    
370
    /**
371
     * Obtains the layer manager used in the panel that shows the different
372
     * layers that compose the symbol.
373
     *
374
     * @return layerManager SymbolLayerManager
375
     */
376
    private SymbolLayerManager getLayerManager() {
377
        if (layerManager == null) {
378
            layerManager = new SymbolLayerManager(this);
379
        }
380
        return layerManager;
381
    }
382

    
383
    /**
384
     * Obtains the symbol previewer used in the panel that shows the
385
     * previsualization of the final symbol.
386
     *
387
     * @return symbolPreview getSymbolPreviewer
388
     */
389
    private SymbolPreviewer getSymbolPreviewer() {
390
        if (symbolPreview == null) {
391
            symbolPreview = new SymbolPreviewer(getSampleFeature());
392
            symbolPreview.setPreferredSize(new Dimension(150, 100));
393
        }
394
        return symbolPreview;
395
    }
396

    
397
    /**
398
     * Initializes the type and units panel where two Jcomboboxes will be placed
399
     * in order to change the type and the units used in the map.
400
     *
401
     * @return pnlTypeAndUnits JPanel
402
     */
403
    private JPanel getPnlTypeAndUnits() {
404
        if (pnlTypeAndUnits == null) {
405
            pnlTypeAndUnits = new JPanel();
406
            pnlTypeAndUnits.setLayout(new BorderLayout());
407
            JPanel aux = new JPanel(new FlowLayout(FlowLayout.LEADING));
408
            aux.add(new JLabel(Messages.getText("type")));
409
            aux.add(getCmbType());
410
            pnlTypeAndUnits.add(aux, BorderLayout.WEST);
411

    
412
            aux = new JPanel(new FlowLayout(FlowLayout.LEADING));
413
            aux.add(new JLabel(Messages.getText("units")));
414
            aux.add(getCmbUnits());
415
            aux.add(getCmbUnitsReferenceSystem());
416
            pnlTypeAndUnits.add(aux, BorderLayout.EAST);
417

    
418
        }
419
        return pnlTypeAndUnits;
420
    }
421

    
422
    /**
423
     * Obtains the JCombobox to select the reference unit to be used in the
424
     * final representation of the map in this case there are two options (in
425
     * the paper and in the map).
426
     *
427
     * @return
428
     */
429
    private JComboBoxUnitsReferenceSystem getCmbUnitsReferenceSystem() {
430
        if (cmbUnitsReferenceSystem == null) {
431
            cmbUnitsReferenceSystem = new JComboBoxUnitsReferenceSystem();
432

    
433
        }
434

    
435
        return cmbUnitsReferenceSystem;
436
    }
437

    
438
    /**
439
     * Returns the Jcombobox used to select the reference unit (centimeters,
440
     * milimeters and so on) to be used in the final representation of the map.
441
     *
442
     * @return cmbUnits JUnitsComboBox
443
     */
444
    private JComboBoxUnits getCmbUnits() {
445
        if (cmbUnits == null) {
446
            cmbUnits = new JComboBoxUnits();
447
        }
448
        return cmbUnits;
449
    }
450

    
451
    /**
452
     * Returns the option selected in the reference unit Jcombobox
453
     *
454
     */
455
    public int getUnit() {
456
        return getCmbUnits().getSelectedUnitIndex();
457
    }
458

    
459
    public int getReferenceSystem() {
460
        return getCmbUnitsReferenceSystem().getSelectedIndex();
461
    }
462

    
463
    /**
464
     * Returns the Jcombobox used in the panel to select the type of symbol.
465
     *
466
     * @return cmbType JComboBox
467
     */
468
    private JComboBox getCmbType() {
469
        if (cmbType == null) {
470
            cmbType = new JComboBox(tabs);
471
            cmbType.addActionListener(cmbTypeActionListener);
472
        }
473
        return cmbType;
474
    }
475

    
476
    /**
477
     * Sets a layer to a symbol in order to create a final symbol composed by
478
     * different layers.
479
     *
480
     * @param layer
481
     */
482
    protected void setLayerToSymbol(ISymbol layer) {
483
        int i = getLayerManager().getSelectedLayerIndex();
484
        IMultiLayerSymbol s = (IMultiLayerSymbol) symbol;
485
        if (i >= 0 && i < s.getLayerCount()) {
486
            s.setLayer(s.getLayerCount() - 1 - i, layer);
487

    
488
        }
489
        refresh();
490
    }
491

    
492
    public void refresh() {
493
        getSymbolPreviewer().setSymbol(symbol);
494
        doLayout();
495
        repaint();
496
    }
497

    
498
    /**
499
     * <p>
500
     * Returns the type of the symbol that this panels is created for.<br>
501
     * </p>
502
     * <p>
503
     * Possible values returned by this method are
504
     * <ol>
505
     * <li> <b> Geometry.TYPES.POINT </b>, for maker symbols </li>
506
     * <li> <b> Geometry.TYPES.SURFACE </b>, for fill symbols </li>
507
     * <li> <b> Geometry.TYPES.CURVE </b>, for line symbols (not yet
508
     * implemented) </li>
509
     * <li> <b> Geometry.TYPES.TEXT </b>, for text symbols (not yet implemented)
510
     * </li>
511
     * <li> maybe some other in the future </li>
512
     * </ol>
513
     * </p>
514
     *
515
     * @return
516
     */
517
    public int getShapeType() {
518
        return shapeType.getType();
519
    }
520

    
521
    /**
522
     * Obtains a new layer
523
     *
524
     * @return sym ISymbol
525
     */
526
    public ISymbol getNewLayer() {
527
        ISymbol sym = ((AbstractTypeSymbolEditor) getCmbType().getSelectedItem())
528
                .getLayer();
529

    
530
        return sym;
531
    }
532

    
533
    private void replaceOptions(AbstractTypeSymbolEditor options) {
534
        if (!replacing) {
535
            replacing = true;
536
            if (tabbedPane != null) {
537
                getPnlCenter().remove(tabbedPane);
538
            }
539
            JPanel[] theTabs = options.getTabs();
540
            tabbedPane = new JTabbedPane();
541
            tabbedPane.setPreferredSize(new Dimension(300, 300));
542
            for (JPanel theTab : theTabs) {
543
                tabbedPane.addTab(theTab.getName(), theTab);
544
            }
545
            getPnlCenter().add(tabbedPane, BorderLayout.CENTER);
546
            getPnlCenter().doLayout();
547
            replacing = false;
548
        }
549
    }
550

    
551
    public void setOptionsPageFor(ISymbol symbol) {
552
        AbstractTypeSymbolEditor options = getOptionsForSymbol(symbol);
553

    
554
        options.refreshControls(symbol);
555
        getCmbType().setSelectedItem(options);
556
    }
557

    
558
    /**
559
     * Obtains the units to be used for the reference system.
560
     *
561
     */
562
    public int getUnitsReferenceSystem() {
563
        return cmbUnitsReferenceSystem.getSelectedIndex();
564
    }
565

    
566
    /**
567
     * @deprecated use SymblogySwingManager
568
     */
569
    public static void addSymbolEditorPanel(Class<? extends TypeSymbolEditor> symbolEditor, int shapeType) {
570
        SymbologySwingManager manager = SymbologySwingLocator.getSwingManager();
571
        manager.registerSymbolEditor(symbolEditor, shapeType);
572
    }
573

    
574
    /**
575
     * @deprecated use SymblogySwingManager
576
     */
577
    private static List getSymbolsByType(GeometryType geometryType) {
578
        SymbologySwingManager manager = SymbologySwingLocator.getSwingManager();
579
        return manager.getSymbolEditorClassesByGeometryType(geometryType);
580
    }
581

    
582
    @Override
583
    public Object getWindowProfile() {
584
        return WindowInfo.DIALOG_PROFILE;
585
    }
586

    
587
    public void setFeatureStore(FeatureStore store) {
588
        this.featureStore = store;
589
        if (this.featureStore != null) {
590
            this.sampleFeature.setValue(this.featureStore.getSampleFeature());
591
            for (AbstractTypeSymbolEditor editor : tabs) {
592
                editor.setFeatureStore(this.featureStore);
593
            }
594
        }
595
    }
596

    
597
    public MutableObject<Feature> getSampleFeature() {
598
        if (this.sampleFeature == null) {
599
            this.sampleFeature = new MutableObject();
600
            if (this.featureStore != null) {
601
                this.sampleFeature.setValue(this.featureStore.getSampleFeature());
602
            }
603
        }
604
        return this.sampleFeature;
605
    }
606
}