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

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

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

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