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 / DefaultProject.java @ 43976

History | View | Annotate | Download (42 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 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
 *
11
 * 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
 *
16
 * 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
 *
20
 * For any additional information, do not hesitate to contact us at info AT
21
 * gvsig.com, or visit our website www.gvsig.com.
22
 */
23
package org.gvsig.app.project;
24

    
25
import java.awt.Color;
26
import java.awt.Image;
27
import java.awt.geom.AffineTransform;
28
import java.awt.image.AffineTransformOp;
29
import java.awt.image.BufferedImage;
30
import java.beans.PropertyChangeEvent;
31
import java.beans.PropertyChangeListener;
32
import java.beans.PropertyChangeSupport;
33
import java.io.File;
34
import java.io.FileInputStream;
35
import java.io.FileNotFoundException;
36
import java.io.FileOutputStream;
37
import java.io.IOException;
38
import java.io.InputStream;
39
import java.io.OutputStream;
40
import java.io.Serializable;
41
import java.text.DateFormat;
42
import java.text.MessageFormat;
43
import java.util.ArrayList;
44
import java.util.Collections;
45
import java.util.Date;
46
import java.util.HashMap;
47
import java.util.HashSet;
48
import java.util.Iterator;
49
import java.util.List;
50
import java.util.Map;
51
import java.util.Set;
52
import java.util.logging.Level;
53
import java.util.zip.ZipEntry;
54
import java.util.zip.ZipException;
55
import java.util.zip.ZipFile;
56
import java.util.zip.ZipOutputStream;
57
import javax.imageio.ImageIO;
58
import org.apache.commons.io.IOUtils;
59

    
60
import org.cresques.cts.IProjection;
61

    
62
import org.gvsig.andami.PluginServices;
63
import org.gvsig.andami.ui.mdiManager.IWindow;
64
import org.gvsig.andami.ui.mdiManager.MDIManager;
65
import org.gvsig.andami.ui.mdiManager.SingletonWindow;
66
import org.gvsig.andami.ui.mdiManager.WindowInfo;
67
import org.gvsig.app.ApplicationLocator;
68
import org.gvsig.app.ApplicationManager;
69
import org.gvsig.app.extension.ProjectExtension;
70
import org.gvsig.app.extension.Version;
71
import org.gvsig.app.project.ProjectManager.NewProjectEvent;
72
import org.gvsig.app.project.documents.AbstractDocument;
73
import org.gvsig.app.project.documents.Document;
74
import org.gvsig.app.project.documents.exceptions.SaveException;
75
import org.gvsig.app.project.documents.gui.IDocumentWindow;
76
import org.gvsig.app.project.documents.gui.ProjectWindow;
77
import org.gvsig.app.project.documents.view.DefaultViewDocument;
78
import org.gvsig.app.project.documents.view.ViewManager;
79
import org.gvsig.fmap.mapcontext.MapContext;
80
import org.gvsig.fmap.mapcontext.layers.ExtendedPropertiesHelper;
81
import org.gvsig.fmap.mapcontext.layers.FLayer;
82
import org.gvsig.fmap.mapcontext.layers.FLayers;
83
import org.gvsig.tools.ToolsLocator;
84
import org.gvsig.tools.dynobject.DynStruct;
85
import org.gvsig.tools.observer.ObservableHelper;
86
import org.gvsig.tools.observer.Observer;
87
import org.gvsig.tools.persistence.PersistenceManager;
88
import org.gvsig.tools.persistence.Persistent;
89
import org.gvsig.tools.persistence.PersistentContext;
90
import org.gvsig.tools.persistence.PersistentState;
91
import org.gvsig.tools.persistence.exception.PersistenceException;
92
import org.gvsig.utils.StringUtilities;
93
import org.gvsig.utils.save.SaveEvent;
94

    
95
import org.slf4j.Logger;
96
import org.slf4j.LoggerFactory;
97

    
98
/**
99
 * Clase que representa un proyecto de gvSIG
100
 *
101
 */
102
public class DefaultProject implements Serializable, PropertyChangeListener,
103
        Project {
104

    
105
    private Logger LOG = LoggerFactory.getLogger(DefaultProject.class);
106
    /**
107
     * @deprecated see ApplicationLocator.getManager().getVersion()
108
     */
109
    public static String VERSION = Version.format();
110

    
111
    private ExtendedPropertiesHelper propertiesHelper = new ExtendedPropertiesHelper();
112

    
113
    private ObservableHelper observableHelper = new ObservableHelper();
114

    
115
    /**
116
     *
117
     */
118
    private static final long serialVersionUID = -4449622027521773178L;
119

    
120
    private static final Logger logger = LoggerFactory.getLogger(Project.class);
121

    
122
    private static ProjectPreferences preferences = new ProjectPreferences();
123

    
124
    /**
125
     * Index used by the generator of unique names of documents.
126
     */
127
    private Map<String, Integer> nextDocumentIndexByType = new HashMap<String, Integer>();
128

    
129
    private PropertyChangeSupport change;
130

    
131
    private boolean modified = false;
132

    
133
    private String name = null;
134

    
135
    private String creationDate = null;
136

    
137
    private String modificationDate = null;
138

    
139
    private String owner = null;
140

    
141
    private String comments = null;
142

    
143
    private Color selectionColor = null;
144

    
145
    private List<Document> documents = null;
146

    
147
    private List<ProjectExtent> extents = null;
148

    
149
    private IProjection projection;
150

    
151
    private File fname = null;
152

    
153
    private Set<String> unloadedObjects;
154
    private PersistenceException loadErrors = null;
155

    
156
    /**
157
     * Creates a new Project object.
158
     */
159
    DefaultProject() {
160
        this.change = new PropertyChangeSupport(this);
161
        this.clean();
162
        ProjectManager.getInstance().notifyProjectEvent(new NewProjectEvent() {
163
            @Override
164
            public Project getProject() {
165
                return DefaultProject.this;
166
            }
167
        });
168
    }
169

    
170
    protected void clean() {
171
        this.owner = "";
172
        this.comments = "";
173
        this.name = PluginServices.getText(this, "untitled");
174
        this.creationDate = DateFormat.getDateInstance().format(new Date());
175
        this.modificationDate = this.creationDate;
176

    
177
        this.documents = new ArrayList<Document>();
178
        this.extents = new ArrayList<ProjectExtent>();
179

    
180
        this.setSelectionColor(getPreferences().getDefaultSelectionColor());
181

    
182
        this.projection = null; // se inicializa en el getProjection()
183
    }
184

    
185
    public static ProjectPreferences getPreferences() {
186
        return preferences;
187
    }
188

    
189
    public void propertyChange(PropertyChangeEvent evt) {
190
        change.firePropertyChange(evt);
191
    }
192

    
193
    @Override
194
    public synchronized void addPropertyChangeListener(
195
            PropertyChangeListener arg0) {
196
        change.addPropertyChangeListener(arg0);
197
    }
198

    
199
    @Override
200
    public void removePropertyChangeListener(PropertyChangeListener listener) {
201
        change.removePropertyChangeListener(listener);
202
    }
203
    
204
    /**
205
     * Return the creation date of the project
206
     *
207
     * @return
208
     */
209
    public String getCreationDate() {
210
        return creationDate;
211
    }
212

    
213
    protected void setCreationDate(String creationDate) {
214
        this.creationDate = creationDate;
215
        change.firePropertyChange("setCreationDate", null, null);
216
    }
217

    
218
    public Document createDocument(String type) {
219
        logger.info("createDocument('{}')", type);
220
        return ProjectManager.getInstance().createDocument(type);
221
    }
222

    
223
    /**
224
     * Return the name of the project
225
     *
226
     * @return
227
     */
228
    public String getName() {
229
        return name;
230
    }
231

    
232
    /**
233
     * Set the name of he project.
234
     *
235
     * @param string
236
     */
237
    public void setName(String name) {
238
        this.name = name;
239
        change.firePropertyChange("setName", null, null);
240
    }
241

    
242
    /**
243
     * Return the comments associateds with the project
244
     *
245
     * @return comments
246
     */
247
    public String getComments() {
248
        return comments;
249
    }
250

    
251
    /**
252
     * Set the comments associateds with the project
253
     *
254
     * @param comments as string
255
     */
256
    public void setComments(String string) {
257
        comments = string;
258
        change.firePropertyChange("setComments", null, null);
259
    }
260

    
261
    /**
262
     * Retuen the modification date of the project.
263
     *
264
     * @return modification date as string
265
     */
266
    public String getModificationDate() {
267
        return modificationDate;
268
    }
269

    
270
    protected void setModificationDate(String string) {
271
        modificationDate = string;
272
        change.firePropertyChange("setModificationDate", null, null);
273
    }
274

    
275
    /**
276
     * Return the author of the project,
277
     *
278
     * @return author as string
279
     */
280
    public String getOwner() {
281
        return owner;
282
    }
283

    
284
    /**
285
     * Sets the author of the project
286
     *
287
     * @param author name as string
288
     */
289
    public void setOwner(String owner) {
290
        this.owner = owner;
291
        change.firePropertyChange("setOwner", null, null);
292
    }
293

    
294
    /**
295
     * Obtiene el color de selecci�n que se usar� en el proyecto
296
     *
297
     * @return
298
     */
299
    public Color getSelectionColor() {
300
        if (selectionColor == null) {
301
            selectionColor = getPreferences().getDefaultSelectionColor();
302
        }
303
        return selectionColor;
304
    }
305

    
306
    /**
307
     * Sets the selecction color
308
     *
309
     * @param selection color as string
310
     */
311
    public void setSelectionColor(String selectionColor) {
312
        this.setSelectionColor(StringUtilities.string2Color(selectionColor));
313
    }
314

    
315
    /**
316
     * Sets the selecction color
317
     *
318
     * @param selection color as Color
319
     */
320
    public void setSelectionColor(Color selectionColor) {
321
        this.selectionColor = selectionColor;
322
        MapContext.setSelectionColor(selectionColor);
323
        change.firePropertyChange("selectionColor", null, selectionColor);
324
    }
325

    
326
    public IProjection getProjection() {
327
        if (projection == null) {
328
            projection = getPreferences().getDefaultProjection();
329
        }
330
        return projection;
331
    }
332

    
333
    public void setProjection(IProjection projection) {
334
        this.projection = projection;
335
    }
336

    
337
    /**
338
     * Sets the modified state of project.
339
     *
340
     * Can't set to not modified.
341
     *
342
     * @param modified as boolean
343
     */
344
    public void setModified(boolean modified) {
345
        this.modified = modified;
346
        if (modified == false) {
347
            List<Document> documents = this.getDocuments();
348
            for (int i = 0; i < documents.size(); i++) {
349
                documents.get(i).setModified(false);
350
            }
351
        }
352
    }
353

    
354
    public boolean hasChanged() {
355
                // we return true if the project is not empty (until we have a better
356
        // method...)
357
        if ((this.getDocuments().size() != 0) || modified) {
358
            return true;
359
        }
360
        return false;
361
    }
362

    
363
    /**
364
     * Return a list of documents in the project.
365
     *
366
     * @return documents as List of IProjectDocument
367
     */
368
    public List<Document> getDocuments() {
369
        return Collections.unmodifiableList(documents);
370
    }
371

    
372
    /**
373
     * Return a list with all documents of especified type.
374
     *
375
     * @param type of document
376
     *
377
     * @return List of IProjectDocument
378
     */
379
    public List<Document> getDocuments(String type) {
380
        List<Document> docs = new ArrayList<Document>();
381
        if (type != null) {
382
            for (Document document : this.documents) {
383
                if (type.equalsIgnoreCase(document.getTypeName())) {
384
                    docs.add(document);
385
                }
386
            }
387
        }
388
        return Collections.unmodifiableList(docs);
389
    }
390

    
391
    /**
392
     * Adds a document to the project
393
     *
394
     * @param document as Document
395
     */
396
    public void add(Document document) {
397
        this.addDocument(document);
398
    }
399

    
400
    public void addDocument(Document document) {
401
        logger.info("add('{}')", document.toString());
402

    
403
        if (notifyObservers(ProjectNotification.BEFORE_ADD_DOCUMENT, document).isProcessCanceled()) {
404
            return;
405
        }
406
        document.addPropertyChangeListener(this);
407
        document.setProject(this);
408
        document.setName(this.getUniqueNameForDocument(document.getTypeName(),
409
                document.getName()));
410
        documents.add(document);
411
        document.afterAdd();
412
        this.setModified(true);
413
        notifyObservers(ProjectNotification.AFTER_ADD_DOCUMENT, document);
414
        change.firePropertyChange("addDocument", null, document);
415
    }
416

    
417
    public void remove(Document doc) {
418
        this.removeDocument(doc);
419
    }
420

    
421
    public void removeDocument(Document doc) {
422
        logger.info("remove('{}')", doc.toString());
423
        if (notifyObservers(ProjectNotification.BEFORE_REMOVE_DOCUMENT, doc).isProcessCanceled()) {
424
            return;
425
        }
426
        documents.remove(doc);
427
        this.setModified(true);
428
        change.firePropertyChange("delDocument", doc, null);
429
        doc.afterRemove();
430
        notifyObservers(ProjectNotification.AFTER_REMOVE_DOCUMENT, doc);
431
    }
432

    
433
    public Iterator<Document> iterator() {
434
        return documents.iterator();
435
    }
436

    
437
    public boolean isEmpty() {
438
        return documents.isEmpty();
439
    }
440

    
441
    /**
442
     * Return the view that contains the especified layer.
443
     *
444
     * @param layer
445
     *
446
     * @return name of the view that contains the layer
447
     *
448
     * @throws RuntimeException Si la capa que se pasa como par�metro no se
449
     * encuentra en ninguna vista
450
     */
451
    public String getViewName(FLayer layer) {
452
        List<Document> views = getDocuments(ViewManager.TYPENAME);
453
        for (int v = 0; v < views.size(); v++) {
454
            DefaultViewDocument pView = (DefaultViewDocument) views.get(v);
455
            FLayers layers = pView.getMapContext().getLayers();
456
            if (isView(layers, layer)) {
457
                return pView.getName();
458
            }
459
        }
460

    
461
        throw new RuntimeException(MessageFormat.format(
462
                "The layer '{1}' is not in a view", layer.getName()));
463
    }
464

    
465
    private boolean isView(FLayers layers, FLayer layer) {
466
        for (int i = 0; i < layers.getLayersCount(); i++) {
467
            if (layers.getLayer(i) instanceof FLayers) {
468
                if (isView((FLayers) layers.getLayer(i), layer)) {
469
                    return true;
470
                }
471
            }
472
            if (layers.getLayer(i) == layer) {
473
                return true;
474
            }
475
        }
476
        return false;
477
    }
478

    
479
    public void addExtent(ProjectExtent arg1) {
480
        extents.add(arg1);
481
        change.firePropertyChange("addExtent", null, null);
482
    }
483

    
484
    public ProjectExtent removeExtent(int arg0) {
485
        change.firePropertyChange("delExtent", null, null);
486
        return extents.remove(arg0);
487
    }
488

    
489
    public ProjectExtent[] getExtents() {
490
        return (ProjectExtent[]) extents.toArray(new ProjectExtent[0]);
491
    }
492

    
493
    /**
494
     * Obtiene un documento a partir de su nombre y el nombre de registro en el
495
     * pointExtension, este �ltimo se puede obtener del
496
     * Project****Factory.registerName.
497
     *
498
     * @param name Nombre del documento
499
     * @param type nombre de registro en el extensionPoint
500
     *
501
     * @return Documento
502
     */
503
    public Document getDocument(String name, String type) {
504
        if (type == null) {
505
            for (int i = 0; i < documents.size(); i++) {
506
                Document document = documents.get(i);
507
                if ( name.equalsIgnoreCase(document.getName())) {
508
                    return document;
509
                }
510
            }
511
        } else {
512
            for (int i = 0; i < documents.size(); i++) {
513
                Document document = documents.get(i);
514
                if (type.equalsIgnoreCase(document.getTypeName())
515
                        && name.equalsIgnoreCase(document.getName())) {
516
                    return document;
517
                }
518
            }
519
        }
520
        return null;
521
    }
522

    
523
    public Document getDocument(String name) {
524
        return this.getDocument(name, null);
525
    }
526

    
527
    public String getUniqueNameForDocument(String type, String name) {
528
        Document document = getDocument(name, type);
529
        if (document == null) {
530
            return name;
531
        }
532

    
533
        String newName = null;
534
        int num = this.getNextDocumentIndex(type);
535
        while (document != null) {
536
            newName = name + " - " + num++;
537
            document = getDocument(newName, type);
538
        }
539
        this.setNextDocumentIndex(type, num);
540
        return newName;
541
    }
542

    
543
    private int getNextDocumentIndex(String type) {
544
        if (nextDocumentIndexByType.get(type) == null) {
545
            nextDocumentIndexByType.put(type, new Integer(1));
546
            return 1;
547
        }
548
        return nextDocumentIndexByType.get(type).intValue();
549
    }
550

    
551
    private void setNextDocumentIndex(String type, int newIndex) {
552
        if (nextDocumentIndexByType.get(type) == null) {
553
            nextDocumentIndexByType.put(type, new Integer(newIndex));
554
        } else {
555
            nextDocumentIndexByType.put(type, new Integer(newIndex));
556
        }
557
    }
558

    
559
    public void saveState(File out) throws PersistenceException {
560
        FileOutputStream fout;
561
        if (notifyObservers(ProjectNotification.BEFORE_SAVE_TO_FILE, out).isProcessCanceled()) {
562
            return;
563
        }
564
        try {
565
            fout = new FileOutputStream(out);
566
            saveState(fout, new File(out.getParent()));
567
        } catch (FileNotFoundException e) {
568
            throw new PersistenceException(e);
569
        }
570
        if( !isValidZIP(out) ) {
571
            throw new PersistenceException(new ZipException());
572
        }
573
        this.fname = out;
574
        notifyObservers(ProjectNotification.AFTER_SAVE_TO_FILE, out);
575
    }
576

    
577
    boolean isValidZIP(final File file) {
578
        ZipFile zipfile = null;
579
        try {
580
            zipfile = new ZipFile(file);
581
            return true;
582
        } catch (IOException e) {
583
            return false;
584
        } finally {
585
            try {
586
                if (zipfile != null) {
587
                    zipfile.close();
588
                    zipfile = null;
589
                }
590
            } catch (IOException e) {
591
            }
592
        }
593
    }
594
   
595
    @Override
596
    public File getFile() {
597
        return this.fname;
598
    }
599

    
600
    @Deprecated
601
    @Override
602
    public void saveState(OutputStream out) throws PersistenceException {
603
        saveState(out, null);
604
    }
605
    
606
    @Override
607
    public void saveState(File file, BufferedImage preview) {
608
        FileOutputStream fout=null;
609
        ZipOutputStream zout=null;
610
        try {
611
            fout = new FileOutputStream(file);
612
            zout = new ZipOutputStream(fout);
613
            this.saveState(zout, file.getParentFile());
614

    
615
            zout.putNextEntry(new ZipEntry("preview.jpg"));
616
            try {
617
                ImageIO.write(preview, "jpg", zout);
618
            } catch (IOException ex) {
619
                LOG.warn("Can't save preview image'.", ex);
620
            }
621
            IOUtils.closeQuietly(zout);
622
            IOUtils.closeQuietly(fout);
623

    
624
            if( !isValidZIP(file) ) {
625
                throw new ZipException("Invalid project file '"+file.getAbsolutePath()+"'");
626
            }
627
            this.fname = file;
628
        } catch (Exception ex) {
629
            throw new RuntimeException("Can't write project in '"+file.getAbsolutePath()+".",ex);
630
        } finally {
631
            IOUtils.closeQuietly(zout);
632
            IOUtils.closeQuietly(fout);            
633
        }
634
    }
635
    
636
    @Override
637
    public void saveState(OutputStream out, File rootFolder)
638
            throws PersistenceException {
639
        if (notifyObservers(ProjectNotification.BEFORE_SAVE_TO_STREAM, rootFolder).isProcessCanceled()) {
640
            return;
641
        }
642
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
643
        PersistentState state = null;
644
        state = manager.getState(this, true);
645
        try {
646
            if (rootFolder != null) {
647
                state.relativizeFiles(rootFolder);
648
            }
649
        } catch (Exception ex) {
650
            state.getContext().addError(ex);
651
        }
652
        manager.saveState(state, out, true);
653
        if (state.getContext().getErrors() != null) {
654
            throw state.getContext().getErrors();
655
        }
656
        this.fname = null;
657
        notifyObservers(ProjectNotification.AFTER_SAVE_TO_STREAM, rootFolder);
658
    }
659

    
660
    @Deprecated
661
    public void loadState(InputStream in) {
662
        loadState(in, null);
663
    }
664

    
665
    public void loadState(InputStream in, File rootFolder) {
666
        if (notifyObservers(ProjectNotification.BEFORE_LOAD_FROM_STREAM, rootFolder).isProcessCanceled()) {
667
            return;
668
        }
669
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
670
        try {
671
            PersistentContext context = manager.getNewContext();
672
            context.setCollectErrors(true);
673
            PersistentState state = manager.loadState(in, context);
674
            try {
675
                if (rootFolder != null) {
676
                    state.derelativizeFiles(rootFolder);
677
                }
678
            } catch (Exception ex) {
679
                state.getContext().addError(ex);
680
            }
681
            this.loadFromState(state);
682
            this.unloadedObjects = getUnloadedObjects(state.getContext());
683
            this.loadErrors = state.getContext().getErrors();
684

    
685
        } catch (PersistenceException e) {
686
            LOG.info("Can't load project to stream", e);
687
        }
688
        this.fname = null;
689
        notifyObservers(ProjectNotification.AFTER_LOAD_FROM_STREAM, rootFolder);
690

    
691
    }
692

    
693

    
694

    
695
    /**
696
     * @param context
697
     * @return
698
     */
699
    private Set<String> getUnloadedObjects(PersistentContext context) {
700
        Set unloadedObjects = new HashSet();
701

    
702
        Iterator statesIterator = context.iterator();
703
        String className = null;
704

    
705
        while (statesIterator.hasNext()) {
706
            PersistentState aState = (PersistentState) statesIterator.next();
707
            try {
708
                className = aState.getTheClassName();
709
                DynStruct definition = aState.getDefinition();
710
                if (definition == null) {
711
                    unloadedObjects.add(className);
712
                }
713
            } catch (Throwable e) {
714
                // do nothing
715
            }
716
        }
717

    
718
        if(unloadedObjects.isEmpty()){
719
            return null;
720
        }
721

    
722
        return unloadedObjects;
723
    }
724

    
725
    @Override
726
    public Set<String> getUnloadedObjects() {
727
        return this.unloadedObjects;
728
    }
729

    
730
    @Override
731
    public List<Exception> getLoadErrors() {
732
        return this.loadErrors;
733
    }
734
    
735
    @Override
736
    public void loadState(File in) {
737
        if (notifyObservers(ProjectNotification.BEFORE_LOAD_FROM_FILE, in).isProcessCanceled()) {
738
            return;
739
        }
740
        FileInputStream fin;
741
        try {
742
            fin = new FileInputStream(in);
743
            loadState(fin, new File(in.getParent()));
744
        } catch (FileNotFoundException e) {
745
            LOG.info("Can't load project to stream", e);
746
        }
747
        this.fname = in;
748
        notifyObservers(ProjectNotification.AFTER_LOAD_FROM_FILE, in);
749
    }
750

    
751
    //@SuppressWarnings("unchecked")
752
    @Override
753
    public void loadFromState(PersistentState state)
754
            throws PersistenceException {
755
        this.clean();
756
        PersistentContext context = state.getContext();
757
        
758
        notifyObservers(ProjectNotification.BEFORE_LOAD_FROM_STATE, state);
759

    
760
        this.setComments(state.getString("comments"));
761
        this.setCreationDate(state.getString("creationDate"));
762
        this.setModificationDate(state.getString("modificationDate"));
763
        this.setName(state.getString("name"));
764
        this.setOwner(state.getString("owner"));
765
        this.setSelectionColor((Color) state.get("selectionColor"));
766
        this.setProjection((IProjection) state.get("projection"));
767

    
768
        this.propertiesHelper = (ExtendedPropertiesHelper) state.get("propertiesHelper");
769

    
770
        List<ProjectExtent> extents = (List<ProjectExtent>) state
771
                .get("extents");
772
        for (int i = 0; i < extents.size(); i++) {
773
            this.addExtent(extents.get(i));
774
        }
775

    
776
        List<AbstractDocument> documents = (List<AbstractDocument>) state
777
                .get("documents");
778
        for (int i = 0; i < documents.size(); i++) {
779
            AbstractDocument doc = documents.get(i);
780
            if( doc != null ) {
781
                this.add(doc);
782
            }
783
        }
784

    
785
        try {
786
            List<DocumentWindowInfo> persistentWindows = (List<DocumentWindowInfo>) state.get("documentWindowsInformation");
787

    
788
            for (int i = 0; i < persistentWindows.size(); i++) {
789
                try {
790
                    DocumentWindowInfo persistentWindow = persistentWindows.get(i);
791
                    String docName = persistentWindow.getDocumentName();
792
                    String docType = persistentWindow.getDocumentType();
793
                    Document doc = this.getDocument(docName, docType);
794
                    IWindow win = doc.getFactory().getMainWindow(doc);
795
                    if(win!=null){
796
                        win.getWindowInfo().setWindowInfo(persistentWindow.getWindowInfo());
797
                        PluginServices.getMDIManager().addWindow(win);
798
                    }
799
                } catch(Exception ex) {
800
                    if( !context.getCollectErrors() ) {
801
                        throw ex;
802
                    }
803
                    context.addError(ex);
804
                }
805
            }
806

    
807
            if (state.hasValue("projectWindowInfo")) {
808
                WindowInfo projectWindowInfo = (WindowInfo) state.get("projectWindowInfo");
809
                ProjectExtension pe = (ProjectExtension) PluginServices.getExtension(org.gvsig.app.extension.ProjectExtension.class);
810
                pe.setProject(this);
811
                pe.showProjectWindow(projectWindowInfo);
812
            }
813
        } catch(Exception ex) {
814
            if( !context.getCollectErrors() ) {
815
                throw ex;
816
            }
817
            context.addError(ex);
818
        }
819
        notifyObservers(ProjectNotification.AFTER_LOAD_FROM_STATE, state);
820
    }
821

    
822
    public void saveToState(PersistentState state) throws PersistenceException {
823
        state.set("version", VERSION);
824
        state.set("comments", getComments());
825
        state.set("creationDate", this.getCreationDate());
826

    
827
        state.set("modificationDate", this.getModificationDate());
828
        state.set("name", this.getName());
829
        state.set("owner", this.getOwner());
830
        state.set("selectionColor", this.getSelectionColor());
831

    
832
        state.set("projection", this.getProjection());
833

    
834
        state.set("extents", this.extents);
835
        List<Document> docs = this.getDocuments();
836
        List<Document> noTempDocs = new ArrayList<Document>();
837
        for (Iterator iterator = docs.iterator(); iterator.hasNext();) {
838
            Document document = (Document) iterator.next();
839
            if(!document.isTemporary()){
840
                noTempDocs.add(document);
841
            }
842
        }
843
        state.set("documents", noTempDocs);
844

    
845
        state.set("propertiesHelper",propertiesHelper);
846

    
847
        List<DocumentWindowInfo> persistentWindows = new ArrayList<DocumentWindowInfo>();
848
        MDIManager mdiMan = PluginServices.getMDIManager();
849
        IWindow[] windows = mdiMan.getOrderedWindows();
850
        for (int i = windows.length - 1; i >= 0; i--) {
851
            IWindow window = windows[i];
852
            if (window instanceof IDocumentWindow) {
853
                WindowInfo wi = mdiMan.getWindowInfo(window);
854
                DocumentWindowInfo dwi = new DocumentWindowInfo(
855
                        wi,
856
                        ((IDocumentWindow) window).getDocument().getTypeName(),
857
                        ((IDocumentWindow) window).getDocument().getName());
858
                persistentWindows.add(dwi);
859
            } else if (window instanceof ProjectWindow) {
860
                state.set("projectWindowInfo", mdiMan.getWindowInfo(window));
861
            }
862
        }
863
        state.set("documentWindowsInformation", persistentWindows);
864

    
865
    }
866

    
867
    public Object getProperty(Object key) {
868
        return this.propertiesHelper.getProperty(key);
869
    }
870

    
871
    public void setProperty(Object key, Object obj) {
872
        this.propertiesHelper.setProperty(key, obj);
873
    }
874

    
875
    public Map getExtendedProperties() {
876
        return this.propertiesHelper.getExtendedProperties();
877
    }
878

    
879
    public static class DocumentWindowInfo implements Persistent {
880

    
881
        public static final String PERSISTENCE_DEFINITION_NAME = "DocumentWindowInfo";
882

    
883
        private WindowInfo windowInfo;
884
        private String documentType;
885
        private String documentName;
886

    
887
        public DocumentWindowInfo() {
888
        }
889

    
890
        DocumentWindowInfo(WindowInfo wi, String docType, String docName) {
891
            windowInfo = wi;
892
            documentType = docType;
893
            documentName = docName;
894
        }
895

    
896
        public WindowInfo getWindowInfo() {
897
            return windowInfo;
898
        }
899

    
900
        public String getDocumentType() {
901
            return documentType;
902
        }
903

    
904
        public String getDocumentName() {
905
            return documentName;
906
        }
907

    
908
        public void saveToState(PersistentState state)
909
                throws PersistenceException {
910
            state.set("windowInfo", this.windowInfo);
911
            state.set("documentType", this.documentType);
912
            state.set("documentName", this.documentName);
913
        }
914

    
915
        public void loadFromState(PersistentState state)
916
                throws PersistenceException {
917
            this.windowInfo = (WindowInfo) state.get("windowInfo");
918
            this.documentType = state.getString("documentType");
919
            this.documentName = state.getString("documentName");
920
        }
921

    
922
        public static void registerPersistent() {
923
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
924
            DynStruct definition = manager.getDefinition(PERSISTENCE_DEFINITION_NAME);
925
            if (definition == null) {
926
                definition = manager.addDefinition(
927
                        DocumentWindowInfo.class,
928
                        PERSISTENCE_DEFINITION_NAME,
929
                        "DocumentWindowInfo persistence definition",
930
                        null,
931
                        null
932
                );
933
                definition.addDynFieldObject("windowInfo").setMandatory(true).setClassOfValue(WindowInfo.class);
934
                definition.addDynFieldString("documentType").setMandatory(true);
935
                definition.addDynFieldString("documentName").setMandatory(true);
936
            }
937

    
938
        }
939
    }
940

    
941
    public static void registerPersistent() {
942
        AbstractDocument.registerPersistent();
943
        DocumentWindowInfo.registerPersistent();
944
        ProjectExtent.registerPersistent();
945

    
946
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
947
        DynStruct definition = manager.addDefinition(DefaultProject.class,
948
                "Project", "Project Persistence definition", null, null);
949
        definition.addDynFieldString("version").setMandatory(true);
950
        definition.addDynFieldString("comments").setMandatory(true);
951
        definition.addDynFieldString("creationDate").setMandatory(true);
952
        definition.addDynFieldString("modificationDate").setMandatory(true);
953
        definition.addDynFieldString("name").setMandatory(true);
954
        definition.addDynFieldString("owner").setMandatory(true);
955

    
956
        definition.addDynFieldObject("selectionColor")
957
                .setClassOfValue(Color.class).setMandatory(true);
958
        definition.addDynFieldObject("projection")
959
                .setClassOfValue(IProjection.class).setMandatory(true);
960

    
961
        definition.addDynFieldList("extents")
962
                .setClassOfItems(ProjectExtent.class).setMandatory(true);
963

    
964
        definition.addDynFieldList("documents").setClassOfItems(Document.class)
965
                .setMandatory(true);
966

    
967
        definition.addDynFieldObject("projectWindowInfo").setClassOfValue(WindowInfo.class).setMandatory(false);
968

    
969
        definition.addDynFieldList("documentWindowsInformation").setClassOfItems(WindowInfo.class).setMandatory(false);
970

    
971

    
972
        definition.addDynFieldObject("propertiesHelper").setClassOfValue(ExtendedPropertiesHelper.class)
973
                        .setMandatory(false);
974

    
975
    }
976

    
977
    /**
978
     * @deprecated use getPreferences().setDefaultSelectionColor()
979
     */
980
    public static void setDefaultSelectionColor(Color color) {
981
        getPreferences().setDefaultSelectionColor(color);
982
    }
983

    
984
    /**
985
     * @deprecated use getPreferences().getDefaultSelectionColor()
986
     */
987
    public static Color getDefaultSelectionColor() {
988
        return getPreferences().getDefaultSelectionColor();
989
    }
990

    
991
    /**
992
     * @deprecated use getPreferences().getDefaultMapUnits()
993
     */
994
    public static int getDefaultMapUnits() {
995
        return getPreferences().getDefaultMapUnits();
996
    }
997

    
998
    /**
999
     * @deprecated use getPreferences().getDefaultDistanceUnits()
1000
     */
1001
    public static int getDefaultDistanceUnits() {
1002
        return getPreferences().getDefaultDistanceUnits();
1003
    }
1004

    
1005
    /**
1006
     * @deprecated use getPreferences().getDefaultDistanceArea()
1007
     */
1008
    public static int getDefaultDistanceArea() {
1009
        return getPreferences().getDefaultDistanceArea();
1010
    }
1011

    
1012
    /**
1013
     * @deprecated use getPreferences().setDefaultMapUnits()
1014
     */
1015
    public static void setDefaultMapUnits(int mapUnits) {
1016
        getPreferences().setDefaultMapUnits(mapUnits);
1017
    }
1018

    
1019
    /**
1020
     * @deprecated use getPreferences().setDefaultDistanceUnits()
1021
     */
1022
    public static void setDefaultDistanceUnits(int distanceUnits) {
1023
        getPreferences().setDefaultDistanceUnits(distanceUnits);
1024
    }
1025

    
1026
    /**
1027
     * @deprecated use getPreferences().setDefaultDistanceArea()
1028
     */
1029
    public static void setDefaultDistanceArea(int distanceArea) {
1030
        getPreferences().setDefaultDistanceArea(distanceArea);
1031
    }
1032

    
1033
    /**
1034
     * @deprecated use getPreferences().setDefaultProjection()
1035
     */
1036
    public static void setDefaultProjection(IProjection defaultProjection) {
1037
        getPreferences().setDefaultProjection(defaultProjection);
1038
    }
1039

    
1040
    /**
1041
     * @deprecated use getPreferences().getDefaultProjection()
1042
     */
1043
    public static IProjection getDefaultProjection() {
1044
        return getPreferences().getDefaultProjection();
1045
    }
1046

    
1047
    /**
1048
     * @deprecated see {@link #setSelectionColor(String)}, to be remove in gvSIG
1049
     * 2.1.0
1050
     */
1051
    public void setColor(String color) {
1052
        this.setSelectionColor(StringUtilities.string2Color(color));
1053
    }
1054

    
1055
    /**
1056
     * Return the selection color
1057
     *
1058
     * @return selection color as string
1059
     * @deprecated use {@link #getSelectionColor()}
1060
     */
1061
    public String getColor() {
1062
        return StringUtilities.color2String(selectionColor);
1063
    }
1064

    
1065
    /**
1066
     * Return the list of views of the project
1067
     *
1068
     * @return views as ArrayList of ProjectDocument
1069
     *
1070
     * @deprecated see {@link #getDocumentsByType(String)}
1071
     */
1072
    public List<Document> getViews() {
1073
        return getDocuments(ViewManager.TYPENAME);
1074
    }
1075

    
1076
    /**
1077
     * Add a view to the project
1078
     *
1079
     * @deprecated see {@link #add(AbstractDocument)}
1080
     */
1081
    public void addView(DefaultViewDocument v) {
1082
        add(v);
1083
    }
1084

    
1085
    /**
1086
     * Remove a view of the project
1087
     *
1088
     * @param index of the view as integer
1089
     *
1090
     * @deprecated see {@link #remove(AbstractDocument)}
1091
     */
1092
    public void delView(int i) {
1093
        List<Document> list = getDocuments(ViewManager.TYPENAME);
1094
        remove(list.get(i));
1095
    }
1096

    
1097
    /**
1098
     * @deprecated see {@link #getDocument(String, String)}
1099
     */
1100
    public Document getProjectDocumentByName(String name, String type) {
1101
        return this.getDocument(name, type);
1102
    }
1103

    
1104
    /**
1105
     * @deprecated see {@link #getDocuments(String)}
1106
     */
1107
    public List<Document> getDocumentsByType(String type) {
1108
        return this.getDocuments(type);
1109
    }
1110

    
1111
    /**
1112
     * @deprecated aun por decidir que API darle al copy/paste
1113
     */
1114
    public String exportToXML(AbstractDocument[] selectedItems)
1115
            throws SaveException {
1116
        // FIXME jjdc:hay que decirdir que API darle al copy/paste
1117
        throw new UnsupportedOperationException("This method is not supported");
1118
    }
1119

    
1120
    /**
1121
     * @deprecated aun por decidir que API darle al copy/paste
1122
     */
1123
    public void importFromXML(String sourceString, String docType) {
1124
        // FIXME jjdc:hay que decirdir que API darle al copy/paste
1125
        throw new UnsupportedOperationException("This method is not supported");
1126
    }
1127

    
1128
    /**
1129
     * @deprecated aun por decidir que API darle al copy/paste
1130
     */
1131
    public boolean isValidXMLForImport(String sourceString, String docType) {
1132
        // FIXME jjdc:hay que decirdir que API darle al copy/paste
1133
        throw new UnsupportedOperationException("This method is not supported");
1134
    }
1135

    
1136
    public boolean canImportDocuments(String data, String doctype) {
1137
        // TODO Auto-generated method stub
1138
        return false;
1139
    }
1140

    
1141
    public String exportDocumentsAsText(List<Document> documents) {
1142
        // TODO Auto-generated method stub
1143
        return null;
1144
    }
1145

    
1146
    public void importDocuments(String data, String doctype) {
1147
        // TODO Auto-generated method stub
1148

    
1149
    }
1150

    
1151
    public Document getActiveDocument() {
1152
        return this.getActiveDocument((Class<? extends Document>)null);
1153
    }
1154

    
1155
    public Document getActiveDocument(String documentTypeName) {
1156
        ApplicationManager application = ApplicationLocator.getManager();
1157

    
1158
        Document document = null;
1159
        IWindow[] windows = application.getUIManager().getOrderedWindows();
1160
        IWindow window = null;
1161
        for (int i = 0; i < windows.length; i++) {
1162
            window = windows[i];
1163
            if (window instanceof SingletonWindow) {
1164
                // Cogemos no la primera ventana, si no la primera
1165
                // ventana de tipo documento (SingletonWindow).
1166
                // Y por si las mosca no es un documento, atrapamos
1167
                // los errores y continuamos si no puede hacer un cast
1168
                // del Model a Document
1169
                try {
1170
                    document = (Document) ((SingletonWindow) window).getWindowModel();
1171
                    if (documentTypeName == null) {
1172
                        return document;
1173
                    }
1174
                    if( document.getTypeName().equalsIgnoreCase(documentTypeName) ) {
1175
                        return document;
1176
                    }
1177
                    if( document instanceof DocumentsContainer ) {
1178
                        Document subdoc = ((DocumentsContainer)document).getActiveDocument(documentTypeName);
1179
                        return subdoc;
1180
                    }
1181

    
1182
                } catch (ClassCastException e) {
1183
                    // Do nothing, skip this window
1184
                }
1185
            }
1186
        }
1187
        return null;
1188
    }
1189

    
1190
    public Document getActiveDocument(Class<? extends Document> documentClass) {
1191
        ApplicationManager application = ApplicationLocator.getManager();
1192

    
1193
        Document document = null;
1194
        IWindow[] windows = application.getUIManager().getOrderedWindows();
1195
        IWindow window = null;
1196
        for (int i = 0; i < windows.length; i++) {
1197
            window = windows[i];
1198
            if (window instanceof SingletonWindow && window instanceof IDocumentWindow) {
1199
                // Cogemos no la primera ventana, si no la primera
1200
                // ventana de tipo documento (SingletonWindow).
1201
                // Y por si las mosca no es un documento, atrapamos
1202
                // los errores y continuamos si no puede hacer un cast
1203
                // del Model a Document
1204
                try {
1205
                    document = (Document) ((SingletonWindow) window).getWindowModel();
1206
                    if (documentClass == null) {
1207
                        return document;
1208
                    }
1209
                    if (documentClass.isAssignableFrom(document.getClass())) {
1210
                        return document;
1211
                    }
1212
                    if( document instanceof DocumentsContainer ) {
1213
                        Document subdoc = ((DocumentsContainer)document).getActiveDocument(documentClass);
1214
                        return subdoc;
1215
                    }
1216

    
1217
                } catch (ClassCastException e) {
1218
                    // Do nothing, skip this window
1219
                }
1220
            }
1221
        }
1222
        return null;
1223
    }
1224

    
1225
    public void addObserver(Observer o) {
1226
        observableHelper.addObserver(o);
1227
    }
1228

    
1229
    public void deleteObserver(Observer o) {
1230
        observableHelper.deleteObserver(o);
1231
    }
1232

    
1233
    public void deleteObservers() {
1234
        observableHelper.deleteObservers();
1235
    }
1236

    
1237
    private ProjectNotification notifyObservers(int type) {
1238
        return notifyObservers(new DefaultProjectNotification(type));
1239
    }
1240

    
1241
    private ProjectNotification notifyObservers(int type, Document document) {
1242
        return notifyObservers(new DefaultProjectNotification(type, document));
1243
    }
1244
    
1245
    private ProjectNotification notifyObservers(int type, PersistentState state) {
1246
        return notifyObservers(new DefaultProjectNotification(type, state));
1247
    }
1248

    
1249
    private ProjectNotification notifyObservers(int type, File file) {
1250
        return notifyObservers(new DefaultProjectNotification(type, file));
1251
    }
1252

    
1253
    private ProjectNotification notifyObservers(ProjectNotification notifycation) {
1254
        try {
1255
            observableHelper.notifyObservers(this, notifycation);
1256
        } catch (Exception ex) {
1257
            LOG.info("Can't notify observers", ex);
1258
        }
1259
        return notifycation;
1260
    }
1261
    
1262
    class DefaultProjectNotification implements ProjectNotification {
1263

    
1264
        private int type;
1265
        private Document document;
1266
        private File file;
1267
        private boolean processCanceled = false;
1268
        private PersistentState state = null;
1269

    
1270
        DefaultProjectNotification(int type) {
1271
            this.type = type;
1272
        }
1273

    
1274
        DefaultProjectNotification(int type, Document document) {
1275
            this(type);
1276
            this.document = document;
1277
        }
1278

    
1279
        DefaultProjectNotification(int type, File file) {
1280
            this(type);
1281
            this.file = file;
1282
        }
1283

    
1284
        DefaultProjectNotification(int type, PersistentState state) {
1285
            this(type);
1286
            this.state = state;
1287
        }
1288

    
1289
        @Override
1290
        public int getNotificationType() {
1291
            return type;
1292
        }
1293

    
1294
        @Override
1295
        public Document getDocument() {
1296
            return document;
1297
        }
1298

    
1299
        @Override
1300
        public void cancelProcess() {
1301
            processCanceled = true;
1302
        }
1303

    
1304
        @Override
1305
        public boolean isProcessCanceled() {
1306
            return processCanceled;
1307
        }
1308

    
1309
        @Override
1310
        public File getFile() {
1311
            return file;
1312
        }
1313

    
1314
        @Override
1315
        public PersistentState getState() {
1316
            return this.state;
1317
        }
1318

    
1319
        @Override
1320
        public Project getProject() {
1321
            return DefaultProject.this;
1322
        }
1323
    }
1324

    
1325
}