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

Last change on this file since 1102 was 1102, checked in by davidb, 6 years ago

Reworking of the code-base to separate logic from graphics. This version of Expeditee now supports a JFX graphics as an alternative to SWING

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