add method to return complete path of a project file
[jSite2.git] / src / net / pterodactylus / jsite / project / Project.java
1 /*
2  * jSite2 - Project.java -
3  * Copyright © 2008 David Roden
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 package net.pterodactylus.jsite.project;
21
22 import java.beans.PropertyChangeListener;
23 import java.io.File;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29
30 import net.pterodactylus.util.beans.AbstractBean;
31
32 /**
33  * Container for project information. A Project is capable of notifying
34  * {@link PropertyChangeListener}s if any of the contained properties change.
35  * 
36  * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
37  */
38 public class Project extends AbstractBean {
39
40         /** Name of the “name” property. */
41         public static final String PROPERTY_NAME = "name";
42
43         /** Name of the “description” property. */
44         public static final String PROPERTY_DESCRIPTION = "description";
45
46         /** Name of the “public key” property. */
47         public static final String PROPERTY_PUBLIC_KEY = "publicKey";
48
49         /** Name of the “private key” property. */
50         public static final String PROPERTY_PRIVATE_KEY = "privateKey";
51
52         /** Name of the “base path” property. */
53         public static final String PROPERTY_BASE_PATH = "basePath";
54
55         /** Name of the “default file” property. */
56         public static final String PROPERTY_DEFAULT_FILE = "defaultFile";
57
58         /** Internal ID. */
59         private String id;
60
61         /** The name of the project. */
62         private String name;
63
64         /** The description of the project. */
65         private String description;
66
67         /** The public key. */
68         private String publicKey;
69
70         /** The private key. */
71         private String privateKey;
72
73         /** The base path of the project. */
74         private String basePath;
75
76         /** The default file. */
77         private String defaultFile;
78
79         /** The overrides. */
80         private final Map<String, Override> overrides = new HashMap<String, Override>();
81
82         /**
83          * Creates a new project.
84          */
85         public Project() {
86                 /* do nothing. */
87         }
88
89         /**
90          * Clones the given project.
91          * 
92          * @param project
93          */
94         Project(Project project) {
95                 this.name = project.name;
96                 this.description = project.description;
97                 this.publicKey = project.publicKey;
98                 this.privateKey = project.privateKey;
99                 this.basePath = project.basePath;
100         }
101
102         /**
103          * Returns the internal ID.
104          * 
105          * @return The internal ID
106          */
107         String getId() {
108                 return id;
109         }
110
111         /**
112          * Sets the internal ID.
113          * 
114          * @param id
115          *            The internal ID
116          */
117         void setId(String id) {
118                 this.id = id;
119         }
120
121         /**
122          * Returns the name of the project.
123          * 
124          * @return The name of the project
125          */
126         public String getName() {
127                 return name;
128         }
129
130         /**
131          * Sets the name of the project.
132          * 
133          * @param name
134          *            The name of the project
135          */
136         public void setName(String name) {
137                 String oldName = this.name;
138                 this.name = name;
139                 fireIfPropertyChanged(PROPERTY_NAME, oldName, name);
140         }
141
142         /**
143          * Returns the description of the project.
144          * 
145          * @return The description of the project
146          */
147         public String getDescription() {
148                 return description;
149         }
150
151         /**
152          * Sets the description of the project
153          * 
154          * @param description
155          *            The description of the project
156          */
157         public void setDescription(String description) {
158                 String oldDescription = this.description;
159                 this.description = description;
160                 fireIfPropertyChanged(PROPERTY_DESCRIPTION, oldDescription, description);
161         }
162
163         /**
164          * Returns the public key of the project.
165          * 
166          * @return The public key of the project
167          */
168         public String getPublicKey() {
169                 return publicKey;
170         }
171
172         /**
173          * Sets the public key of the project.
174          * 
175          * @param publicKey
176          *            The public key of the project
177          */
178         void setPublicKey(String publicKey) {
179                 String oldPublicKey = this.publicKey;
180                 this.publicKey = publicKey;
181                 fireIfPropertyChanged(PROPERTY_PUBLIC_KEY, oldPublicKey, publicKey);
182         }
183
184         /**
185          * Returns the private key of the project.
186          * 
187          * @return The private key of the project
188          */
189         public String getPrivateKey() {
190                 return privateKey;
191         }
192
193         /**
194          * Sets the private key of the project.
195          * 
196          * @param privateKey
197          *            The private key of the project
198          */
199         void setPrivateKey(String privateKey) {
200                 String oldPrivateKey = this.privateKey;
201                 this.privateKey = privateKey;
202                 fireIfPropertyChanged(PROPERTY_PRIVATE_KEY, oldPrivateKey, privateKey);
203         }
204
205         /**
206          * Returns the base path of the project.
207          * 
208          * @return The base path of the project
209          */
210         public String getBasePath() {
211                 return basePath;
212         }
213
214         /**
215          * Sets the base path of the project.
216          * 
217          * @param basePath
218          *            The base path of the project
219          */
220         public void setBasePath(String basePath) {
221                 String oldBasePath = this.basePath;
222                 this.basePath = basePath;
223                 fireIfPropertyChanged(PROPERTY_BASE_PATH, oldBasePath, basePath);
224         }
225
226         /**
227          * Returns the default file.
228          * 
229          * @return The default file
230          */
231         public String getDefaultFile() {
232                 return defaultFile;
233         }
234
235         /**
236          * Sets the default file.
237          * 
238          * @param defaultFile
239          *            The default file
240          */
241         public void setDefaultFile(String defaultFile) {
242                 String oldDefaultFile = this.defaultFile;
243                 this.defaultFile = defaultFile;
244                 fireIfPropertyChanged(PROPERTY_DEFAULT_FILE, oldDefaultFile, defaultFile);
245         }
246
247         /**
248          * Adds an override for the given file.
249          * 
250          * @param filePath
251          *            The file path
252          * @param override
253          *            The override for the file
254          */
255         public void addOverride(String filePath, Override override) {
256                 overrides.put(filePath, override);
257         }
258
259         /**
260          * Removes the override for the given file.
261          * 
262          * @param filePath
263          *            The file path for which to remove the override
264          */
265         public void removeOverride(String filePath) {
266                 overrides.remove(filePath);
267         }
268
269         /**
270          * Returns the list of {@link Override}s.
271          * 
272          * @return All overrides
273          */
274         public Map<String, Override> getOverrides() {
275                 return overrides;
276         }
277
278         /**
279          * Scans the base path for files and returns the {@link ProjectFile} for the
280          * base path. From this file it is possible to reach all files in the base
281          * path. This method is disk-intensive and may take some time on larger
282          * directories!
283          * 
284          * @return The file for the base path, or <code>null</code> if the base
285          *         path does not denote an existing directory
286          */
287         public ProjectFile getBaseFile() {
288                 File basePathFile = new File(basePath);
289                 if (!basePathFile.exists() || !basePathFile.isDirectory()) {
290                         return null;
291                 }
292                 ProjectFileImpl rootProjectFile = new ProjectFileImpl(null, "", true, false);
293                 scanDirectory(basePathFile, rootProjectFile);
294                 return rootProjectFile;
295         }
296
297         //
298         // PRIVATE METHODS
299         //
300
301         /**
302          * Scans the given directory and recreates the file and directory structure
303          * in the given project file.
304          * 
305          * @param directory
306          *            The directory to scan
307          * @param projectFile
308          *            The project file in which to recreate the directory and file
309          *            structure
310          */
311         private void scanDirectory(File directory, ProjectFileImpl projectFile) {
312                 if (!directory.isDirectory()) {
313                         return;
314                 }
315                 for (File file: directory.listFiles()) {
316                         ProjectFileImpl projectFileChild = projectFile.addFile(file.getName(), file.isDirectory(), file.isHidden());
317                         if (file.isDirectory()) {
318                                 scanDirectory(file, projectFileChild);
319                         }
320                 }
321                 projectFile.sort();
322         }
323
324         /**
325          * Implementation of a {@link ProjectFile}.
326          * 
327          * @author David ‘Bombe’ Roden &lt;bombe@freenetproject.org&gt;
328          */
329         private static class ProjectFileImpl implements ProjectFile, Comparable<ProjectFileImpl> {
330
331                 /** The parent of this project file. */
332                 private final ProjectFileImpl parentProjectFile;
333
334                 /** The name of this project file. */
335                 private final String name;
336
337                 /** Whether this project file is a directory. */
338                 private final boolean directory;
339
340                 /** Whether this file is hidden. */
341                 private final boolean hidden;
342
343                 /** This project file’s children. */
344                 private List<ProjectFileImpl> childProjectFiles = new ArrayList<ProjectFileImpl>();
345
346                 /**
347                  * Creates a new project fie.
348                  * 
349                  * @param parentProjectFile
350                  *            The parent of the project file, or <code>null</code> if
351                  *            the new project file does not have a parent
352                  * @param name
353                  *            The name of the project file
354                  * @param isDirectory
355                  *            <code>true</code> if this project file is a directory,
356                  *            <code>false</code> otherwise
357                  * @param isHidden
358                  *            <code>true</code> if this project file is hidden,
359                  *            <code>false</code> otherwise
360                  */
361                 ProjectFileImpl(ProjectFileImpl parentProjectFile, String name, boolean isDirectory, boolean isHidden) {
362                         this.parentProjectFile = parentProjectFile;
363                         this.name = name;
364                         this.directory = isDirectory;
365                         this.hidden = isHidden;
366                 }
367
368                 //
369                 // INTERFACE ProjectFile
370                 //
371
372                 /**
373                  * @see net.pterodactylus.jsite.project.ProjectFile#getName()
374                  */
375                 public String getName() {
376                         return name;
377                 }
378
379                 /**
380                  * @see net.pterodactylus.jsite.project.ProjectFile#getParents()
381                  */
382                 public List<ProjectFile> getParents() {
383                         List<ProjectFile> parentProjectFiles = new ArrayList<ProjectFile>();
384                         ProjectFileImpl currentProjectFile = this;
385                         do {
386                                 parentProjectFiles.add(0, currentProjectFile);
387                         } while ((currentProjectFile = currentProjectFile.parentProjectFile) != null);
388                         return parentProjectFiles;
389                 }
390
391                 /**
392                  * {@inheritDoc}
393                  */
394                 /* TODO - caching? */
395                 public String getCompletePath() {
396                         StringBuilder completePath = new StringBuilder();
397                         ProjectFileImpl currentProjectFile = this;
398                         do {
399                                 completePath.insert(0, File.separatorChar).insert(0, this.getName());
400                         } while ((currentProjectFile = currentProjectFile.parentProjectFile) != null);
401                         return completePath.substring(1);
402                 }
403
404                 /**
405                  * @see net.pterodactylus.jsite.project.ProjectFile#isFile()
406                  */
407                 public boolean isFile() {
408                         return !directory;
409                 }
410
411                 /**
412                  * @see net.pterodactylus.jsite.project.ProjectFile#isDirectory()
413                  */
414                 public boolean isDirectory() {
415                         return directory;
416                 }
417
418                 /**
419                  * @see net.pterodactylus.jsite.project.ProjectFile#isHidden()
420                  */
421                 public boolean isHidden() {
422                         return hidden;
423                 }
424
425                 /**
426                  * @see net.pterodactylus.jsite.project.ProjectFile#getFiles()
427                  */
428                 public List<ProjectFile> getFiles() {
429                         List<ProjectFile> projectFiles = new ArrayList<ProjectFile>(childProjectFiles);
430                         return projectFiles;
431                 }
432
433                 //
434                 // ACTIONS
435                 //
436
437                 /**
438                  * Adds a new project file as child to this project file.
439                  * 
440                  * @param name
441                  *            The name of the file
442                  * @param isDirectory
443                  *            <code>true</code> if the new file is a directory,
444                  *            <code>false</code> otherwise
445                  * @param isHidden
446                  *            <code>true</code> if the new file is hidden,
447                  *            <code>false</code> otherwise
448                  * @return The created project file
449                  */
450                 public ProjectFileImpl addFile(String name, boolean isDirectory, boolean isHidden) {
451                         ProjectFileImpl newProjectFile = new ProjectFileImpl(this, name, isDirectory, isHidden);
452                         childProjectFiles.add(newProjectFile);
453                         return newProjectFile;
454                 }
455
456                 /**
457                  * Sorts the children of this file.
458                  */
459                 public void sort() {
460                         Collections.sort(childProjectFiles);
461                 }
462
463                 //
464                 // INTERFACE Comparable
465                 //
466
467                 /**
468                  * {@inheritDoc}
469                  */
470                 public int compareTo(ProjectFileImpl otherProjectFileImpl) {
471                         return name.compareTo(otherProjectFileImpl.name);
472                 }
473
474         }
475
476 }