Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
ApplicationState |
|
| 2.3529411764705883;2.353 |
1 | /* | |
2 | * Copyright (c) 2009, Swiss Federal Department of Defence Civil Protection and Sport | |
3 | * (http://www.vbs.admin.ch) | |
4 | * Copyright (c) 2009, Ergon Informatik AG (http://www.ergon.ch) | |
5 | * All rights reserved. | |
6 | * | |
7 | * Licensed under the Open Permis License which accompanies this distribution, | |
8 | * and is available at http://www.openpermis.org/BSDlicenceKent.txt | |
9 | */ | |
10 | package org.openpermis.editor.policy; | |
11 | ||
12 | import java.beans.PropertyChangeListener; | |
13 | import java.beans.PropertyChangeSupport; | |
14 | import java.io.File; | |
15 | ||
16 | /** | |
17 | * Describes persistent application state. | |
18 | * @since 0.1.0 | |
19 | */ | |
20 | public final class ApplicationState { | |
21 | ||
22 | //---- State | |
23 | ||
24 | /** | |
25 | * The working directory of the application. | |
26 | * @since 0.1.0 | |
27 | */ | |
28 | private String workingDirectory; | |
29 | ||
30 | /** | |
31 | * List of recent files, never {@code null}. | |
32 | * @since 0.1.0 | |
33 | */ | |
34 | private String[] recentFiles; | |
35 | ||
36 | /** | |
37 | * The property change support for bound properties. | |
38 | * @since 0.1.0 | |
39 | */ | |
40 | private final PropertyChangeSupport propertyChangeSupport; | |
41 | ||
42 | //---- Constructors | |
43 | ||
44 | /** | |
45 | * Creates a new application state. | |
46 | * @since 0.1.0 | |
47 | */ | |
48 | 7 | public ApplicationState () { |
49 | 7 | this.recentFiles = new String[0]; |
50 | 7 | this.propertyChangeSupport = new PropertyChangeSupport(this); |
51 | 7 | } |
52 | ||
53 | //---- Methods | |
54 | ||
55 | /** | |
56 | * Adds a property change listener that gets notified on bound property changes. | |
57 | * <p>The same listener object may be added more than once, and will be called | |
58 | * as many times as it is added. If <code>listener</code> is {@code null}, no exception | |
59 | * is thrown and no action is taken.</p> | |
60 | * @param listener the listener to add. | |
61 | * @since 0.1.0 | |
62 | */ | |
63 | public void addPropertyChangeListener (PropertyChangeListener listener) { | |
64 | 6 | this.propertyChangeSupport.addPropertyChangeListener(listener); |
65 | 6 | } |
66 | ||
67 | /** | |
68 | * Removes the specified property change listener. | |
69 | * <p>If <code>listener</code> was added more than once to the same event source, | |
70 | * it will be notified one less time after being removed. If <code>listener</code> is | |
71 | * {@code null}, or was never added, no exception is thrown and no action is taken.</p> | |
72 | * @param listener the listener to remove. | |
73 | * @since 0.1.0 | |
74 | */ | |
75 | public void removePropertyChangeListener (PropertyChangeListener listener) { | |
76 | 0 | this.propertyChangeSupport.removePropertyChangeListener(listener); |
77 | 0 | } |
78 | ||
79 | /** | |
80 | * Returns the working directory bean property. | |
81 | * <p>Use the {@link #getWorkingDirectoryFile() file version} if you are interested | |
82 | * in an actual {@link File} object.</p> | |
83 | * @return the working directory bean property. | |
84 | * @see #getWorkingDirectoryFile() | |
85 | * @since 0.1.0 | |
86 | */ | |
87 | public String getWorkingDirectory () { | |
88 | 3 | return this.workingDirectory; |
89 | } | |
90 | ||
91 | /** | |
92 | * Sets the working directory bean property. | |
93 | * <p>Use the {@link #setWorkingDirectoryFile(File) file version} if your source | |
94 | * is an actual {@link File} object.</p> | |
95 | * @param workingDirectory the working directory bean property. | |
96 | * @see #setWorkingDirectoryFile(File) | |
97 | * @since 0.1.0 | |
98 | */ | |
99 | public void setWorkingDirectory (String workingDirectory) { | |
100 | 2 | final String oldWorkingDirectory = this.workingDirectory; |
101 | 2 | this.workingDirectory = workingDirectory; |
102 | 2 | this.propertyChangeSupport.firePropertyChange( |
103 | "workingDirectory", oldWorkingDirectory, this.workingDirectory | |
104 | ); | |
105 | 2 | } |
106 | ||
107 | /** | |
108 | * Returns the application working directory as file. | |
109 | * <p>Convenience method for the working directory bean property.</p> | |
110 | * @return the application working directory as file. | |
111 | * @see #getWorkingDirectory() | |
112 | * @since 0.1.0 | |
113 | */ | |
114 | public File getWorkingDirectoryFile () { | |
115 | 0 | if (this.workingDirectory != null && this.workingDirectory.length() > 0) { |
116 | 0 | final File directory = new File(this.workingDirectory); |
117 | 0 | if (directory.isDirectory()) { |
118 | 0 | return directory; |
119 | } | |
120 | } | |
121 | // Fallback, use the current system working directory. | |
122 | 0 | return new File(System.getProperty("user.dir")); |
123 | } | |
124 | ||
125 | /** | |
126 | * Sets the application working directory from the given file. | |
127 | * <p>If the file denotes a directory it is used as is, in case of a plain | |
128 | * file the parent directory is chosen.</p> | |
129 | * <p>Convenience method for the working directory bean property.</p> | |
130 | * @param file the working directory to set. | |
131 | * @see #setWorkingDirectory(String) | |
132 | * @since 0.1.0 | |
133 | */ | |
134 | public void setWorkingDirectoryFile (File file) { | |
135 | 0 | if (file == null) { |
136 | 0 | this.workingDirectory = null; |
137 | 0 | } else if (file.isFile()) { |
138 | 0 | this.workingDirectory = file.getParent(); |
139 | 0 | } else if (file.isFile()) { |
140 | 0 | this.workingDirectory = file.getPath(); |
141 | } | |
142 | 0 | } |
143 | ||
144 | /** | |
145 | * Returns a recent files entry at the specified index. | |
146 | * @param index the index of the recent files entry to retrieve. | |
147 | * @return the recent files entry requested or {@code null} if there is no such entry. | |
148 | * @since 0.1.0 | |
149 | */ | |
150 | public String getRecentFiles (int index) { | |
151 | 1 | if (index < 0 || index >= this.recentFiles.length) { |
152 | 0 | return null; |
153 | } | |
154 | 1 | return this.recentFiles[index]; |
155 | } | |
156 | ||
157 | /** | |
158 | * Returns the number of recent files stored at this application state. | |
159 | * @return the number of recent files stored at this application state. | |
160 | * @since 0.1.0 | |
161 | */ | |
162 | public int getRecentFilesCount () { | |
163 | 14 | return this.recentFiles.length; |
164 | } | |
165 | ||
166 | /** | |
167 | * Returns a clone of the recent files list of this application state. | |
168 | * @return the recent files list requested, guaranteed not to be {@code null}. | |
169 | * @since 0.1.0 | |
170 | */ | |
171 | public String[] getRecentFiles () { | |
172 | 26 | return this.recentFiles.clone(); |
173 | } | |
174 | ||
175 | /** | |
176 | * Checks if the specified recent files index is valid. | |
177 | * @param index the index to check. | |
178 | * @throws IllegalArgumentException if the index is not valid. | |
179 | * @since 0.1.0 | |
180 | */ | |
181 | private void assertValidRecentFilesIndex (int index) { | |
182 | 4 | if (index < 0 || index >= this.recentFiles.length) { |
183 | 1 | throw new IllegalArgumentException( |
184 | "Invalid recent files index [" + index + | |
185 | "] (maximum is [" + getRecentFilesCount() + "]." | |
186 | ); | |
187 | } | |
188 | 3 | } |
189 | ||
190 | /** | |
191 | * Sets the recent files entry at the specified index. | |
192 | * @param index the index of the file entry to set, [0..{@link #getRecentFilesCount()}[. | |
193 | * @param file the file to entry to set, {@code null} to remove the entry. | |
194 | * @throws IllegalArgumentException if the index is not a valid index. | |
195 | * @see #getRecentFilesCount() | |
196 | * @since 0.1.0 | |
197 | */ | |
198 | public void setRecentFiles (int index, String file) { | |
199 | 3 | if (file == null) { |
200 | 2 | removeRecentFiles(index); |
201 | 1 | return; |
202 | } | |
203 | 1 | assertValidRecentFilesIndex(index); |
204 | 1 | final String oldFile = this.recentFiles[index]; |
205 | 1 | this.recentFiles[index] = file; |
206 | 1 | this.propertyChangeSupport.fireIndexedPropertyChange( |
207 | "recentFiles", index, oldFile, file | |
208 | ); | |
209 | 1 | } |
210 | ||
211 | /** | |
212 | * Convenience method to remove the file entry at the specified index. | |
213 | * <p>This method changes the whole recent files list.</p> | |
214 | * @param index the index of the file entry to set, [0..{@link #getRecentFilesCount()}[. | |
215 | * @throws IllegalArgumentException if the index is not a valid index. | |
216 | * @since 0.1.0 | |
217 | */ | |
218 | public void removeRecentFiles (int index) { | |
219 | 3 | assertValidRecentFilesIndex(index); |
220 | 2 | final String[] newFiles = new String[this.recentFiles.length - 1]; |
221 | 2 | System.arraycopy(this.recentFiles, 0, newFiles, 0, index); |
222 | 2 | System.arraycopy(this.recentFiles, index + 1, newFiles, index, newFiles.length - index); |
223 | 2 | setRecentFiles(newFiles); |
224 | 2 | } |
225 | ||
226 | /** | |
227 | * Convenience method to add a file entry to the recent files list. | |
228 | * <p>This method does nothing if the file entry is {@code null} or there is already a | |
229 | * file entry equal to the one specified contained.</p> | |
230 | * <p>This method changes the whole recent files list.</p> | |
231 | * @param file the file entry to add, may be {@code null}. | |
232 | * @since 0.1.0 | |
233 | */ | |
234 | public void addRecentFiles (String file) { | |
235 | 6 | if (file == null) { |
236 | 0 | return; |
237 | } | |
238 | 15 | for (int i = 0; i < this.recentFiles.length; i++) { |
239 | 12 | if (this.recentFiles[i].equals(file)) { |
240 | // Already contained, move to front. | |
241 | // (Generate new array to guarantee property change event.) | |
242 | 3 | final String[] newFiles = this.recentFiles.clone(); |
243 | 3 | System.arraycopy(this.recentFiles, 0, newFiles, 1, i); |
244 | 3 | newFiles[0] = this.recentFiles[i]; |
245 | 3 | setRecentFiles(newFiles); |
246 | 3 | return; |
247 | } | |
248 | } | |
249 | 3 | final String[] newFiles = new String[this.recentFiles.length + 1]; |
250 | 3 | System.arraycopy(this.recentFiles, 0, newFiles, 1, this.recentFiles.length); |
251 | 3 | newFiles[0] = file; |
252 | 3 | setRecentFiles(newFiles); |
253 | 3 | } |
254 | ||
255 | /** | |
256 | * Sets the recent files list of this application state. | |
257 | * @param files the new files list to set, {@code null} to set an empty files list. | |
258 | * @since 0.1.0 | |
259 | */ | |
260 | public void setRecentFiles (String[] files) { | |
261 | 13 | final String[] oldFiles = getRecentFiles(); |
262 | 13 | this.recentFiles = files == null ? new String[0] : files.clone(); |
263 | 13 | this.propertyChangeSupport.firePropertyChange( |
264 | "recentFiles", oldFiles, this.recentFiles | |
265 | ); | |
266 | 13 | } |
267 | ||
268 | /** | |
269 | * Returns a string representation for the recent files list. | |
270 | * @return the string representation for the recent files list. | |
271 | * @since 0.1.0 | |
272 | */ | |
273 | private String getRecentFilesAsString () { | |
274 | 0 | final StringBuilder sb = new StringBuilder("["); |
275 | 0 | for (String file : this.recentFiles) { |
276 | 0 | if (sb.length() > 1) { |
277 | 0 | sb.append(","); |
278 | } | |
279 | 0 | sb.append(file); |
280 | } | |
281 | 0 | return sb.append("]").toString(); |
282 | } | |
283 | ||
284 | //---- Object | |
285 | ||
286 | /** | |
287 | * @since 0.1.0 | |
288 | */ | |
289 | @Override | |
290 | public String toString () { | |
291 | 0 | return new StringBuilder("ApplicationState["). |
292 | append("workingDirectory=").append(getWorkingDirectory()). | |
293 | append(",recentFiles=").append(getRecentFilesAsString()). | |
294 | append("]").toString(); | |
295 | } | |
296 | ||
297 | } |