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

Last change on this file since 1468 was 1468, checked in by bnemhaus, 5 years ago

Add a key character

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