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

Last change on this file since 1102 was 1102, checked in by davidb, 6 years ago

Reworking of the code-base to separate logic from graphics. This version of Expeditee now supports a JFX graphics as an alternative to SWING

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