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

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

GitPushFrame now gets UserSettings.UserName for username rather than UserSettings.ProfileName for username.
Normally these things mean the same thing, however, in this case the difference is significant.

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.