source: trunk/src/org/expeditee/actions/Misc.java@ 1477

Last change on this file since 1477 was 1477, checked in by bnemhaus, 4 years ago

Added label existance check for when setting encryption label on a frame.

Added padlock icon on items that are encrypted.

Added key icon on items with KeyImage property set to 'PartialKey' or 'FullKey'. This will hopefully soon transformed into automatically setting these properties on key items that are on the secrets frame. The property should not be set-able by user once fully implemented and is only atm for debug purposes.

File size: 48.0 KB
Line 
1/**
2 * Misc.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.actions;
20
21import java.io.BufferedReader;
22import java.io.File;
23import java.io.FileNotFoundException;
24import java.io.IOException;
25import java.io.InputStream;
26import java.io.InputStreamReader;
27import java.lang.reflect.Method;
28import java.net.URL;
29import java.net.URLClassLoader;
30import java.nio.file.Path;
31import java.nio.file.Paths;
32import java.util.ArrayList;
33import java.util.Collection;
34import java.util.HashMap;
35import java.util.LinkedList;
36import java.util.List;
37import java.util.Map;
38import java.util.Map.Entry;
39import java.util.jar.Attributes;
40import java.util.jar.JarFile;
41
42import org.expeditee.core.Colour;
43import org.expeditee.core.Image;
44import org.expeditee.core.Point;
45import org.expeditee.gio.EcosystemManager;
46import org.expeditee.gio.gesture.StandardGestureActions;
47import org.expeditee.gui.AttributeUtils;
48import org.expeditee.gui.DisplayController;
49import org.expeditee.gui.Frame;
50import org.expeditee.gui.FrameGraphics;
51import org.expeditee.gui.FrameIO;
52import org.expeditee.gui.FrameUtils;
53import org.expeditee.gui.FreeItems;
54import org.expeditee.gui.MessageBay;
55import org.expeditee.gui.MessageBay.Progress;
56import org.expeditee.gui.Reminders;
57import org.expeditee.gui.TimeKeeper;
58import org.expeditee.io.Conversion;
59import org.expeditee.io.ExpReader;
60import org.expeditee.items.Item;
61import org.expeditee.items.ItemUtils;
62import org.expeditee.items.Line;
63import org.expeditee.items.Picture;
64import org.expeditee.items.Text;
65import org.expeditee.items.XRayable;
66import org.expeditee.items.widgets.Widget;
67import org.expeditee.items.widgets.WidgetCorner;
68import org.expeditee.items.widgets.WidgetEdge;
69import org.expeditee.math.ExpediteeJEP;
70import org.expeditee.settings.UserSettings;
71import org.expeditee.simple.SString;
72import org.expeditee.stats.CometStats;
73import org.expeditee.stats.DocumentStatsFast;
74import org.expeditee.stats.SessionStats;
75import org.expeditee.stats.StatsLogger;
76import org.expeditee.stats.TreeStats;
77import org.nfunk.jep.Node;
78import org.nfunk.jep.ParseException;
79
80
81
82/**
83 * A list of miscellaneous Actions specific to Expeditee
84 *
85 */
86public class Misc {
87
88 /**
89 * Causes the system to beep
90 */
91 public static void beep()
92 {
93 EcosystemManager.getMiscManager().beep();
94 }
95
96 /**
97 * Returns an Item located at the specified position.
98 * kgas1 - 23/01/2012
99 * @param x
100 * @param y
101 * @return
102 */
103 public static Item getItemAtPosition(int x, int y, Frame f)
104 {
105 Frame current = f;
106 List<Item> allItems = current.getSortedItems();
107
108 for(Item i : allItems)
109 {
110 if(i.getX() == x && i.getY() == y)
111 return i;
112 }
113
114 return null;
115 }
116
117 /**
118 * Returns an item containing a specified piece of data.
119 * kgas1 - 7/06/2012
120 * @param s
121 * @param f
122 * @return
123 */
124 public static Item getItemContainingData(String s, Frame f){
125
126 Frame current = f;
127
128 List<Item> allItems = current.getSortedItems();
129
130
131 for(Item i : allItems){
132
133
134 if(i.getData() != null && i.getData().size() > 0){
135 if(i.getData().contains(s)){
136 return i;
137 }
138 }
139 }
140
141 return null;
142 }
143
144 public static void openURL(Item item){
145
146 if(item.getData() != null && item.getData().size() > 0){
147
148 String url = item.getData().get(0);
149 openURL(url);
150 }
151
152 //openURL("http://www.google.com");
153 }
154 /**
155 * Treats a string as a URL and attempts to open it
156 */
157 public static void openURL(String siteURL)
158 {
159 boolean success = EcosystemManager.getMiscManager().browse(siteURL);
160
161 if (!success) MessageBay.displayMessage("'" + siteURL + "' is not a valid URL");
162 }
163 /**
164 * Backs up the current frame as a default and saves it to the file
165 */
166 public static void setRestorePoint()
167 {
168 Frame current = DisplayController.getCurrentFrame();
169 current.change();
170 FrameIO.SaveFrameAsRestore(current, true, true);
171 }
172 /**
173 * Forces a repaint of the current Frame
174 */
175 public static void display() {
176 DisplayController.requestRefresh(false);
177 }
178
179 public static String getWindowSize() {
180 return EcosystemManager.getGraphicsManager().getWindowSize().toString();
181 }
182
183 /**
184 * Restores the current frame to the last saved version currently on the
185 * hard disk
186 */
187 public static void restore() {
188 FrameIO.Reload();
189 // MessageBay.displayMessage("Restoration complete.");
190 }
191
192 /**
193 * Toggles AudienceMode on or off
194 */
195 public static void toggleAudienceMode() {
196 DisplayController.ToggleAudienceMode();
197 }
198
199 /**
200 * Toggles TwinFrames mode on or off
201 */
202 public static void toggleTwinFramesMode() {
203 DisplayController.toggleTwinFrames();
204 }
205
206 /**
207 * If the given Item is a Text Item, then the text of the Item is
208 * interpreted as actions, if not this method does nothing.
209 *
210 * @param current
211 * The Item to read the Actions from
212 */
213 public static void runItem(Item current) throws Exception {
214 if (current instanceof Text) {
215 List<String> actions = ((Text) current).getTextList();
216 for (String action : actions) {
217 if (!action.equalsIgnoreCase("runitem")) {
218 Actions.LegacyPerformAction(DisplayController.getCurrentFrame(), current,
219 action);
220 }
221 }
222 } else {
223 MessageBay.errorMessage("Item must be a text item.");
224 }
225 }
226
227 /**
228 * Prompts the user to confirm deletion of the current Frame, and deletes if
229 * the user chooses. After deletion this action calls back(), to ensure the
230 * deleted frame is not still being shown
231 *
232 */
233 public static void DeleteFrame(Frame toDelete) {
234 String deletedFrame = toDelete.getName();
235 String deletedFrameNameLowercase = deletedFrame.toLowerCase();
236 String errorMessage = "Error deleting " + deletedFrame;
237 try {
238 String deletedFrameName = FrameIO.DeleteFrame(toDelete);
239 if (deletedFrameName != null) {
240 DisplayController.Back();
241 // Remove any links on the previous frame to the one being
242 // deleted
243 Frame current = DisplayController.getCurrentFrame();
244 for (Item i : current.getSortedItems())
245 if (i.getLink() != null
246 && i.getAbsoluteLink().toLowerCase().equals(
247 deletedFrameNameLowercase)) {
248 i.setLink(null);
249 }
250 MessageBay.displayMessage(deletedFrame + " renamed "
251 + deletedFrameName);
252 // FrameGraphics.Repaint();
253 return;
254 }
255 } catch (IOException ioe) {
256 if (ioe.getMessage() != null)
257 errorMessage += ". " + ioe.getMessage();
258 } catch (SecurityException se) {
259 if (se.getMessage() != null)
260 errorMessage += ". " + se.getMessage();
261 } catch (Exception e) {
262 e.printStackTrace();
263 }
264 MessageBay.errorMessage(errorMessage);
265 }
266
267 /**
268 * Loads the Frame linked to by the given Item. The first Item on the Frame
269 * that is not the title or name is then placed on the cursor. If the given
270 * Item has no link, or no item is found then this is a no-op.
271 *
272 * @param current
273 * The Item that links to the Frame that the Item will be loaded
274 * from.
275 */
276 public static Item GetItemFromChildFrame(Item current) {
277 return getFromChildFrame(current, false);
278 }
279
280 public static void GetItemsFromChildFrame(Item current) {
281 getItemsFromChildFrame(current, false);
282 }
283
284 /**
285 * Loads the Frame linked to by the given Item. The first Text Item on the
286 * Frame that is not the title or name is then placed on the cursor. If the
287 * given Item has no link, or no item is found then this is a no-op.
288 *
289 * @param current
290 * The Item that links to the Frame that the Item will be loaded
291 * from.
292 */
293 public static Item GetTextFromChildFrame(Item current) {
294 return getFromChildFrame(current, true);
295 }
296
297 private static Item getFromChildFrame(Item current, boolean textOnly) {
298 Item item = getFirstBodyItemOnChildFrame(current, textOnly);
299 // if no item was found
300 if (item != null) {
301 // copy the item and switch
302 item = item.copy();
303 item.setPosition(DisplayController.getMousePosition());
304 }
305 return item;
306 }
307
308 private static void getItemsFromChildFrame(Item current, boolean textOnly) {
309 Collection<Item> items = getItemsOnChildFrame(current, textOnly);
310 // if no item was found
311 if (items == null || items.size() == 0) {
312 return;
313 }
314
315 // copy the item and switch
316 Collection<Item> copies = ItemUtils.CopyItems(items);
317 Item first = items.iterator().next();
318 float deltaX = DisplayController.getMouseX() - first.getX();
319 float deltaY = DisplayController.getMouseY() - first.getY();
320 for (Item i : copies) {
321 if (i.isVisible())
322 i.setXY(i.getX() + deltaX, i.getY() + deltaY);
323 i.setParent(null);
324 }
325 StandardGestureActions.pickup(copies);
326 DisplayController.requestRefresh(true);
327 }
328
329 /**
330 * Sets the given Item to have the Given Color. Color can be null (for
331 * default)
332 *
333 * @param toChange
334 * The Item to set the Color.
335 * @param toUse
336 * The Color to give the Item.
337 */
338 public static void SetItemBackgroundColor(Item toChange, Colour toUse) {
339 if (toChange == null)
340 return;
341
342 toChange.setBackgroundColor(toUse);
343 DisplayController.requestRefresh(true);
344 }
345
346 /**
347 * Sets the given Item to have the Given Color. Color can be null (for
348 * default)
349 *
350 * @param toChange
351 * The Item to set the Color.
352 * @param toUse
353 * The Color to give the Item.
354 */
355 public static void SetItemColor(Item toChange, Colour toUse) {
356 if (toChange == null)
357 return;
358
359 toChange.setColor(toUse);
360 DisplayController.requestRefresh(true);
361 }
362
363 /**
364 * Creates a new Text Object containing general statistics for the current
365 * session. The newly created Text Object is then attached to the cursor via
366 * FrameMouseActions.pickup(Item)
367 */
368 public static void GetSessionStats() {
369 attachStatsToCursor(SessionStats.getCurrentStats());
370 }
371
372 /**
373 * Creates a new Text Object containing statistics for the current tree.
374 */
375 public static String GetCometStats(Frame frame) {
376 TimeKeeper timer = new TimeKeeper();
377 MessageBay.displayMessage("Computing comet stats...");
378 CometStats cometStats = new CometStats(frame);
379 String result = cometStats.toString();
380 MessageBay.overwriteMessage("Comet stats time: "
381 + timer.getElapsedStringSeconds());
382 return result;
383 }
384
385 public static String GetTreeStats(Frame frame) {
386 TimeKeeper timer = new TimeKeeper();
387 MessageBay.displayMessage("Computing tree stats...");
388
389 TreeStats treeStats = new TreeStats(frame);
390 String result = treeStats.toString();
391 MessageBay.overwriteMessage("Tree stats time: "
392 + timer.getElapsedStringSeconds());
393 return result;
394
395 }
396
397 public static String GetDocumentStats(Frame frame) {
398 TimeKeeper timer = new TimeKeeper();
399 MessageBay.displayMessage("Computing document stats...");
400 FrameIO.ForceSaveFrame(frame);
401 DocumentStatsFast docStats = new DocumentStatsFast(frame.getName(),
402 frame.getTitle());
403 String result = docStats.toString();
404
405 MessageBay.overwriteMessage("Document stats time: "
406 + timer.getElapsedStringSeconds());
407 return result;
408
409 }
410
411 /**
412 * Creates a text item and attaches it to the cursor.
413 *
414 * @param itemText
415 * the text to attach to the cursor
416 */
417 public static void attachStatsToCursor(String itemText) {
418 SessionStats.CreatedText();
419 Frame current = DisplayController.getCurrentFrame();
420 Item text = current.getStatsTextItem(itemText);
421 StandardGestureActions.pickup(text);
422 DisplayController.requestRefresh(true);
423 }
424
425 public static void attachTextToCursor(String itemText) {
426 SessionStats.CreatedText();
427 Frame current = DisplayController.getCurrentFrame();
428 Item text = current.getTextItem(itemText);
429 StandardGestureActions.pickup(text);
430 DisplayController.requestRefresh(true);
431 }
432
433 /**
434 * Creates a new Text Object containing statistics for moving, deleting and
435 * creating items in the current session. The newly created Text Object is
436 * then attached to the cursor via FrameMouseActions.pickup(Item)
437 */
438 public static String getItemStats() {
439 return SessionStats.getItemStats();
440 }
441
442 /**
443 * Creates a new Text Object containing statistics for the time between
444 * events triggered by the user through mouse clicks and key presses. The
445 * newly created Text Object is then attached to the cursor via
446 * FrameMouseActions.pickup(Item)
447 */
448 public static String getEventStats() {
449 return SessionStats.getEventStats();
450 }
451
452 /**
453 * Creates a new Text Object containing the contents of the current frames
454 * file.
455 */
456 public static String getFrameFile(Frame frame) {
457 return FrameIO.ForceSaveFrame(frame);
458 }
459
460 /**
461 * Creates a new Text Object containing the available fonts.
462 */
463 public static String getFontNames() {
464 Collection<String> availableFonts = Actions.getFonts().values();
465 StringBuilder fontsList = new StringBuilder();
466 for (String s : availableFonts) {
467 fontsList.append(s).append(Text.LINE_SEPARATOR);
468 }
469 fontsList.deleteCharAt(fontsList.length() - 1);
470
471 return fontsList.toString();
472 }
473 /**
474 * Creates a new Text Object containing the available fonts already loaded into Expeditee.
475 */
476 public static String getExpediteeFontNames(){
477
478 StringBuilder fontsList = new StringBuilder();
479
480 for (String s: Text.FONT_WHEEL){
481
482 fontsList.append(s).append(Text.LINE_SEPARATOR);
483 }
484
485 for (Entry<String, org.expeditee.core.Font> entry: Text.FONT_WHEEL_ADDITIONAL_LOOKUP.entrySet()){
486
487 String fontName = entry.getKey();
488 fontsList.append(fontName).append(Text.LINE_SEPARATOR);
489 }
490 //add the default soon too
491 fontsList.deleteCharAt(fontsList.length() - 1);
492 return fontsList.toString();
493 }
494
495 public static String getUnicodeCharacters(int start, int finish) {
496 if (start < 0 && finish < 0) {
497 throw new RuntimeException("Parameters must be non negative");
498 }
499 // Swap the start and finish if they are inthe wrong order
500 if (start > finish) {
501 start += finish;
502 finish = start - finish;
503 start = start - finish;
504 }
505 StringBuilder charList = new StringBuilder();
506 int count = 0;
507 charList.append(String.format("Unicode block 0x%x - 0x%x", start,
508 finish));
509 System.out.println(); // Is this println needed?
510 // charList.append("Unicode block: ").append(String.format(format,
511 // args))
512 for (char i = (char) start; i < (char) finish; i++) {
513 if (Character.isDefined(i)) {
514 if (count++ % 64 == 0)
515 charList.append(Text.LINE_SEPARATOR);
516 charList.append(Character.valueOf(i));
517 }
518 }
519 return charList.toString();
520 }
521
522 /**
523 * Gets a single block of Unicode characters.
524 *
525 * @param start
526 * the start of the block
527 */
528 public static String getUnicodeCharacters(int start) {
529 return getUnicodeCharacters(start, start + 256);
530 }
531
532 /**
533 * Get a single Unicode character
534 *
535 * @param codePoint
536 * the Unicode codePoint
537 */
538 public static String getUnicodeCharacter(int codePoint) {
539 char codePointChar = (char) codePoint;
540 if (Character.isDefined(codePointChar)) {
541 return Character.valueOf(codePointChar).toString();
542 }
543 else {
544 MessageBay.errorMessage("Character value '" + codePoint +"' not defined");
545 return "";
546 }
547 }
548
549 public static String getMathSymbols() {
550 return getUnicodeCharacters('\u2200', '\u2300');
551 }
552
553 /**
554 * Resets the statistics back to zero.
555 */
556 public static void repaint() {
557 StatsLogger.WriteStatsFile();
558 SessionStats.resetStats();
559 }
560
561 /**
562 * Loads a frame with the given name and saves it as a JPEG image.
563 *
564 * @param framename
565 * The name of the Frame to save
566 */
567 public static void jpegFrame(String framename) {
568 ImageFrame(framename, "JPEG");
569 }
570
571 /**
572 * Saves the current frame as a JPEG image. This is the same as calling
573 * JpegFrame(currentFrame.getName())
574 */
575 public static void jpegFrame() {
576 ImageFrame(DisplayController.getCurrentFrame().getName(), "JPEG");
577 }
578
579 public static void jpgFrame() {
580 jpegFrame();
581 }
582
583 /**
584 * Loads a frame with the given name and saves it as a PNG image.
585 *
586 * @param framename
587 * The name of the Frame to save
588 */
589 public static void PNGFrame(String framename) {
590 ImageFrame(framename, "PNG");
591 }
592
593 /**
594 * Saves the current frame as a PNG image. This is the same as calling
595 * PNGFrame(currentFrame.getName())
596 */
597 public static void PNGFrame(Frame frame) {
598 ImageFrame(frame.getName(), "PNG");
599 }
600
601 public static String SaveImage(Image screen, String format,
602 String directory, String fileName) {
603 String suffix = "." + format.toLowerCase();
604 String shortFileName = fileName;
605 // Check if we need to append the suffix
606 if (fileName.indexOf('.') < 0)
607 fileName += suffix;
608 else
609 shortFileName = fileName.substring(0, fileName.length() - suffix.length());
610
611 try {
612 int count = 2;
613 // set up the file for output
614 File out = new File(directory + fileName);
615 while (out.exists()) {
616 fileName = shortFileName + "_" + count++ + suffix;
617 out = new File(directory + fileName);
618 }
619
620 if (!out.getParentFile().exists())
621 out.mkdirs();
622
623 // If the image is successfully written out return the fileName
624 if (screen.writeToDisk(format, out))
625 return fileName;
626
627 } catch (Exception e) {
628 e.printStackTrace();
629 }
630 return null;
631 }
632
633 public static String ImageFrame(Frame frame, String format, String directory) {
634 assert (frame != null);
635
636 Image oldBuffer = frame.getBuffer();
637 frame.setBuffer(null);
638 // Jpeg only works properly with volatile frames
639 // Png transparency only works with bufferedImage form
640 Image frameBuffer = FrameGraphics.getFrameImage(frame, null, null, false, format.equalsIgnoreCase("jpeg"));
641 // Make sure overlay stuff doesnt disappear on the frame visible on the
642 // screen
643 frame.setBuffer(oldBuffer);
644
645 return SaveImage(frameBuffer, format, directory, frame.getExportFileName());
646 }
647
648 /**
649 * Saves the Frame with the given Framename as an image of the given format.
650 *
651 * @param framename
652 * The name of the Frame to save as an image
653 * @param format
654 * The Image format to use (i.e. "PNG", "BMP", etc)
655 */
656 public static void ImageFrame(String framename, String format) {
657 Frame loaded = FrameIO.LoadFrame(framename);
658
659 // if the frame was loaded successfully
660 if (loaded != null) {
661 String path = FrameIO.EXPORTS_PATH;
662 String frameName = ImageFrame(loaded, format, path);
663 if (frameName != null)
664 MessageBay.displayMessage("Frame successfully saved to " + path
665 + frameName);
666 else
667 MessageBay.errorMessage("Could not find image writer for "
668 + format + " format");
669 // if the frame was not loaded successfully, alert the user
670 } else {
671 MessageBay.displayMessage("Frame '" + framename
672 + "' could not be found.");
673 }
674 }
675
676 public static void MessageLn(Item message) {
677 if (message instanceof Text)
678 MessageBay.displayMessage((Text) message);
679 }
680
681 /**
682 * Displays a message in the message box area.
683 *
684 * @param message
685 * the message to display
686 */
687 public static void MessageLn(String message) {
688 MessageBay.displayMessage(message);
689 }
690
691 public static void MessageLn2(String message, String message2) {
692 MessageBay.displayMessage(message + " " + message2);
693 }
694
695 public static void FramesetMigrateImages() {
696 final Frame current = DisplayController.getCurrentFrame();
697 final String frameset = current.getFramesetName();
698 final int lastNumber = FrameIO.getLastNumber(frameset);
699 for(int i = 0; i <= lastNumber; i++) {
700 MigrateImages(FrameUtils.getFrame(frameset + i));
701 }
702 }
703
704 public static void MigrateImages() { MigrateImages(DisplayController.getCurrentFrame()); }
705
706 public static void MigrateImages(Frame frame) {
707 //Collect the images on frame
708 final Collection<Item> items = frame.getSortedItems();
709 final Collection<Item> imagesTextItems = new LinkedList<Item>();
710 items.forEach(i -> { if(i.getText().startsWith("@i")) imagesTextItems.add(i); });
711 final Map<Item, Collection<Path>> images = new HashMap<Item, Collection<Path>>();
712 imagesTextItems.forEach(it -> {
713 final Collection<? extends XRayable> enclosures = it.getEnclosures();
714 final Collection<Path> paths = new LinkedList<Path>();
715 enclosures.forEach(enc -> { if(enc instanceof Picture) paths.add(Paths.get(enc.getName())); });
716 images.put(it, paths);
717 });
718
719 //Separate into categories: absolute external, absolute internal. Discard relative.
720 final Map<Item, Collection<Path>> imagesAbsolute = new HashMap<Item, Collection<Path>>();
721 images.keySet().forEach(key -> images.get(key).forEach(path -> {
722 if(path.isAbsolute())
723 if(imagesAbsolute.containsKey(key)) imagesAbsolute.get(key).add(path);
724 else {
725 final Collection<Path> paths = new LinkedList<Path>();
726 paths.add(path);
727 imagesAbsolute.put(key, paths);
728 }
729 }));
730 final Path imagesPath = Paths.get(FrameIO.IMAGES_PATH);
731 final Map<Item, Collection<Path>> imagesAbsoluteInternal = new HashMap<Item, Collection<Path>>();
732 imagesAbsolute.keySet().forEach(key -> imagesAbsolute.get(key).forEach(path -> {
733 if(path.startsWith(imagesPath))
734 if(imagesAbsoluteInternal.containsKey(key)) imagesAbsoluteInternal.get(key).add(path);
735 else {
736 final Collection<Path> paths = new LinkedList<Path>();
737 paths.add(path);
738 imagesAbsoluteInternal.put(key, paths);
739 }
740 }));
741 final Map<Item, Collection<Path>> imagesAbsoluteExternal = new HashMap<Item, Collection<Path>>();
742 imagesAbsolute.keySet().forEach(key -> imagesAbsolute.get(key).forEach(path -> {
743 if(!path.startsWith(imagesPath))
744 if(imagesAbsoluteExternal.containsKey(key)) imagesAbsoluteExternal.get(key).add(path);
745 else {
746 final Collection<Path> paths = new LinkedList<Path>();
747 paths.add(path);
748 imagesAbsoluteExternal.put(key, paths);
749 }
750 }));
751
752 //Bryce: I am not sure why each Item is programmed to be able to have a collection of XRayables rather
753 //than a single one. Up until this point I have programmed defensively to retain this possibility. At
754 //this point the code will begin to simply use the first XRayable to determine the content of the @i.
755
756 //Transform absolute internal images into relative.
757 imagesAbsoluteInternal.keySet().forEach(key -> {
758 final Path imagePath = imagesAbsoluteInternal.get(key).iterator().next();
759 final Path relative = imagesPath.relativize(imagePath);
760 key.setText(key.getText().replace(imagePath.toString(), relative.toString()));
761 MessageBay.displayMessage("Migrated image: " + imagePath + ". It now uses the relative path: " + relative);
762 });
763
764 //Transform absolute external images into relative
765 imagesAbsoluteExternal.keySet().forEach(key -> {
766 final Path imagePath = imagesAbsoluteExternal.get(key).iterator().next();
767 try {
768 Path p = imagesPath.resolve(imagePath.getFileName());
769 FrameIO.copyFile(imagePath.toString(), p.toString());
770 final Path relative = imagesPath.relativize(p);
771 key.setText(key.getText().replace(imagePath.toString(), relative.toString()));
772 MessageBay.displayMessage("Migrated image: " + imagePath + ". It now uses the relative path: " + relative);
773 } catch (IOException e) {
774 MessageBay.displayMessage("Unable to Migrate file: " + imagePath);
775 }
776 });
777 }
778
779 public static void CopyFile(String existingFile, String newFileName) {
780 try {
781 // TODO is there a built in method which will do this faster?
782
783 MessageBay.displayMessage("Copying file " + existingFile + " to "
784 + newFileName + "...");
785 FrameIO.copyFile(existingFile, newFileName);
786 MessageBay.displayMessage("File copied successfully");
787 } catch (FileNotFoundException e) {
788 MessageBay.displayMessage("Error opening file: " + existingFile);
789 } catch (Exception e) {
790 MessageBay.displayMessage("File could not be copied");
791 }
792 }
793
794 /**
795 * Runs two methods alternatively a specified number of times and reports on
796 * the time spent running each method.
797 *
798 * @param fullMethodNameA
799 * @param fullMethodNameB
800 * @param repsPerTest
801 * the number of time each method is run per test
802 * @param tests
803 * the number of tests to conduct
804 *
805 */
806 public static void CompareMethods(String fullMethodNameA,
807 String fullMethodNameB, int repsPerTest, int tests) {
808 try {
809 String classNameA = getClassName(fullMethodNameA);
810 String classNameB = getClassName(fullMethodNameB);
811 String methodNameA = getMethodName(fullMethodNameA);
812 String methodNameB = getMethodName(fullMethodNameB);
813
814 Class<?> classA = Class.forName(classNameA);
815 Class<?> classB = Class.forName(classNameB);
816 Method methodA = classA.getDeclaredMethod(methodNameA,
817 new Class[] {});
818 Method methodB = classB.getDeclaredMethod(methodNameB,
819 new Class[] {});
820 TimeKeeper timeKeeper = new TimeKeeper();
821 long timeA = 0;
822 long timeB = 0;
823 // Run the tests
824 for (int i = 0; i < tests; i++) {
825 // Test methodA
826 timeKeeper.restart();
827 for (int j = 0; j < repsPerTest; j++) {
828 methodA.invoke((Object) null, new Object[] {});
829 }
830 timeA += timeKeeper.getElapsedMillis();
831 timeKeeper.restart();
832 // Test methodB
833 for (int j = 0; j < repsPerTest; j++) {
834 methodB.invoke((Object) null, new Object[] {});
835 }
836 timeB += timeKeeper.getElapsedMillis();
837 }
838
839 float aveTimeA = timeA * 1000F / repsPerTest / tests;
840 float aveTimeB = timeB * 1000F / repsPerTest / tests;
841 // Display Results
842 MessageBay.displayMessage("Average Execution Time");
843 MessageBay.displayMessage(methodNameA + ": "
844 + TimeKeeper.Formatter.format(aveTimeA) + "us");
845 MessageBay.displayMessage(methodNameB + ": "
846 + TimeKeeper.Formatter.format(aveTimeB) + "us");
847 } catch (Exception e) {
848 MessageBay.errorMessage(e.getClass().getSimpleName() + ": "
849 + e.getMessage());
850 }
851 }
852
853 public static String getClassName(String fullMethodName) {
854 assert (fullMethodName != null);
855 assert (fullMethodName.length() > 0);
856 int lastPeriod = fullMethodName.lastIndexOf('.');
857 if (lastPeriod > 0 && lastPeriod < fullMethodName.length() - 1)
858 return fullMethodName.substring(0, lastPeriod);
859 throw new RuntimeException("Invalid method name: " + fullMethodName);
860 }
861
862 public static String getMethodName(String methodName) {
863 assert (methodName != null);
864 assert (methodName.length() > 0);
865 int lastPeriod = methodName.lastIndexOf('.');
866 if (lastPeriod > 0 && lastPeriod < methodName.length() - 1)
867 return methodName.substring(1 + lastPeriod);
868 throw new RuntimeException("Invalid method name: " + methodName);
869 }
870
871 /**
872 * Loads the Frame linked to by the given Item. The first Item on the Frame
873 * that is not the title or name is then placed on the current frame. The
874 * item that was clicked on is placed on the frame it was linked to and the
875 * link is switched to the item from the child frame. If the given Item has
876 * no link, or no item is found then this is a no-op.
877 *
878 * @param current
879 * The Item that links to the Frame that the Item will be loaded
880 * from.
881 */
882 public static void SwapItemWithItemOnChildFrame(Item current) {
883 Item item = getFirstBodyItemOnChildFrame(current, false);
884 // if no item was found
885 if (item == null) {
886 return;
887 }
888
889 // swap the items parents
890 Frame parentFrame = current.getParent();
891 Frame childFrame = item.getParent();
892 current.setParent(childFrame);
893 item.setParent(parentFrame);
894
895 // swap the items on the frames
896 parentFrame.removeItem(current);
897 childFrame.removeItem(item);
898 parentFrame.addItem(item);
899 childFrame.addItem(current);
900
901 // swap the items links
902 item.setActions(current.getAction());
903 item.setLink(childFrame.getName());
904 current.setLink(parentFrame.getName());
905 // current.setLink(null);
906 current.setActions(null);
907
908 DisplayController.requestRefresh(true);
909 }
910
911 private static Item getFirstBodyItemOnChildFrame(Item current,
912 boolean textOnly) {
913 // the item must link to a frame
914 if (current.getLink() == null) {
915 MessageBay
916 .displayMessage("Cannot get item from child - this item has no link");
917 return null;
918 }
919
920 Frame child = FrameIO.LoadFrame(current.getAbsoluteLink());
921
922 // if the frame could not be loaded
923 if (child == null) {
924 MessageBay.errorMessage("Could not load child frame.");
925 return null;
926 }
927
928 // find the first non-title and non-name item
929 List<Item> body = new ArrayList<Item>();
930 if (textOnly)
931 body.addAll(child.getBodyTextItems(false));
932 else
933 body.addAll(child.getSortedItems());
934 Item item = null;
935
936 for (Item i : body)
937 if (i != child.getTitleItem() && !i.isAnnotation()) {
938 item = i;
939 break;
940 }
941
942 // if no item was found
943 if (item == null) {
944 MessageBay.displayMessage("No item found to copy");
945 return null;
946 }
947
948 return item;
949 }
950
951 private static Collection<Item> getItemsOnChildFrame(Item current,
952 boolean textOnly) {
953 // the item must link to a frame
954 if (current.getLink() == null) {
955 MessageBay
956 .displayMessage("Cannot get item from child - this item has no link");
957 return null;
958 }
959 Frame child = FrameIO.LoadFrame(current.getAbsoluteLink());
960
961 // if the frame could not be loaded
962 if (child == null) {
963 MessageBay.errorMessage("Could not load child frame.");
964 return null;
965 }
966
967 // find the first non-title and non-name item
968 Collection<Item> body = new ArrayList<Item>();
969 if (textOnly)
970 body.addAll(child.getBodyTextItems(false));
971 else
972 body.addAll(child.getSortedItems());
973
974 return body;
975 }
976
977 public static void calculate(Frame frame, Item toCalculate) {
978 if (toCalculate instanceof Text) {
979 Text text = (Text) toCalculate;
980 ExpediteeJEP myParser = new ExpediteeJEP();
981 myParser.addVariables(frame);
982 String linkedFrame = toCalculate.getAbsoluteLink();
983 if (linkedFrame != null) {
984 myParser.addVariables(FrameIO.LoadFrame(linkedFrame));
985 }
986 myParser.resetObserver();
987
988 // Do the calculation
989 String formulaFullCase = text.getText().replace('\n', ' ');
990 String formula = formulaFullCase.toLowerCase();
991
992 try {
993 Node node = myParser.parse(formula);
994 Object result = myParser.evaluate(node);
995 text.setText(result.toString(), true);
996 text.setFormula(formulaFullCase);
997 if (text.isFloating()) {
998 Point cursorPos = EcosystemManager.getInputManager().getCursorPosition();
999 text.setPosition(cursorPos.getX(), cursorPos.getY());
1000 StandardGestureActions.resetOffset();
1001 } else {
1002 text.getParentOrCurrentFrame().change();
1003 }
1004 } catch (ParseException e) {
1005 MessageBay.errorMessage("Parse error "
1006 + e.getMessage().replace("\n", ""));
1007 } catch (Exception e) {
1008 MessageBay.errorMessage("evaluation error "
1009 + e.getMessage().replace("\n", ""));
1010 e.printStackTrace();
1011 }
1012 }
1013 }
1014
1015 /**
1016 * Attach an item to the cursor.
1017 *
1018 * @param item
1019 */
1020 public static void attachToCursor(Item item) {
1021 item.setParent(null);
1022 StandardGestureActions.pickup(item);
1023 DisplayController.requestRefresh(true);
1024 }
1025
1026 public static void attachToCursor(Collection<Item> items) {
1027 for (Item i : items) {
1028 i.setParent(null);
1029 i.invalidateAll();
1030 }
1031 StandardGestureActions.pickup(items);
1032 // TODO figure out why this isnt repainting stuff immediately
1033 // All of text item doesnt repaint until the cursor is moved
1034 DisplayController.requestRefresh(true);
1035 }
1036
1037 public static void importFiles(Item item) {
1038 List<File> files = new LinkedList<File>();
1039 for (String s : item.getText().split("\\s+")) {
1040 File file = new File(s.trim());
1041 if (file.exists()) {
1042 files.add(file);
1043 }
1044 }
1045 try {
1046 EcosystemManager.getDragAndDropManager().importFileList(files, EcosystemManager.getInputManager().getCursorPosition(), false);
1047 } catch (Exception e) {
1048 }
1049 }
1050
1051 public static void importFile(Item item) {
1052 File file = new File(item.getText().trim());
1053 if (file.exists()) {
1054 try {
1055 EcosystemManager.getDragAndDropManager().importFile(file, EcosystemManager.getInputManager().getCursorPosition(), false);
1056 } catch (Exception e) {
1057 e.printStackTrace();
1058 }
1059 }
1060 }
1061
1062 public static Item createPolygon(Item item, int sides) {
1063 if (item instanceof Text) {
1064 try {
1065 SString s = new SString(item.getText());
1066 sides = s.integerValue().intValue();
1067 } catch (NumberFormatException e) {
1068 }
1069 }
1070
1071 if (sides < 3) {
1072 MessageBay.errorMessage("Shapes must have at least 3 sides");
1073 }
1074 double angle = -(180 - ((sides - 2) * 180.0F) / sides);
1075 double curAngle = 0;
1076 double size = 50F;
1077 if (item.isLineEnd() && item.getLines().size() > 0) {
1078 item = item.getLines().get(0);
1079 }
1080 // Use line length to determine the size of the shape
1081 if (item instanceof Line) {
1082 size = ((Line) item).getLength();
1083 }
1084
1085 Point cursorPos = DisplayController.getMousePosition();
1086 float curX = cursorPos.getX();
1087 float curY = cursorPos.getY();
1088
1089 Collection<Item> newItems = new LinkedList<Item>();
1090 Item[] d = new Item[sides];
1091 // create dots
1092 Frame current = DisplayController.getCurrentFrame();
1093 for (int i = 0; i < d.length; i++) {
1094 d[i] = current.createDot();
1095 newItems.add(d[i]);
1096 d[i].setPosition(curX, curY);
1097 curX += (float) (Math.cos((curAngle) * Math.PI / 180.0) * size);
1098 curY += (float) (Math.sin((curAngle) * Math.PI / 180.0) * size);
1099
1100 curAngle += angle;
1101 }
1102 // create lines
1103 for (int i = 1; i < d.length; i++) {
1104 newItems.add(new Line(d[i - 1], d[i], current.getNextItemID()));
1105 }
1106 newItems.add(new Line(d[d.length - 1], d[0], current.getNextItemID()));
1107
1108 current.addAllItems(newItems);
1109 if (item instanceof Text) {
1110 for (Item i : item.getAllConnected()) {
1111 if (i instanceof Line) {
1112 item = i;
1113 break;
1114 }
1115 }
1116 }
1117
1118 Colour newColor = item.getColor();
1119 if (newColor != null) {
1120 d[0].setColor(item.getColor());
1121 if (item instanceof Text && item.getBackgroundColor() != null) {
1122 d[0].setFillColor(item.getBackgroundColor());
1123 } else {
1124 d[0].setFillColor(item.getFillColor());
1125 }
1126 }
1127 float newThickness = item.getThickness();
1128 if (newThickness > 0) {
1129 d[0].setThickness(newThickness);
1130 }
1131
1132 ItemUtils.EnclosedCheck(newItems);
1133 DisplayController.requestRefresh(false);
1134
1135 return d[0];
1136 }
1137
1138 public static void StopReminder() {
1139 Reminders.stop();
1140 }
1141
1142 public static void print(String file)
1143 {
1144 String errorMessage = EcosystemManager.getMiscManager().print(file);
1145
1146 if (errorMessage != null) MessageBay.errorMessage("Printing error: " + errorMessage);
1147 }
1148
1149 public static int wordCount(String paragraph) {
1150 return paragraph.trim().split("\\s+").length + 1;
1151 }
1152
1153 public static int wordCount(Frame frame) {
1154 int count = 0;
1155
1156 for (Text t : frame.getBodyTextItems(false)) {
1157 count += wordCount(t.getText());
1158 }
1159
1160 return count;
1161 }
1162
1163 public static void moveToPublic(Frame frame) {
1164 FrameIO.moveFrameset(frame.getFramesetName(), FrameIO.PUBLIC_PATH, false);
1165 }
1166
1167 public static void moveToPrivate(Frame frame) {
1168 FrameIO.moveFrameset(frame.getFramesetName(), FrameIO.FRAME_PATH, false);
1169 }
1170
1171 /**
1172 * Returns the value of a specified item attribute.
1173 *
1174 * @param item
1175 * from which to extract the value
1176 * @param attribute
1177 * name of an items attribute
1178 * @return the value of the attribute
1179 */
1180 public static String extract(Item item, String attribute) {
1181 return AttributeUtils.getAttribute(item, attribute);
1182 }
1183
1184 /**
1185 * Launches items.widgets.Browser and uses Text item as URL.
1186 * @param text Text item which passes contents as URL for browser.
1187 * @throws Exception
1188 */
1189/* public static void startLoboBrowser(Item text) throws Exception {
1190 if (!(text instanceof Text)) {
1191 MessageBay.errorMessage("Must be a text item.");
1192 return;
1193 }
1194 if(text.getLink() != null) {
1195 MessageBay.errorMessage("Text item cannot have link.");
1196 return;
1197 }
1198
1199 FreeItems.getInstance().clear(); // remove url text from cursor
1200
1201 Text wt = new Text("@iw:org.expeditee.items.widgets.Browser"); // create new text item for browser widget
1202 wt.setParent(DisplayIO.getCurrentFrame()); // set parent of text source for InteractiveWidget.createWidget()
1203 wt.setXY(FrameMouseActions.getX(), FrameMouseActions.getY());
1204 // create widget from text item
1205 org.expeditee.items.widgets.Browser browser = (org.expeditee.items.widgets.Browser) InteractiveWidget.createWidget(wt);
1206
1207 if(FreeItems.textOnlyAttachedToCursor()) { // navigates to url specified by the text item
1208 browser.navigate(text.getText());
1209 } else {
1210 browser.navigate("http://www.waikato.ac.nz");
1211 }
1212
1213 FrameMouseActions.pickup(browser.getItems()); // attach browser widget to mouse
1214 }*/
1215
1216 /**
1217 * Text item becomes link to new frame containing items.widgets.Browser and uses Text item as URL for browser.
1218 * @param text Text item which passes contents as URL for browser and becomes link to the browser's new frame.
1219 * @throws Exception
1220 */
1221 public static void startLoboBrowserNewFrame(Item text) throws Exception
1222 {
1223 if (!(text instanceof Text)) {
1224 MessageBay.errorMessage("Must be a text item.");
1225 return;
1226 }
1227
1228 if(text.getLink() != null) { // text item can't already have a link
1229 MessageBay.errorMessage("Text item already has link.");
1230 return;
1231 }
1232
1233 // Create new frame and text item for browser widget and parse created frame; loads browser widget
1234 Frame frame = FrameIO.CreateNewFrame(text);
1235 frame.addText(0, 50, "@iw:org.expeditee.items.widgets.Browser", null);
1236 FrameUtils.Parse(frame);
1237
1238 for(Widget iw : frame.getInteractiveWidgets()) { // may be other widgets on frame
1239 if(iw instanceof org.expeditee.items.widgets.Browser) {
1240 // Set browser to 'full screen'
1241 iw.setSize(-1, -1, -1, -1, DisplayController.getFramePaintAreaWidth(), DisplayController.getFramePaintAreaHeight() - 80);
1242
1243 // If there is a text item attached to cursor use it as url for browser
1244 if (FreeItems.textOnlyAttachedToCursor()) {
1245 text.setLink("" + frame.getNumber());
1246 ((org.expeditee.items.widgets.Browser)iw).navigate(text.getText());
1247 } else {
1248 // Navigate to www.waikato.ac.nz by default if no url supplied and create new text item to be the link
1249 ((org.expeditee.items.widgets.Browser)iw).navigate("http://www.waikato.ac.nz");
1250 Text t = new Text("http://www.waikato.ac.nz");
1251 t.setParent(DisplayController.getCurrentFrame()); // set parent of text source for InteractiveWidget.createWidget()
1252 t.setXY(DisplayController.getFloatMouseX(), DisplayController.getFloatMouseY());
1253 t.setLink("" + frame.getNumber()); // link url text to new browser frame
1254 StandardGestureActions.pickup(t); // Attach new text link to cursor
1255 }
1256 }
1257 }
1258
1259 FrameIO.SaveFrame(frame); // save frame to disk
1260 }
1261
1262 private static boolean startWidget(String name) throws Exception
1263 {
1264 String fullName = Actions.getClassName(name);
1265 if(fullName == null) {
1266 return false;
1267 }
1268 MessageBay.displayMessage("Creating new \"" + fullName + "\"");
1269
1270 FreeItems.getInstance().clear();
1271 Text wt = new Text("@iw:" + fullName); // create new text item for browser widget
1272 wt.setParent(DisplayController.getCurrentFrame()); // set parent of text source for InteractiveWidget.createWidget()
1273 wt.setXY(DisplayController.getMouseX(), DisplayController.getMouseY()); // move to the mouse cursor
1274 Widget widget = Widget.createWidget(wt);
1275 StandardGestureActions.pickup(widget.getItems());
1276
1277 return true;
1278 }
1279
1280 private static void runUnknown(String command) throws Exception {
1281 if(startWidget(command)) {
1282 return;
1283 }
1284
1285 Actions.PerformAction(DisplayController.getCurrentFrame(), null, command, null);
1286 }
1287
1288 public static void run(String command) throws Exception {
1289 if(command == null) {
1290 MessageBay.warningMessage("Please provide a command to run");
1291 return;
1292 }
1293 int firstSpace = command.indexOf(" ");
1294 if(firstSpace == -1) {
1295 runUnknown(command);
1296 return;
1297 }
1298 String argLower = command.toLowerCase();
1299 String name = argLower.substring(0, firstSpace).trim(); // first word
1300 String args = argLower.substring(firstSpace).trim(); // remainder after first word
1301 if(name == "action" || name == "agent") {
1302 if(args.length() > 0) {
1303 Actions.LegacyPerformAction(DisplayController.getCurrentFrame(), null, args);
1304 } else {
1305 MessageBay.displayMessage("Please specify an action/agent name");
1306 }
1307 } else if(name == "widget") {
1308 if(args.length() > 0) {
1309 if(!startWidget(args)) {
1310 MessageBay.displayMessage("Widget \"" + name + "\" does not exist");
1311 }
1312 } else {
1313 MessageBay.displayMessage("Please specify a widget name");
1314 }
1315 } else {
1316 runUnknown(command);
1317 }
1318 }
1319
1320 public static void run(Item item) throws Exception {
1321 if(item == null) {
1322 MessageBay.warningMessage("Please provide a command to run");
1323 return;
1324 }
1325 run(((Text)item).getText());
1326 }
1327
1328 /**
1329 * Rebuilds the home frame restoring its original presentation.
1330 * Basically removes all items on the frame and reruns FrameUtils.CreateDefaultProfile().
1331 */
1332 public static void resetHomeFrame() {
1333 Frame homeFrame = FrameIO.LoadFrame(UserSettings.HomeFrame.get());
1334 homeFrame.removeAllItems(homeFrame.getSortedItems());
1335 homeFrame.addText(0, 0, "title", null);
1336 FrameUtils.CreateDefaultProfile(UserSettings.UserName.get(), homeFrame, null, null);
1337 }
1338
1339 /**
1340 * Loads and runs an executable jar file in a new Thread
1341 * @param jar path to the jar file to run
1342 */
1343 public static void runJar(String jar) throws Exception {
1344 File jf = new File(jar);
1345 if(!jf.exists()) {
1346 System.err.println("jar '" + jar + "' could not be found");
1347 return;
1348 }
1349 JarFile jarFile = new JarFile(jf);
1350
1351 String mainClassName = (String) jarFile.getManifest().getMainAttributes().get(new Attributes.Name("Main-Class"));
1352 if(mainClassName == null) {
1353 System.err.println("jar '" + jar + "' does not have a Main-Class entry");
1354 jarFile.close();
1355 return;
1356 }
1357 jarFile.close();
1358 System.out.println("Main-Class = " + mainClassName);
1359
1360 ClassLoader classLoader = ClassLoader.getSystemClassLoader();
1361
1362 Method addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
1363 addURL.setAccessible(true);
1364 addURL.invoke(classLoader, jf.toURI().toURL());
1365
1366 final Class<?> jarClass = classLoader.loadClass(mainClassName);
1367
1368 final Method main = jarClass.getDeclaredMethod("main", String[].class);
1369
1370 new Thread(new Runnable() {
1371 public void run() {
1372 try {
1373 main.invoke(jarClass, new Object[] {new String[0]});
1374 } catch (Exception e) {
1375 System.out.println("Failed to start jar");
1376 e.printStackTrace();
1377 }
1378 }
1379 }).start();
1380 }
1381
1382 public static void pan(Frame frame, int x, int y) {
1383 for (Item i : frame.getAllItems()) {
1384 if (i instanceof WidgetEdge || i instanceof WidgetCorner) {
1385 continue;
1386 } else {
1387 int new_x = i.getX();
1388 int new_y = i.getY();
1389
1390 if (!i.isAnchoredX()) {
1391 new_x += x;
1392 }
1393
1394 if (!i.isAnchoredY()) {
1395 new_y += y;
1396 }
1397
1398 if(i instanceof XRayable) {
1399 i.setPosition(new_x,new_y);
1400 }
1401 else {
1402 i.setXY(new_x,new_y);
1403 }
1404 }
1405 // update the polygon, otherwise stuff moves but leaves it's outline behind
1406 i.invalidateBounds();
1407 }
1408
1409 for (Widget iw : frame.getInteractiveWidgets()) {
1410
1411 int new_x = iw.getX();
1412 int new_y = iw.getY();
1413
1414 if (!iw.isAnchoredX()) {
1415 new_x += x;
1416 }
1417
1418 if (!iw.isAnchoredY()) {
1419 new_y += y;
1420 }
1421
1422 iw.setPosition(new_x,new_y);
1423
1424 }
1425
1426 // make sure we save the panning of the frame
1427 frame.change();
1428 // redraw everything
1429 StandardGestureActions.Refresh();
1430 }
1431
1432 public static void pan(Frame frame, String pan) {
1433 String[] split = pan.split("\\s+");
1434 int x = 0;
1435 int y = 0;
1436 try {
1437 if(split.length != 2) throw new Exception();
1438 x = Integer.parseInt(split[0]);
1439 y = Integer.parseInt(split[1]);
1440 } catch(Exception e) {
1441 MessageBay.errorMessage("Panning takes 2 integer arguments");
1442 return;
1443 }
1444 pan(frame, x, y);
1445 }
1446
1447 public static void pan(Frame frame, Text pan) {
1448 pan(frame, pan.getText());
1449 }
1450
1451 public static String exec(String cmd) throws Exception {
1452
1453 String[] command;
1454
1455 // run command through sh if possible
1456 if(System.getProperty("os.name").toLowerCase().indexOf("win") == -1) {
1457 command = new String[] { "sh", "-c", cmd };
1458 } else {
1459 command = cmd.split("\\s+");
1460 }
1461
1462 ProcessBuilder pb = new ProcessBuilder(command);
1463 pb.redirectErrorStream(true);
1464 Process ps = pb.start();
1465
1466 BufferedReader in = new BufferedReader(new InputStreamReader(ps.getInputStream()));
1467 StringBuffer sb = new StringBuffer();
1468 String line;
1469 while ((line = in.readLine()) != null) {
1470 sb.append(line).append('\n');
1471 }
1472 ps.waitFor();
1473 in.close();
1474
1475 if(sb.length() > 0) {
1476 sb.deleteCharAt(sb.length() - 1);
1477 }
1478 return sb.toString();
1479 }
1480
1481 public static void testProgress() {
1482 new Thread(new Runnable() {
1483
1484 @Override
1485 public void run() {
1486 Progress p = MessageBay.displayProgress("Loading something");
1487 for(int i = 1; i <= 100; i++) {
1488 try {
1489 Thread.sleep(100);
1490 p.set(i);
1491 } catch (Exception e) {
1492 e.printStackTrace();
1493 }
1494 }
1495 }
1496
1497 }).start();
1498 }
1499
1500 public static void getIDs(Frame f) {
1501 for(Item i : f.getAllItems()) {
1502 System.out.println(i + " (" + i.getID() + ")");
1503 }
1504 }
1505
1506 public static void flushResources() {
1507 FrameUtils.extractResources(true);
1508 MessageBay.displayMessage("Re-extracted resources, Expeditee may need to be restarted for certain resources to be reloaded");
1509 }
1510
1511 // Some experimental actions to do with keeping framesets stored within a Git repository
1512
1513
1514 // For custom merge, some potentially useful information at:
1515 // http://stackoverflow.com/questions/23140240/git-how-do-i-add-a-custom-merge-strategy
1516 // http://stackoverflow.com/questions/7607125/git-merge-conflict-to-always-take-the-newest-file
1517
1518 protected static String gitexe = "git";
1519
1520 protected static void runGitCommand(Frame frame, List<String> cmd_array) {
1521
1522 String framePath = frame.getPath();
1523 String frameName = frame.getName();
1524
1525 String frameDir = frame.getFramesetPath(); //framePath + Conversion.getFramesetName(frameName) + File.separator;
1526 String localFname = Conversion.getFrameNumber(frameName)
1527 + ExpReader.EXTENTION;
1528
1529 ProcessBuilder process_builder = new ProcessBuilder(cmd_array);
1530
1531 process_builder.directory(new File(frameDir));
1532
1533 /*
1534 System.err.println("\nPATH:");
1535
1536 Map<String, String> env_map = process_builder.environment();
1537
1538 for (Entry<String, String> entry: env_map.entrySet()) {
1539 String key = entry.getKey();
1540 String value = entry.getValue();
1541 System.err.println(key + " = " + value);
1542 }
1543 */
1544
1545
1546 try {
1547 final Process process = process_builder.start();
1548 InputStream is = process.getInputStream();
1549 InputStreamReader isr = new InputStreamReader(is);
1550 BufferedReader br = new BufferedReader(isr);
1551 String line;
1552 while ((line = br.readLine()) != null) {
1553 System.out.println(line);
1554 }
1555 System.out.println("Program terminated!");
1556 }
1557 catch (Exception e) {
1558 e.printStackTrace();
1559 }
1560
1561 }
1562
1563 public static void GitPushFrame() {
1564
1565 StandardGestureActions.Save();
1566
1567 Frame current = DisplayController.getCurrentFrame();
1568 String userName = UserSettings.UserName.get();
1569
1570 String frameName = current.getName();
1571 String localFname = Conversion.getFrameNumber(frameName)+ ExpReader.EXTENTION;
1572
1573 List<String> status_cmd_array = new ArrayList<String>();
1574 status_cmd_array.add(gitexe);
1575 status_cmd_array.add("status");
1576 status_cmd_array.add(".");
1577
1578 List<String> add_cmd_array = new ArrayList<String>();
1579 add_cmd_array.add(gitexe);
1580 add_cmd_array.add("add");
1581 add_cmd_array.add(localFname);
1582 add_cmd_array.add("frame.inf");
1583
1584 runGitCommand(current,add_cmd_array);
1585
1586 List<String> commit_cmd_array = new ArrayList<String>();
1587 commit_cmd_array.add(gitexe);
1588 commit_cmd_array.add("commit");
1589 commit_cmd_array.add("-m");
1590 commit_cmd_array.add("expeditee-edit-"+userName);
1591
1592 runGitCommand(current,commit_cmd_array);
1593
1594 List<String> push_cmd_array = new ArrayList<String>();
1595 push_cmd_array.add(gitexe);
1596 push_cmd_array.add("push");
1597 push_cmd_array.add("origin");
1598 push_cmd_array.add("master");
1599
1600 runGitCommand(current,push_cmd_array);
1601 }
1602
1603 public static void GitPullFrame() {
1604 Frame current = DisplayController.getCurrentFrame();
1605
1606 List<String> cmd_array = new ArrayList<String>();
1607 cmd_array.add(gitexe);
1608 cmd_array.add("pull");
1609 cmd_array.add("origin");
1610 cmd_array.add("master");
1611 runGitCommand(current,cmd_array);
1612
1613 FrameIO.Reload();
1614 StandardGestureActions.Refresh();
1615 }
1616
1617}
Note: See TracBrowser for help on using the repository browser.