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

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

Updates to the look of some of the more prominant expeditee pages. More to come.
Also first draft of Encryption Cockpit.

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