Statistics
| Revision:

gvsig-raster / org.gvsig.raster.wmts / branches / org.gvsig.raster.wmts_dataaccess_refactoring / org.gvsig.raster.wmts.app.wmtsclient / src / main / java / org / gvsig / raster / wmts / app / wmtsclient / gui / wizard / WMTSWizard.java @ 2316

History | View | Annotate | Download (19.2 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
*
3
* Copyright (C) 2007-2008 Infrastructures and Transports Department
4
* of the Valencian Government (CIT)
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 2
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
*/
22
 
23
package org.gvsig.raster.wmts.app.wmtsclient.gui.wizard;
24

    
25
import java.awt.GridBagConstraints;
26
import java.awt.GridBagLayout;
27
import java.awt.event.ActionEvent;
28
import java.awt.event.ActionListener;
29
import java.io.File;
30
import java.io.FileInputStream;
31
import java.io.FileNotFoundException;
32
import java.io.FileOutputStream;
33
import java.io.IOException;
34
import java.net.MalformedURLException;
35
import java.net.URL;
36
import java.util.Properties;
37
import java.util.prefs.Preferences;
38

    
39
import javax.swing.JOptionPane;
40
import javax.swing.JPanel;
41

    
42
import org.cresques.cts.IProjection;
43
import org.gvsig.andami.Launcher;
44
import org.gvsig.andami.PluginServices;
45
import org.gvsig.andami.PluginsLocator;
46
import org.gvsig.andami.persistence.serverData.ServerDataPersistence;
47
import org.gvsig.andami.ui.mdiManager.IWindow;
48
import org.gvsig.app.gui.WizardPanel;
49
import org.gvsig.app.gui.wizards.WizardListener;
50
import org.gvsig.app.gui.wizards.WizardListenerSupport;
51
import org.gvsig.app.project.documents.view.gui.AbstractViewPanel;
52
import org.gvsig.compat.net.ICancellable;
53
import org.gvsig.fmap.dal.DALLocator;
54
import org.gvsig.fmap.dal.DataManager;
55
import org.gvsig.fmap.dal.DataParameters;
56
import org.gvsig.fmap.dal.DataStoreParameters;
57
import org.gvsig.fmap.dal.coverage.exception.ConnectException;
58
import org.gvsig.fmap.dal.coverage.store.parameter.TileDataParameters;
59
import org.gvsig.fmap.dal.exception.InitializeException;
60
import org.gvsig.fmap.dal.exception.ProviderNotRegisteredException;
61
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
62
import org.gvsig.fmap.mapcontext.exceptions.LoadLayerException;
63
import org.gvsig.gui.beans.Messages;
64
import org.gvsig.raster.util.CancelTaskImpl;
65
import org.gvsig.raster.wmts.app.wmtsclient.gui.panel.WMTSParamsPanel;
66
import org.gvsig.raster.wmts.app.wmtsclient.gui.panel.main.IServerPanel;
67
import org.gvsig.raster.wmts.app.wmtsclient.gui.panel.main.NextPrevPanel;
68
import org.gvsig.raster.wmts.app.wmtsclient.layer.FLyrWMTS;
69
import org.gvsig.raster.wmts.io.WMTSDataParameters;
70
import org.gvsig.raster.wmts.io.WMTSServerExplorer;
71
import org.gvsig.raster.wmts.io.WMTSServerExplorerParameters;
72
import org.gvsig.raster.wmts.ogc.struct.WMTSServiceIdentification;
73
import org.gvsig.tools.ToolsLocator;
74
import org.gvsig.tools.persistence.PersistenceManager;
75
import org.gvsig.utils.swing.jcomboServer.ServerData;
76
import org.slf4j.Logger;
77
import org.slf4j.LoggerFactory;
78

    
79
/**
80
 * The WMTS properties container panel.
81
 * @author Nacho Brodin (nachobrodin@gmail.com)
82
 */
83
@SuppressWarnings({ "unused", "deprecation" })
84
public class WMTSWizard extends WizardPanel implements ActionListener {
85
        private static final long             serialVersionUID       = 1L;
86
        private static Logger                 logger                 = LoggerFactory.getLogger(WMTSWizard.class);
87
        private String                        pluginName             = "org.gvsig.raster.wmts.app.wmtsclient";
88
        private File                          pluginPersistenceFile  = null;
89
        private File                          serverPropertiesFile   = null;
90
        private ServerDataPersistence         serverDataPersistence  = null;
91
        private String                        serversPropsFile       = "servers.properties";
92
        
93
        protected int                         page                   = 0;
94
        protected boolean                     connected              = false;
95
        private IServerPanel                  serverPanel            = null;
96
        private NextPrevPanel                 nextPrevPanel          = null;
97
        
98
        private WizardListenerSupport         listenerSupport        = null;
99
        protected WMTSParamsPanel             wmtsParamsPanel        = null;
100
        private static Preferences            fPrefs                 = Preferences.userRoot().node( "gvsig.wmts-wizard" );
101
        private boolean                       refreshing             = fPrefs.getBoolean("refresh_capabilities", false);
102
        protected int                         firstPage              = 0;
103
        private IProjection                   proj                   = null;
104
        private ICancellable                  cancel                 = null;
105
        private WMTSDataParameters            storeParams            = null;
106
        private WMTSServerExplorer            explorer               = null;
107

    
108
        /**
109
         * This is the default constructor
110
         */
111
        public WMTSWizard() {
112
                super();
113
                firstPage = 0;
114
                page = firstPage;
115
                initialize();
116
                
117
                IWindow[] windows = PluginServices.getMDIManager().getAllWindows();
118
                for (int i = 0; i < windows.length; i++) {
119
                        if(windows[i] instanceof AbstractViewPanel)
120
                                proj = ((AbstractViewPanel)windows[i]).getProjection();
121
                }
122
                cancel = new CancelTaskImpl();
123
        }
124
        
125
        /**
126
         * This method initializes this
127
         */
128
        private void initialize() {
129
                setTabName("WMTS");
130
                setLayout(new GridBagLayout());
131
                GridBagConstraints gridBagConstraints1 = new GridBagConstraints();
132
                gridBagConstraints1.fill = GridBagConstraints.BOTH;
133
                gridBagConstraints1.weightx = 1.0;
134
                gridBagConstraints1.weighty = 1.0;
135
                gridBagConstraints1.insets = new java.awt.Insets(2, 12, 10, 12);
136
                
137
                setVisible(true);
138
                add(getIserverPanel(), gridBagConstraints1);
139
                
140
                gridBagConstraints1.insets = new java.awt.Insets(2, 0, 10, 0);
141
                add(getPanelPage2(), gridBagConstraints1);
142
                gridBagConstraints1.fill = GridBagConstraints.HORIZONTAL;
143
                gridBagConstraints1.anchor = GridBagConstraints.EAST;
144
                gridBagConstraints1.weighty = 0;
145
                gridBagConstraints1.gridy = 1;
146
                add(getNextPrevPanel(), gridBagConstraints1);
147
                activarVisualizarBotones();
148
                serverPanel.getTxtHost().setServerList(getServerDataPersistence().getArrayOfServerData());
149
        }
150
        
151
        /**
152
         * This method checks for the options selected within the configuration
153
         * dialog are correct.
154
         *
155
         * @return true if you're done, false if not.
156
         */
157
        public boolean areSettingsValid() {
158
                return wmtsParamsPanel.isCorrectlyConfigured();
159
        }
160
        
161
        private WizardListenerSupport getWizardListenerSupport() {
162
                if(listenerSupport == null)
163
                        listenerSupport = new WizardListenerSupport();
164
                return listenerSupport;
165
        }
166
        
167
        /**
168
         * This method initializes jPanel
169
         *
170
         * @return javax.swing.JPanel
171
         */
172
        public NextPrevPanel getNextPrevPanel() {
173
                if (nextPrevPanel == null) {
174
                        nextPrevPanel = new NextPrevPanel();
175
                        nextPrevPanel.getBtnNext().addActionListener(this);
176
                        nextPrevPanel.getBtnPrev().addActionListener(this);
177
                }
178
                return nextPrevPanel;
179
        }
180

    
181
        /**
182
         * Thread to connect to a WMTS server
183
         * @author Nacho Brodin (nachobrodin@gmail.com)
184
         */
185
        public class ConnectThread extends Thread {
186
                private ICancellable              cancel      = null;
187
                private WMTSServerExplorer        explorer    = null;
188
                private WMTSWizard                wizard      = null;
189
                
190
                public ConnectThread(ICancellable cancel, WMTSServerExplorer explorer, WMTSWizard wizard) {
191
                        this.cancel = cancel;
192
                        this.explorer = explorer;
193
                        this.wizard = wizard;
194
                }
195
                
196
            public void run() {
197
                    if(!checkHostAndNetwork())
198
                            return;
199
                    
200
                    try {
201
                            explorer.connect(cancel);
202
                            saveServerListFromComboBox();
203
                        } catch (ConnectException e) {
204
                                serverPanel.getTxtAbstract().setText("Connection closed... \n" + e.getMessage());
205
                                JOptionPane.showMessageDialog(null, Messages.getText("wmts_cant_connect"), Messages.getText("Error"), JOptionPane.ERROR_MESSAGE);
206
                                return;
207
                        } finally {
208
                                ((CancelTaskImpl)cancel).setCanceled(false);
209
                        }
210
                        
211
                        DataStoreParameters parameters = explorer.getStoredParameters();
212
                        if(parameters instanceof WMTSDataParameters) {
213
                                storeParams = (WMTSDataParameters) parameters;
214
                        }
215
                        
216
                        if(parameters instanceof TileDataParameters) {
217
                                DataParameters p = ((TileDataParameters) parameters).getDataParameters();
218
                                if(p instanceof WMTSDataParameters)
219
                                        storeParams = (WMTSDataParameters) p;
220
                        }
221
                        
222
                        wizard.rellenarControles();
223
            }
224
        }
225
        
226
        /**
227
         * Checks if the network and host are reachable
228
         * @return true if both are reachable and false if they are not
229
         */
230
        private boolean checkHostAndNetwork() {
231
                if(!explorer.isHostReachable()) {
232
                        JOptionPane.showMessageDialog(null, Messages.getText("host_unreachable"), Messages.getText("Error"), JOptionPane.ERROR_MESSAGE);
233
                        serverPanel.getTxtAbstract().setText("Connection closed... \n");
234
                        return false;
235
                }
236
                return true;
237
        }
238

    
239
        /**
240
         * DOCUMENT ME!
241
         */
242
        private void rellenarControles() {
243
                try {
244
                        String host = serverPanel.getTxtHost().getModel().getSelectedItem().toString();
245
                        WMTSServiceIdentification id = explorer.getOGCClient().getServiceIdentification();
246
                        
247
                        serverPanel.getJLabelTitle().setText(id.getTitle());
248
                        nextPrevPanel.getJLabelServerTypeValue().setText(id.getServiceType());
249
                        serverPanel.getTxtAbstract().setText(id.getAbstract());
250

    
251
                        wmtsParamsPanel.setWizardData(explorer);
252
                        connected = true;
253
                        activarVisualizarBotones();
254
                } catch (Exception e) {
255
                        if (e.getMessage() == null) {
256
                                serverPanel.getTxtAbstract().setText(PluginServices.getText(this,"error"));
257
                        } else {
258
                                serverPanel.getTxtAbstract().setText(e.getMessage());
259
                        }
260
                        getWizardListenerSupport().callError(e);
261
                        nextPrevPanel.getBtnNext().setEnabled(false);
262
                        nextPrevPanel.getBtnPrev().setEnabled(true);
263
                } finally {
264
                        serverPanel.getBtnCancel().setEnabled(false);
265
                }
266
        }
267
        
268
        public void actionPerformed(ActionEvent e) {
269
                if(e.getSource() == serverPanel.getBtnConnect()) {
270
                        serverPanel.getBtnCancel().setEnabled(true);
271
                        serverPanel.getTxtAbstract().setText("Trying to connect...");
272
                        
273
                        String host = serverPanel.getTxtHost().getModel().getSelectedItem().toString();
274
                        try {
275
                                DataManager datamanager = DALLocator.getDataManager();
276
                                WMTSServerExplorerParameters explorerParams = (WMTSServerExplorerParameters) datamanager.createServerExplorerParameters(WMTSServerExplorer.NAME);
277
                                explorerParams.setHost(host);
278
                                explorerParams.setLongitudeFirst(serverPanel.getChkInvertAxisOrder().isSelected());
279
                                
280
                                explorer = (WMTSServerExplorer) datamanager.createServerExplorer(explorerParams);
281
                                
282
                                ((CancelTaskImpl)cancel).setCanceled(false);
283
                                new ConnectThread(cancel, explorer, this).start();
284
                                
285
                        } catch (InitializeException e1) {
286
                                serverPanel.getTxtAbstract().setText("Error creating WMTS layer");
287
                        } catch (ProviderNotRegisteredException e1) {
288
                                serverPanel.getTxtAbstract().setText("Provider not registered. I cannot connect.");
289
                        } catch (ValidateDataParametersException e1) {
290
                                serverPanel.getTxtAbstract().setText("Parameters not valid. I cannot connect.");
291
                        }
292
                }
293
                
294
                if(e.getSource() == serverPanel.getBtnCancel()) {
295
                        serverPanel.getTxtAbstract().setText("Cancelled...");
296
                        ((CancelTaskImpl)cancel).setCanceled(true);
297
                        serverPanel.getBtnCancel().setEnabled(false);
298
                }
299
                
300
                if(e.getSource() == nextPrevPanel.getBtnPrev()) {
301
                        page --;
302
                        if (page > firstPage) {
303
                                wmtsParamsPanel.retrocedeTab();
304
                                page = wmtsParamsPanel.currentPage() + 1;
305
                                activarVisualizarBotones();
306
                        } else if (page == firstPage){
307
                                activarVisualizarBotones();
308
                                page = firstPage +1;
309
                                serverPanel.getJLabelTitle().setText("-");
310
                                serverPanel.getTxtAbstract().setText("");
311
                                wmtsParamsPanel.retrocedeTab();
312
                                getIserverPanel().setVisible(true);
313
                                getPanelPage2().setVisible(false);
314
                                nextPrevPanel.getBtnNext().setEnabled(false);
315
                                connected = false;
316
                        }
317
                        getWizardListenerSupport().callStateChanged(wmtsParamsPanel.isCorrectlyConfigured());
318
                }
319
                
320
                if(e.getSource() == nextPrevPanel.getBtnNext()) {
321
                        if (page > firstPage) {
322
                                // si page es mayor que cero, vamos enfocando las
323
                                // sucesivas SOLAPAS del WMTSParamsPanel
324
                                wmtsParamsPanel.avanzaTab();
325
                                page = wmtsParamsPanel.currentPage();
326
                        }
327
                        page++;
328
                        getIserverPanel().setVisible(false);
329
                        getPanelPage2().setVisible(true);
330
                        activarVisualizarBotones();
331
                }
332
        }
333
        
334
        private JPanel getIserverPanel() {
335
                if (serverPanel == null) {
336
                        serverPanel = new IServerPanel();
337
                        serverPanel.getBtnCancel().addActionListener(this);
338
                        serverPanel.getBtnConnect().addActionListener(this);
339
                }
340
                return serverPanel;
341
        }        
342
        
343
        protected JPanel getPanelPage2() {
344
                if (wmtsParamsPanel == null){
345
                        wmtsParamsPanel = new WMTSParamsPanel();
346
                        wmtsParamsPanel.setListenerSupport(getWizardListenerSupport());
347
                        wmtsParamsPanel.getJTabbedPane().addMouseListener(
348
                                        new java.awt.event.MouseAdapter() {
349
                                                public void mouseClicked(java.awt.event.MouseEvent e) {
350
                                                        page = wmtsParamsPanel.currentPage() + 1;
351
                                                        activarVisualizarBotones();
352
                                                }
353
                                        });
354
                }
355
                return wmtsParamsPanel;
356
        }
357

    
358
        /**
359
         * DOCUMENT ME!
360
         */
361
        protected void activarVisualizarBotones() {
362
                if (page == firstPage) {
363
                        nextPrevPanel.getBtnPrev().setEnabled(false);
364
                        nextPrevPanel.getBtnPrev().setVisible(true);
365

    
366
                        if (connected) {
367
                                nextPrevPanel.getBtnNext().setEnabled(true);
368
                        } else {
369
                                nextPrevPanel.getBtnNext().setEnabled(false);
370
                        }
371
                } else if (page < wmtsParamsPanel.getNumTabs()) {
372
                        nextPrevPanel.getBtnNext().setEnabled(true);
373
                        nextPrevPanel.getBtnNext().setVisible(true);
374
                        nextPrevPanel.getBtnPrev().setEnabled(true);
375
                        nextPrevPanel.getBtnPrev().setVisible(true);
376
                        if (wmtsParamsPanel.nextEnabledPage()==-1) {
377
                                nextPrevPanel.getBtnNext().setEnabled(false);
378
                        }
379
                        getWizardListenerSupport().callStateChanged(wmtsParamsPanel.isCorrectlyConfigured());
380
                } else if (page == wmtsParamsPanel.getNumTabs()) {
381
                        nextPrevPanel.getBtnNext().setVisible(false);
382
                        nextPrevPanel.getBtnNext().setEnabled(false);
383
                        getWizardListenerSupport().callStateChanged(wmtsParamsPanel.isCorrectlyConfigured());
384
                }
385
        }
386
        
387
        /**
388
         * Gets the list of servers that have been persisted or added in the properties file
389
         * @return
390
         */
391
        private ServerDataPersistence getServerDataPersistence() {
392
                if(serverDataPersistence == null) {
393
                        PersistenceManager persistenceManager = ToolsLocator.getPersistenceManager();
394

    
395
                        //Lee los servidores de la persistencia
396
                        try {
397
                                FileInputStream is = new FileInputStream(getPluginPersistenceFile());
398
                                serverDataPersistence = (ServerDataPersistence) persistenceManager.getObject(is);
399
                        } catch (FileNotFoundException e) {
400
                                logger.info("Persistence file not found for WMS plugin", e);
401
                        }
402

    
403
                        if(serverDataPersistence == null)
404
                                serverDataPersistence = new ServerDataPersistence(ServerData.SERVER_TYPE_WMTS);
405

    
406
                        //Lee los servidores del properties y los mezcla con los que hay en la persistencia
407
                        Properties prop = new Properties();
408
                        try {
409
                                prop.load(new FileInputStream(getServerPropertiesFile()));
410
                        } catch (FileNotFoundException e) {
411
                                logger.info("Properties file not found for WMS plugin", e);
412
                        } catch (IOException e) {
413
                                logger.info("Error reading properties file", e);
414
                        }
415

    
416
                        boolean newProjectServers = false;
417
                        for (int i = 0; i < prop.size(); i++) {
418
                                Object value = prop.get("server[" + i + "]");
419
                                if(!serverDataPersistence.existsServer(value.toString())) {
420
                                        serverDataPersistence.addServerData(new ServerData(value.toString(), ServerData.SERVER_TYPE_WMTS));
421
                                        newProjectServers = true;
422
                                }
423
                        }
424

    
425
                        //Si hay servidores nuevos los persiste
426
                        if(newProjectServers) {
427
                                try {
428
                                        FileOutputStream os = new FileOutputStream(getPluginPersistenceFile());
429
                                        persistenceManager.putObject(os, serverDataPersistence);
430
                                } catch (FileNotFoundException e) {
431
                                        logger.info("Persistence file not found for WMS plugin", e);
432
                                }
433
                        }
434
                }
435

    
436
                return serverDataPersistence;
437
        }
438
        
439
        /**
440
         * Saves the list of server reading from the <code>ComboBox</code>
441
         */
442
        private void saveServerListFromComboBox() {
443
                PersistenceManager persistenceManager = ToolsLocator.getPersistenceManager();
444
                ServerDataPersistence persistence = new ServerDataPersistence(ServerData.SERVER_TYPE_WMTS);
445
                String urlSelected = serverPanel.getTxtHost().getModel().getSelectedItem().toString();
446
                
447
                boolean isSelectedInModel = false;
448
                for (int i = 0; i < serverPanel.getTxtHost().getItemCount(); i++) {
449
                        String url = serverPanel.getTxtHost().getItemAt(i).toString();
450
                        persistence.addServerData(new ServerData(url, ServerData.SERVER_TYPE_WMTS));
451
                        if(url.equals(urlSelected))
452
                                isSelectedInModel = true;
453
                }
454
                
455
                if(!isSelectedInModel)
456
                        persistence.addServerData(new ServerData(urlSelected, ServerData.SERVER_TYPE_WMTS));
457
                
458
                if(getServerDataPersistence().compareTo(persistence) != 0) {
459
                        try {
460
                                FileOutputStream os = new FileOutputStream(getPluginPersistenceFile());
461
                                persistenceManager.putObject(os, persistence);
462
                        } catch (FileNotFoundException e) {
463
                                logger.info("Persistence file not found for WMS plugin", e);
464
                        }
465
                }
466
        }
467
        
468
        /**
469
         * Gets the persistence file of this plugin
470
         * @return
471
         */
472
        private File getPluginPersistenceFile() {
473
                if(pluginPersistenceFile == null) {
474
                        File persistenceFolder = new File(Launcher.getAppHomeDir()
475
                                        + File.separator + "plugins" + File.separator + pluginName);
476
                        
477
                        if (!persistenceFolder.exists()) {
478
                                persistenceFolder.mkdirs();
479
                        }
480
                        
481
                        pluginPersistenceFile = new File(persistenceFolder.getAbsolutePath() + 
482
                                File.separator + 
483
                                "plugin-persistence.dat");
484
                }
485
                return pluginPersistenceFile;
486
        }
487
        
488
        /**
489
         * Gets the file which contains the default list of servers
490
         * @return
491
         */
492
        private File getServerPropertiesFile() {
493
                if(serverPropertiesFile == null) {
494
                        File pluginFolder = PluginsLocator.getManager().getPluginsFolder();
495
                        serverPropertiesFile = new File(pluginFolder.getAbsolutePath() + 
496
                                        File.separator + 
497
                                        pluginName + 
498
                                        File.separator + 
499
                                        serversPropsFile);
500
                }
501
                return serverPropertiesFile;
502
        }
503

    
504
        /**
505
         * DOCUMENT ME!
506
         * @param listener
507
         */
508
        public void addWizardListener(WizardListener listener) {
509
                getWizardListenerSupport().addWizardListener(listener);
510
                getWizardListenerSupport().callStateChanged(false);
511
        }
512

    
513
        /**
514
         * DOCUMENT ME!
515
         * @param listener
516
         */
517
        public void removeWizardListener(WizardListener listener) {
518
                getWizardListenerSupport().removeWizardListener(listener);
519
        }
520

    
521
        /**
522
         * Devuelve el host que est� escrito en el cuadro de texto del host o null
523
         * en caso de que no haya nada escrito o est� mal escrito
524
         *
525
         * @return URL del host
526
         */
527
        public URL getHost() {
528
                try {
529
                        if ((serverPanel.getTxtHost() == null)|| (serverPanel.getTxtHost().getModel().getSelectedItem() == null)) {
530
                                return new URL(explorer.getHost());
531
                        } else {
532
                                return new URL(serverPanel.getTxtHost().getModel().getSelectedItem().toString());
533
                        }
534
                } catch (MalformedURLException e) {
535
                        return null;
536
                }
537
        }
538

    
539
        public void initWizard() {
540
        }
541
        
542
        @Override
543
        public DataStoreParameters[] getParameters() {
544
                return null;
545
        }
546

    
547
        @Override
548
        public void close() {
549
        }
550

    
551
        @Override
552
        public void execute() {
553
                try {
554
                        wmtsParamsPanel.setDeleteCache(serverPanel.getChkCaching().isSelected());
555
                        FLyrWMTS[] layerList = wmtsParamsPanel.getLayers();
556
                        for (int i = 0; i < layerList.length; i++) {
557
                                getMapCtrl().getMapContext().getLayers().addLayer(layerList[i]);
558
                        }
559
                } catch (LoadLayerException e) {
560
                        e.printStackTrace();
561
                }
562
        }
563
}  //  @jve:decl-index=0:visual-constraint="10,10"