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

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

Relativisation of image paths now only relativies back to expeditee home.
Also, when loading images and audio, paths can now be relative to expeditee home, even if it is not listed in the users settings. It is always tried last.

File size: 11.1 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 for (String s: unresolved) {
314 String local = ResourceUtil.substitute(s, ResourceUtil.CURRENT_FRAMESET_FLAG, context);
315 resolved.add(local);
316 }
317 return resolved;
318 }
319
320 private List<String> resolveWithNullContext(List<String> unresolved) {
321 List<String> resolved = new ArrayList<String>();
322
323 if (unresolved == null) {
324 return resolved;
325 }
326
327 for (String s: unresolved) {
328 String local = ResourceUtil.substitute(s, ResourceUtil.CURRENT_FRAMESET_FLAG, "ERROR.");
329 if (s.equals(local)) {
330 resolved.add(local);
331 }
332 }
333
334 return resolved;
335 }
336 }
337}
Note: See TracBrowser for help on using the repository browser.