source: trunk/src/org/expeditee/gui/FrameIO.java@ 1357

Last change on this file since 1357 was 1357, checked in by bln4, 5 years ago

Fixes to permission on items.

File size: 66.3 KB
Line 
1/**
2 * FrameIO.java
3 * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
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 3 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, see <http://www.gnu.org/licenses/>.
17 */
18
19package org.expeditee.gui;
20
21import java.io.BufferedOutputStream;
22import java.io.BufferedReader;
23import java.io.BufferedWriter;
24import java.io.File;
25import java.io.FileInputStream;
26import java.io.FileNotFoundException;
27import java.io.FileOutputStream;
28import java.io.FileReader;
29import java.io.FileWriter;
30import java.io.IOException;
31import java.io.OutputStream;
32import java.io.OutputStreamWriter;
33import java.io.Writer;
34import java.nio.channels.FileChannel;
35import java.nio.file.Files;
36import java.nio.file.Path;
37import java.nio.file.Paths;
38import java.nio.file.StandardCopyOption;
39import java.sql.Time;
40import java.util.ArrayList;
41import java.util.Arrays;
42import java.util.Collection;
43import java.util.HashMap;
44import java.util.LinkedList;
45import java.util.List;
46import java.util.Map;
47import java.util.function.Consumer;
48import java.util.stream.Collectors;
49
50import org.apollo.io.AudioPathManager;
51import org.expeditee.actions.Actions;
52import org.expeditee.agents.ExistingFramesetException;
53import org.expeditee.agents.InvalidFramesetNameException;
54import org.expeditee.auth.AuthenticatorBrowser;
55import org.expeditee.auth.EncryptedExpReader;
56import org.expeditee.auth.EncryptedExpWriter;
57import org.expeditee.auth.gui.MailBay;
58import org.expeditee.gio.EcosystemManager;
59import org.expeditee.io.Conversion;
60import org.expeditee.io.ExpReader;
61import org.expeditee.io.ExpWriter;
62import org.expeditee.io.FrameReader;
63import org.expeditee.io.FrameWriter;
64import org.expeditee.io.KMSReader;
65import org.expeditee.io.KMSWriter;
66import org.expeditee.items.Item;
67import org.expeditee.items.ItemUtils;
68import org.expeditee.items.Justification;
69import org.expeditee.items.PermissionPair;
70import org.expeditee.items.Text;
71import org.expeditee.items.UserAppliedPermission;
72import org.expeditee.network.FrameShare;
73import org.expeditee.setting.Setting;
74import org.expeditee.settings.UserSettings;
75import org.expeditee.settings.folders.FolderSettings;
76import org.expeditee.settings.templates.TemplateSettings;
77import org.expeditee.stats.Formatter;
78import org.expeditee.stats.Logger;
79import org.expeditee.stats.SessionStats;
80
81/**
82 * This class provides static methods for all saving and loading of Frames
83 * to\from disk. This class also handles any caching of previously loaded
84 * Frames.
85 *
86 * @author jdm18
87 *
88 */
89
90
91public class FrameIO {
92
93 private static final char FRAME_NAME_LAST_CHAR = 'A';
94
95 // The parent path that all others are relative to. Also referred to as Expeditee Home.
96 public static String PARENT_FOLDER;
97
98 public static String PROFILE_PATH;
99 public static String FRAME_PATH;
100 public static String IMAGES_PATH;
101 public static String AUDIO_PATH;
102 public static String PUBLIC_PATH;
103 public static String TRASH_PATH;
104 public static String FONT_PATH;
105 public static String DICT_PATH;
106 public static String EXPORTS_PATH;
107 public static String STATISTICS_PATH;
108 public static String LOGS_PATH;
109 public static String MESSAGES_PATH;
110 public static String MAIL_PATH;
111 public static String SHARED_FRAMESETS_PATH;
112 public static String CONTACTS_PATH;
113 public static String RESOURCES_PRIVATE_PATH;
114 public static String RESOURCES_PATH;
115 public static String FRAME_PRIVATE_PATH;
116 public static String IMAGES_PRIVATE_PATH;
117 public static String AUDIO_PRIVATE_PATH;
118 public static String HELP_PRIVATE_PATH;
119 public static String HELP_PATH;
120 public static String DEAD_DROPS_PATH;
121
122 // Paths that appear to be unused.
123 public static String TEMPLATES_PATH;
124
125 // Variables for controlling cache functionality.
126 public static final int MAX_NAME_LENGTH = 64;
127 public static final int MAX_CACHE = 100;
128 private static HashMap<String, Frame> _Cache = new FrameCache();
129 private static final boolean ENABLE_CACHE = true;
130 private static boolean _UseCache = true;
131 private static boolean _SuspendedCache = false;
132
133 private static final String INF_FILENAME = "frame.inf";
134
135 public static void changeParentAndSubFolders(String newFolder) {
136 // Partial Paths
137 PARENT_FOLDER = newFolder;
138 PUBLIC_PATH = PARENT_FOLDER + "public" + File.separator;
139 TRASH_PATH = PARENT_FOLDER + "trash" + File.separator;
140 PROFILE_PATH = PARENT_FOLDER + "profiles" + File.separator;
141 EXPORTS_PATH = PARENT_FOLDER + "exports" + File.separator;
142 STATISTICS_PATH = PARENT_FOLDER + "statistics" + File.separator;
143 LOGS_PATH = PARENT_FOLDER + "logs" + File.separator;
144
145 String resourcesPublicPath = PARENT_FOLDER + "resources-public" + File.separator;
146 String resourcesPrivateIndividualPath = PARENT_FOLDER + "resources-" + UserSettings.UserName.get() + File.separator;
147
148 if (UserSettings.PublicAndPrivateResources) {
149 // Paths for the new regime
150 FONT_PATH = resourcesPublicPath + "fonts" + File.separator;
151 DICT_PATH = resourcesPublicPath + "dict" + File.separator;
152 HELP_PATH = resourcesPublicPath + "documentation" + File.separator;
153 HELP_PRIVATE_PATH = resourcesPrivateIndividualPath + "documentation" + File.separator;
154 FRAME_PATH = resourcesPublicPath + "framesets" + File.separator;
155 FRAME_PRIVATE_PATH = resourcesPrivateIndividualPath + "framesets" + File.separator;
156 MESSAGES_PATH = resourcesPrivateIndividualPath + "messages" + File.separator;
157 IMAGES_PATH = resourcesPublicPath + "images" + File.separator;
158 IMAGES_PRIVATE_PATH = resourcesPrivateIndividualPath + "images" + File.separator;
159 AUDIO_PATH = resourcesPublicPath + "audio" + File.separator;
160 AUDIO_PRIVATE_PATH = resourcesPrivateIndividualPath + "audio" + File.separator;
161
162 // Used only when extracting resources (when expeditee is run for first time)
163 RESOURCES_PRIVATE_PATH = PARENT_FOLDER + "resources-private" + File.separator;
164
165 if (AuthenticatorBrowser.isAuthenticated()) {
166 // Paths for the new regime while authenticated
167 SHARED_FRAMESETS_PATH = resourcesPrivateIndividualPath + "framesets-shared" + File.separator;
168 DEAD_DROPS_PATH = resourcesPrivateIndividualPath + "deaddrops" + File.separator;
169 CONTACTS_PATH = resourcesPrivateIndividualPath + "contacts" + File.separator;
170 MAIL_PATH = resourcesPrivateIndividualPath + "mail" + File.separator;
171 } else {
172 SHARED_FRAMESETS_PATH = null;
173 DEAD_DROPS_PATH = null;
174 CONTACTS_PATH = null;
175 MAIL_PATH = null;
176 }
177 } else {
178 // Paths for the old regime
179 FONT_PATH = PARENT_FOLDER + "fonts" + File.separator;
180 DICT_PATH = PARENT_FOLDER + "dict" + File.separator;
181 HELP_PATH = PARENT_FOLDER + "documentation" + File.separator;
182 FRAME_PATH = PARENT_FOLDER + "framesets" + File.separator;
183 MESSAGES_PATH = PARENT_FOLDER + "messages" + File.separator;
184 IMAGES_PATH = PARENT_FOLDER + "images" + File.separator;
185 AUDIO_PATH = PARENT_FOLDER + "audio" + File.separator;
186
187 // These paths are not used by old regime.
188 HELP_PRIVATE_PATH = null;
189 FRAME_PRIVATE_PATH = null;
190 IMAGES_PRIVATE_PATH = null;
191 AUDIO_PRIVATE_PATH = null;
192 // - This last one is never used because old regime is never extracted. If we are going to FrameUtils.extractResources then we are doing new regime.
193 RESOURCES_PRIVATE_PATH = null;
194
195 if (AuthenticatorBrowser.isAuthenticated()) {
196 // Paths for the old regime while authenticated
197 SHARED_FRAMESETS_PATH = PARENT_FOLDER + "framesets-shared" + File.separator;
198 DEAD_DROPS_PATH = PARENT_FOLDER + "deaddrops" + File.separator;
199 CONTACTS_PATH = PARENT_FOLDER + "contacts" + File.separator;
200 MAIL_PATH = PARENT_FOLDER + "mail" + File.separator;
201 } else {
202 SHARED_FRAMESETS_PATH = null;
203 DEAD_DROPS_PATH = null;
204 CONTACTS_PATH = null;
205 MAIL_PATH = null;
206 }
207 }
208
209 System.err.println("**** FrameIO::changeParentAndSubFolder(): Calling AudioPathManger.changeParentAndSubFolder()");
210 AudioPathManager.changeParentAndSubFolders(newFolder);
211 }
212
213// public static void changeParentAndSubFolders(String newFolder) {
214// // Partial Paths.
215// PARENT_FOLDER = newFolder;
216// String resourcesPublicPath = PARENT_FOLDER + "resources-public" + File.separator;
217// String resourcesPrivateIndividualPath = PARENT_FOLDER + "resources-" + UserSettings.UserName.get() + File.separator;
218//
219// // Standard paths.
220// PUBLIC_PATH = PARENT_FOLDER + "public" + File.separator;
221// TRASH_PATH = PARENT_FOLDER + "trash" + File.separator;
222// HELP_PATH = PARENT_FOLDER + "documentation" + File.separator;
223// PROFILE_PATH = PARENT_FOLDER + "profiles" + File.separator;
224// EXPORTS_PATH = PARENT_FOLDER + "exports" + File.separator;
225// STATISTICS_PATH = PARENT_FOLDER + "statistics" + File.separator;
226// LOGS_PATH = PARENT_FOLDER + "logs" + File.separator;
227//
228//
229// // Conditional paths
230// if (UserSettings.PublicAndPrivateResources) {
231// // Work with a system of public and private folders
232//
233// FONT_PATH = resourcesPublicPath + "fonts" + File.separator;
234// DICT_PATH = resourcesPublicPath + "dict" + File.separator;
235// IMAGES_PATH = resourcesPublicPath + "images" + File.separator;
236// AUDIO_PATH = resourcesPublicPath + "audio" + File.separator;
237// FRAME_PATH = resourcesPublicPath + "framesets" + File.separator;
238// } else {
239// FONT_PATH = PARENT_FOLDER + "fonts" + File.separator;
240// DICT_PATH = PARENT_FOLDER + "dict" + File.separator;
241// IMAGES_PATH = PARENT_FOLDER + "images" + File.separator;
242// AUDIO_PATH = PARENT_FOLDER + "audio" + File.separator;
243// FRAME_PATH = PARENT_FOLDER + "framesets" + File.separator;
244// DEAD_DROPS_PATH = PARENT_FOLDER + "deaddrops" + File.separator;
245// }
246//
247// if (!UserSettings.PublicAndPrivateResources || (AuthenticatorBrowser.isAuthenticationRequired() && !AuthenticatorBrowser.isAuthenticated())) {
248//
249// if (UserSettings.UserName.get().equals(AuthenticatorBrowser.USER_NOBODY)) {
250// System.err.println("**** FrameIO::changeParentAndSubFolders(): Not setting subfolders for user '"+AuthenticatorBrowser.USER_NOBODY+"'");
251// }
252//
253// // If we are using the old regime, or user.name set to Browser.USER_NOBODY
254// // => then these paths should not be used.
255// RESOURCES_PATH = null;
256// SHARED_FRAMESETS_PATH = null;
257// RESOURCES_PRIVATE_PATH = null;
258// FRAME_PRIVATE_PATH = null;
259// IMAGES_PRIVATE_PATH = null;
260// AUDIO_PRIVATE_PATH = null;
261// CONTACTS_PATH = null;
262// HELP_PRIVATE_PATH = null;
263//
264// if (!UserSettings.PublicAndPrivateResources) {
265// MESSAGES_PATH = PARENT_FOLDER + "messages" + File.separator;
266// } else {
267// MESSAGES_PATH = resourcesPrivateIndividualPath + "messages" + File.separator;
268// }
269//
270// } else {
271// RESOURCES_PATH = resourcesPublicPath + "documentation" + File.separator;
272// SHARED_FRAMESETS_PATH = resourcesPrivateIndividualPath + "framesets-shared" + File.separator;
273//
274// RESOURCES_PRIVATE_PATH = PARENT_FOLDER + "resources-private" + File.separator;
275// FRAME_PRIVATE_PATH = resourcesPrivateIndividualPath + "framesets" + File.separator;
276// IMAGES_PRIVATE_PATH = resourcesPrivateIndividualPath + "images" + File.separator;
277// AUDIO_PRIVATE_PATH = resourcesPrivateIndividualPath + "audio" + File.separator;
278// CONTACTS_PATH = resourcesPrivateIndividualPath + "contacts" + File.separator;
279// HELP_PRIVATE_PATH = resourcesPrivateIndividualPath + "documentation" + File.separator;
280// MESSAGES_PATH = resourcesPrivateIndividualPath + "messages" + File.separator;
281// MAIL_PATH = resourcesPrivateIndividualPath + "mail" + File.separator;
282// DEAD_DROPS_PATH = resourcesPrivateIndividualPath + "deaddrops" + File.separator;
283// }
284//
285//
286// System.err.println("**** FrameIO::changeParentAndSubFolder(): Calling AudioPathManger.changeParentAndSubFolder()");
287// AudioPathManager.changeParentAndSubFolders(newFolder);
288// }
289
290 // All methods are static, this should not be instantiated
291 private FrameIO() {
292 }
293
294 public static boolean isCacheOn() {
295 return _UseCache && ENABLE_CACHE;
296 }
297
298 public static void Precache(String framename) {
299 // if the cache is turned off, do nothing
300 if (!isCacheOn()) {
301 return;
302 }
303
304 // if the frame is already in the cache, do nothing
305 if (_Cache.containsKey(framename.toLowerCase())) {
306 return;
307 }
308
309 // otherwise, load the frame and put it in the cache
310 Logger.Log(Logger.SYSTEM, Logger.LOAD, "Precaching " + framename + ".");
311
312 // do not display errors encountered to the user
313 // (they will be shown at load time)
314 MessageBay.suppressMessages(true);
315 // loading automatically caches the frame is caching is turned on
316 LoadFromDisk(framename, null, false);
317 MessageBay.suppressMessages(false);
318 }
319
320 /**
321 * Checks if a string is a representation of a positive integer.
322 *
323 * @param s
324 * @return true if s is a positive integer
325 */
326 public static boolean isPositiveInteger(String s) {
327 if (s == null || s.length() == 0) {
328 return false;
329 }
330
331 for (int i = 0; i < s.length(); i++) {
332 if (!Character.isDigit(s.charAt(i))) {
333 return false;
334 }
335 }
336 return true;
337 }
338
339 /**
340 * Loads a frame with the specified name.
341 * By using a dot separated framename, users are able to specify the path to find the frameset in.
342 * @param frameName The frame to load.
343 * @return the loaded frame
344 */
345 public static Frame LoadFrame(String frameName) {
346 if (frameName.contains(".")) {
347 String[] split = frameName.split("\\.");
348 String[] pathSplit = Arrays.copyOfRange(split, 0, split.length - 1);
349 String name = split[split.length - 1];
350 String path = Arrays.asList(pathSplit).stream().collect(Collectors.joining(File.separator));
351 return LoadFrame(name, Paths.get(FrameIO.PARENT_FOLDER).resolve(path).toString() + File.separator, false);
352 } else {
353 return LoadFrame(frameName, null, false);
354 }
355 }
356
357 public static Frame LoadFrame(String frameName, String path) {
358 return LoadFrame(frameName, path, false);
359 }
360
361 public static Frame LoadFrame(String frameName, String path, boolean ignoreAnnotations) {
362 if (!isValidFrameName(frameName)) {
363 return null;
364 }
365
366 String frameNameLower = frameName.toLowerCase();
367 // first try reading from cache
368 if (isCacheOn() && _Cache.containsKey(frameNameLower)) {
369 Logger.Log(Logger.SYSTEM, Logger.LOAD, "Loading " + frameName + " from cache.");
370 Frame frame = _Cache.get(frameNameLower);
371
372 // if frame in cache is older than the one on disk then don't use the cached one
373 File file = new File(frame.getFramePathReal());
374 long lastModified = file.lastModified();
375 if (lastModified <= frame.getLastModifyPrecise()) {
376 return frame;
377 }
378 }
379
380 Logger.Log(Logger.SYSTEM, Logger.LOAD, "Loading " + frameName
381 + " from disk.");
382
383 Frame fromDisk = LoadFromDisk(frameName, path, ignoreAnnotations);
384 return fromDisk;
385 }
386
387 //Loads the 'restore' version of a frame if there is one
388 public static Frame LoadRestoreFrame(Frame frameToRestore) {
389
390 String fullPath = getFrameFullPathName(frameToRestore.getPath(), frameToRestore
391 .getName());
392 //System.out.println("fullpath: " + fullPath);
393 String restoreVersion = fullPath + ".restore";
394 //System.out.println("restoreversion" + restoreVersion);
395 File source = new File(restoreVersion);
396 File dest = new File(fullPath);
397
398 FileChannel inputChannel = null;
399 FileChannel outputChannel = null;
400
401 try{
402 FileInputStream source_fis = new FileInputStream(source);
403 inputChannel = source_fis.getChannel();
404
405 FileOutputStream dest_fos = new FileOutputStream(dest);
406 outputChannel = dest_fos.getChannel();
407
408 outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
409 inputChannel.close();
410 outputChannel.close();
411 source_fis.close();
412 dest_fos.close();
413 }
414 catch(Exception e){
415 System.err.println("No restore point detected.");
416 }
417 String frameName = frameToRestore.getName();
418 String frameNameLower = frameName.toLowerCase();
419
420 // first try reading from cache
421 if (isCacheOn() && _Cache.containsKey(frameNameLower)) {
422 Logger.Log(Logger.SYSTEM, Logger.LOAD, "Clearing " + frameName
423 + " from cache.");
424 _Cache.remove(frameNameLower);
425 }
426
427 return LoadFrame(frameName, frameToRestore.getPath(), true);
428 }
429
430 public static BufferedReader LoadPublicFrame(String frameName) {
431 String fullPath = FrameIO.getFrameFullPathName(PUBLIC_PATH, frameName);
432
433 if (fullPath == null) {
434 return null;
435 }
436
437 File frameFile = new File(fullPath);
438 if (frameFile.exists() && frameFile.canRead()) {
439 try {
440 return new BufferedReader(new FileReader(frameFile));
441 } catch (FileNotFoundException e) {
442 e.printStackTrace();
443 }
444 }
445 return null;
446 }
447
448 private static Frame LoadFromDisk(String framename, String knownPath,
449 boolean ignoreAnnotations) {
450 Frame loaded = null;
451
452 if (knownPath != null) {
453 loaded = LoadKnownPath(knownPath, framename);
454 } else {
455 List<String> directoriesToSearch = FolderSettings.FrameDirs.getAbsoluteDirs();
456
457// if (AuthenticatorBrowser.Authenticated) {
458// // if we are running Expeditee Authenticated, consult user profile as location for framesets first
459// String profilePath = FrameIO.PROFILE_PATH + UserSettings.UserName.get() + File.separator;
460// directoriesToSearch.add(0, profilePath);
461// }
462
463 for (String path : directoriesToSearch) {
464 loaded = LoadKnownPath(path, framename);
465 if (loaded != null) {
466 break;
467 }
468 }
469 }
470
471 if (loaded == null && FrameShare.getInstance() != null) {
472 loaded = FrameShare.getInstance().loadFrame(framename, knownPath);
473 }
474
475 if (loaded != null) {
476 FrameUtils.Parse(loaded, true, ignoreAnnotations);
477 FrameIO.setSavedProperties(loaded);
478 }
479
480 return loaded;
481 }
482
483 /**
484 * Gets a list of all the framesets available to the user
485 *
486 * @return a string containing a list of all the available framesets on
487 * separate lines
488 */
489 public static String getFramesetList() {
490 StringBuffer list = new StringBuffer();
491
492 for (String path : FolderSettings.FrameDirs.getAbsoluteDirs()) {
493 File files = new File(path);
494 if (!files.exists()) {
495 continue;
496 }
497 for (File f : (new File(path)).listFiles()) {
498 if (f.isDirectory()) {
499 list.append(f.getName()).append('\n');
500 }
501 }
502 }
503 // remove the final new line char
504 list.deleteCharAt(list.length() - 1);
505 return list.toString();
506 }
507
508 /**
509 * Gets a list of all the profiles available to the user
510 *
511 * @return a list containing all the available framesets on separate lines
512 */
513 public static List<String> getProfilesList() {
514 File[] listFiles = new File(FrameIO.PROFILE_PATH).listFiles();
515 if (listFiles == null) return new ArrayList<String>();
516 List<File> potentialProfiles = Arrays.asList(listFiles);
517 potentialProfiles.removeIf(file -> !file.isDirectory());
518 return potentialProfiles.stream().map(dir -> dir.getName()).collect(Collectors.toList());
519 }
520
521 /**
522 * Gets the full path and file name of the frame.
523 * This is a alias for Frame::getFramePathLogical
524 * @param path-
525 * the directory in which to look for the frameset containing the
526 * frame.
527 * @param frameName-
528 * the name of the frame for which the path is being requested.
529 * @return null if the frame can not be located.
530 */
531 public static synchronized String getFrameFullPathName(String path,
532 String frameName) {
533
534 String source;
535 String fileName = null;
536 if(frameName.contains("restore")){
537 source = path + File.separator;// + frameName;
538 fileName = path + File.separator + frameName + ExpReader.EXTENTION;
539
540 }
541 else
542 {
543 source = path + Conversion.getFramesetName(frameName)
544 + File.separator;
545 }
546
547
548 File tester = new File(source);
549 if (!tester.exists()) {
550 return null;
551 }
552
553 String fullPath;
554
555 if(frameName.contains("restore")){
556
557 fullPath = fileName;
558 }
559 else
560 {
561 // check for the new file name format
562 fullPath = source + Conversion.getFrameNumber(frameName)
563 + ExpReader.EXTENTION;
564 }
565
566 tester = new File(fullPath);
567
568 if (tester.exists()) {
569 return fullPath;
570 }
571
572 // check for oldfile name format
573 fullPath = source + Conversion.getFramesetName(frameName) + "."
574 + Conversion.getFrameNumber(frameName);
575 tester = new File(fullPath);
576
577 if (tester.exists()) {
578 return fullPath;
579 }
580
581 return null;
582 }
583
584 public static boolean canAccessFrame(String frameName) {
585 Frame current = DisplayController.getCurrentFrame();
586 // Just in case the current frame is not yet saved...
587 if (frameName.equals(current.getName())) {
588 FrameIO.SaveFrame(current, false, false);
589 current.change();
590 return true;
591 }
592
593 for (String path : FolderSettings.FrameDirs.getAbsoluteDirs()) {
594 if (getFrameFullPathName(path, frameName) != null) {
595 return true;
596 }
597 }
598 return false;
599 }
600
601 public static Collection<String> searchFrame(String frameName,
602 String pattern, String path) {
603 String fullPath = null;
604 if (path == null) {
605 for (String possiblePath : FolderSettings.FrameDirs.getAbsoluteDirs()) {
606 fullPath = getFrameFullPathName(possiblePath, frameName);
607 if (fullPath != null) {
608 break;
609 }
610 }
611 } else {
612 fullPath = getFrameFullPathName(path, frameName);
613 }
614 // If the frame was not located return null
615 if (fullPath == null) {
616 return null;
617 }
618 Collection<String> results = new LinkedList<String>();
619 // Open the file and search the text items
620 try {
621 BufferedReader reader = new BufferedReader(new FileReader(fullPath));
622 String next;
623 while (reader.ready() && ((next = reader.readLine()) != null)) {
624 if (next.startsWith("T")) {
625 String toSearch = next.substring(2);
626 if (toSearch.toLowerCase().contains(pattern)) {
627 results.add(toSearch);
628 }
629 } else if (next.startsWith("+T+")) {
630 String toSearch = next.substring(4);
631 if (toSearch.toLowerCase().contains(pattern)) {
632 results.add(toSearch);
633 }
634 }
635 }
636 reader.close();
637 } catch (FileNotFoundException e) {
638 e.printStackTrace();
639 return null;
640 } catch (IOException e) {
641 e.printStackTrace();
642 }
643 return results;
644 }
645
646 private static Frame LoadKnownPath(String path, String frameName) {
647 String fullPath = getFrameFullPathName(path, frameName);
648 if (fullPath == null) {
649 return null;
650 }
651
652 try {
653 FrameReader reader;
654
655 // Get the frameset name.
656 int i = frameName.length() - 1;
657 for (; i >= 0; i--) {
658 if (!Character.isDigit(frameName.charAt(i))) {
659 break;
660 }
661 }
662 if (i < 0) {
663 System.err.println("LoadKnownFrame was provided with a invalid Frame name: " + frameName);
664 return null;
665 }
666 String framesetName = frameName.substring(0, i + 1);
667
668 String redirectTo = ExpReader.redirectTo(fullPath);
669 while (redirectTo != null) {
670 fullPath = path + framesetName + File.separator + redirectTo;
671 redirectTo = ExpReader.redirectTo(fullPath);
672 }
673
674 if (fullPath.endsWith(ExpReader.EXTENTION)) {
675 if (EncryptedExpReader.isEncryptedExpediteeFile(fullPath)) {
676 reader = new EncryptedExpReader(frameName);
677 } else {
678 reader = new ExpReader(frameName);
679 }
680 } else {
681 reader = new KMSReader();
682 }
683 Frame frame = reader.readFrame(fullPath);
684
685 if (frame == null) {
686 MessageBay.errorMessage("Error: " + frameName
687 + " could not be successfully loaded.");
688 return null;
689 }
690
691 frame.setPath(path);
692
693 // do not put 0 frames or virtual frames into the cache
694 // Why are zero frames not put in the cache
695 if (_Cache.size() > MAX_CACHE) {
696 _Cache.clear();
697 }
698
699 if (frame.getNumber() > 0 && isCacheOn()) {
700 _Cache.put(frameName.toLowerCase(), frame);
701 }
702
703 return frame;
704 } catch (IOException ioe) {
705 ioe.printStackTrace();
706 Logger.Log(ioe);
707 } catch (Exception e) {
708 e.printStackTrace();
709 Logger.Log(e);
710 MessageBay.errorMessage("Error: " + frameName
711 + " could not be successfully loaded.");
712 }
713
714 return null;
715 }
716
717 public static void Reload() {
718 // disable cache
719 boolean cache = _UseCache;
720
721 _UseCache = false;
722 Frame fresh = FrameIO.LoadFrame(DisplayController.getCurrentFrame().getName());
723 _UseCache = cache;
724 if (_Cache.containsKey(fresh.getName().toLowerCase())) {
725 addToCache(fresh);
726 }
727 DisplayController.setCurrentFrame(fresh, false);
728 }
729
730 public static Frame LoadPrevious(Frame current) {
731 checkTDFC(current);
732
733 // the current name and number
734 String name = current.getFramesetName();
735 int num = current.getNumber() - 1;
736
737 // loop until a frame that exists is found
738 for (; num >= 0; num--) {
739 Frame f = LoadFrame(name + num, current.getPath());
740 if (f != null) {
741 return f;
742 }
743 }
744
745 // if we did not find another Frame then this one must be the last one
746 // in the frameset
747 MessageBay
748 .displayMessageOnce("This is the first frame in the frameset");
749 return null;
750 }
751
752 /**
753 * Returns the next Frame in the current Frameset (The Frame with the next
754 * highest Frame number) If the current Frame is the last one in the
755 * Frameset, or an error occurs then null is returned.
756 *
757 * @return The Frame after this one in the current frameset, or null
758 */
759 public static Frame LoadNext(Frame current) {
760 checkTDFC(current);
761
762 // the current name and number
763 int num = current.getNumber() + 1;
764 int max = num + 1;
765 String name = current.getFramesetName();
766
767 // read the maximum from the INF file
768 try {
769 max = ReadINF(current.getPath(), current.getFramesetName(), false);
770 } catch (IOException ioe) {
771 MessageBay.errorMessage("Error loading INF file for frameset '"
772 + name + "'");
773 return null;
774 }
775
776 // loop until a frame that exists is found
777 for (; num <= max; num++) {
778 Frame f = LoadFrame(name + num, current.getPath());
779 if (f != null) {
780 return f;
781 }
782 }
783
784 // if we did not find another Frame then this one must be the last one
785 // in the frameset
786 MessageBay.displayMessageOnce("This is the last frame in the frameset");
787 return null;
788 }
789
790 /**
791 * This method checks if the current frame has just been created with TDFC.
792 * If it has the frame is saved regardless of whether it has been edited or
793 * not and the TDFC item property is cleared. This is to ensure that the
794 * link is saved on the parent frame.
795 *
796 * @param current
797 */
798 public static void checkTDFC(Frame current) {
799 if (FrameUtils.getTdfcItem() != null) {
800 FrameUtils.setTdfcItem(null);
801 current.change();
802 }
803 }
804
805 public static Frame LoadLast(String framesetName, String path) {
806 // read the maximum from the INF file
807 int max;
808 try {
809 max = ReadINF(path, framesetName, false);
810 } catch (IOException ioe) {
811 MessageBay.errorMessage("Error loading INF file for frameset '"
812 + framesetName + "'");
813 return null;
814 }
815
816 // loop backwards until a frame that exists is found
817 for (int num = max; num > 0; num--) {
818 Frame f = LoadFromDisk(framesetName + num, path, false);
819 if (f != null) {
820 return f;
821 }
822 }
823
824 // if we did not find another Frame then this one must be the last one
825 // in the frameset
826 MessageBay.displayMessage("This is the last frame in the frameset");
827 return null;
828 }
829
830 public static Frame LoadZero(String framesetName, String path) {
831 return LoadFrame(framesetName + 0);
832 }
833
834 public static Frame LoadZero() {
835 Frame current = DisplayController.getCurrentFrame();
836 return LoadZero(current.getFramesetName(), current.getPath());
837 }
838
839 public static Frame LoadLast() {
840 Frame current = DisplayController.getCurrentFrame();
841 return LoadLast(current.getFramesetName(), current.getPath());
842 }
843
844 public static Frame LoadNext() {
845 return LoadNext(DisplayController.getCurrentFrame());
846 }
847
848 public static Frame LoadPrevious() {
849 return LoadPrevious(DisplayController.getCurrentFrame());
850 }
851
852 /**
853 * Deletes the given Frame on disk and removes the cached Frame if there is
854 * one. Also adds the deleted frame into the deletedFrames frameset.
855 *
856 * @param toDelete
857 * The Frame to be deleted
858 * @return The name the deleted frame was changed to, or null if the delete
859 * failed
860 */
861 public static String DeleteFrame(Frame toDelete) throws IOException,
862 SecurityException {
863 if (toDelete == null) {
864 return null;
865 }
866
867 // Dont delete the zero frame
868 if (toDelete.getNumber() == 0) {
869 throw new SecurityException("Deleting a zero frame is illegal");
870 }
871
872 // Dont delete the zero frame
873 if (!toDelete.isLocal()) {
874 throw new SecurityException("Attempted to delete remote frame");
875 }
876
877 SaveFrame(toDelete);
878
879 // Copy deleted frames to the DeletedFrames frameset
880 // get the last used frame in the destination frameset
881 final String DELETED_FRAMES = "DeletedFrames";
882 int lastNumber = FrameIO.getLastNumber(DELETED_FRAMES);
883 String framePath;
884 try {
885 // create the new frameset
886 Frame one = FrameIO.CreateFrameset(DELETED_FRAMES, toDelete
887 .getPath());
888 framePath = one.getPath();
889 lastNumber = 0;
890 } catch (Exception e) {
891 Frame zero = FrameIO.LoadFrame(DELETED_FRAMES + "0");
892 framePath = zero.getPath();
893 }
894
895 // get the fill path to determine which file version it is
896 String source = getFrameFullPathName(toDelete.getPath(), toDelete
897 .getName());
898
899 String oldFrameName = toDelete.getName().toLowerCase();
900 // Now save the frame in the new location
901 toDelete.setFrameset(DELETED_FRAMES);
902 toDelete.setFrameNumber(lastNumber + 1);
903 toDelete.setPath(framePath);
904 ForceSaveFrame(toDelete);
905
906 if (_Cache.containsKey(oldFrameName)) {
907 _Cache.remove(oldFrameName);
908 }
909
910 File del = new File(source);
911
912 java.io.FileInputStream ff = new java.io.FileInputStream(del);
913 ff.close();
914
915 if (del.delete()) {
916 return toDelete.getName();
917 }
918
919 return null;
920 }
921
922 /**
923 * Creates a new Frame in the given frameset and assigns it the given Title,
924 * which can be null. The newly created Frame is a copy of the frameset's .0
925 * file with the number updated based on the last recorded Frame name in the
926 * frameset's INF file.
927 *
928 * @param frameset
929 * The frameset to create the new Frame in
930 * @param frameTitle
931 * The title to assign to the newly created Frame (can be NULL).
932 * @return The newly created Frame.
933 */
934 public static synchronized Frame CreateFrame(String frameset,
935 String frameTitle, String templateFrame) throws RuntimeException {
936
937 if (!FrameIO.isValidFramesetName(frameset)) {
938 throw new RuntimeException(frameset
939 + " is not a valid frameset name");
940 }
941
942 int next = -1;
943
944 // disable caching of 0 frames
945 // Mike says: Why is caching of 0 frames being disabled?
946 /*
947 * Especially since 0 frames are not event put into the cache in the
948 * frist place
949 */
950 // SuspendCache();
951 /*
952 * Suspending the cache causes infinate loops when trying to load a zero
953 * frame which has a ao which contains an v or av which contains a link
954 * to the ao frame
955 */
956
957 String zeroFrameName = frameset + "0";
958 Frame destFramesetZero = LoadFrame(zeroFrameName);
959 if (destFramesetZero == null) {
960 throw new RuntimeException(zeroFrameName + " could not be found");
961 }
962
963 Frame template = null;
964 if (templateFrame == null) {
965 // load in frame.0
966 template = destFramesetZero;
967 } else {
968 template = LoadFrame(templateFrame);
969 if (template == null) {
970 throw new RuntimeException("LinkTemplate " + templateFrame
971 + " could not be found");
972 }
973 }
974
975 ResumeCache();
976
977 // read the next number from the INF file
978 try {
979 next = ReadINF(destFramesetZero.getPath(), frameset, true);
980 } catch (IOException ioe) {
981 ioe.printStackTrace();
982 throw new RuntimeException("INF file could not be read");
983 }
984
985 // Remove the old frame from the cache then add the new one
986 // TODO figure out some way that we can put both in the cache
987 _Cache.remove(template.getName().toLowerCase());
988 // set the number and title of the new frame
989 template.setName(frameset, ++next);
990 template.setTitle(frameTitle);
991 // _Cache.put(template.getName().toLowerCase(), template);
992
993 Logger.Log(Logger.SYSTEM, Logger.TDFC, "Creating new frame: "
994 + template.getName() + " from TDFC");
995
996 template.setOwner(UserSettings.UserName.get());
997 template.reset();
998 template.resetDateCreated();
999
1000 for (Item i : template.getItems()) {
1001 if (ItemUtils.startsWithTag(i, ItemUtils.TAG_PARENT)) {
1002 i.setLink(null);
1003 }
1004 }
1005
1006 // do auto shrinking of the title IF not in twin frames mode and the title is not centred
1007 Item titleItem = template.getTitleItem();
1008
1009 if (!DisplayController.isTwinFramesOn() && !Justification.center.equals(((Text)titleItem).getJustification())) {
1010 if ((titleItem.getX() + 1) < template.getNameItem().getX()) {
1011 int title_item_xr = titleItem.getX() + titleItem.getBoundsWidth(); // should really be '... -1'
1012 int frame_name_xl = template.getNameItem().getX();
1013 if (frame_name_xl < DisplayController.MINIMUM_FRAME_WIDTH) {
1014 frame_name_xl = DisplayController.MINIMUM_FRAME_WIDTH;
1015 }
1016
1017 while ((titleItem.getSize() > Text.MINIMUM_FONT_SIZE) && title_item_xr > frame_name_xl) {
1018 titleItem.setSize(titleItem.getSize() - 1);
1019 System.err.println("**** shrunk titleItem: " + titleItem + " to font size: " + titleItem.getSize());
1020 }
1021 } else {
1022 System.out.println("Bad title x position: " + titleItem.getX());
1023 }
1024 }
1025 // Assign a width to the title.
1026 titleItem.setRightMargin(template.getNameItem().getX(), true);
1027
1028 return template;
1029 }
1030
1031 public static void DisableCache() {
1032 //System.err.println(" --------- Cache Disabled --------- ");
1033 _UseCache = false;
1034 }
1035
1036 public static void EnableCache() {
1037 //System.err.println(" --------- Cache Enabled --------- ");
1038 _UseCache = true;
1039 }
1040
1041 public static void SuspendCache() {
1042 //System.err.println("SuspendCache: _UseCache" + " was " + _UseCache);
1043 if (_UseCache) {
1044 DisableCache();
1045 _SuspendedCache = true;
1046 } else {
1047 _SuspendedCache = false;
1048 }
1049 //System.err.println(" Cache is suspended -> " + _SuspendedCache);
1050 //System.err.println(" _UseCache is -> " + _UseCache);
1051 //System.err.println();
1052 }
1053
1054 public static void ResumeCache() {
1055 //System.err.println("ResumeCache: _UseCache" + " was " + _UseCache);
1056 if (_SuspendedCache) {
1057 EnableCache();
1058 _SuspendedCache = false;
1059 }
1060 //System.err.println(" Cache is suspended -> " + _SuspendedCache);
1061 //System.err.println(" _UseCache is -> " + _UseCache);
1062 //System.err.println();
1063 }
1064
1065 public static void RefreshCacheImages()
1066 {
1067 SuspendCache();
1068 for (Frame frame : _Cache.values()) {
1069 frame.setBuffer(null);
1070 }
1071 ResumeCache();
1072 }
1073
1074 /**
1075 * Creates a new frameset using the given name. This includes creating a new
1076 * subdirectory in the <code>FRAME_PATH</code> directory, Copying over the
1077 * default.0 frame from the default frameset, copying the .0 Frame to make a
1078 * .1 Frame, and creating the frameset's INF file.
1079 *
1080 * @param frameset
1081 * The name of the Frameset to create
1082 * @return The first Frame of the new Frameset (Frame.1)
1083 */
1084 public static Frame CreateFrameset(String frameset, String path)
1085 throws Exception {
1086 return CreateFrameset(frameset, path, false);
1087 }
1088
1089 /**
1090 * Tests if the given String is a 'proper' framename, that is, the String
1091 * must begin with a character, end with a number with 0 or more letters and
1092 * numbers in between.
1093 *
1094 * @param frameName
1095 * The String to test for validity as a frame name
1096 * @return True if the given framename is proper, false otherwise.
1097 */
1098 public static boolean isValidFrameName(String frameName) {
1099
1100 if (frameName == null || frameName.length() < 2) {
1101 return false;
1102 }
1103
1104 int lastCharIndex = frameName.length() - 1;
1105 // String must begin with a letter and end with a digit
1106 if (!Character.isLetter(frameName.charAt(0))
1107 || !Character.isDigit(frameName.charAt(lastCharIndex))) {
1108 return false;
1109 }
1110
1111 // All the characters between first and last must be letters
1112 // or digits
1113 for (int i = 1; i < lastCharIndex; i++) {
1114 if (!isValidFrameNameChar(frameName.charAt(i))) {
1115 return false;
1116 }
1117 }
1118 return true;
1119 }
1120
1121 private static boolean isValidFrameNameChar(char c) {
1122 return c == '-' || c == '.' || Character.isLetterOrDigit(c);
1123 }
1124
1125 /**
1126 * Saves the given Frame to disk in the corresponding frameset directory.
1127 * This is the same as calling SaveFrame(toSave, true)
1128 *
1129 * @param toSave
1130 * The Frame to save to disk
1131 */
1132 public static String SaveFrame(Frame toSave) {
1133 return SaveFrame(toSave, true);
1134 }
1135
1136 /**
1137 * Saves a frame.
1138 *
1139 * @param toSave
1140 * the frame to save
1141 * @param inc
1142 * true if the frames counter should be incremented
1143 * @return the text content of the frame
1144 */
1145 public static String SaveFrame(Frame toSave, boolean inc) {
1146 return SaveFrame(toSave, inc, true);
1147 }
1148
1149 /**
1150 * Saves the given Frame to disk in the corresponding frameset directory, if
1151 * inc is true then the saved frames counter is incremented, otherwise it is
1152 * untouched.
1153 *
1154 * @param toSave
1155 * The Frame to save to disk
1156 * @param inc
1157 * True if the saved frames counter should be incremented, false otherwise.
1158 * @param checkBackup
1159 * True if the frame should be checked for the back up tag
1160 */
1161 public static String SaveFrame(Frame toSave, boolean inc, boolean checkBackup) {
1162 // TODO When loading a frame maybe append onto the event history too-
1163 // with a break to indicate the end of a session
1164
1165 if (toSave == null || !toSave.hasChanged() || toSave.isSaved()) {
1166 return "";
1167 }
1168
1169 // Dont save if the frame is protected and it exists
1170 if (checkBackup && toSave.isReadOnly()) {
1171 _Cache.remove(toSave.getName().toLowerCase());
1172 return "";
1173 }
1174
1175 /* Dont save the frame if it has the noSave tag */
1176 if (toSave.hasAnnotation("nosave")) {
1177 Actions.LegacyPerformActionCatchErrors(toSave, null, "Restore");
1178 return "";
1179 }
1180
1181 // Save frame that is not local through the Networking classes
1182 if (!toSave.isLocal()) {
1183 return FrameShare.getInstance().saveFrame(toSave);
1184 }
1185
1186 /* Format the frame if it has the autoFormat tag */
1187 if (toSave.hasAnnotation("autoformat")) {
1188 Actions.LegacyPerformActionCatchErrors(toSave, null, "Format");
1189 }
1190
1191 /**
1192 * Get the full path only to determine which format to use for saving
1193 * the frame. At this stage use Exp format for saving Exp frames only.
1194 * Later this will be changed so that KMS frames will be updated to the
1195 * Exp format.
1196 */
1197 String fullPath = getFrameFullPathName(toSave.getPath(), toSave
1198 .getName());
1199
1200 // Check if the frame exists
1201 if (checkBackup && fullPath == null) {
1202 // The first time a frame with the backup tag is saved, dont back it
1203 // up
1204 checkBackup = false;
1205 }
1206
1207 FrameWriter writer = null;
1208 int savedVersion;
1209 try {
1210 // if its a new frame or an existing Exp frame...
1211 if (fullPath == null || fullPath.endsWith(ExpReader.EXTENTION)) {
1212 if (toSave.getNumber() != AuthenticatorBrowser.CREDENTIALS_FRAME &&
1213 toSave.getEncryptionLabel() != null) {
1214 writer = new EncryptedExpWriter(toSave.getEncryptionLabel());
1215 savedVersion = EncryptedExpReader.getVersion(fullPath);
1216 } else {
1217 writer = new ExpWriter();
1218 savedVersion = ExpReader.getVersion(fullPath);
1219 }
1220
1221 // Is the file this would be saved to a redirect?
1222 String redirectTo = ExpReader.redirectTo(fullPath);
1223 if (redirectTo != null) {
1224 String redirectedPath = toSave.getFramePathReal();
1225 writer.setOutputLocation(redirectedPath);
1226 }
1227
1228 } else {
1229 writer = new KMSWriter();
1230 savedVersion = KMSReader.getVersion(fullPath);
1231 }
1232
1233 // Check if the frame doesnt exist
1234 // if (savedVersion < 0) {
1235 // /*
1236 // * This will happen if the user has two Expeditee's running at
1237 // * once and closes the first. When the second one closes the
1238 // * messages directory will have been deleted.
1239 // */
1240 // MessageBay
1241 // .errorMessage("Could not save frame that does not exist: "
1242 // + toSave.getName());
1243 // return null;
1244 // }
1245
1246 // Check if we are trying to save an out of date version
1247 // Q: Why do we ignore version conflicts if the saved version is zero?
1248 // A: Sometimes a Frame object in memory with a specified path is not 'connected'
1249 // to the file found at that specified path yet. This occurs if a frame object
1250 // has been created, its path assigned and saved to disk; with the intention
1251 // discarding this Frame object and later saving a different Frame object to
1252 // that File. One example of this is when @old frames are created.
1253 // The new Frame object that is created and saved only to be discarded, has a
1254 // version number of zero.
1255 // Therefore, if the file created from the discarded Frame has its modification
1256 // date compared to the modification date on the Frame object that will eventually
1257 // be used to overwrite that file, it causes a false positive conflict. Checking
1258 // for the zero version number fixes this.
1259 String framesetName = toSave.getFramesetName();
1260 boolean isBayFrameset =
1261 framesetName.equalsIgnoreCase(MessageBay.MESSAGES_FRAMESET_NAME) ||
1262 framesetName.equalsIgnoreCase(MailBay.EXPEDITEE_MAIL_FRAMESET_NAME);
1263 long fileLastModify = fullPath != null ? new File(fullPath).lastModified() : 0;
1264 long frameLastModify = toSave.getLastModifyPrecise();
1265 boolean fileModifyConflict = fileLastModify > frameLastModify && !isBayFrameset;
1266 boolean versionConflict = savedVersion > toSave.getVersion() && !isBayFrameset;
1267 if ((fileModifyConflict || versionConflict) && savedVersion > 0) {
1268 // remove this frame from the cache if it is there
1269 // This will make sure links to the original are set correctly
1270 _Cache.remove(toSave.getName().toLowerCase());
1271 int nextnum = ReadINF(toSave.getPath(), toSave
1272 .getFramesetName(), false) + 1;
1273 SuspendCache();
1274 Frame original = LoadFrame(toSave.getName());
1275 toSave.setFrameNumber(nextnum);
1276 ResumeCache();
1277 // Put the modified version in the cache
1278 addToCache(toSave);
1279 // Show the messages alerting the user
1280 Text originalMessage = new Text(-1);
1281 originalMessage.setColor(MessageBay.ERROR_COLOR);
1282 StringBuilder message = new StringBuilder(original.getName()
1283 + " was updated by another user. ");
1284 if (fileModifyConflict) {
1285 message.append("{ File modify conflict }");
1286 System.err.println("Thread name: " + Thread.currentThread().getName());
1287 StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
1288 for (StackTraceElement ste: stackTrace) {
1289 System.err.println(ste.toString());
1290 }
1291 }
1292 if (versionConflict) {
1293 message.append("{ Version conflict }");
1294 }
1295 originalMessage.setText(message.toString());
1296 originalMessage.setLink(original.getName());
1297 Text yourMessage = new Text(-1);
1298 yourMessage.setColor(MessageBay.ERROR_COLOR);
1299 yourMessage.setText("Your version was renamed "
1300 + toSave.getName());
1301 yourMessage.setLink(toSave.getName());
1302 MessageBay.displayMessage(originalMessage);
1303 MessageBay.displayMessage(yourMessage);
1304 EcosystemManager.getMiscManager().beep();
1305 } else if (checkBackup
1306 && ItemUtils.ContainsExactTag(toSave.getItems(),
1307 ItemUtils.TAG_BACKUP)) {
1308 SuspendCache();
1309 String oldFramesetName = toSave.getFramesetName() + "-old";
1310
1311 Frame original = LoadFrame(toSave.getName());
1312 if (original == null) {
1313 original = toSave;
1314 }
1315 int orignum = original.getNumber();
1316
1317 int nextnum = -1;
1318 try {
1319 nextnum = ReadINF(toSave.getPath(), oldFramesetName, false) + 1;
1320 } catch (RuntimeException e) {
1321 try {
1322 CreateFrameset(oldFramesetName, toSave.getPath());
1323 nextnum = 1;
1324 } catch (Exception e1) {
1325 e1.printStackTrace();
1326 }
1327 }
1328
1329 if (nextnum > 0) {
1330 original.setFrameset(oldFramesetName);
1331 original.setFrameNumber(nextnum);
1332 original.setPermission(new PermissionPair(UserAppliedPermission.copy));
1333 original.change();
1334 SaveFrame(original, false, false);
1335 }
1336
1337 Item i = ItemUtils.FindExactTag(toSave.getItems(),
1338 ItemUtils.TAG_BACKUP);
1339 i.setLink(original.getName());
1340 toSave.setFrameNumber(orignum);
1341 ResumeCache();
1342 }
1343
1344 // int oldMode = FrameGraphics.getMode();
1345 // if (oldMode != FrameGraphics.MODE_XRAY)
1346 // FrameGraphics.setMode(FrameGraphics.MODE_XRAY, true);
1347
1348 writer.writeFrame(toSave);
1349 // FrameGraphics.setMode(oldMode, true);
1350 toSave.setSaved();
1351
1352 // Update general stuff about frame
1353 setSavedProperties(toSave);
1354
1355 if (inc) {
1356 SessionStats.SavedFrame(toSave.getName());
1357 }
1358
1359 // avoid out-of-sync frames (when in TwinFrames mode)
1360 if (_Cache.containsKey(toSave.getName().toLowerCase())) {
1361 addToCache(toSave);
1362 }
1363
1364 Logger.Log(Logger.SYSTEM, Logger.SAVE, "Saving " + toSave.getName()
1365 + " to disk.");
1366
1367 // check that the INF file is not out of date
1368 int last = ReadINF(toSave.getPath(), toSave.getFramesetName(),
1369 false);
1370 if (last <= toSave.getNumber()) {
1371 WriteINF(toSave.getPath(), toSave.getFramesetName(), toSave
1372 .getName());
1373 }
1374
1375 // check if this was the profile frame (and thus needs
1376 // re-parsing)
1377 if (isProfileFrame(toSave)) {
1378 Frame profile = FrameIO.LoadFrame(toSave.getFramesetName() + "1");
1379 assert (profile != null);
1380 FrameUtils.ParseProfile(profile);
1381 }
1382 } catch (IOException ioe) {
1383 ioe.printStackTrace();
1384 ioe.getStackTrace();
1385 Logger.Log(ioe);
1386 return null;
1387 }
1388 toSave.notifyObservers(false);
1389
1390 return writer.getFileContents();
1391 }
1392
1393 /**
1394 * Saves the given Frame to disk in the corresponding frameset directory as a RESTORE, if
1395 * inc is true then the saved frames counter is incremented, otherwise it is
1396 * untouched.
1397 *
1398 * @param toSave
1399 * The Frame to save to disk as the DEFAULT COPY
1400 * @param inc
1401 * True if the saved frames counter should be incremented, false
1402 * otherwise.
1403 * @param checkBackup
1404 * True if the frame should be checked for the back up tag
1405 */
1406 public static String SaveFrameAsRestore(Frame toSave, boolean inc,
1407 boolean checkBackup) {
1408
1409 String sf = SaveFrame(toSave, inc, checkBackup);
1410 String fullPath = getFrameFullPathName(toSave.getPath(), toSave
1411 .getName());
1412 //System.out.println(fullPath);
1413 String restoreVersion = fullPath + ".restore";
1414 File source = new File(fullPath);
1415 File dest = new File(restoreVersion);
1416
1417 FileChannel inputChannel = null;
1418 FileChannel outputChannel = null;
1419
1420 try{
1421 FileInputStream source_fis = new FileInputStream(source);
1422 inputChannel = source_fis.getChannel();
1423
1424 FileOutputStream dest_fos = new FileOutputStream(dest);
1425 outputChannel = dest_fos.getChannel();
1426
1427 outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
1428 inputChannel.close();
1429 outputChannel.close();
1430 source_fis.close();
1431 dest_fos.close();
1432 }
1433 catch(Exception e){
1434 e.printStackTrace();
1435 }
1436
1437 return sf;
1438 }
1439
1440 /**
1441 * @param toAdd
1442 */
1443 public static void addToCache(Frame toAdd) {
1444 _Cache.put(toAdd.getName().toLowerCase(), toAdd);
1445 }
1446
1447 public static void ClearCache() {
1448 _Cache.clear();
1449 }
1450
1451 /**
1452 * Checks if a frame is in the current user profile frameset.
1453 *
1454 * @param toCheck
1455 * the frame to check
1456 * @return true if the frame is in the current user profile frameset
1457 */
1458 public static boolean isProfileFrame(Frame toCheck)
1459 {
1460 if (toCheck.getNumber() == 0) {
1461 return false;
1462 }
1463
1464 return toCheck.getPath().equals(PROFILE_PATH);
1465 // return toCheck.getFramesetName()
1466 // .equalsIgnoreCase(UserSettings.ProfileName);
1467 }
1468
1469 public static Frame LoadProfile(String userName)
1470 {
1471 final String profilesLoc = System.getProperty("profiles.loc");
1472 if (profilesLoc != null) {
1473 return LoadFrame(userName + "1", profilesLoc);
1474 } else {
1475 return LoadFrame(userName + "1");
1476 }
1477 }
1478
1479 public static Frame CreateNewProfile(String username, Map<String, Setting> initialSettings, Map<String, Consumer<Frame>> toNotifyOnSet) throws InvalidFramesetNameException, ExistingFramesetException {
1480 Frame profile = CreateFrameset(username, PROFILE_PATH, true);
1481 if (profile != null) {
1482 FrameUtils.CreateDefaultProfile(username, profile, initialSettings, toNotifyOnSet);
1483 } else {
1484 System.err.println("An error occured while attempting to create the profile named: " + username);
1485 System.err.println("Unable to proceed.");
1486 System.exit(1);
1487 }
1488 return profile;
1489 }
1490
1491 /**
1492 * Reads the INF file that corresponds to the given Frame name
1493 *
1494 * @param framename
1495 * The Frame to lookup the INF file for
1496 * @throws IOException
1497 * Any exceptions encountered by the BufferedReader used to read
1498 * the INF.
1499 */
1500 public static int ReadINF(String path, String frameset, boolean update)
1501 throws IOException {
1502 assert (!frameset.endsWith("."));
1503 try {
1504 // read INF
1505 BufferedReader reader;
1506 try {
1507 // Check on the local drive
1508 reader = new BufferedReader(new FileReader(path
1509 + frameset.toLowerCase() + File.separator
1510 + INF_FILENAME));
1511 } catch (Exception e) {
1512 reader = new BufferedReader(new FileReader(path
1513 + frameset.toLowerCase() + File.separator
1514 + frameset.toLowerCase() + ".inf"));
1515 }
1516 String inf = reader.readLine();
1517 reader.close();
1518
1519 int next = Conversion.getFrameNumber(inf);
1520 // update INF file
1521 if (update) {
1522 try {
1523 WriteINF(path, frameset, frameset + (next + 1));
1524 } catch (IOException ioe) {
1525 ioe.printStackTrace();
1526 Logger.Log(ioe);
1527 }
1528 }
1529 return next;
1530 } catch (Exception e) {
1531 }
1532
1533 // Check peers
1534 return FrameShare.getInstance().getInfNumber(path, frameset, update);
1535 }
1536
1537 /**
1538 * Writes the given String out to the INF file corresponding to the current
1539 * frameset.
1540 *
1541 * @param toWrite
1542 * The String to write to the file.
1543 * @throws IOException
1544 * Any exception encountered by the BufferedWriter.
1545 */
1546 public static void WriteINF(String path, String frameset, String frameName)
1547 throws IOException {
1548 try {
1549 assert (!frameset.endsWith("."));
1550
1551 path += frameset.toLowerCase() + File.separator + INF_FILENAME;
1552
1553 BufferedWriter writer = new BufferedWriter(new FileWriter(path));
1554 writer.write(frameName);
1555 writer.close();
1556 } catch (Exception e) {
1557
1558 }
1559 }
1560
1561 public static boolean FrameIsCached(String name) {
1562 return _Cache.containsKey(name);
1563 }
1564
1565 /**
1566 * Gets a frame from the cache.
1567 *
1568 * @param name
1569 * The frame to get from the cache
1570 *
1571 * @return The frame from cache. Null if not cached.
1572 */
1573 public static Frame FrameFromCache(String name) {
1574 return _Cache.get(name);
1575 }
1576
1577 public static String ConvertToValidFramesetName(String toValidate) {
1578 assert (toValidate != null && toValidate.length() > 0);
1579
1580 StringBuffer result = new StringBuffer();
1581
1582 if (Character.isDigit(toValidate.charAt(0))) {
1583 result.append(FRAME_NAME_LAST_CHAR);
1584 }
1585
1586 boolean capital = false;
1587 for (int i = 0; i < toValidate.length()
1588 && result.length() < MAX_NAME_LENGTH; i++) {
1589 char cur = toValidate.charAt(i);
1590
1591 // capitalize all characters after spaces
1592 if (Character.isLetterOrDigit(cur)) {
1593 if (capital) {
1594 capital = false;
1595 result.append(Character.toUpperCase(cur));
1596 } else {
1597 result.append(cur);
1598 }
1599 } else {
1600 capital = true;
1601 }
1602 }
1603 assert (result.length() > 0);
1604 int lastCharIndex = result.length() - 1;
1605 if (!Character.isLetter(result.charAt(lastCharIndex))) {
1606 if (lastCharIndex == MAX_NAME_LENGTH - 1) {
1607 result.setCharAt(lastCharIndex, FRAME_NAME_LAST_CHAR);
1608 } else {
1609 result.append(FRAME_NAME_LAST_CHAR);
1610 }
1611 }
1612
1613 assert (isValidFramesetName(result.toString()));
1614 return result.toString();
1615 }
1616
1617 public static Frame CreateNewFrame(Item linker) throws RuntimeException {
1618 String title = linker.getName();
1619
1620 String templateLink = linker.getAbsoluteLinkTemplate();
1621 String framesetLink = linker.getAbsoluteLinkFrameset();
1622 String frameset = (framesetLink != null ? framesetLink : DisplayController
1623 .getCurrentFrame().getFramesetName());
1624
1625 Frame newFrame = FrameIO.CreateFrame(frameset, title, templateLink);
1626 return newFrame;
1627 }
1628
1629 public static Frame CreateNewFrame(Item linker, OnNewFrameAction action) throws RuntimeException {
1630 Frame newFrame = FrameIO.CreateNewFrame(linker);
1631 if(action != null) {
1632 action.exec(linker, newFrame);
1633 }
1634 return newFrame;
1635 }
1636
1637 /**
1638 * Creates a new Frameset on disk, including a .0, .1, and .inf files. The
1639 * Default.0 frame is copied to make the initial .0 and .1 Frames
1640 *
1641 * @param name
1642 * The Frameset name to use
1643 * @return The name of the first Frame in the newly created Frameset (the .1
1644 * frame)
1645 */
1646 public static Frame CreateNewFrameset(String name) throws Exception {
1647 String path = DisplayController.getCurrentFrame().getPath();
1648
1649 // if current frameset is profile directory change it to framesets
1650 if (path.equals(FrameIO.PROFILE_PATH)) {
1651 path = FrameIO.FRAME_PATH;
1652 }
1653
1654 Frame newFrame = FrameIO.CreateFrameset(name, path);
1655
1656 if (newFrame == null) {
1657 // Cant create directories if the path is readonly or there is no
1658 // space available
1659 newFrame = FrameIO.CreateFrameset(name, FrameIO.FRAME_PATH);
1660 }
1661
1662 if (newFrame == null) {
1663 // TODO handle running out of disk space here
1664 }
1665
1666 return newFrame;
1667 }
1668
1669 /**
1670 *
1671 * @param frameset
1672 * @return
1673 */
1674 public static int getLastNumber(String frameset) { // Rob thinks it might
1675 // have been
1676 // GetHighestNumExFrame
1677 // TODO minimise the number of frames being read in!!
1678 int num = -1;
1679
1680 Frame zero = LoadFrame(frameset + "0");
1681
1682 // the frameset does not exist (or has no 0 frame)
1683 if (zero == null) {
1684 return -1;
1685 }
1686
1687 try {
1688 num = ReadINF(zero.getPath(), frameset, false);
1689 } catch (IOException e) {
1690 // TODO Auto-generated catch block
1691 // e.printStackTrace();
1692 }
1693
1694 /*
1695 * Michael doesnt think the code below is really needed... it will just
1696 * slow things down when we are reading frames over a network***** for (;
1697 * num >= 0; num--) { System.out.println("This code is loading frames to
1698 * find the highest existing frame..."); if (LoadFrame(frameset + num) !=
1699 * null) break; }
1700 */
1701
1702 return num;
1703 }
1704
1705 /**
1706 * Checks if a given frameset is accessable.
1707 *
1708 * @param framesetName
1709 * @return
1710 */
1711 public static boolean canAccessFrameset(String framesetName) {
1712 framesetName = framesetName.toLowerCase();
1713 for (String path : FolderSettings.FrameDirs.getAbsoluteDirs()) {
1714 if (canAccessFrameset(framesetName, Paths.get(path))) {
1715 return true;
1716 }
1717 }
1718 return false;
1719 }
1720
1721 public static boolean canAccessFrameset(String framesetName, Path path) {
1722 File framesetDir = path.resolve(framesetName).toFile();
1723 if (framesetDir.exists() && framesetDir.isDirectory()) {
1724 return true;
1725 } else {
1726 return false;
1727 }
1728 }
1729
1730 public static Frame CreateFrameset(String frameset, String path, boolean recreate) throws InvalidFramesetNameException, ExistingFramesetException {
1731 String conversion = frameset + " --> ";
1732
1733 if (!isValidFramesetName(frameset)) {
1734 throw new InvalidFramesetNameException(frameset);
1735 }
1736
1737 if (!recreate && FrameIO.canAccessFrameset(frameset)) {
1738 throw new ExistingFramesetException(frameset);
1739 }
1740
1741 conversion += frameset;
1742 Logger.Log(Logger.SYSTEM, Logger.NEW_FRAMESET, "Frameset Name: "
1743 + conversion);
1744 conversion = frameset;
1745
1746 /**
1747 * TODO: Update this to exclude any\all invalid filename characters
1748 */
1749 // ignore annotation character
1750 if (frameset.startsWith("@")) {
1751 frameset = frameset.substring(1);
1752 }
1753
1754 conversion += " --> " + frameset;
1755 Logger.Log(Logger.SYSTEM, Logger.NEW_FRAMESET, "Name: " + conversion);
1756
1757 // create the new Frameset directory
1758 File dir = new File(path + frameset.toLowerCase() + File.separator);
1759
1760 // If the directory doesnt already exist then create it...
1761 if (!dir.exists()) {
1762 if (!dir.mkdirs()) {
1763 /*
1764 * If the directory does not exist, but could not be created then there is something wrong.
1765 * Prior to May 2019 the only known reason for this was because the disk could be full.
1766 * Since then, we have discovered that null can occur when working with Google file stream.
1767 * A directory can return false to an existence check, but then fail to create the directory
1768 * due to it already existing because of sync issues. While we have not confirmed, this may
1769 * be the case with other network drives as well.
1770 */
1771 System.err.println("Failed to create directory for frameset: " + frameset);
1772 return null;
1773 }
1774 }
1775
1776 // create the new INF file
1777 try {
1778 WriteINF(path, frameset, frameset + '1');
1779 } catch (IOException ioe) {
1780 ioe.printStackTrace();
1781 Logger.Log(ioe);
1782 }
1783
1784 SuspendCache();
1785 // copy the default .0 and .1 files
1786 Frame base = null;
1787 try {
1788 base = LoadFrame(TemplateSettings.DefaultFrame.get());
1789 } catch (Exception e) {
1790 }
1791 // The frame may not be accessed for various reasons... in all these
1792 // cases just create a new one
1793 if (base == null) {
1794 base = new Frame();
1795 }
1796
1797 ResumeCache();
1798
1799 base.reset();
1800 base.resetDateCreated();
1801 base.setFrameset(frameset);
1802 base.setFrameNumber(0);
1803 base.setTitle(base.getFramesetName() + "0");
1804 base.setPath(path);
1805 base.change();
1806 base.setOwner(UserSettings.UserName.get());
1807 SaveFrame(base, false);
1808
1809 base.reset();
1810 base.resetDateCreated();
1811 base.setFrameNumber(1);
1812 base.setTitle(frameset);
1813 base.change();
1814 base.setOwner(UserSettings.UserName.get());
1815 SaveFrame(base, true);
1816
1817 FrameIO.setSavedProperties(base);
1818
1819 Logger.Log(Logger.SYSTEM, Logger.NEW_FRAMESET, "Created new frameset: " + frameset);
1820
1821 return base;
1822 }
1823
1824 /**
1825 * Tests if a frameset name is valid. That is it must begin and end with a
1826 * letter and contain only letters and digits in between.
1827 *
1828 * @param frameset
1829 * the name to be tested
1830 * @return true if the frameset name is valid
1831 */
1832 public static boolean isValidFramesetName(String frameset) {
1833 if (frameset == null) {
1834 return false;
1835 }
1836
1837 int nameLength = frameset.length();
1838 if (frameset.length() <= 0 || nameLength > MAX_NAME_LENGTH) {
1839 return false;
1840 }
1841
1842 int lastCharIndex = nameLength - 1;
1843
1844 if (!Character.isLetter(frameset.charAt(0))
1845 || !Character.isLetter(frameset.charAt(lastCharIndex))) {
1846 return false;
1847 }
1848
1849 for (int i = 1; i < lastCharIndex; i++) {
1850 if (!isValidFrameNameChar(frameset.charAt(i))) {
1851 return false;
1852 }
1853 }
1854 return true;
1855 }
1856
1857 public static boolean deleteFrameset(String framesetName) {
1858 return moveFrameset(framesetName, FrameIO.TRASH_PATH, true);
1859 }
1860
1861 public static boolean moveFrameset(String framesetName, String destinationFolder, boolean override) {
1862 if (!FrameIO.canAccessFrameset(framesetName)) {
1863 return false;
1864 }
1865 // Clear the cache
1866 _Cache.clear();
1867
1868 // Search all the available directories for the directory
1869 for (String path : FolderSettings.FrameDirs.getAbsoluteDirs()) {
1870 return moveFrameset(framesetName, path, destinationFolder, override);
1871 }
1872 return false;
1873 }
1874
1875 public static boolean moveFrameset(String framesetName, String path, String destinationFolder, boolean override) {
1876 String source = path + framesetName.toLowerCase() + File.separator;
1877 File framesetDirectory = new File(source);
1878 // Once we have found the directory move it
1879 if (framesetDirectory.exists()) {
1880 String destPath = destinationFolder
1881 + framesetName.toLowerCase();
1882 int copyNumber = 1;
1883 File dest = new File(destPath + File.separator);
1884 // Create the destination folder if it doesnt already exist
1885 if (!dest.getParentFile().exists()) {
1886 dest.mkdirs();
1887 }
1888 // If a frameset with the same name is already in the
1889 // destination add
1890 // a number to the end
1891 while (dest.exists() && !override) {
1892 dest = new File(destPath + ++copyNumber + File.separator);
1893 }
1894 try {
1895 moveFileTree(framesetDirectory.toPath(), dest.toPath());
1896 } catch (IOException e) {
1897 e.printStackTrace();
1898 return false;
1899 }
1900
1901 for (File f : framesetDirectory.listFiles()) {
1902 if (!f.delete()) {
1903 return false;
1904 }
1905 }
1906 if (!framesetDirectory.delete()) {
1907 return false;
1908 }
1909 return true;
1910 } else {
1911 return false;
1912 }
1913 }
1914
1915 public static boolean CopyFrameset(String framesetToCopy,
1916 String copiedFrameset) throws Exception {
1917 if (!FrameIO.canAccessFrameset(framesetToCopy)) {
1918 return false;
1919 }
1920 if (FrameIO.canAccessFrameset(copiedFrameset)) {
1921 return false;
1922 }
1923 // search through all the directories to find the frameset we are
1924 // copying
1925 for (String path : FolderSettings.FrameDirs.getAbsoluteDirs()) {
1926 String source = path + framesetToCopy.toLowerCase()
1927 + File.separator;
1928 File framesetDirectory = new File(source);
1929 if (framesetDirectory.exists()) {
1930 // copy the frameset
1931 File copyFramesetDirectory = new File(path
1932 + copiedFrameset.toLowerCase() + File.separator);
1933 if (!copyFramesetDirectory.mkdirs()) {
1934 return false;
1935 }
1936 // copy each of the frames
1937 for (File f : framesetDirectory.listFiles()) {
1938 // Ignore hidden files
1939 if (f.getName().charAt(0) == '.') {
1940 continue;
1941 }
1942 String copyPath = copyFramesetDirectory.getAbsolutePath()
1943 + File.separator + f.getName();
1944 FrameIO.copyFile(f.getAbsolutePath(), copyPath);
1945 }
1946 return true;
1947 }
1948 }
1949 return false;
1950 }
1951
1952 /**
1953 * Copies a file from one location to another.
1954 *
1955 * @param existingFile
1956 * @param newFileName
1957 * @throws Exception
1958 */
1959 public static void copyFile(String existingFile, String newFileName)
1960 throws IOException {
1961 FileInputStream is = new FileInputStream(existingFile);
1962 FileOutputStream os = new FileOutputStream(newFileName, false);
1963 int data;
1964 while ((data = is.read()) != -1) {
1965 os.write(data);
1966 }
1967 os.flush();
1968 os.close();
1969 is.close();
1970 }
1971
1972 /**
1973 * Saves a frame regardless of whether or not the frame is marked as having
1974 * been changed.
1975 *
1976 * @param frame
1977 * the frame to save
1978 * @return the contents of the frame or null if it could not be saved
1979 */
1980 public static String ForceSaveFrame(Frame frame) {
1981 frame.change();
1982 return SaveFrame(frame, false);
1983 }
1984
1985 public static boolean isValidLink(String frameName) {
1986 return frameName == null || isPositiveInteger(frameName)
1987 || isValidFrameName(frameName);
1988 }
1989
1990 public static void SavePublicFrame(String peerName, String frameName,
1991 int version, BufferedReader packetContents) {
1992 // TODO handle versioning - add version to the header
1993 // Remote user uploads version based on an old version
1994
1995 // Remove it from the cache so that next time it is loaded we get the up
1996 // todate version
1997 _Cache.remove(frameName.toLowerCase());
1998
1999 // Save to file
2000 String filename = PUBLIC_PATH + Conversion.getFramesetName(frameName)
2001 + File.separator + Conversion.getFrameNumber(frameName)
2002 + ExpReader.EXTENTION;
2003
2004 File file = new File(filename);
2005 // Ensure the file exists
2006 if (file.exists()) {
2007 // Check the versions
2008 int savedVersion = ExpReader.getVersion(filename);
2009
2010 if (savedVersion > version) {
2011 // remove this frame from the cache if it is there
2012 // This will make sure links to the original are set correctly
2013 // _Cache.remove(frameName.toLowerCase());
2014
2015 int nextNum = 0;
2016 try {
2017 nextNum = ReadINF(PUBLIC_PATH, Conversion
2018 .getFramesetName(frameName), false) + 1;
2019 } catch (IOException e) {
2020 e.printStackTrace();
2021 }
2022
2023 String newName = Conversion.getFramesetName(frameName)
2024 + nextNum;
2025 filename = PUBLIC_PATH + Conversion.getFramesetName(frameName)
2026 + File.separator + nextNum + ExpReader.EXTENTION;
2027
2028 // Show the messages alerting the user
2029 Text originalMessage = new Text(-1);
2030 originalMessage.setColor(MessageBay.ERROR_COLOR);
2031 originalMessage.setText(frameName + " was edited by "
2032 + peerName);
2033 originalMessage.setLink(frameName);
2034 Text yourMessage = new Text(-1);
2035 yourMessage.setColor(MessageBay.ERROR_COLOR);
2036 yourMessage.setText("Their version was renamed " + newName);
2037 yourMessage.setLink(newName);
2038 MessageBay.displayMessage(originalMessage);
2039 MessageBay.displayMessage(yourMessage);
2040
2041 Frame editedFrame = FrameIO.LoadFrame(frameName);
2042
2043 FrameShare.getInstance().sendMessage(
2044 frameName + " was recently edited by "
2045 + editedFrame.getLastModifyUser(), peerName);
2046 FrameShare.getInstance().sendMessage(
2047 "Your version was renamed " + newName, peerName);
2048 }
2049 }
2050
2051 // Save the new version
2052 try {
2053 // FileWriter fw = new FileWriter(file);
2054
2055 // Open an Output Stream Writer to set encoding
2056 OutputStream fout = new FileOutputStream(file);
2057 OutputStream bout = new BufferedOutputStream(fout);
2058 Writer fw = new OutputStreamWriter(bout, "UTF-8");
2059
2060 String nextLine = null;
2061 while ((nextLine = packetContents.readLine()) != null) {
2062 fw.write(nextLine + '\n');
2063 }
2064 fw.flush();
2065 fw.close();
2066 MessageBay.displayMessage("Saved remote frame: " + frameName);
2067 } catch (IOException e) {
2068 MessageBay.errorMessage("Error remote saving " + frameName + ": "
2069 + e.getMessage());
2070 e.printStackTrace();
2071 }
2072 }
2073
2074 public static void setSavedProperties(Frame toSave) {
2075 toSave.setLastModifyDate(Formatter.getDateTime(), System.currentTimeMillis());
2076 toSave.setLastModifyUser(UserSettings.UserName.get());
2077 toSave.setVersion(toSave.getVersion() + 1);
2078 Time darkTime = new Time(SessionStats.getFrameDarkTime().getTime()
2079 + toSave.getDarkTime().getTime());
2080 Time activeTime = new Time(SessionStats.getFrameActiveTime().getTime()
2081 + toSave.getActiveTime().getTime());
2082 toSave.setDarkTime(darkTime);
2083 toSave.setActiveTime(activeTime);
2084 }
2085
2086 public static Path setupPersonalResources(String username) {
2087 Path personalResources = Paths.get(FrameIO.PARENT_FOLDER).resolve("resources-" + username);
2088 personalResources.toFile().mkdir();
2089 File[] globalResourcesToCopy = Paths.get(FrameIO.RESOURCES_PRIVATE_PATH).toFile().listFiles();
2090
2091 try {
2092 for (File toCopy: globalResourcesToCopy) {
2093 Path p = Paths.get(toCopy.getAbsolutePath());
2094 if (!p.getFileName().toString().equals(".res") && !p.getFileName().toString().equals("about")) {
2095 moveFileTree(p.toAbsolutePath(), personalResources.resolve(p.getFileName()));
2096 }
2097 }
2098 } catch (IOException e) {
2099 e.printStackTrace();
2100 personalResources = null;
2101 }
2102
2103 return personalResources;
2104 }
2105
2106 public static void migrateFrame(Frame toMigrate, Path destinationDirectory) {
2107 Path source = Paths.get(toMigrate.getFramePathReal());
2108 String destination = source.relativize(destinationDirectory).toString().substring(3).replace(File.separator, "/");
2109 try {
2110 Files.move(source, destinationDirectory);
2111 } catch (IOException e) {
2112 System.err.println("FrameIO::migrateFrame: failed to migrate from to new location. Message: " + e.getMessage());
2113 return;
2114 }
2115 try {
2116 FileWriter out = new FileWriter(source.toFile());
2117 out.write("REDIRECT:" + destination);
2118 out.flush();
2119 out.close();
2120 } catch (IOException e) {
2121 System.err.println("FrameIO::migrateFrame: failed to update file [" + source + "] to redirect to [" + destination + "] following migration. Message: " + e.getMessage());
2122 }
2123 }
2124
2125 private static void moveFileTree(Path source, Path target) throws IOException {
2126 if (source.toFile().isDirectory()) {
2127 if (!target.toFile().exists()) {
2128 Files.copy(source, target);
2129 }
2130 File[] files = source.toFile().listFiles();
2131 for (File file: files) {
2132 Path asPath = Paths.get(file.getAbsolutePath());
2133 moveFileTree(asPath, target.resolve(asPath.getFileName()));
2134 }
2135 } else {
2136 Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
2137 }
2138 }
2139}
Note: See TracBrowser for help on using the repository browser.