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

Last change on this file since 967 was 950, checked in by bln4, 9 years ago
File size: 39.1 KB
Line 
1/**
2 * Misc.java
3 * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package org.expeditee.actions;
20
21import java.awt.Color;
22import java.awt.Desktop;
23import java.awt.Image;
24import java.awt.image.BufferedImage;
25import java.awt.image.VolatileImage;
26import java.io.BufferedReader;
27import java.io.File;
28import java.io.FileNotFoundException;
29import java.io.IOException;
30import java.io.InputStreamReader;
31import java.lang.reflect.Method;
32import java.net.URL;
33import java.net.URLClassLoader;
34import java.util.ArrayList;
35import java.util.Collection;
36import java.util.LinkedList;
37import java.util.List;
38import java.util.jar.Attributes;
39import java.util.jar.JarFile;
40
41import javax.imageio.ImageIO;
42
43import org.expeditee.gui.AttributeUtils;
44import org.expeditee.gui.Browser;
45import org.expeditee.gui.DisplayIO;
46import org.expeditee.gui.Frame;
47import org.expeditee.gui.FrameGraphics;
48import org.expeditee.gui.FrameIO;
49import org.expeditee.gui.FrameKeyboardActions;
50import org.expeditee.gui.FrameMouseActions;
51import org.expeditee.gui.FrameUtils;
52import org.expeditee.gui.FreeItems;
53import org.expeditee.gui.MessageBay;
54import org.expeditee.gui.MessageBay.Progress;
55import org.expeditee.gui.Reminders;
56import org.expeditee.gui.TimeKeeper;
57import org.expeditee.importer.FrameDNDTransferHandler;
58import org.expeditee.items.Item;
59import org.expeditee.items.ItemUtils;
60import org.expeditee.items.Line;
61import org.expeditee.items.Text;
62import org.expeditee.items.XRayable;
63import org.expeditee.items.widgets.InteractiveWidget;
64import org.expeditee.items.widgets.WidgetCorner;
65import org.expeditee.items.widgets.WidgetEdge;
66import org.expeditee.math.ExpediteeJEP;
67import org.expeditee.settings.UserSettings;
68import org.expeditee.simple.SString;
69import org.expeditee.stats.CometStats;
70import org.expeditee.stats.DocumentStatsFast;
71import org.expeditee.stats.SessionStats;
72import org.expeditee.stats.StatsLogger;
73import org.expeditee.stats.TreeStats;
74import org.nfunk.jep.Node;
75import org.nfunk.jep.ParseException;
76
77
78
79/**
80 * A list of miscellaneous Actions and Actions specific to Expeditee
81 *
82 */
83public class Misc {
84
85 /**
86 * Causes the system to beep
87 */
88 public static void beep() {
89 java.awt.Toolkit.getDefaultToolkit().beep();
90 }
91
92 /**
93 * Returns an Item located at the specified position.
94 * kgas1 - 23/01/2012
95 * @param x
96 * @param y
97 * @return
98 */
99 public static Item getItemAtPosition(int x, int y, Frame f)
100 {
101 Frame current = f;
102 List<Item> allItems = current.getItems();
103
104 for(Item i : allItems)
105 {
106 if(i.getX() == x && i.getY() == y)
107 return i;
108 }
109
110 return null;
111 }
112
113 /**
114 * Returns an item containing a specified piece of data.
115 * kgas1 - 7/06/2012
116 * @param s
117 * @param f
118 * @return
119 */
120 public static Item getItemContainingData(String s, Frame f){
121
122 Frame current = f;
123
124 List<Item> allItems = current.getItems();
125
126
127 for(Item i : allItems){
128
129
130 if(i.getData() != null && i.getData().size() > 0){
131 if(i.getData().contains(s)){
132 return i;
133 }
134 }
135 }
136
137 return null;
138 }
139
140 /**
141 * Forces a repaint of the current Frame
142 */
143 public static void display() {
144 FrameGraphics.refresh(false);
145 }
146
147 public static String getWindowSize() {
148 return Browser.getWindows()[0].getSize().toString();
149 }
150
151 /**
152 * Restores the current frame to the last saved version currently on the
153 * hard disk
154 */
155 public static void restore() {
156 FrameIO.Reload();
157 // MessageBay.displayMessage("Restoration complete.");
158 }
159
160 /**
161 * Toggles AudienceMode on or off
162 */
163 public static void toggleAudienceMode() {
164 FrameGraphics.ToggleAudienceMode();
165 }
166
167 /**
168 * Toggles TwinFrames mode on or off
169 */
170 public static void toggleTwinFramesMode() {
171 DisplayIO.ToggleTwinFrames();
172 }
173
174 /**
175 * If the given Item is a Text Item, then the text of the Item is
176 * interpreted as actions, if not this method does nothing.
177 *
178 * @param current
179 * The Item to read the Actions from
180 */
181 public static void runItem(Item current) throws Exception {
182 if (current instanceof Text) {
183 List<String> actions = ((Text) current).getTextList();
184 for (String action : actions) {
185 if (!action.equalsIgnoreCase("runitem")) {
186 Actions.PerformAction(DisplayIO.getCurrentFrame(), current,
187 action);
188 }
189 }
190 } else {
191 MessageBay.errorMessage("Item must be a text item.");
192 }
193 }
194
195 /**
196 * Prompts the user to confirm deletion of the current Frame, and deletes if
197 * the user chooses. After deletion this action calls back(), to ensure the
198 * deleted frame is not still being shown
199 *
200 */
201 public static void DeleteFrame(Frame toDelete) {
202 String deletedFrame = toDelete.getName();
203 String deletedFrameNameLowercase = deletedFrame.toLowerCase();
204 String errorMessage = "Error deleting " + deletedFrame;
205 try {
206 String deletedFrameName = FrameIO.DeleteFrame(toDelete);
207 if (deletedFrameName != null) {
208 DisplayIO.Back();
209 // Remove any links on the previous frame to the one being
210 // deleted
211 Frame current = DisplayIO.getCurrentFrame();
212 for (Item i : current.getItems())
213 if (i.getLink() != null
214 && i.getAbsoluteLink().toLowerCase().equals(
215 deletedFrameNameLowercase)) {
216 i.setLink(null);
217 }
218 MessageBay.displayMessage(deletedFrame + " renamed "
219 + deletedFrameName);
220 // FrameGraphics.Repaint();
221 return;
222 }
223 } catch (IOException ioe) {
224 if (ioe.getMessage() != null)
225 errorMessage += ". " + ioe.getMessage();
226 } catch (SecurityException se) {
227 if (se.getMessage() != null)
228 errorMessage += ". " + se.getMessage();
229 } catch (Exception e) {
230 e.printStackTrace();
231 }
232 MessageBay.errorMessage(errorMessage);
233 }
234
235 /**
236 * Loads the Frame linked to by the given Item. The first Item on the Frame
237 * that is not the title or name is then placed on the cursor. If the given
238 * Item has no link, or no item is found then this is a no-op.
239 *
240 * @param current
241 * The Item that links to the Frame that the Item will be loaded
242 * from.
243 */
244 public static Item GetItemFromChildFrame(Item current) {
245 return getFromChildFrame(current, false);
246 }
247
248 public static void GetItemsFromChildFrame(Item current) {
249 getItemsFromChildFrame(current, false);
250 }
251
252 /**
253 * Loads the Frame linked to by the given Item. The first Text Item on the
254 * Frame that is not the title or name is then placed on the cursor. If the
255 * given Item has no link, or no item is found then this is a no-op.
256 *
257 * @param current
258 * The Item that links to the Frame that the Item will be loaded
259 * from.
260 */
261 public static Item GetTextFromChildFrame(Item current) {
262 return getFromChildFrame(current, true);
263 }
264
265 private static Item getFromChildFrame(Item current, boolean textOnly) {
266 Item item = getFirstBodyItemOnChildFrame(current, textOnly);
267 // if no item was found
268 if (item != null) {
269 // copy the item and switch
270 item = item.copy();
271 item.setPosition(DisplayIO.getMouseX(), FrameMouseActions.getY());
272 }
273 return item;
274 }
275
276 private static void getItemsFromChildFrame(Item current, boolean textOnly) {
277 Collection<Item> items = getItemsOnChildFrame(current, textOnly);
278 // if no item was found
279 if (items == null || items.size() == 0) {
280 return;
281 }
282
283 // copy the item and switch
284 Collection<Item> copies = ItemUtils.CopyItems(items);
285 Item first = items.iterator().next();
286 float deltaX = DisplayIO.getMouseX() - first.getX();
287 float deltaY = FrameMouseActions.getY() - first.getY();
288 for (Item i : copies) {
289 if (i.isVisible())
290 i.setXY(i.getX() + deltaX, i.getY() + deltaY);
291 i.setParent(null);
292 }
293 FrameMouseActions.pickup(copies);
294 FrameGraphics.Repaint();
295 }
296
297 /**
298 * Sets the given Item to have the Given Color. Color can be null (for
299 * default)
300 *
301 * @param toChange
302 * The Item to set the Color.
303 * @param toUse
304 * The Color to give the Item.
305 */
306 public static void SetItemBackgroundColor(Item toChange, Color toUse) {
307 if (toChange == null)
308 return;
309
310 toChange.setBackgroundColor(toUse);
311 FrameGraphics.Repaint();
312 }
313
314 /**
315 * Sets the given Item to have the Given Color. Color can be null (for
316 * default)
317 *
318 * @param toChange
319 * The Item to set the Color.
320 * @param toUse
321 * The Color to give the Item.
322 */
323 public static void SetItemColor(Item toChange, Color toUse) {
324 if (toChange == null)
325 return;
326
327 toChange.setColor(toUse);
328 FrameGraphics.Repaint();
329 }
330
331 /**
332 * Creates a new Text Object containing general statistics for the current
333 * session. The newly created Text Object is then attached to the cursor via
334 * FrameMouseActions.pickup(Item)
335 */
336 public static void GetSessionStats() {
337 attachStatsToCursor(SessionStats.getCurrentStats());
338 }
339
340 /**
341 * Creates a new Text Object containing statistics for the current tree.
342 */
343 public static String GetCometStats(Frame frame) {
344 TimeKeeper timer = new TimeKeeper();
345 MessageBay.displayMessage("Computing comet stats...");
346 CometStats cometStats = new CometStats(frame);
347 String result = cometStats.toString();
348 MessageBay.overwriteMessage("Comet stats time: "
349 + timer.getElapsedStringSeconds());
350 return result;
351 }
352
353 public static String GetTreeStats(Frame frame) {
354 TimeKeeper timer = new TimeKeeper();
355 MessageBay.displayMessage("Computing tree stats...");
356
357 TreeStats treeStats = new TreeStats(frame);
358 String result = treeStats.toString();
359 MessageBay.overwriteMessage("Tree stats time: "
360 + timer.getElapsedStringSeconds());
361 return result;
362
363 }
364
365 public static String GetDocumentStats(Frame frame) {
366 TimeKeeper timer = new TimeKeeper();
367 MessageBay.displayMessage("Computing document stats...");
368 FrameIO.ForceSaveFrame(frame);
369 DocumentStatsFast docStats = new DocumentStatsFast(frame.getName(),
370 frame.getTitle());
371 String result = docStats.toString();
372
373 MessageBay.overwriteMessage("Document stats time: "
374 + timer.getElapsedStringSeconds());
375 return result;
376
377 }
378
379 /**
380 * Creates a text item and attaches it to the cursor.
381 *
382 * @param itemText
383 * the text to attach to the cursor
384 */
385 public static void attachStatsToCursor(String itemText) {
386 SessionStats.CreatedText();
387 Frame current = DisplayIO.getCurrentFrame();
388 Item text = current.getStatsTextItem(itemText);
389 FrameMouseActions.pickup(text);
390 FrameGraphics.Repaint();
391 }
392
393 public static void attachTextToCursor(String itemText) {
394 SessionStats.CreatedText();
395 Frame current = DisplayIO.getCurrentFrame();
396 Item text = current.getTextItem(itemText);
397 FrameMouseActions.pickup(text);
398 FrameGraphics.Repaint();
399 }
400
401 /**
402 * Creates a new Text Object containing statistics for moving, deleting and
403 * creating items in the current session. The newly created Text Object is
404 * then attached to the cursor via FrameMouseActions.pickup(Item)
405 */
406 public static String getItemStats() {
407 return SessionStats.getItemStats();
408 }
409
410 /**
411 * Creates a new Text Object containing statistics for the time between
412 * events triggered by the user through mouse clicks and key presses. The
413 * newly created Text Object is then attached to the cursor via
414 * FrameMouseActions.pickup(Item)
415 */
416 public static String getEventStats() {
417 return SessionStats.getEventStats();
418 }
419
420 /**
421 * Creates a new Text Object containing the contents of the current frames
422 * file.
423 */
424 public static String getFrameFile(Frame frame) {
425 return FrameIO.ForceSaveFrame(frame);
426 }
427
428 /**
429 * Creates a new Text Object containing the available fonts.
430 */
431 public static String getFontNames() {
432 Collection<String> availableFonts = Actions.getFonts().values();
433 StringBuilder fontsList = new StringBuilder();
434 for (String s : availableFonts) {
435 fontsList.append(s).append(Text.LINE_SEPARATOR);
436 }
437 fontsList.deleteCharAt(fontsList.length() - 1);
438
439 return fontsList.toString();
440 }
441
442 public static String getUnicodeCharacters(int start, int finish) {
443 if (start < 0 && finish < 0) {
444 throw new RuntimeException("Parameters must be non negative");
445 }
446 // Swap the start and finish if they are inthe wrong order
447 if (start > finish) {
448 start += finish;
449 finish = start - finish;
450 start = start - finish;
451 }
452 StringBuilder charList = new StringBuilder();
453 int count = 0;
454 charList.append(String.format("Unicode block 0x%x - 0x%x", start,
455 finish));
456 System.out.println();
457 // charList.append("Unicode block: ").append(String.format(format,
458 // args))
459 for (char i = (char) start; i < (char) finish; i++) {
460 if (Character.isDefined(i)) {
461 if (count++ % 64 == 0)
462 charList.append(Text.LINE_SEPARATOR);
463 charList.append(Character.valueOf(i));
464 }
465 }
466 return charList.toString();
467 }
468
469 /**
470 * Gets a single block of Unicode characters.
471 *
472 * @param start
473 * the start of the block
474 */
475 public static String getUnicodeCharacters(int start) {
476 return getUnicodeCharacters(start, start + 256);
477 }
478
479 public static String getMathSymbols() {
480 return getUnicodeCharacters('\u2200', '\u2300');
481 }
482
483 /**
484 * Resets the statistics back to zero.
485 */
486 public static void repaint() {
487 StatsLogger.WriteStatsFile();
488 SessionStats.resetStats();
489 }
490
491 /**
492 * Loads a frame with the given name and saves it as a JPEG image.
493 *
494 * @param framename
495 * The name of the Frame to save
496 */
497 public static void jpegFrame(String framename) {
498 ImageFrame(framename, "JPEG");
499 }
500
501 /**
502 * Saves the current frame as a JPEG image. This is the same as calling
503 * JpegFrame(currentFrame.getName())
504 */
505 public static void jpegFrame() {
506 ImageFrame(DisplayIO.getCurrentFrame().getName(), "JPEG");
507 }
508
509 public static void jpgFrame() {
510 jpegFrame();
511 }
512
513 /**
514 * Loads a frame with the given name and saves it as a PNG image.
515 *
516 * @param framename
517 * The name of the Frame to save
518 */
519 public static void PNGFrame(String framename) {
520 ImageFrame(framename, "PNG");
521 }
522
523 /**
524 * Saves the current frame as a PNG image. This is the same as calling
525 * PNGFrame(currentFrame.getName())
526 */
527 public static void PNGFrame(Frame frame) {
528 ImageFrame(frame.getName(), "PNG");
529 }
530
531 public static String SaveImage(BufferedImage screen, String format,
532 String directory, String fileName) {
533 String suffix = "." + format.toLowerCase();
534 String shortFileName = fileName;
535 // Check if we need to append the suffix
536 if (fileName.indexOf('.') < 0)
537 fileName += suffix;
538 else
539 shortFileName = fileName.substring(0, fileName.length() - suffix.length());
540
541 try {
542 int count = 2;
543 // set up the file for output
544 File out = new File(directory + fileName);
545 while (out.exists()) {
546 fileName = shortFileName + "_" + count++ + suffix;
547 out = new File(directory + fileName);
548 }
549
550 if (!out.getParentFile().exists())
551 out.mkdirs();
552
553 // If the image is successfully written out return the fileName
554 if (ImageIO.write(screen, format, out))
555 return fileName;
556
557 } catch (Exception e) {
558 e.printStackTrace();
559 }
560 return null;
561 }
562
563 public static String ImageFrame(Frame frame, String format, String directory) {
564 assert (frame != null);
565
566 Image oldBuffer = frame.getBuffer();
567 frame.setBuffer(null);
568 // Jpeg only works properly with volitile frames
569 // Png transparency only works with bufferedImage form
570 Image frameBuffer = FrameGraphics.getBuffer(frame, false, format
571 .equalsIgnoreCase("jpeg"));
572 // Make sure overlay stuff doesnt disapear on the frame visible on the
573 // screen
574 frame.setBuffer(oldBuffer);
575 BufferedImage screen = null;
576
577 if (frameBuffer instanceof VolatileImage) {
578 // If its the current frame it will be a volitive image
579 screen = ((VolatileImage) frameBuffer).getSnapshot();
580 } else {
581 assert (frameBuffer instanceof BufferedImage);
582 screen = (BufferedImage) frameBuffer;
583 }
584 return SaveImage(screen, format, directory, frame.getExportFileName());
585 }
586
587 /**
588 * Saves the Frame with the given Framename as an image of the given format.
589 *
590 * @param framename
591 * The name of the Frame to save as an image
592 * @param format
593 * The Image format to use (i.e. "PNG", "BMP", etc)
594 */
595 public static void ImageFrame(String framename, String format) {
596 Frame loaded = FrameIO.LoadFrame(framename);
597
598 // if the frame was loaded successfully
599 if (loaded != null) {
600 String path = FrameIO.EXPORTS_DIR;
601 String frameName = ImageFrame(loaded, format, path);
602 if (frameName != null)
603 MessageBay.displayMessage("Frame successfully saved to " + path
604 + frameName);
605 else
606 MessageBay.errorMessage("Could not find image writer for "
607 + format + " format");
608 // if the frame was not loaded successfully, alert the user
609 } else {
610 MessageBay.displayMessage("Frame '" + framename
611 + "' could not be found.");
612 }
613 }
614
615 public static void MessageLn(Item message) {
616 if (message instanceof Text)
617 MessageBay.displayMessage((Text) message);
618 }
619
620 /**
621 * Displays a message in the message box area.
622 *
623 * @param message
624 * the message to display
625 */
626 public static void MessageLn(String message) {
627 MessageBay.displayMessage(message);
628 }
629
630 public static void MessageLn2(String message, String message2) {
631 MessageBay.displayMessage(message + " " + message2);
632 }
633
634 public static void CopyFile(String existingFile, String newFileName) {
635 try {
636 // TODO is there a built in method which will do this faster?
637
638 MessageBay.displayMessage("Copying file " + existingFile + " to "
639 + newFileName + "...");
640 FrameIO.copyFile(existingFile, newFileName);
641 MessageBay.displayMessage("File copied successfully");
642 } catch (FileNotFoundException e) {
643 MessageBay.displayMessage("Error opening file: " + existingFile);
644 } catch (Exception e) {
645 MessageBay.displayMessage("File could not be copied");
646 }
647 }
648
649 /**
650 * Runs two methods alternatively a specified number of times and reports on
651 * the time spent running each method.
652 *
653 * @param fullMethodNameA
654 * @param fullMethodNameB
655 * @param repsPerTest
656 * the number of time each method is run per test
657 * @param tests
658 * the number of tests to conduct
659 *
660 */
661 public static void CompareMethods(String fullMethodNameA,
662 String fullMethodNameB, int repsPerTest, int tests) {
663 try {
664 String classNameA = getClassName(fullMethodNameA);
665 String classNameB = getClassName(fullMethodNameB);
666 String methodNameA = getMethodName(fullMethodNameA);
667 String methodNameB = getMethodName(fullMethodNameB);
668
669 Class<?> classA = Class.forName(classNameA);
670 Class<?> classB = Class.forName(classNameB);
671 Method methodA = classA.getDeclaredMethod(methodNameA,
672 new Class[] {});
673 Method methodB = classB.getDeclaredMethod(methodNameB,
674 new Class[] {});
675 TimeKeeper timeKeeper = new TimeKeeper();
676 long timeA = 0;
677 long timeB = 0;
678 // Run the tests
679 for (int i = 0; i < tests; i++) {
680 // Test methodA
681 timeKeeper.restart();
682 for (int j = 0; j < repsPerTest; j++) {
683 methodA.invoke((Object) null, new Object[] {});
684 }
685 timeA += timeKeeper.getElapsedMillis();
686 timeKeeper.restart();
687 // Test methodB
688 for (int j = 0; j < repsPerTest; j++) {
689 methodB.invoke((Object) null, new Object[] {});
690 }
691 timeB += timeKeeper.getElapsedMillis();
692 }
693
694 float aveTimeA = timeA * 1000F / repsPerTest / tests;
695 float aveTimeB = timeB * 1000F / repsPerTest / tests;
696 // Display Results
697 MessageBay.displayMessage("Average Execution Time");
698 MessageBay.displayMessage(methodNameA + ": "
699 + TimeKeeper.Formatter.format(aveTimeA) + "us");
700 MessageBay.displayMessage(methodNameB + ": "
701 + TimeKeeper.Formatter.format(aveTimeB) + "us");
702 } catch (Exception e) {
703 MessageBay.errorMessage(e.getClass().getSimpleName() + ": "
704 + e.getMessage());
705 }
706 }
707
708 public static String getClassName(String fullMethodName) {
709 assert (fullMethodName != null);
710 assert (fullMethodName.length() > 0);
711 int lastPeriod = fullMethodName.lastIndexOf('.');
712 if (lastPeriod > 0 && lastPeriod < fullMethodName.length() - 1)
713 return fullMethodName.substring(0, lastPeriod);
714 throw new RuntimeException("Invalid method name: " + fullMethodName);
715 }
716
717 public static String getMethodName(String methodName) {
718 assert (methodName != null);
719 assert (methodName.length() > 0);
720 int lastPeriod = methodName.lastIndexOf('.');
721 if (lastPeriod > 0 && lastPeriod < methodName.length() - 1)
722 return methodName.substring(1 + lastPeriod);
723 throw new RuntimeException("Invalid method name: " + methodName);
724 }
725
726 /**
727 * Loads the Frame linked to by the given Item. The first Item on the Frame
728 * that is not the title or name is then placed on the current frame. The
729 * item that was clicked on is placed on the frame it was linked to and the
730 * link is switched to the item from the child frame. If the given Item has
731 * no link, or no item is found then this is a no-op.
732 *
733 * @param current
734 * The Item that links to the Frame that the Item will be loaded
735 * from.
736 */
737 public static void SwapItemWithItemOnChildFrame(Item current) {
738 Item item = getFirstBodyItemOnChildFrame(current, false);
739 // if no item was found
740 if (item == null) {
741 return;
742 }
743
744 // swap the items parents
745 Frame parentFrame = current.getParent();
746 Frame childFrame = item.getParent();
747 current.setParent(childFrame);
748 item.setParent(parentFrame);
749
750 // swap the items on the frames
751 parentFrame.removeItem(current);
752 childFrame.removeItem(item);
753 parentFrame.addItem(item);
754 childFrame.addItem(current);
755
756 // swap the items links
757 item.setActions(current.getAction());
758 item.setLink(childFrame.getName());
759 current.setLink(parentFrame.getName());
760 // current.setLink(null);
761 current.setActions(null);
762
763 FrameGraphics.Repaint();
764 }
765
766 private static Item getFirstBodyItemOnChildFrame(Item current,
767 boolean textOnly) {
768 // the item must link to a frame
769 if (current.getLink() == null) {
770 MessageBay
771 .displayMessage("Cannot get item from child - this item has no link");
772 return null;
773 }
774
775 Frame child = FrameIO.LoadFrame(current.getAbsoluteLink());
776
777 // if the frame could not be loaded
778 if (child == null) {
779 MessageBay.errorMessage("Could not load child frame.");
780 return null;
781 }
782
783 // find the first non-title and non-name item
784 List<Item> body = new ArrayList<Item>();
785 if (textOnly)
786 body.addAll(child.getBodyTextItems(false));
787 else
788 body.addAll(child.getItems());
789 Item item = null;
790
791 for (Item i : body)
792 if (i != child.getTitleItem() && !i.isAnnotation()) {
793 item = i;
794 break;
795 }
796
797 // if no item was found
798 if (item == null) {
799 MessageBay.displayMessage("No item found to copy");
800 return null;
801 }
802
803 return item;
804 }
805
806 private static Collection<Item> getItemsOnChildFrame(Item current,
807 boolean textOnly) {
808 // the item must link to a frame
809 if (current.getLink() == null) {
810 MessageBay
811 .displayMessage("Cannot get item from child - this item has no link");
812 return null;
813 }
814 Frame child = FrameIO.LoadFrame(current.getAbsoluteLink());
815
816 // if the frame could not be loaded
817 if (child == null) {
818 MessageBay.errorMessage("Could not load child frame.");
819 return null;
820 }
821
822 // find the first non-title and non-name item
823 Collection<Item> body = new ArrayList<Item>();
824 if (textOnly)
825 body.addAll(child.getBodyTextItems(false));
826 else
827 body.addAll(child.getItems());
828
829 return body;
830 }
831
832 public static void calculate(Frame frame, Item toCalculate) {
833 if (toCalculate instanceof Text) {
834 Text text = (Text) toCalculate;
835 ExpediteeJEP myParser = new ExpediteeJEP();
836 myParser.addVariables(frame);
837 String linkedFrame = toCalculate.getAbsoluteLink();
838 if (linkedFrame != null) {
839 myParser.addVariables(FrameIO.LoadFrame(linkedFrame));
840 }
841 myParser.resetObserver();
842
843 // Do the calculation
844 String formulaFullCase = text.getText().replace('\n', ' ');
845 String formula = formulaFullCase.toLowerCase();
846
847 try {
848 Node node = myParser.parse(formula);
849 Object result = myParser.evaluate(node);
850 text.setText(result.toString(), true);
851 text.setFormula(formulaFullCase);
852 if (text.isFloating()) {
853 text.setPosition(FrameMouseActions.MouseX,
854 FrameMouseActions.MouseY);
855 FrameMouseActions.resetOffset();
856 } else {
857 text.getParentOrCurrentFrame().change();
858 }
859 } catch (ParseException e) {
860 MessageBay.errorMessage("Parse error "
861 + e.getMessage().replace("\n", ""));
862 } catch (Exception e) {
863 MessageBay.errorMessage("evaluation error "
864 + e.getMessage().replace("\n", ""));
865 e.printStackTrace();
866 }
867 }
868 }
869
870 /**
871 * Attach an item to the cursor.
872 *
873 * @param item
874 */
875 public static void attachToCursor(Item item) {
876 item.setParent(null);
877 FrameMouseActions.pickup(item);
878 FrameGraphics.Repaint();
879 }
880
881 public static void attachToCursor(Collection<Item> items) {
882 for (Item i : items) {
883 i.setParent(null);
884 i.invalidateAll();
885 }
886 FrameMouseActions.pickup(items);
887 // TODO figure out why this isnt repainting stuff immediately
888 // All of text item doesnt repaint until the cursor is moved
889 FrameGraphics.requestRefresh(true);
890 }
891
892 public static void importFiles(Item item) {
893 List<File> files = new LinkedList<File>();
894 for (String s : item.getText().split("\\s+")) {
895 File file = new File(s.trim());
896 if (file.exists()) {
897 files.add(file);
898 }
899 }
900 try {
901 FrameDNDTransferHandler.getInstance().importFileList(files,
902 FrameMouseActions.getPosition());
903 } catch (Exception e) {
904 }
905 }
906
907 public static void importFile(Item item) {
908 File file = new File(item.getText().trim());
909 if (file.exists()) {
910 try {
911 FrameDNDTransferHandler.getInstance().importFile(file,
912 FrameMouseActions.getPosition());
913 } catch (Exception e) {
914 e.printStackTrace();
915 }
916 }
917 }
918
919 public static Item createPolygon(Item item, int sides) {
920 if (item instanceof Text) {
921 try {
922 SString s = new SString(item.getText());
923 sides = s.integerValue().intValue();
924 } catch (NumberFormatException e) {
925 }
926 }
927
928 if (sides < 3) {
929 MessageBay.errorMessage("Shapes must have at least 3 sides");
930 }
931 double angle = -(180 - ((sides - 2) * 180.0F) / sides);
932 double curAngle = 0;
933 double size = 50F;
934 if (item.isLineEnd() && item.getLines().size() > 0) {
935 item = item.getLines().get(0);
936 }
937 // Use line length to determine the size of the shape
938 if (item instanceof Line) {
939 size = ((Line) item).getLength();
940 }
941
942 float curX = FrameMouseActions.MouseX;
943 float curY = FrameMouseActions.MouseY;
944
945 Collection<Item> newItems = new LinkedList<Item>();
946 Item[] d = new Item[sides];
947 // create dots
948 Frame current = DisplayIO.getCurrentFrame();
949 for (int i = 0; i < d.length; i++) {
950 d[i] = current.createDot();
951 newItems.add(d[i]);
952 d[i].setPosition(curX, curY);
953 curX += (float) (Math.cos((curAngle) * Math.PI / 180.0) * size);
954 curY += (float) (Math.sin((curAngle) * Math.PI / 180.0) * size);
955
956 curAngle += angle;
957 }
958 // create lines
959 for (int i = 1; i < d.length; i++) {
960 newItems.add(new Line(d[i - 1], d[i], current.getNextItemID()));
961 }
962 newItems.add(new Line(d[d.length - 1], d[0], current.getNextItemID()));
963
964 current.addAllItems(newItems);
965 if (item instanceof Text) {
966 for (Item i : item.getAllConnected()) {
967 if (i instanceof Line) {
968 item = i;
969 break;
970 }
971 }
972 }
973
974 Color newColor = item.getColor();
975 if (newColor != null) {
976 d[0].setColor(item.getColor());
977 if (item instanceof Text && item.getBackgroundColor() != null) {
978 d[0].setFillColor(item.getBackgroundColor());
979 } else {
980 d[0].setFillColor(item.getFillColor());
981 }
982 }
983 float newThickness = item.getThickness();
984 if (newThickness > 0) {
985 d[0].setThickness(newThickness);
986 }
987
988 ItemUtils.EnclosedCheck(newItems);
989 FrameGraphics.refresh(false);
990
991 return d[0];
992 }
993
994 public static void StopReminder() {
995 Reminders.stop();
996 }
997
998 public static void print(String file) {
999 try {
1000 if (Browser._theBrowser.isMinimumVersion6()) {
1001 if (Desktop.isDesktopSupported()) {
1002 Desktop.getDesktop().print(new File(file));
1003 }
1004 }
1005 } catch (Exception e) {
1006 MessageBay.errorMessage("Printing error: " + e.getMessage());
1007 }
1008 }
1009
1010 public static int wordCount(String paragraph) {
1011 return paragraph.trim().split("\\s+").length + 1;
1012 }
1013
1014 public static int wordCount(Frame frame) {
1015 int count = 0;
1016
1017 for (Text t : frame.getBodyTextItems(false)) {
1018 count += wordCount(t.getText());
1019 }
1020
1021 return count;
1022 }
1023
1024 public static void moveToPublic(Frame frame) {
1025 FrameIO.moveFrameset(frame.getFramesetName(), FrameIO.PUBLIC_PATH);
1026 }
1027
1028 public static void moveToPrivate(Frame frame) {
1029 FrameIO.moveFrameset(frame.getFramesetName(), FrameIO.FRAME_PATH);
1030 }
1031
1032 /**
1033 * Returns the value of a specified item attribute.
1034 *
1035 * @param item
1036 * from which to extract the value
1037 * @param attribute
1038 * name of an items attribute
1039 * @return the value of the attribute
1040 */
1041 public static String extract(Item item, String attribute) {
1042 return AttributeUtils.getAttribute(item, attribute);
1043 }
1044
1045 /**
1046 * Launches items.widgets.Browser and uses Text item as URL.
1047 * @param text Text item which passes contents as URL for browser.
1048 * @throws Exception
1049 */
1050 public static void startLoboBrowser(Item text) throws Exception {
1051 if (!(text instanceof Text)) {
1052 MessageBay.errorMessage("Must be a text item.");
1053 return;
1054 }
1055 if(text.getLink() != null) {
1056 MessageBay.errorMessage("Text item cannot have link.");
1057 return;
1058 }
1059
1060 FreeItems.getInstance().clear(); // remove url text from cursor
1061
1062 Text wt = new Text("@iw:org.expeditee.items.widgets.Browser"); // create new text item for browser widget
1063 wt.setParent(DisplayIO.getCurrentFrame()); // set parent of text source for InteractiveWidget.createWidget()
1064 wt.setXY(FrameMouseActions.getX(), FrameMouseActions.getY());
1065 // create widget from text item
1066 org.expeditee.items.widgets.Browser browser = (org.expeditee.items.widgets.Browser) InteractiveWidget.createWidget(wt);
1067
1068 if(FreeItems.textOnlyAttachedToCursor()) { // navigates to url specified by the text item
1069 browser.navigate(text.getText());
1070 } else {
1071 browser.navigate("http://www.waikato.ac.nz");
1072 }
1073
1074 FrameMouseActions.pickup(browser.getItems()); // attach browser widget to mouse
1075 }
1076
1077 /**
1078 * Text item becomes link to new frame containing items.widgets.Browser and uses Text item as URL for browser.
1079 * @param text Text item which passes contents as URL for browser and becomes link to the browser's new frame.
1080 * @throws Exception
1081 */
1082 public static void startLoboBrowserNewFrame(Item text) throws Exception {
1083 if (!(text instanceof Text)) {
1084 MessageBay.errorMessage("Must be a text item.");
1085 return;
1086 }
1087 if(text.getLink() != null) { // text item can't already have a link
1088 MessageBay.errorMessage("Text item already has link.");
1089 return;
1090 }
1091
1092 // Create new frame and text item for browser widget and parse created frame; loads browser widget
1093 Frame frame = FrameIO.CreateNewFrame(text);
1094 frame.addText(0, 50, "@iw:org.expeditee.items.widgets.Browser", null);
1095 FrameUtils.Parse(frame);
1096
1097 for(InteractiveWidget iw : frame.getInteractiveWidgets()) { // may be other widgets on frame
1098 if(iw instanceof org.expeditee.items.widgets.Browser) {
1099 // Set browser to 'full screen'
1100 iw.setSize(-1, -1, -1, -1, Browser._theBrowser.getWidth(), Browser._theBrowser.getHeight()
1101 - MessageBay.MESSAGE_BUFFER_HEIGHT - 80);
1102
1103 // If there is a text item attached to cursor use it as url for browser
1104 if(FreeItems.textOnlyAttachedToCursor()) {
1105 text.setLink("" + frame.getNumber());
1106 ((org.expeditee.items.widgets.Browser)iw).navigate(text.getText());
1107 } else {
1108 // Navigate to www.waikato.ac.nz by default if no url supplied and create new text item to be the link
1109 ((org.expeditee.items.widgets.Browser)iw).navigate("http://www.waikato.ac.nz");
1110 Text t = new Text("http://www.waikato.ac.nz");
1111 t.setParent(DisplayIO.getCurrentFrame()); // set parent of text source for InteractiveWidget.createWidget()
1112 t.setXY(FrameMouseActions.getX(), FrameMouseActions.getY());
1113 t.setLink("" + frame.getNumber()); // link url text to new browser frame
1114 FrameMouseActions.pickup(t); // Attach new text link to cursor
1115 }
1116 }
1117 }
1118
1119 FrameIO.SaveFrame(frame); // save frame to disk
1120 }
1121
1122 private static boolean startWidget(String name) throws Exception {
1123 String fullName = Actions.getClassName(name);
1124 if(fullName == null) {
1125 return false;
1126 }
1127 MessageBay.displayMessage("Creating new \"" + fullName + "\"");
1128
1129 FreeItems.getInstance().clear();
1130 Text wt = new Text("@iw:" + fullName); // create new text item for browser widget
1131 wt.setParent(DisplayIO.getCurrentFrame()); // set parent of text source for InteractiveWidget.createWidget()
1132 wt.setXY(FrameMouseActions.getX(), FrameMouseActions.getY()); // move to the mouse cursor
1133 InteractiveWidget widget = InteractiveWidget.createWidget(wt);
1134 FrameMouseActions.pickup(widget.getItems());
1135
1136 return true;
1137 }
1138
1139 private static void runUnknown(String command) throws Exception {
1140 if(startWidget(command)) {
1141 return;
1142 }
1143
1144 Actions.PerformAction(DisplayIO.getCurrentFrame(), null, command);
1145 }
1146
1147 public static void run(String command) throws Exception {
1148 if(command == null) {
1149 MessageBay.warningMessage("Please provide a command to run");
1150 return;
1151 }
1152 int firstSpace = command.indexOf(" ");
1153 if(firstSpace == -1) {
1154 runUnknown(command);
1155 return;
1156 }
1157 String argLower = command.toLowerCase();
1158 String name = argLower.substring(0, firstSpace).trim(); // first word
1159 String args = argLower.substring(firstSpace).trim(); // remainder after first word
1160 if(name == "action" || name == "agent") {
1161 if(args.length() > 0) {
1162 Actions.PerformAction(DisplayIO.getCurrentFrame(), null, args);
1163 } else {
1164 MessageBay.displayMessage("Please specify an action/agent name");
1165 }
1166 } else if(name == "widget") {
1167 if(args.length() > 0) {
1168 if(!startWidget(args)) {
1169 MessageBay.displayMessage("Widget \"" + name + "\" does not exist");
1170 }
1171 } else {
1172 MessageBay.displayMessage("Please specify a widget name");
1173 }
1174 } else {
1175 runUnknown(command);
1176 }
1177 }
1178
1179 public static void run(Item item) throws Exception {
1180 if(item == null) {
1181 MessageBay.warningMessage("Please provide a command to run");
1182 return;
1183 }
1184 run(((Text)item).getText());
1185 }
1186
1187 /**
1188 * Rebuilds the home frame restoring its original presentation.
1189 * Basically removes all items on the frame and reruns FrameUtils.CreateDefaultProfile().
1190 */
1191 public static void resetHomeFrame() {
1192 Frame homeFrame = FrameIO.LoadFrame(UserSettings.HomeFrame.get());
1193 homeFrame.removeAllItems(homeFrame.getItems());
1194 homeFrame.addText(0, 0, "title", null);
1195 FrameUtils.CreateDefaultProfile(UserSettings.UserName.get(), homeFrame);
1196 }
1197
1198 /**
1199 * Loads and runs an executable jar file in a new Thread
1200 * @param jar path to the jar file to run
1201 */
1202 public static void runJar(String jar) throws Exception {
1203 File jf = new File(jar);
1204 if(!jf.exists()) {
1205 System.err.println("jar '" + jar + "' could not be found");
1206 return;
1207 }
1208 JarFile jarFile = new JarFile(jf);
1209
1210 String mainClassName = (String) jarFile.getManifest().getMainAttributes().get(new Attributes.Name("Main-Class"));
1211 if(mainClassName == null) {
1212 System.err.println("jar '" + jar + "' does not have a Main-Class entry");
1213 jarFile.close();
1214 return;
1215 }
1216 jarFile.close();
1217 System.out.println("Main-Class = " + mainClassName);
1218
1219 ClassLoader classLoader = ClassLoader.getSystemClassLoader();
1220
1221 Method addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
1222 addURL.setAccessible(true);
1223 addURL.invoke(classLoader, jf.toURI().toURL());
1224
1225 final Class<?> jarClass = classLoader.loadClass(mainClassName);
1226
1227 final Method main = jarClass.getDeclaredMethod("main", String[].class);
1228
1229 new Thread(new Runnable() {
1230 public void run() {
1231 try {
1232 main.invoke(jarClass, new Object[] {new String[0]});
1233 } catch (Exception e) {
1234 System.out.println("Failed to start jar");
1235 e.printStackTrace();
1236 }
1237 }
1238 }).start();
1239 }
1240
1241 public static void pan(Frame frame, int x, int y) {
1242 for (Item i : frame.getAllItems()) {
1243 if (i instanceof WidgetEdge || i instanceof WidgetCorner) {
1244 continue;
1245 }
1246 else {
1247 int new_x = i.getX();
1248 int new_y = i.getY();
1249
1250 if (!i.isAnchoredX()) {
1251 new_x += x;
1252 }
1253
1254 if (!i.isAnchoredY()) {
1255 new_y += y;
1256 }
1257
1258 if(i instanceof XRayable) {
1259 i.setPosition(new_x,new_y);
1260 }
1261 else {
1262 i.setXY(new_x,new_y);
1263 }
1264 }
1265 // update the polygon, otherwise stuff moves but leaves it's outline behind
1266 i.updatePolygon();
1267 }
1268
1269 for (InteractiveWidget iw : frame.getInteractiveWidgets()) {
1270
1271 int new_x = iw.getX();
1272 int new_y = iw.getY();
1273
1274 if (!iw.isAnchoredX()) {
1275 new_x += x;
1276 }
1277
1278 if (!iw.isAnchoredY()) {
1279 new_y += y;
1280 }
1281
1282 iw.setPosition(new_x,new_y);
1283
1284 }
1285
1286 // make sure we save the panning of the frame
1287 frame.change();
1288 // redraw everything
1289 FrameKeyboardActions.Refresh();
1290 }
1291
1292 public static void pan(Frame frame, String pan) {
1293 String[] split = pan.split("\\s+");
1294 int x = 0;
1295 int y = 0;
1296 try {
1297 if(split.length != 2) throw new Exception();
1298 x = Integer.parseInt(split[0]);
1299 y = Integer.parseInt(split[1]);
1300 } catch(Exception e) {
1301 MessageBay.errorMessage("Panning takes 2 integer arguments");
1302 return;
1303 }
1304 pan(frame, x, y);
1305 }
1306
1307 public static void pan(Frame frame, Text pan) {
1308 pan(frame, pan.getText());
1309 }
1310
1311 public static String exec(String cmd) throws Exception {
1312
1313 String[] command;
1314
1315 // run command through sh if possible
1316 if(System.getProperty("os.name").toLowerCase().indexOf("win") == -1) {
1317 command = new String[] { "sh", "-c", cmd };
1318 } else {
1319 command = cmd.split("\\s+");
1320 }
1321
1322 ProcessBuilder pb = new ProcessBuilder(command);
1323 pb.redirectErrorStream(true);
1324 Process ps = pb.start();
1325
1326 BufferedReader in = new BufferedReader(new InputStreamReader(ps.getInputStream()));
1327 StringBuffer sb = new StringBuffer();
1328 String line;
1329 while ((line = in.readLine()) != null) {
1330 sb.append(line).append('\n');
1331 }
1332 ps.waitFor();
1333 in.close();
1334
1335 if(sb.length() > 0) {
1336 sb.deleteCharAt(sb.length() - 1);
1337 }
1338 return sb.toString();
1339 }
1340
1341 public static void testProgress() {
1342 new Thread(new Runnable() {
1343
1344 @Override
1345 public void run() {
1346 Progress p = MessageBay.displayProgress("Loading something");
1347 for(int i = 1; i <= 100; i++) {
1348 try {
1349 Thread.sleep(100);
1350 p.set(i);
1351 } catch (Exception e) {
1352 e.printStackTrace();
1353 }
1354 }
1355 }
1356
1357 }).start();
1358 }
1359
1360 public static void getIDs(Frame f) {
1361 for(Item i : f.getAllItems()) {
1362 System.out.println(i + " (" + i.getID() + ")");
1363 }
1364 }
1365
1366 public static void flushResources() {
1367 FrameUtils.extractResources(true);
1368 MessageBay.displayMessage("Re-extracted resources, Expeditee may need to be restarted for certain resources to be reloaded");
1369 }
1370}
Note: See TracBrowser for help on using the repository browser.