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

Last change on this file since 1193 was 1188, checked in by bln4, 6 years ago

org.expeditee.gui.FrameIO ->

Added ability to specify were frames are being loaded from.

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