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

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

Added the ability to copy/paste recognised files (mostly images) into Expeditee. This functionality already existed when drag n dropping, but now also works when using copy/paste.

At this stage, recognised files get imported as a approapriate Text Item. For example, a image will create a @i Text Item and attach it to your cursor. Ideally this would be the image directly. Unfortunately, items attached to the cursor (FreeItems) are not currently parsed. This is something I will discuss with David as there are confounding issues to consider. For example: surrogates...

Attached to the bottom of this commit message are my current thoughts.

Also made it so when creating a @i through DND or Copy/Paste, that @i is as relative as possible. The users image directories setting is used to achieve this.


  • FreeItems need to be parsed...we would need to deal with primaries/surrogates in them...
  • Do we want FreeItems to be parsed? If I attach an item to my cursor and then enter surrogate mode, should it change?
  • My gut says no. Both because it would be work, and also because it kind of feels like a free win if we do not.
  • But we do want to replace @i with images etc. Therefore, we want an old style parse for FreeItems?
File size: 10.8 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 /**
55 * Creates a Frame object from an associated resour
56 * @param frameName
57 * @param knownPath
58 * @param ignoreAnnotationsOnParse
59 * @return
60 */
61 public static Frame getExpediteeFrame(String frameName, String knownPath, boolean ignoreAnnotationsOnParse) {
62 Frame loaded = null;
63 if (knownPath != null) {
64 return FrameIO.LoadKnownPath(knownPath, frameName);
65 } else {
66 List<String> canditateDirectoriesForResource = frames.getDirectories();
67 for (String path: canditateDirectoriesForResource) {
68 loaded = FrameIO.LoadKnownPath(path, frameName);
69 if (loaded != null) {
70 break;
71 }
72 }
73 }
74
75 if (loaded == null && FrameShare.getInstance() != null) {
76 loaded = FrameShare.getInstance().loadFrame(frameName, knownPath);
77 }
78
79 if (loaded != null) {
80 FrameUtils.Parse(loaded, true, ignoreAnnotationsOnParse);
81 FrameIO.setSavedProperties(loaded);
82 }
83
84 return loaded;
85 }
86
87 /**
88 * Creates a picture object from the information stored in the given Text
89 * object.
90 * @param source
91 * The Text file containing the information for sourcing and displaying the information.
92 * @param tryRemote
93 * True if the FrameShare should be consulted to source the image after local locations
94 * have failed to find the corresponding file.
95 * @return
96 */
97 public static Picture getExpediteePicture(Text source, boolean tryRemote) {
98 // Extract useful content from source text.
99 String content = source.getText().replaceFirst("@i:", "");
100 String path = "";
101 String size = "";
102 String fileName = "";
103 content = content.replaceAll("\n", "");
104 content = content.trim();
105
106 // Image file names must contain a '.' to separate the file name from extension.
107 int fileSuffixCharIndex = content.indexOf('.');
108 if (fileSuffixCharIndex < 0) {
109 return null;
110 }
111 // Separate the path to resource file from additional information.
112 int endOfFileNameIndex = content.indexOf(' ', fileSuffixCharIndex);
113 if (endOfFileNameIndex < 0) {
114 path = content;
115 size = "";
116 } else {
117 path = content.substring(0, endOfFileNameIndex);
118 size = content.substring(endOfFileNameIndex).trim();
119 }
120 fileName = path;
121
122 // Redacted images are generated in memory as noise rather than being
123 // associated with a specific resource on the file system. Therefore,
124 // no more work is required.
125 if (fileName.equals(Picture.REDACTED_IMAGE_NAME)) {
126 return new Picture(source, fileName, path, size);
127 }
128
129 // Having gotten to this point, we now have to find the resource described
130 // by this Expeditee Text Item.
131 List<String> canditateDirectoriesForResource = images.getDirectories(source);
132
133 // First try finding the resource in the directories specified by the
134 // users settings frame.
135 File resourceFile = null;
136 for (String dir: canditateDirectoriesForResource) {
137 resourceFile = new File(dir + path);
138 if (resourceFile.exists() && !resourceFile.isDirectory()) {
139 break;
140 }
141 }
142
143 // At this point, if resourceFile is pointing to a file object that
144 // either doesn't exist or is a directory, then we have not been able
145 // to find the correct file.
146 //
147 // If the correct file is out there then two more possibilities:
148 // a. The text Item is specifying an absolute path or,
149 // b. The text Item is specifying a path relative to this java project.
150 // These are of the format "/packageA/packageB/filename". For
151 // example: "/org/expeditee/gui.management/ResourceManager.java"
152 //
153 // Bryce: Do we want to allow for the option of
154 // it being a path relative to expeditee.home?
155 if (resourceFile == null || !resourceFile.exists() || resourceFile.isDirectory()) {
156 // Prepare for case a.
157 resourceFile = new File(path);
158 }
159
160 if (!resourceFile.exists() || resourceFile.isDirectory()) {
161 // We are not looking at an absolute path so check option b.
162 URL resourceFileURL = ResourceManager.class.getResource(path);
163
164 // Decode to remove %20 in Windows folder names
165 if (resourceFileURL != null) {
166 try {
167 path = URLDecoder.decode(resourceFileURL.getFile(), "UTF-8");
168 } catch (UnsupportedEncodingException e) {
169 e.printStackTrace();
170 }
171 }
172 } else {
173 // We are looking at an absolute path, option a.
174 path = resourceFile.getPath();
175 }
176
177 // At this point, the resource has not been found locally. One last
178 // option is that the FrameShare might be able to help us.
179 resourceFile = new File(path);
180 if (!resourceFile.exists() || resourceFile.isDirectory()) {
181 if (tryRemote && FrameShare.getInstance().loadImage(fileName, null)) {
182 // Recursive call, but with try remote as false.
183 // The above call to the FrameShare should have gotten us a local copy.
184 return getExpediteePicture(source, false);
185 } else {
186 return null;
187 }
188 }
189
190 // If we have gotten here, we should have found the correct resourceFile
191 return new Picture(source, fileName, path, size);
192 }
193
194 /**
195 * Gets the audio file named 'localFileName' on the file system. Searches
196 * the locations listed in the users settings frame.
197 * @param localFileName
198 * @param parentFrame
199 * @return
200 */
201 public static File getAudioResource(String localFileName, Frame parentFrame) {
202 List<String> directories = audio.getDirectories(parentFrame);
203 for (String directory: directories) {
204 Path pathToFile = Paths.get(directory).resolve(localFileName);
205 File file = pathToFile.toFile();
206 if (file.exists() && !file.isDirectory()) {
207 return file;
208 }
209 }
210
211 return null;
212 }
213
214 /**
215 * Gets all the audio files that match the given predicate 'includeFile'.
216 * @param includeFile
217 * @param parentFrame
218 * @return
219 */
220 public static List<File> gatherAudioResources(Predicate<File> includeFile, Frame parentFrame) {
221 List<String> directories = audio.getDirectories(parentFrame);
222 List<File> results = new ArrayList<File>();
223 for (String directory: directories) {
224 File dir = new File(directory);
225 if (dir.exists()) {
226 File[] canditates = dir.listFiles();
227 for (File f: canditates) {
228 if (!f.isDirectory() && includeFile.test(f)) {
229 results.add(f);
230 }
231 }
232 }
233 }
234 return results;
235 }
236
237 public static void invalidateAllResourceDirectories() {
238 commonInvalidated = true;
239 }
240
241 private static void refreshAll() {
242 Frame currentFrame = DisplayController.getCurrentFrame();
243 String framesetPath = currentFrame == null ? null : currentFrame.getFramesetPath();
244 frames.refresh(framesetPath);
245 images.refresh(framesetPath);
246 audio.refresh(framesetPath);
247 }
248
249 private class ResolvedDirectoryList {
250 private List<String> directories = null;
251 private String contextFramesetPath = null;
252 private DirectoryListSetting source;
253
254 public ResolvedDirectoryList(DirectoryListSetting source) {
255 this.source = source;
256 }
257
258 public List<String> getDirectories(Text context) {
259 return getDirectories(context.getParentOrCurrentFrame());
260 }
261
262 public List<String> getDirectories(Frame context) {
263 String contextPath = context == null ? null : context.getFramesetPath();
264 return getDirectories(contextPath);
265 }
266
267 public List<String> getDirectories() {
268 return getDirectories("");
269 }
270
271 private List<String> getDirectories(String context) {
272 if (commonInvalidated) {
273 ResourceManager.refreshAll();
274 } else {
275 boolean isInitialSet = contextFramesetPath == null && context != null;
276 boolean settingToNull = context == null && contextFramesetPath != null;
277 boolean requiresRefresh = isInitialSet || settingToNull || !contextFramesetPath.equals(context);
278 if (requiresRefresh) {
279 refresh(context);
280 }
281 }
282
283 return directories;
284 }
285
286 private void refresh(String context) {
287
288 List<String> unresolved = source.getAbsoluteDirs();
289 directories = resolve(unresolved, context);
290 contextFramesetPath = context;
291 }
292
293 private List<String> resolve(List<String> unresolved, String context) {
294 if (context == null) {
295 return resolveWithNullContext(unresolved);
296 }
297
298 List<String> resolved = new ArrayList<String>();
299
300 if (unresolved == null) {
301 return resolved;
302 }
303
304 for (String s: unresolved) {
305 String local = ResourceUtil.substitute(s, ResourceUtil.CURRENT_FRAMESET_FLAG, context);
306 resolved.add(local);
307 }
308 return resolved;
309 }
310
311 private List<String> resolveWithNullContext(List<String> unresolved) {
312 List<String> resolved = new ArrayList<String>();
313
314 if (unresolved == null) {
315 return resolved;
316 }
317
318 for (String s: unresolved) {
319 String local = ResourceUtil.substitute(s, ResourceUtil.CURRENT_FRAMESET_FLAG, "ERROR.");
320 if (s.equals(local)) {
321 resolved.add(local);
322 }
323 }
324
325 return resolved;
326 }
327 }
328}
Note: See TracBrowser for help on using the repository browser.