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 / extension / ProjectExtension.java @ 42186

History | View | Annotate | Download (23.9 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.extension;
25

    
26
import java.awt.Component;
27
import java.io.File;
28
import java.text.MessageFormat;
29
import java.util.ArrayList;
30
import java.util.Iterator;
31
import java.util.List;
32
import java.util.prefs.Preferences;
33

    
34
import javax.swing.JOptionPane;
35
import javax.swing.SwingUtilities;
36

    
37
import org.slf4j.Logger;
38
import org.slf4j.LoggerFactory;
39
import org.gvsig.tools.util.ArrayUtils;
40
import org.apache.commons.lang.StringUtils;
41
import org.gvsig.andami.IconThemeHelper;
42
import org.gvsig.andami.Launcher;
43
import org.gvsig.andami.Launcher.TerminationProcess;
44
import org.gvsig.andami.PluginServices;
45
import org.gvsig.andami.PluginsLocator;
46
import org.gvsig.andami.actioninfo.ActionInfo;
47
import org.gvsig.andami.actioninfo.ActionInfoManager;
48
import org.gvsig.andami.messages.NotificationManager;
49
import org.gvsig.andami.plugins.Extension;
50
import org.gvsig.andami.plugins.IExtension;
51
import org.gvsig.andami.plugins.status.IExtensionStatus;
52
import org.gvsig.andami.plugins.status.IUnsavedData;
53
import org.gvsig.andami.plugins.status.UnsavedData;
54
import org.gvsig.andami.ui.mdiManager.IWindow;
55
import org.gvsig.andami.ui.mdiManager.WindowInfo;
56
import org.gvsig.andami.ui.wizard.UnsavedDataPanel;
57
import org.gvsig.app.project.Project;
58
import org.gvsig.app.project.ProjectManager;
59
import org.gvsig.app.project.documents.gui.ProjectWindow;
60
import org.gvsig.app.project.documents.view.ViewManager;
61
import org.gvsig.gui.beans.swing.JFileChooser;
62
import org.gvsig.tools.ToolsLocator;
63
import org.gvsig.tools.dataTypes.DataTypes;
64
import org.gvsig.tools.extensionpoint.ExtensionPointManager;
65
import org.gvsig.tools.persistence.exception.PersistenceException;
66
import org.gvsig.utils.GenericFileFilter;
67
import org.gvsig.utils.save.AfterSavingListener;
68
import org.gvsig.utils.save.BeforeSavingListener;
69
import org.gvsig.utils.save.SaveEvent;
70
import org.gvsig.utils.swing.threads.IMonitorableTask;
71

    
72

    
73
/**
74
 * Extension que proporciona controles para crear proyectos nuevos, abrirlos y
75
 * guardarlos. Adem?s los tipos de tabla que soporta el proyecto son a?adidos en
76
 * esta clase.
77
 * 
78
 * @author Fernando Gonz?lez Cort?s
79
 */
80
public class ProjectExtension extends Extension implements IExtensionStatus {
81
        private static final Logger LOG = LoggerFactory
82
                        .getLogger(ProjectExtension.class);
83

    
84
        private static String projectPath = null;
85
        private ProjectWindow projectFrame;
86
        private Project p;
87
        private String lastSavePath;
88
        private WindowInfo seedProjectWindow;
89
        public static final String PROJECT_FILE_CHOOSER_ID = "PROJECT_FILECHOOSER_ID";
90
        /**
91
         * Use UTF-8 for encoding, as it can represent characters from any language.
92
         * 
93
         * Another sensible option would be encoding =
94
         * System.getProperty("file.encoding"); but this would need some extra
95
         * testing.
96
         * 
97
         * @deprecated see PersistentManager
98
         */
99
        public static String PROJECTENCODING = "UTF-8";
100

    
101
        private List<BeforeSavingListener> beforeSavingListeners = new ArrayList<BeforeSavingListener>();
102

    
103
        private List<AfterSavingListener> afterSavingListeners = new ArrayList<AfterSavingListener>();
104

    
105
        public void initialize() {
106
            initializeDocumentActionsExtensionPoint();
107
            registerDocuments();
108
            registerIcons();
109
            
110
            File projectFile = getProjectFileFromArguments();
111
            if( projectFile!=null ) {
112
                // Posponemos la apertura del proyecto ya que en este momento
113
                // puede que no este inicializado algun plugin que precise el
114
                // proyecto para poderse cargar.
115
                PluginsLocator.getManager().addStartupTask(
116
                    "Open project",
117
                    new OpenInitialProjectTask(projectFile), true, 1000);
118
            }
119
        }
120

    
121
        private void registerIcons() {
122
                IconThemeHelper.registerIcon("action", "application-project-new", this);
123
                IconThemeHelper
124
                                .registerIcon("action", "application-project-open", this);
125
                IconThemeHelper
126
                                .registerIcon("action", "application-project-save", this);
127
                IconThemeHelper.registerIcon("action", "application-project-save-as",
128
                                this);
129

    
130
                IconThemeHelper.registerIcon("project", "project-icon", this);
131
        }
132

    
133
        /**
134
         * Returns the file to be opened or null if no parameter
135
         * or file does not exist
136
         * 
137
         * @return
138
         */
139
        private File getProjectFileFromArguments() {
140
            String[] theArgs = PluginServices.getArguments();
141
            if( theArgs.length< 3 ) {
142
                // application-name and extensions-folder are fixed arguments
143
                return null;
144
            }
145
            String lastArg = theArgs[theArgs.length - 1];
146
            if ( StringUtils.isEmpty(lastArg) ) {
147
                return null;
148
            }
149
            if( lastArg.startsWith("-") ) {
150
                // Args starts with "-" are flags
151
                return null;
152
            }
153
            if (!lastArg.toLowerCase().endsWith(Project.FILE_EXTENSION.toLowerCase())) {
154
                LOG.info("Do not open project file, does not have the expected extension '" + 
155
                        Project.FILE_EXTENSION +"' ("+lastArg+").");
156
                return null;
157
            }
158
            File projectFile = new File(lastArg);
159
            if ( !projectFile.exists()) {
160
                LOG.info("Do not open project file, '" +projectFile.getAbsolutePath() + "' do not exist.");
161
                return null;
162
            }
163
            return projectFile;
164
        }   
165

    
166
        private class OpenInitialProjectTask implements Runnable {
167
            private File projectFile;
168
            public OpenInitialProjectTask(File projectFile) {
169
                this.projectFile = projectFile;
170
            }
171
            public void run() {
172
                if (this.projectFile == null) {
173
                    return;
174
                }
175
                ActionInfoManager actionManager = PluginsLocator.getActionInfoManager();
176
                ActionInfo action = actionManager.getAction("application-project-open");
177
                action.execute(this.projectFile);
178
            }
179
        }
180

    
181
        public ProjectWindow getProjectFrame() {
182
                if (projectFrame == null) {
183
                        projectFrame = new ProjectWindow();
184
                }
185
                return projectFrame;
186
        }
187

    
188
        /**
189
         * Muestra la ventana con el gestor de proyectos.
190
         */
191
        public void showProjectWindow() {
192
                if (seedProjectWindow != null) {
193
                        if (seedProjectWindow.isClosed()) {
194
                                // if it was closed, we just don't open the window now
195
                                seedProjectWindow.setClosed(false);
196
                                return;
197
                        }
198
                        WindowInfo winProps = seedProjectWindow;
199
                        seedProjectWindow = null;
200
                        PluginServices.getMDIManager().addWindow(getProjectFrame());
201
                        PluginServices.getMDIManager().changeWindowInfo(getProjectFrame(),
202
                                        winProps);
203
                } else {
204
                        PluginServices.getMDIManager().addWindow(getProjectFrame());
205
                }
206
        }
207

    
208
        /**
209
         * Muestra la ventana con el gestor de proyectos, con las propiedades de
210
         * ventana especificadas.
211
         */
212
        public void showProjectWindow(WindowInfo wi) {
213
                seedProjectWindow = wi;
214
                showProjectWindow();
215
        }
216

    
217
        /**
218
         * Guarda el proyecto actual en disco.
219
         */
220
        private boolean saveProject() {
221
                boolean saved = false;
222
                // if (p.getPath() == null) {
223
                if (projectPath == null) {
224
                        saved = saveAsProject(null);
225
                } else {
226
                        long t1, t2;
227
                        t1 = System.currentTimeMillis();
228
                        saved = writeProject(new File(projectPath), p, false);
229
                        t2 = System.currentTimeMillis();
230
                        PluginServices.getLogger().info(
231
                                        "Project saved. " + (t2 - t1) + " miliseconds");
232
                        getProjectFrame().refreshControls();
233
                }
234
                return saved;
235
        }
236

    
237
        private boolean saveAsProject(File file) {
238
                boolean saved = false;
239

    
240
                if (lastSavePath == null) {
241
                        lastSavePath = projectPath;
242
                }
243

    
244
                if (file == null) {
245
                        Preferences prefs = Preferences.userRoot().node("gvsig.foldering");
246
                        JFileChooser jfc = new JFileChooser(PROJECT_FILE_CHOOSER_ID,
247
                                        prefs.get("ProjectsFolder", null));
248

    
249
                        jfc.setDialogTitle(PluginServices.getText(this, "guardar_proyecto"));
250
                        
251
                        GenericFileFilter projExtensionFilter = new GenericFileFilter(
252
                                        Project.FILE_EXTENSION, MessageFormat.format(PluginServices
253
                                                        .getText(this, "tipo_fichero_proyecto"),
254
                                                        Project.FILE_EXTENSION));
255
      jfc.addChoosableFileFilter(projExtensionFilter);
256
      jfc.setFileFilter(projExtensionFilter);
257

    
258
                        if (jfc.showSaveDialog((Component) PluginServices.getMainFrame()) != JFileChooser.APPROVE_OPTION) {
259
                                return saved;
260
                        }
261
                        file = jfc.getSelectedFile();
262
                }
263

    
264
                if (!(file.getPath().toLowerCase().endsWith(Project.FILE_EXTENSION
265
                                .toLowerCase()))) {
266
                        file = new File(file.getPath() + Project.FILE_EXTENSION);
267
                }
268
                saved = writeProject(file, p);
269
                String filePath = file.getAbsolutePath();
270
                lastSavePath = filePath.substring(0,
271
                                filePath.lastIndexOf(File.separatorChar));
272

    
273
                getProjectFrame().refreshControls();
274
                return saved;
275
        }
276

    
277
        /**
278
         * Checks whether the project and related unsaved data is modified, and
279
         * allows the user to save it.
280
         * 
281
         * @return true if the data has been correctly saved, false otherwise
282
         */
283
        private boolean askSave() {
284
                if (p != null && p.hasChanged()) {
285
                        TerminationProcess process = Launcher.getTerminationProcess();
286
                        UnsavedDataPanel panel = process.getUnsavedDataPanel();
287
                        panel.setHeaderText(PluginServices.getText(this,
288
                                        "_Select_resources_to_save_before_closing_current_project"));
289
                        panel.setAcceptText(
290
                                        PluginServices.getText(this, "save_resources"),
291
                                        PluginServices
292
                                                        .getText(this,
293
                                                                        "Save_the_selected_resources_and_close_current_project"));
294
                        panel.setCancelText(PluginServices.getText(this, "Cancel"),
295
                                        PluginServices.getText(this, "Return_to_current_project"));
296
                        int closeCurrProj;
297
                        try {
298
                                closeCurrProj = process.manageUnsavedData();
299
                                if (closeCurrProj == JOptionPane.NO_OPTION) {
300
                                        // the user chose to return to current project
301
                                        return false;
302
                                }
303
                        } catch (Exception e) {
304
                                LOG.error("Some data can not be saved", e);
305
                        }
306
                }
307
                return true;
308
        }
309

    
310
        public void execute(String command) {
311
                this.execute(command, null);
312
        }
313
        
314
        public void execute(String actionCommand, Object[] args) {
315
                if (actionCommand.equals("application-project-new")) {
316
                        if (!askSave()) {
317
                                return;
318
                        }
319

    
320
                        projectPath = null;
321
                        PluginServices.getMDIManager().closeAllWindows();
322
                        setProject(ProjectManager.getInstance().createProject());
323
                        getProjectFrame().setProject(p);
324
                        showProjectWindow();
325
                        PluginServices.getMainFrame().setTitle(
326
                                        PluginServices.getText(this, "sin_titulo"));
327

    
328
                } else if (actionCommand.equals("application-project-open")) {
329
                        if (!askSave()) {
330
                                return;
331
                        }
332
                        File projectFile = (File) ArrayUtils.get(args, 0, DataTypes.FILE);
333
                        if ( projectFile != null && !projectFile.exists() ) {
334
                            LOG.warn("Can't load project '"
335
                                    + projectFile.getAbsolutePath()
336
                                    + "', file not exist.");
337
                            projectFile = null;
338
                        }
339

    
340
                        if (projectFile == null) {
341
                                Preferences prefs = Preferences.userRoot().node(
342
                                                "gvsig.foldering");
343
                                JFileChooser jfc = new JFileChooser(PROJECT_FILE_CHOOSER_ID,
344
                                                prefs.get("ProjectsFolder", null));
345
                                
346
                                GenericFileFilter projExtensionFilter = new GenericFileFilter(
347
                                                Project.FILE_EXTENSION, PluginServices.getText(this,
348
                                                                "tipo_fichero_proyecto"));
349
        jfc.addChoosableFileFilter(projExtensionFilter);
350
                                jfc.setFileFilter(projExtensionFilter);
351

    
352
                                if (jfc.showOpenDialog((Component) PluginServices
353
                                                .getMainFrame()) != JFileChooser.APPROVE_OPTION) {
354
                                        return;
355
                                }
356
                                // ProjectDocument.initializeNUMS();
357
                                
358

    
359
                                projectFile = jfc.getSelectedFile();
360
                        }
361
                        
362
                        PluginServices.getMDIManager().closeAllWindows();
363

    
364
                        Project o = readProject(projectFile);
365
                        setPath(projectFile.getAbsolutePath());
366
                        // lastPath = getPath();
367
                        if (o != null) {
368
                                setProject(o);
369
                        }
370

    
371
                        getProjectFrame().setProject(p);
372
                        PluginServices.getMainFrame().setTitle(projectFile.getName());
373
                        getProjectFrame().refreshControls();
374

    
375
                        // p.restoreWindowProperties();
376

    
377
                } else if (actionCommand.equals("application-project-save")) {
378
                        saveProject();
379
                } else if (actionCommand.equals("application-project-save-as")) {
380
                        File file = (File) ArrayUtils.get(args, 0, DataTypes.FILE);
381
                        saveAsProject(file);
382
                }
383

    
384
        }
385

    
386
        
387
    private void createEmptyProject() {
388
        setProject(ProjectManager.getInstance().createProject());
389
        p.setName(PluginServices.getText(this, "untitled"));
390
        p.setModified(false);
391
        PluginServices.getMainFrame().setTitle(
392
                PluginServices.getText(this, "sin_titulo"));
393
        setProject(p);
394
        showProjectWindow();
395
    }
396

    
397
    /**
398
     * @see com.iver.mdiApp.plugins.IExtension#postInitialize()
399
     */
400
    public void postInitialize() {
401
        try {
402
            if( !SwingUtilities.isEventDispatchThread() ) {
403
                SwingUtilities.invokeAndWait(new Runnable() {
404
                    public void run() {
405
                        createEmptyProject();
406
                    }
407
                });
408
            } else {
409
                createEmptyProject();
410
            }
411
        } catch (Exception e) {
412
            LOG.warn("Can't load initial project.",e);
413
        }
414
    }        
415
        
416
        
417
        /**
418
         * Escribe el proyecto en XML.
419
         * 
420
         * @param file
421
         *            Fichero.
422
         * @param p
423
         *            Proyecto.
424
         */
425
        public boolean writeProject(File file, Project p) {
426
                return writeProject(file, p, true);
427
        }
428

    
429
        /**
430
         * Escribe el proyecto en XML. Pero permite decidir si se pide confirmaci?n
431
         * para sobreescribir
432
         * 
433
         * @param file
434
         *            Fichero.
435
         * @param p
436
         *            Proyecto.
437
         * @param askConfirmation
438
         *            boolean
439
         */
440
        public boolean writeProject(File file, Project p, boolean askConfirmation) {
441
                if (askConfirmation && file.exists()) {
442
                        int resp = JOptionPane.showConfirmDialog((Component) PluginServices
443
                                        .getMainFrame(), PluginServices.getText(this,
444
                                        "fichero_ya_existe_seguro_desea_guardarlo"), PluginServices
445
                                        .getText(this, "guardar"), JOptionPane.YES_NO_OPTION);
446
                        if (resp != JOptionPane.YES_OPTION) {
447
                                return false;
448
                        }
449
                }
450
                NotificationManager.addInfo(PluginServices.getText(this,
451
                                "writinng_project") + ": " + file.getName());
452

    
453
                // write it out as XML
454
                try {
455
                        fireBeforeSavingFileEvent(new SaveEvent(this,
456
                                        SaveEvent.BEFORE_SAVING, file));
457
                        p.saveState(file);
458
                        fireAfterSavingFileEvent(new SaveEvent(this,
459
                                        SaveEvent.AFTER_SAVING, file));
460

    
461
                        PluginServices.getMainFrame().setTitle(file.getName());
462
                        setPath(file.toString());
463

    
464
                } catch (PersistenceException e) {
465
                        String messagestack = e.getLocalizedMessageStack();
466
                        NotificationManager.addError(
467
                                        PluginServices.getText(this, "error_writing_project")
468
                                                        + ": " + file.getName() + "\n" + messagestack, e);
469
                        return false;
470
                } catch (Exception e) {
471
                        NotificationManager.addError(
472
                                        PluginServices.getText(this, "error_writing_project")
473
                                                        + ": " + file.getName(), e);
474
                        return false;
475
                }
476
                NotificationManager.addInfo(PluginServices.getText(this,
477
                                "wrote_project") + ": " + file.getName());
478
                return true;
479
        }
480

    
481
        public Project readProject(String path) {
482
                Project project = ProjectManager.getInstance().createProject();
483

    
484
                project.loadState(new File(path));
485
                return (Project) project;
486
        }
487

    
488
        /**
489
         * Lee del XML el proyecto.<br>
490
         * <br>
491
         * 
492
         * Reads the XML of the project.<br>
493
         * It returns a project object holding all needed info that is not linked to
494
         * the Project Dialog. <br>
495
         * In case you want the project to be linked to the window you must set this
496
         * object to the extension:<br>
497
         * 
498
         * <b>Example:</b><br>
499
         * 
500
         * ...<br>
501
         * ...<br>
502
         * Project p = ProjectExtension.readProject(projectFile);<br>
503
         * ProjectExtension.setProject(p); ...<br>
504
         * ...<br>
505
         * 
506
         * @param file
507
         *            Fichero.
508
         * 
509
         * @return Project
510
         * 
511
         */
512
        public Project readProject(File file) {
513
                Project project = ProjectManager.getInstance().createProject();
514

    
515
                project.loadState(file);
516
                return (Project) project;
517
        }
518

    
519
        /**
520
         * Devuelve el proyecto.
521
         * 
522
         * @return Proyecto.
523
         */
524
        public Project getProject() {
525
                return p;
526
        }
527

    
528
        /**
529
         * @see org.gvsig.andami.plugins.IExtension#isEnabled()
530
         */
531
        public boolean isEnabled() {
532
                return true;
533
        }
534

    
535
        /**
536
         * @see org.gvsig.andami.plugins.IExtension#isVisible()
537
         */
538
        public boolean isVisible() {
539
                return true;
540
        }
541

    
542
        /**
543
         * Sets the project
544
         * 
545
         * @param p
546
         */
547
        public void setProject(Project p) {
548
                getProjectFrame().setProject(p);
549
                this.p = p;
550
        }
551

    
552
        private void registerDocuments() {
553
                ViewManager.register();
554
        }
555

    
556
        private void initializeDocumentActionsExtensionPoint() {
557
                ExtensionPointManager epMan = ToolsLocator.getExtensionPointManager();
558
                epMan.add(
559
                                "DocumentActions_View",
560
                                "Context menu options of the view document list"
561
                                                + " in the project window "
562
                                                + "(register instances of "
563
                                                + "org.gvsig.app.project.AbstractDocumentContextMenuAction)");
564
        }
565

    
566
        public static String getPath() {
567
                return projectPath;
568
        }
569

    
570
        public static void setPath(String path) {
571
                projectPath = path;
572
        }
573

    
574
        public IWindow getProjectWindow() {
575
                return getProjectFrame();
576
        }
577

    
578
        public IExtensionStatus getStatus() {
579
                return this;
580
        }
581

    
582
        public boolean hasUnsavedData() {
583
                return p.hasChanged();
584
        }
585

    
586
        public IUnsavedData[] getUnsavedData() {
587
                if (hasUnsavedData()) {
588
                        UnsavedProject data = new UnsavedProject(this);
589
                        IUnsavedData[] dataArray = { data };
590
                        return dataArray;
591
                } else {
592
                        return null;
593
                }
594
        }
595

    
596
        /**
597
         * Implements the IUnsavedData interface to show unsaved projects in the
598
         * Unsavad Data dialog.
599
         * 
600
         * @author Cesar Martinez Izquierdo <cesar.martinez@iver.es>
601
         */
602
        public class UnsavedProject extends UnsavedData {
603

    
604
                public UnsavedProject(IExtension extension) {
605
                        super(extension);
606
                }
607

    
608
                public String getDescription() {
609
                        if (getPath() == null) {
610
                                return PluginServices.getText(ProjectExtension.this,
611
                                                "Unnamed_new_gvsig_project_");
612
                        } else {
613
                                return PluginServices.getText(ProjectExtension.this,
614
                                                "Modified_project_");
615
                        }
616
                }
617

    
618
                public String getResourceName() {
619
                        if (getPath() == null) {
620
                                return PluginServices.getText(ProjectExtension.this, "Unnamed");
621
                        } else {
622
                                return getPath();
623
                        }
624

    
625
                }
626

    
627
                public boolean saveData() {
628
                        return saveProject();
629
                }
630

    
631
                public String getIcon() {
632
                        return "project-icon";
633
                }
634
        }
635

    
636
        public IMonitorableTask[] getRunningProcesses() {
637
                // TODO Auto-generated method stub
638
                return null;
639
        }
640

    
641
        public boolean hasRunningProcesses() {
642
                // TODO Auto-generated method stub
643
                return false;
644
        }
645

    
646
        /**
647
         * Adds the specified before saving listener to receive
648
         * "before saving file events" from this component. If l is null, no
649
         * exception is thrown and no action is performed.
650
         * 
651
         * @author Pablo Piqueras Bartolom? <pablo.piqueras@iver.es>
652
         * 
653
         * @param l
654
         *            the before saving listener.
655
         * @see SaveEvent
656
         * @see BeforeSavingListener
657
         * @see #removeListener(BeforeSavingListener)
658
         * @see #getBeforeSavingListeners
659
         */
660
        public synchronized void addListener(BeforeSavingListener l) {
661
                if (l == null) {
662
                        return;
663
                }
664
                if (!this.beforeSavingListeners.contains(l)) {
665
                        this.beforeSavingListeners.add(l);
666
                }
667
        }
668

    
669
        /**
670
         * Adds the specified after saving listener to receive
671
         * "after saving file events" from this component. If l is null, no
672
         * exception is thrown and no action is performed.
673
         * 
674
         * @author Pablo Piqueras Bartolom? <pablo.piqueras@iver.es>
675
         * 
676
         * @param l
677
         *            the after saving listener.
678
         * @see SaveEvent
679
         * @see AfterSavingListener
680
         * @see #removeListener(AfterSavingListener)
681
         * @see #getAfterSavingListeners()
682
         */
683
        public synchronized void addListener(AfterSavingListener l) {
684
                if (l == null) {
685
                        return;
686
                }
687

    
688
                if (!this.afterSavingListeners.contains(l)) {
689
                        this.afterSavingListeners.add(l);
690
                }
691

    
692
        }
693

    
694
        /**
695
         * Returns an array of all the before saving listeners registered on this
696
         * component.
697
         * 
698
         * @author Pablo Piqueras Bartolom? <pablo.piqueras@iver.es>
699
         * 
700
         * @return all of this component's <code>BeforeSavingListener</code>s or an
701
         *         empty array if no key listeners are currently registered
702
         * 
703
         * @see #addBeforeSavingListener(BeforeSavingListener)
704
         * @see #removeBeforeSavingListener(BeforeSavingListener)
705
         */
706
        public synchronized BeforeSavingListener[] getBeforeSavingListeners() {
707
                return this.beforeSavingListeners
708
                                .toArray(new BeforeSavingListener[] {});
709
        }
710

    
711
        /**
712
         * Returns an array of all the after saving listeners registered on this
713
         * component.
714
         * 
715
         * @author Pablo Piqueras Bartolom? <pablo.piqueras@iver.es>
716
         * 
717
         * @return all of this component's <code>AfterSavingListener</code>s or an
718
         *         empty array if no key listeners are currently registered
719
         * 
720
         * @see #addAfterSavingListener(AfterSavingListener)
721
         * @see #removeAfterSavingListener
722
         */
723
        public synchronized AfterSavingListener[] getAfterSavingListeners() {
724
                return this.afterSavingListeners.toArray(new AfterSavingListener[] {});
725

    
726
        }
727

    
728
        /**
729
         * Removes the specified before saving listener so that it no longer
730
         * receives save file events from this component. This method performs no
731
         * function, nor does it throw an exception, if the listener specified by
732
         * the argument was not previously added to this component. If listener
733
         * <code>l</code> is <code>null</code>, no exception is thrown and no action
734
         * is performed.
735
         * 
736
         * @author Pablo Piqueras Bartolom? <pablo.piqueras@iver.es>
737
         * 
738
         * @param l
739
         *            the before saving listener
740
         * @see SaveEvent
741
         * @see BeforeSavingListener
742
         * @see #addListener(BeforeSavingListener)
743
         * @see #getBeforeSavingListeners()
744
         */
745
        public synchronized void removeListener(BeforeSavingListener l) {
746
                if (l == null) {
747
                        return;
748
                }
749

    
750
                this.beforeSavingListeners.remove(l);
751
        }
752

    
753
        /**
754
         * Removes the specified after saving listener so that it no longer receives
755
         * save file events from this component. This method performs no function,
756
         * nor does it throw an exception, if the listener specified by the argument
757
         * was not previously added to this component. If listener <code>l</code> is
758
         * <code>null</code>, no exception is thrown and no action is performed.
759
         * 
760
         * @author Pablo Piqueras Bartolom? <pablo.piqueras@iver.es>
761
         * 
762
         * @param l
763
         *            the after saving listener
764
         * @see SaveEvent
765
         * @see AfterSavingListener
766
         * @see #addListener(AfterSavingListener)
767
         * @see #getAfterSavingListeners()
768
         */
769
        public synchronized void removeListener(AfterSavingListener l) {
770
                if (l == null) {
771
                        return;
772
                }
773

    
774
                this.afterSavingListeners.remove(l);
775
        }
776

    
777
        /**
778
         * Reports a before saving file event.
779
         * 
780
         * @author Pablo Piqueras Bartolom? <pablo.piqueras@iver.es>
781
         * 
782
         * @param evt
783
         *            the before saving file event
784
         */
785
        protected void fireBeforeSavingFileEvent(SaveEvent evt) {
786
                if ((evt.getID() != SaveEvent.BEFORE_SAVING) || (evt.getFile() == null)) {
787
                        return;
788
                }
789

    
790
                Iterator<BeforeSavingListener> iter = this.beforeSavingListeners
791
                                .iterator();
792

    
793
                while (iter.hasNext()) {
794
                        iter.next().beforeSaving(evt);
795
                }
796
        }
797

    
798
        /**
799
         * Reports a after saving file event.
800
         * 
801
         * @author Pablo Piqueras Bartolom? <pablo.piqueras@iver.es>
802
         * 
803
         * @param evt
804
         *            the after saving file event
805
         */
806
        protected void fireAfterSavingFileEvent(SaveEvent evt) {
807
                if ((evt.getID() != SaveEvent.AFTER_SAVING) || (evt.getFile() == null)) {
808
                        return;
809
                }
810
                Iterator<AfterSavingListener> iter = this.afterSavingListeners
811
                                .iterator();
812

    
813
                while (iter.hasNext()) {
814
                        iter.next().afterSaving(evt);
815
                }
816

    
817
        }
818
}