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

Last change on this file since 1293 was 1293, checked in by bln4, 5 years ago

Fixed bug relating to FrameCreator under 'OverrideExistingFrames' mode that was causing multiple unnecessary messages frames from stacking framesets and messages.

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