source: trunk/src/org/expeditee/gui/management/ResourceManager.java@ 1439

Last change on this file since 1439 was 1439, checked in by bnemhaus, 5 years ago

Fixed a bug causing ${CURRENT_FRAMESET} flag not to work.

File size: 11.3 KB
Line 
1package org.expeditee.gui.management;
2
3import java.io.File;
4import java.io.UnsupportedEncodingException;
5import java.net.URL;
6import java.net.URLDecoder;
7import java.nio.file.Path;
8import java.nio.file.Paths;
9import java.util.ArrayList;
10import java.util.List;
11import java.util.function.Predicate;
12
13import org.expeditee.gui.DisplayController;
14import org.expeditee.gui.Frame;
15import org.expeditee.gui.FrameIO;
16import org.expeditee.gui.FrameUtils;
17import org.expeditee.items.Picture;
18import org.expeditee.items.Text;
19import org.expeditee.network.FrameShare;
20import org.expeditee.setting.DirectoryListSetting;
21import org.expeditee.settings.folders.FolderSettings;
22
23public class ResourceManager {
24
25 private static boolean commonInvalidated = false;
26 private static ResourceManager instance = new ResourceManager();
27 private static ResolvedDirectoryList frames = instance.new ResolvedDirectoryList(FolderSettings.FrameDirs);
28 private static ResolvedDirectoryList images = instance.new ResolvedDirectoryList(FolderSettings.ImageDirs);
29 private static ResolvedDirectoryList audio = instance.new ResolvedDirectoryList(FolderSettings.AudioDirs);
30
31 /**
32 * Attempts to relativise a image path using the users the directories listed for images in their settings.
33 * @param path The path to attempt to relativise
34 * @param context The context to use. Most likely the Frame that the image is on.
35 * @return Returns the most relativised path if one exists, otherwise returns a copy of the ref parameter passed in.
36 */
37 /*public static Path relativiseImagePath(Path path, Frame context) {
38 String pathStr = path.toString();
39
40 // Consult the resolved images directory for a list of paths to relativise too.
41 List<String> directories = images.getDirectories(context);
42
43 // Find the longest match that can be used to relativise the path.
44 String longestMatch = "";
45 for (String dir: directories) {
46 if (pathStr.startsWith(dir) && (dir.length() > longestMatch.length())) {
47 longestMatch = dir;
48 }
49 }
50
51 return Paths.get(pathStr.replace(longestMatch, ""));
52 }*/
53
54 public static Path relativiseImagePath(Path path, Frame context) {
55 Path expediteeHome = Paths.get(FrameIO.PARENT_FOLDER);
56 if (path.startsWith(expediteeHome)) {
57 return expediteeHome.relativize(path);
58 } else {
59 return path;
60 }
61 }
62
63 /**
64 * Creates a Frame object from an associated resour
65 * @param frameName
66 * @param knownPath
67 * @param ignoreAnnotationsOnParse
68 * @return
69 */
70 public static Frame getExpediteeFrame(String frameName, String knownPath, boolean ignoreAnnotationsOnParse) {
71 Frame loaded = null;
72 if (knownPath != null) {
73 return FrameIO.LoadKnownPath(knownPath, frameName);
74 } else {
75 List<String> canditateDirectoriesForResource = frames.getDirectories();
76 for (String path: canditateDirectoriesForResource) {
77 loaded = FrameIO.LoadKnownPath(path, frameName);
78 if (loaded != null) {
79 break;
80 }
81 }
82 }
83
84 if (loaded == null && FrameShare.getInstance() != null) {
85 loaded = FrameShare.getInstance().loadFrame(frameName, knownPath);
86 }
87
88 if (loaded != null) {
89 FrameUtils.Parse(loaded, true, ignoreAnnotationsOnParse);
90 FrameIO.setSavedProperties(loaded);
91 }
92
93 return loaded;
94 }
95
96 /**
97 * Creates a picture object from the information stored in the given Text
98 * object.
99 * @param source
100 * The Text file containing the information for sourcing and displaying the information.
101 * @param tryRemote
102 * True if the FrameShare should be consulted to source the image after local locations
103 * have failed to find the corresponding file.
104 * @return
105 */
106 public static Picture getExpediteePicture(Text source, boolean tryRemote) {
107 // Extract useful content from source text.
108 String content = source.getText().replaceFirst("@i:", "");
109 String path = "";
110 String size = "";
111 String fileName = "";
112 content = content.replaceAll("\n", "");
113 content = content.trim();
114
115 // Image file names must contain a '.' to separate the file name from extension.
116 int fileSuffixCharIndex = content.indexOf('.');
117 if (fileSuffixCharIndex < 0) {
118 return null;
119 }
120 // Separate the path to resource file from additional information.
121 int endOfFileNameIndex = content.indexOf(' ', fileSuffixCharIndex);
122 if (endOfFileNameIndex < 0) {
123 path = content;
124 size = "";
125 } else {
126 path = content.substring(0, endOfFileNameIndex);
127 size = content.substring(endOfFileNameIndex).trim();
128 }
129 fileName = path;
130
131 // Redacted images are generated in memory as noise rather than being
132 // associated with a specific resource on the file system. Therefore,
133 // no more work is required.
134 if (fileName.equals(Picture.REDACTED_IMAGE_NAME)) {
135 return new Picture(source, fileName, path, size);
136 }
137
138 // Having gotten to this point, we now have to find the resource described
139 // by this Expeditee Text Item.
140 List<String> canditateDirectoriesForResource = images.getDirectories(source);
141 canditateDirectoriesForResource.add(FrameIO.PARENT_FOLDER);
142
143 // First try finding the resource in the directories specified by the
144 // users settings frame.
145 File resourceFile = null;
146 for (String dir: canditateDirectoriesForResource) {
147 resourceFile = new File(dir + path);
148 if (resourceFile.exists() && !resourceFile.isDirectory()) {
149 break;
150 }
151 }
152
153 // At this point, if resourceFile is pointing to a file object that
154 // either doesn't exist or is a directory, then we have not been able
155 // to find the correct file.
156 //
157 // If the correct file is out there then two more possibilities:
158 // a. The text Item is specifying an absolute path or,
159 // b. The text Item is specifying a path relative to this java project.
160 // These are of the format "/packageA/packageB/filename". For
161 // example: "/org/expeditee/gui.management/ResourceManager.java"
162 if (resourceFile == null || !resourceFile.exists() || resourceFile.isDirectory()) {
163 // Prepare for case a.
164 resourceFile = new File(path);
165 }
166
167 if (!resourceFile.exists() || resourceFile.isDirectory()) {
168 // We are not looking at an absolute path so check option b.
169 URL resourceFileURL = ResourceManager.class.getResource(path);
170
171 // Decode to remove %20 in Windows folder names
172 if (resourceFileURL != null) {
173 try {
174 path = URLDecoder.decode(resourceFileURL.getFile(), "UTF-8");
175 } catch (UnsupportedEncodingException e) {
176 e.printStackTrace();
177 }
178 }
179 } else {
180 // We are looking at an absolute path, option a.
181 path = resourceFile.getPath();
182 }
183
184 // At this point, the resource has not been found locally. One last
185 // option is that the FrameShare might be able to help us.
186 resourceFile = new File(path);
187 if (!resourceFile.exists() || resourceFile.isDirectory()) {
188 if (tryRemote && FrameShare.getInstance().loadImage(fileName, null)) {
189 // Recursive call, but with try remote as false.
190 // The above call to the FrameShare should have gotten us a local copy.
191 return getExpediteePicture(source, false);
192 } else {
193 return null;
194 }
195 }
196
197 // If we have gotten here, we should have found the correct resourceFile
198 return new Picture(source, fileName, path, size);
199 }
200
201 /**
202 * Gets the audio file named 'localFileName' on the file system. Searches
203 * the locations listed in the users settings frame.
204 * @param localFileName
205 * @param parentFrame
206 * @return
207 */
208 public static File getAudioResource(String localFileName, Frame parentFrame) {
209 List<String> directories = audio.getDirectories(parentFrame);
210 directories.add(FrameIO.PARENT_FOLDER);
211 for (String directory: directories) {
212 Path pathToFile = Paths.get(directory).resolve(localFileName);
213 File file = pathToFile.toFile();
214 if (file.exists() && !file.isDirectory()) {
215 return file;
216 }
217 }
218
219 return null;
220 }
221
222 /**
223 * Gets all the audio files that match the given predicate 'includeFile'.
224 * @param includeFile
225 * @param parentFrame
226 * @return
227 */
228 public static List<File> gatherAudioResources(Predicate<File> includeFile, Frame parentFrame) {
229 List<String> directories = audio.getDirectories(parentFrame);
230 directories.add(FrameIO.PARENT_FOLDER);
231 List<File> results = new ArrayList<File>();
232 for (String directory: directories) {
233 File dir = new File(directory);
234 if (dir.exists()) {
235 File[] canditates = dir.listFiles();
236 for (File f: canditates) {
237 if (!f.isDirectory() && includeFile.test(f)) {
238 results.add(f);
239 }
240 }
241 }
242 }
243 return results;
244 }
245
246 public static void invalidateAllResourceDirectories() {
247 commonInvalidated = true;
248 }
249
250 private static void refreshAll() {
251 Frame currentFrame = DisplayController.getCurrentFrame();
252 String framesetPath = currentFrame == null ? null : currentFrame.getFramesetPath();
253 frames.refresh(framesetPath);
254 images.refresh(framesetPath);
255 audio.refresh(framesetPath);
256 }
257
258 private class ResolvedDirectoryList {
259 private List<String> directories = null;
260 private String contextFramesetPath = null;
261 private DirectoryListSetting source;
262
263 public ResolvedDirectoryList(DirectoryListSetting source) {
264 this.source = source;
265 }
266
267 public List<String> getDirectories(Text context) {
268 return getDirectories(context.getParentOrCurrentFrame());
269 }
270
271 public List<String> getDirectories(Frame context) {
272 String contextPath = context == null ? null : context.getFramesetPath();
273 return getDirectories(contextPath);
274 }
275
276 public List<String> getDirectories() {
277 return getDirectories("");
278 }
279
280 private List<String> getDirectories(String context) {
281 if (commonInvalidated) {
282 ResourceManager.refreshAll();
283 } else {
284 boolean isInitialSet = contextFramesetPath == null && context != null;
285 boolean settingToNull = context == null && contextFramesetPath != null;
286 boolean requiresRefresh = isInitialSet || settingToNull || !contextFramesetPath.equals(context);
287 if (requiresRefresh) {
288 refresh(context);
289 }
290 }
291
292 return directories;
293 }
294
295 private void refresh(String context) {
296
297 List<String> unresolved = source.getAbsoluteDirs();
298 directories = resolve(unresolved, context);
299 contextFramesetPath = context;
300 }
301
302 private List<String> resolve(List<String> unresolved, String context) {
303 if (context == null) {
304 return resolveWithNullContext(unresolved);
305 }
306
307 List<String> resolved = new ArrayList<String>();
308
309 if (unresolved == null) {
310 return resolved;
311 }
312
313 Path expediteeHome = Paths.get(FrameIO.PARENT_FOLDER).toAbsolutePath();
314 Path p = expediteeHome.relativize(Paths.get(context).toAbsolutePath());
315 for (String s: unresolved) {
316 String local = ResourceUtil.substitute(s, ResourceUtil.CURRENT_FRAMESET_FLAG, p.toString());
317 resolved.add(local);
318 }
319 return resolved;
320 }
321
322 private List<String> resolveWithNullContext(List<String> unresolved) {
323 List<String> resolved = new ArrayList<String>();
324
325 if (unresolved == null) {
326 return resolved;
327 }
328
329 for (String s: unresolved) {
330 String local = ResourceUtil.substitute(s, ResourceUtil.CURRENT_FRAMESET_FLAG, "ERROR.");
331 if (s.equals(local)) {
332 resolved.add(local);
333 }
334 }
335
336 return resolved;
337 }
338 }
339}
Note: See TracBrowser for help on using the repository browser.