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

Last change on this file since 997 was 997, checked in by davidb, 8 years ago

Added new version of FrameIO

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