Changeset 1102 for trunk/src/org/expeditee/gui/FrameUtils.java
- Timestamp:
- 05/10/18 16:04:51 (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/expeditee/gui/FrameUtils.java
r1064 r1102 19 19 package org.expeditee.gui; 20 20 21 import java.awt.Color;22 import java.awt.Point;23 import java.awt.Polygon;24 import java.awt.Rectangle;25 21 import java.io.File; 26 22 import java.io.FileInputStream; … … 44 40 import java.util.zip.ZipEntry; 45 41 42 import org.expeditee.core.Colour; 43 import org.expeditee.core.Point; 44 import org.expeditee.core.bounds.AxisAlignedBoxBounds; 45 import org.expeditee.core.bounds.PolygonBounds; 46 import org.expeditee.gio.EcosystemManager; 47 import org.expeditee.gio.gesture.StandardGestureActions; 46 48 import org.expeditee.items.Circle; 47 49 import org.expeditee.items.Dot; … … 60 62 import org.expeditee.items.XRayable; 61 63 import org.expeditee.items.widgets.ButtonWidget; 62 import org.expeditee.items.widgets. InteractiveWidget;64 import org.expeditee.items.widgets.Widget; 63 65 import org.expeditee.items.widgets.InteractiveWidgetInitialisationFailedException; 64 66 import org.expeditee.items.widgets.InteractiveWidgetNotAvailableException; … … 73 75 public class FrameUtils { 74 76 75 private static final int COLUMN_WIDTH = 50; 76 77 /** 78 * Provides a way to monitor the time elapsed between button-down and the 79 * finished painting. 80 */ 81 public static TimeKeeper ResponseTimer = new TimeKeeper(); 82 83 private static float _ResponseTimeSum = 0; 84 85 private static float _LastResponse = 0; 86 87 private static Text LastEdited = null; 88 89 public static int MINIMUM_INTERITEM_SPACING = -6; 90 91 public static float getResponseTimeTotal() { 92 return _ResponseTimeSum; 93 } 94 95 public static float getLastResponseTime() { 96 return _LastResponse; 97 } 98 99 /** 100 * The list of known start pages framesets which will have prepopulated 101 * links in the home frame. 102 */ 103 public static final String[] startPages = { "exploratorysearch", 104 "webbrowser" }; 105 106 /** 107 * Checks if the given top Item is above the given bottom Item, allowing for 108 * the X coordinates to be off by a certain width... 109 * 110 * @param item1 111 * The Item to check is above the other Item 112 * @param item2 113 * The Item to check is below the top Item 114 * @return True if top is above bottom, False otherwise. 115 */ 116 public static boolean inSameColumn(Item item1, Item item2) { 117 if (!(item1 instanceof Text) || !(item2 instanceof Text)) 118 return false; 119 120 if (item1.getID() < 0 || item2.getID() < 0) 121 return false; 122 123 int minX = item2.getX(); 124 int maxX = item2.getX() + item2.getBoundsWidth(); 125 126 int startX = item1.getX(); 127 int endX = item1.getX() + item1.getBoundsWidth(); 128 129 // Check that the two items left values are close 130 if (Math.abs(item1.getX() - item2.getX()) > COLUMN_WIDTH) 131 return false; 132 133 // Ensure the two items 134 if ((minX >= startX && minX <= endX) 135 || (maxX >= startX && maxX <= endX) 136 || (startX >= minX && startX <= maxX) 137 || (endX >= minX && endX <= maxX)) 138 return true; 139 140 return false; 141 } 142 143 public static boolean sameBulletType(String bullet1, String bullet2) { 144 if (bullet1 == null || bullet2 == null) 145 return false; 146 147 if (bullet1.equals("") || bullet2.equals("")) 148 return false; 149 150 if (Character.isLetter(bullet1.charAt(0)) 151 && Character.isLetter(bullet2.charAt(0))) 152 return true; 153 154 if (Character.isDigit(bullet1.charAt(0)) 155 && Character.isDigit(bullet2.charAt(0))) 156 return true; 157 158 // TODO make this more sofisticated 159 160 return false; 161 } 162 163 private static boolean needsRenumbering(String s) { 164 if (s == null || s.equals("")) 165 return false; 166 if (!Character.isLetterOrDigit(s.charAt(0))) 167 return false; 168 169 s = s.trim(); 170 // if its all letters then we dont want to auto adjust 171 if (s.length() > 2) { 172 for (int i = 0; i < s.length() - 1; i++) { 173 if (!Character.isLetter(s.charAt(i))) 174 return true; 175 } 176 } else 177 return true; 178 179 return false; 180 } 181 182 /** 183 * 184 * @param toAlign 185 * @param moveAll 186 * @param adjust 187 * @return 188 */ 189 public static int Align(List<Text> toAlign, boolean moveAll, int adjust, 190 List<Item> changedItems) { 191 Collections.sort(toAlign); 192 193 /* 194 * Single items dont need alignment But if there are two items we may 195 * still want to format them... ie if they are too close together. 196 */ 197 if (toAlign.size() < 1) 198 return 0; 199 200 // get the first item 201 Text from = toAlign.get(0); 202 if (from.getParent() == null) 203 from = toAlign.get(1); 204 int x = from.getX(); 205 206 Frame curr = from.getParent(); 207 Text above = curr.getTextAbove(from); 208 209 String lastBullet = ""; 210 211 if (above != null && curr.isNormalTextItem(above)) 212 lastBullet = FrameKeyboardActions.getAutoBullet(above.getText()); 213 else { 214 lastBullet = FrameKeyboardActions.getBullet(toAlign.get(0) 215 .getText()); 216 } 217 if (needsRenumbering(lastBullet)) { 218 // renumber... 219 for (int i = 0; i < toAlign.size(); i++) { 220 221 Text currentText = toAlign.get(i); 222 String currentBullet = FrameKeyboardActions 223 .getAutoBullet(currentText.getText()); 224 225 if (sameBulletType(lastBullet, currentBullet)) { 226 String oldText = currentText.getText(); 227 228 currentText.stripFirstWord(); 229 230 currentText.setText(lastBullet + currentText.getText()); 231 lastBullet = FrameKeyboardActions.getAutoBullet(currentText 232 .getText()); 233 234 // if we changed the item, add to changedItems list 235 if (changedItems != null 236 && oldText != currentText.getText() 237 && !changedItems.contains(currentText)) { 238 Item copy = currentText.copy(); 239 copy.setID(currentText.getID()); 240 copy.setText(oldText); 241 changedItems.add(copy); 242 } 243 } 244 } 245 } 246 247 // work out the spacing between the first item and the one above it 248 249 int space = 10 + adjust; 250 251 // if we are dropping from the title make the space a little bigger 252 // than normal 253 254 // If there are only two items get the gap from the start item on the 255 // zero frame if there is one 256 if (above == curr.getTitleItem()) { 257 Frame zero = FrameIO.LoadFrame(curr.getFramesetName() + '0'); 258 String strGap = zero.getAnnotationValue("start"); 259 if (strGap != null) { 77 /** 78 * The list of known start pages framesets which will have prepopulated 79 * links in the home frame. 80 */ 81 public static final String[] startPages = { "exploratorysearch", "webbrowser" }; 82 83 private static final int COLUMN_WIDTH = 50; 84 85 /** 86 * Provides a way to monitor the time elapsed between button-down and the 87 * finished painting. 88 */ 89 public static TimeKeeper ResponseTimer = new TimeKeeper(); 90 91 private static float _ResponseTimeSum = 0; 92 93 private static float _LastResponse = 0; 94 95 private static Text LastEdited = null; 96 97 public static int MINIMUM_INTERITEM_SPACING = -6; 98 99 private static Item _tdfcItem = null; 100 101 public static float getResponseTimeTotal() 102 { 103 return _ResponseTimeSum; 104 } 105 106 public static float getLastResponseTime() 107 { 108 return _LastResponse; 109 } 110 111 /** 112 * Checks if the given top Item is above the given bottom Item, allowing for 113 * the X coordinates to be off by a certain width... 114 * 115 * @param item1 116 * The Item to check is above the other Item 117 * @param item2 118 * The Item to check is below the top Item 119 * @return True if top is above bottom, False otherwise. 120 */ 121 public static boolean inSameColumn(Item item1, Item item2) { 122 if (!(item1 instanceof Text) || !(item2 instanceof Text)) 123 return false; 124 125 if (item1.getID() < 0 || item2.getID() < 0) 126 return false; 127 128 int minX = item2.getX(); 129 int maxX = item2.getX() + item2.getBoundsWidth(); 130 131 int startX = item1.getX(); 132 int endX = item1.getX() + item1.getBoundsWidth(); 133 134 // Check that the two items left values are close 135 if (Math.abs(item1.getX() - item2.getX()) > COLUMN_WIDTH) 136 return false; 137 138 // Ensure the two items 139 if ((minX >= startX && minX <= endX) 140 || (maxX >= startX && maxX <= endX) 141 || (startX >= minX && startX <= maxX) 142 || (endX >= minX && endX <= maxX)) 143 return true; 144 145 return false; 146 } 147 148 public static boolean sameBulletType(String bullet1, String bullet2) 149 { 150 if (bullet1 == null || bullet2 == null) 151 return false; 152 153 if (bullet1.equals("") || bullet2.equals("")) 154 return false; 155 156 if (Character.isLetter(bullet1.charAt(0)) 157 && Character.isLetter(bullet2.charAt(0))) 158 return true; 159 160 if (Character.isDigit(bullet1.charAt(0)) 161 && Character.isDigit(bullet2.charAt(0))) 162 return true; 163 164 // TODO make this more sofisticated 165 166 return false; 167 } 168 169 private static boolean needsRenumbering(String s) { 170 if (s == null || s.equals("")) 171 return false; 172 if (!Character.isLetterOrDigit(s.charAt(0))) 173 return false; 174 175 s = s.trim(); 176 // if its all letters then we dont want to auto adjust 177 if (s.length() > 2) { 178 for (int i = 0; i < s.length() - 1; i++) { 179 if (!Character.isLetter(s.charAt(i))) 180 return true; 181 } 182 } else 183 return true; 184 185 return false; 186 } 187 188 /** 189 * 190 * @param toAlign 191 * @param moveAll 192 * @param adjust 193 * @return 194 */ 195 public static int Align(List<Text> toAlign, boolean moveAll, int adjust, 196 List<Item> changedItems) { 197 Collections.sort(toAlign); 198 199 /* 200 * Single items dont need alignment But if there are two items we may 201 * still want to format them... ie if they are too close together. 202 */ 203 if (toAlign.size() < 1) 204 return 0; 205 206 // get the first item 207 Text from = toAlign.get(0); 208 if (from.getParent() == null) 209 from = toAlign.get(1); 210 int x = from.getX(); 211 212 Frame curr = from.getParent(); 213 Text above = curr.getTextAbove(from); 214 215 String lastBullet = ""; 216 217 if (above != null && curr.isNormalTextItem(above)) 218 lastBullet = StandardGestureActions.getAutoBullet(above.getText()); 219 else { 220 lastBullet = StandardGestureActions.getBullet(toAlign.get(0) 221 .getText()); 222 } 223 if (needsRenumbering(lastBullet)) { 224 // renumber... 225 for (int i = 0; i < toAlign.size(); i++) { 226 227 Text currentText = toAlign.get(i); 228 String currentBullet = StandardGestureActions.getAutoBullet(currentText.getText()); 229 230 if (sameBulletType(lastBullet, currentBullet)) { 231 String oldText = currentText.getText(); 232 233 currentText.stripFirstWord(); 234 235 currentText.setText(lastBullet + currentText.getText()); 236 lastBullet = StandardGestureActions.getAutoBullet(currentText.getText()); 237 238 // if we changed the item, add to changedItems list 239 if (changedItems != null 240 && oldText != currentText.getText() 241 && !changedItems.contains(currentText)) { 242 Item copy = currentText.copy(); 243 copy.setID(currentText.getID()); 244 copy.setText(oldText); 245 changedItems.add(copy); 246 } 247 } 248 } 249 } 250 251 // work out the spacing between the first item and the one above it 252 253 int space = 10 + adjust; 254 255 // if we are dropping from the title make the space a little bigger 256 // than normal 257 258 // If there are only two items get the gap from the start item on the 259 // zero frame if there is one 260 if (above == curr.getTitleItem()) { 261 Frame zero = FrameIO.LoadFrame(curr.getFramesetName() + '0'); 262 String strGap = zero.getAnnotationValue("start"); 263 if (strGap != null) { 264 try { 265 int gap = Integer.parseInt(strGap); 266 space = gap; 267 } catch (NumberFormatException nfe) { 268 269 } 270 } 271 } else if (above != null) { 272 // Make the gap between all items the same as the gap between 273 // the first two 274 space = (int) (from.getBounds().getMinY() - above.getBounds().getMaxY()); 275 276 if (space < MINIMUM_INTERITEM_SPACING) 277 space = MINIMUM_INTERITEM_SPACING; 278 279 if (UserSettings.FormatSpacingMax.get() != null) { 280 double maxSpace = UserSettings.FormatSpacingMax.get() 281 * above.getSize(); 282 if (maxSpace < space) { 283 space = (int) Math.round(maxSpace); 284 } 285 } 286 287 if (UserSettings.FormatSpacingMin.get() != null) { 288 double minSpace = UserSettings.FormatSpacingMin.get() 289 * above.getSize(); 290 if (minSpace > space) { 291 space = (int) Math.round(minSpace); 292 } 293 } 294 295 // Need to do things differently for FORMAT than for DROPPING 296 if (moveAll && above != curr.getNameItem() 297 && above != curr.getTitleItem()) { 298 x = above.getX(); 299 int y = (int) above.getBounds().getMaxY() 300 + space 301 + ((int) (from.getY() - from.getBounds().getMinY())); 302 303 if (changedItems != null 304 && (from.getX() != x || from.getY() != y) 305 && !changedItems.contains(from)) { 306 Item copy = from.copy(); 307 copy.setID(from.getID()); 308 changedItems.add(copy); 309 } 310 from.setPosition(x, y); 311 } else { 312 x = from.getX(); 313 } 314 315 space += adjust; 316 } 317 for (int i = 1; i < toAlign.size(); i++) { 318 Item current = toAlign.get(i); 319 Item top = toAlign.get(i - 1); 320 321 // The bottom of the previous item 322 int bottom = (int) top.getBounds().getMaxY(); 323 324 // the difference between the current item's Y coordinate and 325 // the top of the highlight box 326 int diff = (int) (current.getY() - current.getBounds().getMinY()); 327 328 int newPos = bottom + space + diff; 329 330 if (changedItems != null 331 && ((moveAll && current.getX() != x) || current.getY() != newPos) 332 && !changedItems.contains(current)) { 333 Item copy = current.copy(); 334 copy.setID(current.getID()); 335 changedItems.add(copy); 336 } 337 338 if (moveAll) { 339 current.setPosition(x, newPos); 340 } else if (newPos > current.getY()) { 341 current.setY(newPos); 342 } 343 344 } 345 346 // if (insert != null) 347 // return insert.getY(); 348 349 // Michael thinks we return the y value for the next new item?? 350 int y = from.getY() + from.getBoundsHeight() + space; 351 return y; 352 } 353 354 public static int Align(List<Text> toAlign, boolean moveAll, int adjust) { 355 return Align(toAlign, moveAll, adjust, null); 356 } 357 358 public static boolean LeavingFrame(Frame current) { 359 checkTDFCItemWaiting(current); 360 // active overlay frames may also require saving if they have been 361 // changed 362 for (Overlay o : current.getOverlays()) 363 if (!SaveCheck(o.Frame)) 364 return false; 365 366 // if the check fails there is no point continuing 367 if (!SaveCheck(current)) 368 return false; 369 370 for (Item i : current.getItems()) { 371 i.setHighlightMode(Item.HighlightMode.None); 372 i.setHighlightColorToDefault(); 373 } 374 return true; 375 } 376 377 private static boolean SaveCheck(Frame toSave) { 378 // don't bother saving frames that haven't changed 379 if (!toSave.hasChanged()) 380 return true; 381 382 // if the frame has been changed, then save it 383 if (DisplayController.isTwinFramesOn()) { 384 Frame opposite = DisplayController.getOppositeFrame(); 385 386 String side = "left"; 387 if (DisplayController.getCurrentSide() == DisplayController.TwinFramesSide.RIGHT) 388 side = "right"; 389 390 // if the two frames both have changes, prompt the user for the 391 // next move 392 if (opposite.hasChanged() && opposite.equals(toSave)) { 393 if (EcosystemManager.getGraphicsManager().showDialog("Changes", "Leaving this frame will discard changes made in the " + side + " Frame. Continue?")) { 394 FrameIO.SaveFrame(toSave); 395 DisplayController.Reload(DisplayController.getSideFrameIsOn(opposite)); 396 return true; 397 } else 398 return false; 399 } else if (opposite.hasOverlay(toSave)) { 400 if (toSave.hasChanged()) 401 if (EcosystemManager.getGraphicsManager().showDialog("Changes", "Leaving this frame will discard changes made in the " + side + " Frame. Continue?")) { 402 FrameIO.SaveFrame(toSave); 403 DisplayController.Reload(DisplayController.getSideFrameIsOn(opposite)); 404 return true; 405 } else 406 return false; 407 } 408 409 // save the current frame and restore the other side 410 FrameIO.SaveFrame(toSave); 411 return true; 412 } 413 414 // single-frame mode can just save and return 415 FrameIO.SaveFrame(toSave); 416 return true; 417 } 418 419 // TODO: consider reloating this method to Frame class? 420 protected static Item getAnnotation(Frame frame, String annotationStr) 421 { 422 Item matched_item = null; 423 424 // check for an updated template... 425 for (Item i : frame.getAnnotationItems()) { 426 427 if (ItemUtils.startsWithTag(i, annotationStr)) { 428 429 matched_item = i; 430 break; 431 } 432 } 433 434 return matched_item; 435 } 436 437 protected static void doFrameTransition(Item frameTransition, Frame from, Frame to) 438 { 439 String s = frameTransition.getText(); 440 String[] s_array = s.split(":"); 441 if(s_array.length > 1){ 442 String slide_mode_method = s_array[1].trim(); 443 444 FrameTransition transition = new FrameTransition(from.getBuffer(), slide_mode_method); 445 446 DisplayController.setTransition(from, transition); 447 448 System.out.println("Triggered on annotation: " + s); 449 } else { 450 System.err.println("Warning: failed to detect frameTransition type"); 451 // TODO: print list as a result of reflection listing 452 } 453 } 454 455 /** 456 * Displays the given Frame on the display. If the current frame has changed 457 * since the last save then it will be saved before the switch is made. The 458 * caller can also dictate whether the current frame is added to the 459 * back-stack or not. 460 * 461 * @param toDisplay 462 * The Frame to display on the screen 463 * @param addToBack 464 * True if the current Frame should be added to the back-stack, 465 * False otherwise 466 */ 467 public static void DisplayFrame(Frame toDisplay, boolean addToBack, boolean incrementStats) 468 { 469 if (toDisplay == null) 470 return; 471 472 Frame current = DisplayController.getCurrentFrame(); 473 474 // Dont need to do anything if the frame to display is already being 475 // displayed 476 if (current.equals(toDisplay)) 477 return; 478 479 // move any anchored connected items 480 if (FreeItems.hasItemsAttachedToCursor()) { 481 List<Item> toAdd = new ArrayList<Item>(); 482 List<Item> toCheck = new ArrayList<Item>(FreeItems.getInstance()); 483 484 while (toCheck.size() > 0) { 485 Item i = toCheck.get(0); 486 Collection<Item> connected = i.getAllConnected(); 487 488 // // Only move completely enclosed items 489 // if (!toCheck.containsAll(connected)) { 490 // connected.retainAll(FreeItems.getInstance()); 491 // FreeItems.getInstance().removeAll(connected); 492 // toCheck.removeAll(connected); 493 // FrameMouseActions.anchor(connected); 494 // } else { 495 // toCheck.removeAll(connected); 496 // } 497 498 // Anchor overlay items where they belong 499 if (i.getParent() != null && i.getParent() != current) { 500 FreeItems.getInstance().removeAll(connected); 501 toCheck.removeAll(connected); 502 StandardGestureActions.anchor(connected); 503 } else { 504 // Add stuff that is partially enclosed 505 // remove all the connected items from our list to check 506 toCheck.removeAll(connected); 507 // Dont add the items that are free 508 connected.removeAll(FreeItems.getInstance()); 509 toAdd.addAll(connected); 510 } 511 } 512 513 current.removeAllItems(toAdd); 514 515 boolean oldChange = toDisplay.hasChanged(); 516 toDisplay.updateIDs(toAdd); 517 toDisplay.addAllItems(toAdd); 518 toDisplay.setChanged(oldChange); 519 } 520 521 if (addToBack && current != toDisplay) { 522 FrameIO.checkTDFC(current); 523 } 524 525 // if the saving happened properly, we can continue 526 if (!LeavingFrame(current)) { 527 MessageBay.displayMessage("Navigation cancelled"); 528 return; 529 } 530 531 if (addToBack && current != toDisplay) { 532 DisplayController.addToBack(current); 533 } 534 535 Parse(toDisplay); 536 537 if (DisplayController.isAudienceMode()) { 538 // Only need to worry about frame transitions when in Audience Mode 539 540 // Test to see if frame transition specified through annotation, and perform it if one if found 541 Item frameTransition = getAnnotation(toDisplay, "@frameTransition"); 542 if (frameTransition != null) { 543 doFrameTransition(frameTransition,current,toDisplay); 544 } 545 } 546 547 DisplayController.setCurrentFrame(toDisplay, incrementStats); 548 StandardGestureActions.updateCursor(); 549 // FrameMouseActions.getInstance().refreshHighlights(); 550 // update response timer 551 _LastResponse = ResponseTimer.getElapsedSeconds(); 552 _ResponseTimeSum += _LastResponse; 553 DisplayController.updateTitle(); 554 } 555 556 /** 557 * Loads and displays the Frame with the given framename, and adds the 558 * current frame to the back-stack if required. 559 * 560 * @param framename 561 * The name of the Frame to load and display 562 * @param addToBack 563 * True if the current Frame should be added to the back-stack, 564 * false otherwise 565 */ 566 public static void DisplayFrame(String frameName, boolean addToBack, 567 boolean incrementStats) { 568 Frame newFrame = getFrame(frameName); 569 570 if (newFrame != null) 571 // display the frame 572 DisplayFrame(newFrame, addToBack, incrementStats); 573 } 574 575 /** 576 * Loads and displays the Frame with the given framename and adds the 577 * current frame to the back-stack. This is the same as calling 578 * DisplayFrame(framename, true) 579 * 580 * @param framename 581 * The name of the Frame to load and display 582 */ 583 public static void DisplayFrame(String framename) { 584 DisplayFrame(framename, true, true); 585 } 586 587 public static Frame getFrame(String frameName) { 588 // if the new frame does not exist then tell the user 589 Frame f = FrameIO.LoadFrame(frameName); 590 591 if (f == null) { 592 MessageBay.errorMessage("Frame '" + frameName + "' could not be found."); 593 } 594 595 return f; 596 } 597 598 /** 599 * Creates a new Picture Item from the given Text source Item and adds it to 600 * the given Frame. 601 * 602 * @return True if the image was created successfully, false otherwise 603 */ 604 private static boolean createPicture(Frame frame, Text txt) { 605 // attempt to create the picture 606 Picture pic = ItemUtils.CreatePicture(txt); 607 608 // if the picture could not be created successfully 609 if (pic == null) { 610 String imagePath = txt.getText(); 611 assert (imagePath != null); 612 imagePath = new AttributeValuePair(imagePath).getValue().trim(); 613 if (imagePath.length() == 0) { 614 return false; 615 // MessageBay.errorMessage("Expected image path after @i:"); 616 } else { 617 MessageBay.errorMessage("Image " + imagePath 618 + " could not be loaded"); 619 } 620 return false; 621 } 622 frame.addItem(pic); 623 624 return true; 625 } 626 627 /** 628 * Creates an interactive widget and adds it to a frame. If txt has no 629 * parent the parent will be set to frame. 630 * 631 * @param frame 632 * Frame to add widget to. Must not be null. 633 * 634 * @param txt 635 * Text to create the widget from. Must not be null. 636 * 637 * @return True if created/added. False if could not create. 638 * 639 * @author Brook Novak 640 */ 641 private static boolean createWidget(Frame frame, Text txt) { 642 643 if (frame == null) 644 throw new NullPointerException("frame"); 645 if (txt == null) 646 throw new NullPointerException("txt"); 647 648 // Safety 649 if (txt.getParent() == null) 650 txt.setParent(frame); 651 652 Widget iw = null; 653 260 654 try { 261 int gap = Integer.parseInt(strGap); 262 space = gap; 263 } catch (NumberFormatException nfe) { 264 265 } 266 } 267 } else if (above != null) { 268 // Make the gap between all items the same as the gap between 269 // the first two 270 space = (int) (from.getPolygon().getBounds().getMinY() - above 271 .getPolygon().getBounds().getMaxY()); 272 273 if (space < MINIMUM_INTERITEM_SPACING) 274 space = MINIMUM_INTERITEM_SPACING; 275 276 if (UserSettings.FormatSpacingMax.get() != null) { 277 double maxSpace = UserSettings.FormatSpacingMax.get() 278 * above.getSize(); 279 if (maxSpace < space) { 280 space = (int) Math.round(maxSpace); 281 } 282 } 283 284 if (UserSettings.FormatSpacingMin.get() != null) { 285 double minSpace = UserSettings.FormatSpacingMin.get() 286 * above.getSize(); 287 if (minSpace > space) { 288 space = (int) Math.round(minSpace); 289 } 290 } 291 292 // Need to do things differently for FORMAT than for DROPPING 293 if (moveAll && above != curr.getNameItem() 294 && above != curr.getTitleItem()) { 295 x = above.getX(); 296 int y = (int) above.getPolygon().getBounds().getMaxY() 297 + space 298 + ((int) (from.getY() - from.getPolygon().getBounds() 299 .getMinY())); 300 301 if (changedItems != null 302 && (from.getX() != x || from.getY() != y) 303 && !changedItems.contains(from)) { 304 Item copy = from.copy(); 305 copy.setID(from.getID()); 306 changedItems.add(copy); 307 } 308 from.setPosition(x, y); 309 } else { 310 x = from.getX(); 311 } 312 313 space += adjust; 314 } 315 for (int i = 1; i < toAlign.size(); i++) { 316 Item current = toAlign.get(i); 317 Item top = toAlign.get(i - 1); 318 319 // The bottom of the previous item 320 int bottom = (int) top.getPolygon().getBounds().getMaxY(); 321 322 // the difference between the current item's Y coordinate and 323 // the top of the highlight box 324 int diff = (int) (current.getY() - current.getPolygon().getBounds() 325 .getMinY()); 326 327 int newPos = bottom + space + diff; 328 329 if (changedItems != null 330 && ((moveAll && current.getX() != x) || current.getY() != newPos) 331 && !changedItems.contains(current)) { 332 Item copy = current.copy(); 333 copy.setID(current.getID()); 334 changedItems.add(copy); 335 } 336 337 if (moveAll) { 338 current.setPosition(x, newPos); 339 } else if (newPos > current.getY()) { 340 current.setY(newPos); 341 } 342 343 } 344 345 // if (insert != null) 346 // return insert.getY(); 347 348 // Michael thinks we return the y value for the next new item?? 349 int y = from.getY() + from.getBoundsHeight() + space; 350 return y; 351 } 352 353 public static int Align(List<Text> toAlign, boolean moveAll, int adjust) { 354 return Align(toAlign, moveAll, adjust, null); 355 } 356 357 public static boolean LeavingFrame(Frame current) { 358 checkTDFCItemWaiting(current); 359 // active overlay frames may also require saving if they have been 360 // changed 361 for (Overlay o : current.getOverlays()) 362 if (!SaveCheck(o.Frame)) 363 return false; 364 365 // if the check fails there is no point continuing 366 if (!SaveCheck(current)) 367 return false; 368 369 for (Item i : current.getItems()) 370 i.setHighlightMode(Item.HighlightMode.None); 371 return true; 372 } 373 374 private static boolean SaveCheck(Frame toSave) { 375 // don't bother saving frames that haven't changed 376 if (!toSave.hasChanged()) 377 return true; 378 379 // if the frame has been changed, then save it 380 if (DisplayIO.isTwinFramesOn()) { 381 Frame opposite = DisplayIO.getOppositeFrame(); 382 383 String side = "left"; 384 if (DisplayIO.getCurrentSide() == 0) 385 side = "right"; 386 387 // if the two frames both have changes, prompt the user for the 388 // next move 389 if (opposite.hasChanged() && opposite.equals(toSave)) { 390 if (DisplayIO.DisplayConfirmDialog( 391 "Leaving this frame will discard changes made in the " 392 + side + " Frame. Continue?", "Changes", 393 DisplayIO.TYPE_WARNING, DisplayIO.OPTIONS_OK_CANCEL, 394 DisplayIO.RESULT_OK)) { 395 FrameIO.SaveFrame(toSave); 396 DisplayIO.Reload(DisplayIO.FrameOnSide(opposite)); 397 return true; 398 } else 399 return false; 400 } else if (opposite.hasOverlay(toSave)) { 401 if (toSave.hasChanged()) 402 if (DisplayIO.DisplayConfirmDialog( 403 "Leaving this frame will discard changes made in the " 404 + side + " Frame. Continue?", "Changes", 405 DisplayIO.TYPE_WARNING, 406 DisplayIO.OPTIONS_OK_CANCEL, DisplayIO.RESULT_OK)) { 407 FrameIO.SaveFrame(toSave); 408 DisplayIO.Reload(DisplayIO.FrameOnSide(opposite)); 409 return true; 410 } else 655 656 iw = Widget.createWidget(txt); 657 658 } catch (InteractiveWidgetNotAvailableException e) { 659 e.printStackTrace(); 660 MessageBay.errorMessage("Cannot create iWidget: " + e.getMessage()); 661 } catch (InteractiveWidgetInitialisationFailedException e) { 662 e.printStackTrace(); 663 MessageBay.errorMessage("Cannot create iWidget: " + e.getMessage()); 664 } catch (IllegalArgumentException e) { 665 e.printStackTrace(); 666 MessageBay.errorMessage("Cannot create iWidget: " + e.getMessage()); 667 } 668 669 if (iw == null) 411 670 return false; 412 } 413 414 // save the current frame and restore the other side 415 FrameIO.SaveFrame(toSave); 416 return true; 417 } 418 419 // single-frame mode can just save and return 420 FrameIO.SaveFrame(toSave); 421 return true; 422 } 423 424 // TODO: consider reloating this method to Frame class? 425 protected static Item getAnnotation(Frame frame, String annotationStr) 426 { 427 Item matched_item = null; 671 672 frame.removeItem(txt); 673 674 frame.addAllItems(iw.getItems()); 675 676 return true; 677 } 678 679 public static List<String> ParseProfile(Frame profile) 680 { 681 List<String> errors = new LinkedList<String>(); 682 683 if (profile == null) return errors; 684 685 /* 686 * Make sure the correct cursor shows when turning off the custom cursor 687 * and reparsing the profile frame 688 */ 689 FreeItems.getCursor().clear(); 690 DisplayController.setCursor(Item.HIDDEN_CURSOR); 691 DisplayController.setCursor(Item.DEFAULT_CURSOR); 692 693 // check for settings tags 694 for (Text item : profile.getBodyTextItems(true)) { 695 try { 696 697 AttributeValuePair avp = new AttributeValuePair(item.getText()); 698 String attributeFullCase = avp.getAttributeOrValue(); 699 700 if (attributeFullCase == null) continue; 701 702 String attribute = attributeFullCase.trim().toLowerCase().replaceAll("^@", ""); 703 704 if (attribute.equals("settings")) Settings.parseSettings(item); 705 706 } catch (Exception e) { 707 if (e.getMessage() != null) { 708 errors.add(e.getMessage()); 709 } else { 710 e.printStackTrace(); 711 errors.add("Error parsing [" + item.getText() + "] on " + profile.getName()); 712 } 713 } 714 } 715 716 return errors; 717 } 718 719 /** 720 * Sets the first frame to be displayed. 721 * 722 * @param profile 723 */ 724 public static void loadFirstFrame(Frame profile) 725 { 726 if (UserSettings.HomeFrame.get() == null) UserSettings.HomeFrame.set(profile.getName()); 727 728 Frame firstFrame = FrameIO.LoadFrame(UserSettings.HomeFrame.get()); 729 if (firstFrame == null) { 730 MessageBay.warningMessage("Home frame not found: " + UserSettings.HomeFrame); 731 UserSettings.HomeFrame.set(profile.getName()); 732 DisplayController.setCurrentFrame(profile, true); 733 } else { 734 DisplayController.setCurrentFrame(firstFrame, true); 735 } 736 737 } 738 739 public static Colour[] getColorWheel(Frame frame) 740 { 741 if (frame != null) { 742 List<Text> textItems = frame.getBodyTextItems(false); 743 Colour[] colorList = new Colour[textItems.size() + 1]; 744 for (int i = 0; i < textItems.size(); i++) { 745 colorList[i] = textItems.get(i).getColor(); 746 } 747 // Make the last item transparency or default for forecolor 748 colorList[colorList.length - 1] = null; 749 750 return colorList; 751 } 752 return new Colour[] { Colour.BLACK, Colour.WHITE, null }; 753 } 754 755 public static String getLink(Item item, String alt) 756 { 757 if (item == null || !(item instanceof Text)) return alt; 758 759 AttributeValuePair avp = new AttributeValuePair(item.getText()); 760 assert (avp != null); 761 762 if (avp.hasPair() && avp.getValue().trim().length() != 0) { 763 item.setLink(avp.getValue()); 764 return avp.getValue(); 765 } else if (item.getLink() != null) { 766 return item.getAbsoluteLink(); 767 } 768 769 return alt; 770 } 771 772 public static String getDir(String name) 773 { 774 if (name != null) { 775 File tester = new File(name); 776 if (tester.exists() && tester.isDirectory()) { 777 if (name.endsWith(File.separator)) { 778 return name; 779 } else { 780 return name + File.separator; 781 } 782 } else { 783 throw new RuntimeException("Directory not found: " + name); 784 } 785 } 786 throw new RuntimeException("Missing value for profile attribute" + name); 787 } 788 789 public static ArrayList<String> getDirs(Item item) 790 { 791 ArrayList<String> dirsToAdd = new ArrayList<String>(); 792 String dirListFrameName = item.getAbsoluteLink(); 793 if (dirListFrameName != null) { 794 Frame dirListFrame = FrameIO.LoadFrame(dirListFrameName); 795 if (dirListFrame != null) { 796 for (Text t : dirListFrame.getBodyTextItems(false)) { 797 String dirName = t.getText().trim(); 798 File tester = new File(dirName); 799 if (tester.exists() && tester.isDirectory()) { 800 if (dirName.endsWith(File.separator)) 801 dirsToAdd.add(dirName); 802 else 803 dirsToAdd.add(dirName + File.separator); 804 } 805 } 806 } 807 } 808 809 return dirsToAdd; 810 } 811 812 public static void Parse(Frame toParse) 813 { 814 Parse(toParse, false); 815 } 816 817 /** 818 * Checks for any special Annotation items and updates the display as 819 * necessary. Special Items: Images, overlays, sort. 820 * 821 */ 822 public static void Parse(Frame toParse, boolean firstParse) 823 { 824 Parse(toParse, firstParse, false); 825 } 826 827 /** 828 * 829 * @param toParse 830 * @param firstParse 831 * @param ignoreAnnotations 832 * used to prevent infinate loops such as when performing TDFC 833 * with an ao tag linked to a frame with an frameImage of a frame 834 * which also has an ao tag on it. 835 */ 836 public static void Parse(Frame toParse, boolean firstParse, boolean ignoreAnnotations) 837 { 838 // TODO check why we are getting toParse == null... when profile frame 839 // is being created and change the lines below 840 if (toParse == null) return; 841 842 if (firstParse) ItemUtils.EnclosedCheck(toParse.getItems()); 843 844 List<Item> items = toParse.getItems(); 845 846 // if XRayMode is on, replace pictures with their underlying text 847 if (DisplayController.isXRayMode()) { 848 849 // BROOK: Must handle these a little different 850 List<Widget> widgets = toParse.getInteractiveWidgets(); 851 852 for (Item i : items) { 853 if (i instanceof XRayable) { 854 toParse.removeItem(i); 855 // Show the items 856 for (Item item : ((XRayable) i).getConnected()) { 857 item.setVisible(true); 858 item.removeEnclosure(i); 859 } 860 } else if (i instanceof WidgetCorner) { 861 toParse.removeItem(i); 862 } else if (i instanceof WidgetEdge) { 863 toParse.removeItem(i); 864 } else if (i.hasFormula()) { 865 i.setText(i.getFormula()); 866 } else if (i.hasOverlay()) { 867 i.setVisible(true); 868 // int x = i.getBoundsHeight(); 869 } 870 } 871 872 for (Widget iw : widgets) { 873 toParse.addItem(iw.getSource()); 874 } 875 } 876 877 // Text title = null; 878 // Text template = UserSettingsTemplate.copy(); 879 880 List<Overlay> overlays = new ArrayList<Overlay>(); 881 List<Vector> vectors = new ArrayList<Vector>(); 882 883 // disable reading of cached overlays if in twinframes mode 884 if (DisplayController.isTwinFramesOn()) FrameIO.SuspendCache(); 885 886 DotType pointtype = DotType.square; 887 boolean filledPoints = true; 888 889 UserAppliedPermission permission = toParse.getUserAppliedPermission(); 890 toParse.clearAnnotations(); 891 892 // check for any new overlay items 893 for (Item i : toParse.getItems()) { 894 try { 895 // reset overlay permission 896 i.setOverlayPermission(null); 897 // i.setPermission(permission); 898 if (i instanceof WidgetCorner) { 899 // TODO improve efficiency so it only updates once... using 900 // observer design pattern 901 i.update(); 902 } else if (i instanceof Text) { 903 if (i.isAnnotation()) { 904 if (ItemUtils.startsWithTag(i, ItemUtils.TAG_POINTTYPE)) { 905 Text txt = (Text) i; 906 String line = txt.getFirstLine(); 907 line = ItemUtils.StripTag(line, 908 ItemUtils.GetTag(ItemUtils.TAG_POINTTYPE)); 909 910 if (line != null) { 911 line = line.toLowerCase(); 912 if (line.indexOf(" ") > 0) { 913 String fill = line.substring(line 914 .indexOf(" ") + 1); 915 if (fill.startsWith("nofill")) 916 filledPoints = false; 917 else 918 filledPoints = true; 919 } 920 921 if (line.startsWith("circle")) 922 pointtype = DotType.circle; 923 else 924 pointtype = DotType.square; 925 } 926 }// check for new VECTOR items 927 else if (!DisplayController.isXRayMode() 928 && ItemUtils.startsWithTag(i, 929 ItemUtils.TAG_VECTOR) 930 && i.getLink() != null) { 931 if (!i.getAbsoluteLink().equals(toParse.getName())) 932 addVector(vectors, UserAppliedPermission.none, 933 permission, i); 934 } else if (!DisplayController.isXRayMode() 935 && ItemUtils.startsWithTag(i, 936 ItemUtils.TAG_ACTIVE_VECTOR) 937 && i.getLink() != null) { 938 if (!i.getAbsoluteLink().equals(toParse.getName())) 939 addVector(vectors, 940 UserAppliedPermission.followLinks, 941 permission, i); 942 } 943 // check for new OVERLAY items 944 else if (!ignoreAnnotations && ItemUtils.startsWithTag(i, ItemUtils.TAG_OVERLAY) && i.getLink() != null) { 945 if (i.getAbsoluteLink().equalsIgnoreCase(toParse.getName())) { 946 // This frame contains an active overlay which 947 // points to itself 948 MessageBay.errorMessage(toParse.getName() + " contains an @o which links to itself"); 949 continue; 950 } 951 952 Frame overlayFrame = FrameIO.LoadFrame(i.getAbsoluteLink()); 953 // Parse(overlay); 954 if (overlayFrame != null && Overlay.getOverlay(overlays, overlayFrame) == null) { 955 overlays.add(new Overlay(overlayFrame, UserAppliedPermission.none)); 956 } 957 } 958 // check for ACTIVE_OVERLAY items 959 else if (!ignoreAnnotations 960 && ItemUtils.startsWithTag(i, 961 ItemUtils.TAG_ACTIVE_OVERLAY) 962 && i.getLink() != null) { 963 String link = i.getAbsoluteLink(); 964 if (link.equalsIgnoreCase(toParse.getName())) { 965 // This frame contains an active overlay which 966 // points to itself 967 MessageBay 968 .errorMessage(toParse.getName() 969 + " contains an @ao which links to itself"); 970 continue; 971 } 972 Frame overlayFrame = null; 973 974 Frame current = DisplayController.getCurrentFrame(); 975 if (current != null) { 976 for (Overlay o : current.getOverlays()) { 977 if (o.Frame.getName() 978 .equalsIgnoreCase(link)) 979 overlayFrame = o.Frame; 980 } 981 } 982 if (overlayFrame == null) 983 overlayFrame = FrameIO.LoadFrame(link); 984 985 // get level if specified 986 String level = new AttributeValuePair(i.getText()) 987 .getValue(); 988 // default permission (if none is specified) 989 PermissionPair permissionLevel = new PermissionPair( 990 level, UserAppliedPermission.followLinks); 991 992 if (overlayFrame != null) { 993 Overlay existingOverlay = Overlay.getOverlay( 994 overlays, overlayFrame); 995 // If it wasn't in the list create it and add 996 // it. 997 if (existingOverlay == null) { 998 Overlay newOverlay = new Overlay( 999 overlayFrame, 1000 permissionLevel 1001 .getPermission(overlayFrame 1002 .getOwner())); 1003 i.setOverlay(newOverlay); 1004 overlays.add(newOverlay); 1005 } else { 1006 existingOverlay.Frame 1007 .setPermission(permissionLevel); 1008 } 1009 } 1010 } 1011 // check for Images and widgets 1012 else { 1013 if (!DisplayController.isXRayMode()) { 1014 if (ItemUtils.startsWithTag(i, 1015 ItemUtils.TAG_IMAGE, true)) { 1016 if (!i.hasEnclosures()) { 1017 createPicture(toParse, (Text) i); 1018 } 1019 // check for frame images 1020 } else if (ItemUtils.startsWithTag(i, 1021 ItemUtils.TAG_FRAME_IMAGE) 1022 && i.getLink() != null 1023 && !i.getAbsoluteLink() 1024 .equalsIgnoreCase( 1025 toParse.getName())) { 1026 XRayable image = null; 1027 if (i.hasEnclosures()) { 1028 // i.setHidden(true); 1029 // image = 1030 // i.getEnclosures().iterator().next(); 1031 // image.refresh(); 1032 } else { 1033 image = new FrameImage((Text) i, null); 1034 } 1035 // TODO Add the image when creating new 1036 // FrameImage 1037 toParse.addItem(image); 1038 } else if (ItemUtils.startsWithTag(i, 1039 ItemUtils.TAG_BITMAP_IMAGE) 1040 && i.getLink() != null 1041 && !i.getAbsoluteLink() 1042 .equalsIgnoreCase( 1043 toParse.getName())) { 1044 XRayable image = null; 1045 if (i.hasEnclosures()) { 1046 // image = 1047 // i.getEnclosures().iterator().next(); 1048 // image.refresh(); 1049 // i.setHidden(true); 1050 } else { 1051 // If a new bitmap is created for a 1052 // frame which already has a bitmap dont 1053 // recreate the bitmap 1054 image = new FrameBitmap((Text) i, null); 1055 } 1056 toParse.addItem(image); 1057 } else if (ItemUtils.startsWithTag(i, "@c")) { 1058 // Can only have a @c 1059 if (!i.hasEnclosures() 1060 && i.getLines().size() == 1) { 1061 toParse.addItem(new Circle((Text) i)); 1062 } 1063 // Check for JSItem 1064 } else if(ItemUtils.startsWithTag(i, "@js")) { 1065 toParse.addItem(new JSItem((Text) i)); 1066 // Check for interactive widgets 1067 } else if (ItemUtils.startsWithTag(i, ItemUtils.TAG_IWIDGET)) { 1068 createWidget(toParse, (Text) i); 1069 } 1070 } 1071 // TODO decide exactly what to do here!! 1072 toParse.addAnnotation((Text) i); 1073 } 1074 } else if (!DisplayController.isXRayMode() && i.hasFormula()) { 1075 i.calculate(i.getFormula()); 1076 } 1077 } 1078 } catch (Exception e) { 1079 Logger.Log(e); 1080 e.printStackTrace(); 1081 MessageBay.warningMessage("Exception occured when loading " 1082 + i.getClass().getSimpleName() + "(ID: " + i.getID() 1083 + ") " + e.getMessage() != null ? e.getMessage() : ""); 1084 } 1085 } 1086 1087 /* 1088 * for (Item i : items) { if (i instanceof Dot) { ((Dot) 1089 * i).setPointType(pointtype); ((Dot) i).useFilledPoints(filledPoints); 1090 * } } 1091 */ 1092 1093 FrameIO.ResumeCache(); 1094 1095 toParse.clearOverlays(); 1096 toParse.clearVectors(); 1097 toParse.addAllOverlays(overlays); 1098 toParse.addAllVectors(vectors); 1099 1100 } 1101 1102 /** 1103 * TODO: Comment. cts16 1104 * 1105 * @param vectors 1106 * @param permission 1107 * @param i 1108 */ 1109 private static void addVector(List<Vector> vectors, UserAppliedPermission defaultPermission, UserAppliedPermission framePermission, Item i) 1110 { 1111 // TODO It is possible to get into an infinite loop if a 1112 // frame contains an @ao which leads to a frame with an 1113 // @v which points back to the frame with the @ao 1114 Frame vector = FrameIO.LoadFrame(i.getAbsoluteLink()); 1115 1116 // Get the permission from off the vector frame 1117 UserAppliedPermission vectorPermission = UserAppliedPermission.getPermission(vector.getAnnotationValue("permission"), defaultPermission); 1118 1119 // If the frame permission is lower, use that 1120 vectorPermission = UserAppliedPermission.min(vectorPermission, framePermission); 1121 1122 // Highest permissable permission for vectors is copy 1123 vectorPermission = UserAppliedPermission.min(vectorPermission, UserAppliedPermission.copy); 1124 if (vector != null) { 1125 String scaleString = new AttributeValuePair(i.getText()).getValue(); 1126 Float scale = 1F; 1127 try { 1128 scale = Float.parseFloat(scaleString); 1129 } catch (Exception e) { 1130 } 1131 Vector newVector = new Vector(vector, vectorPermission, scale, i); 1132 i.setOverlay(newVector); 1133 i.setVisible(false); 1134 vectors.add(newVector); 1135 } 1136 } 1137 1138 public static Item onItem(float floatX, float floatY, boolean changeLastEdited) 1139 { 1140 return onItem(DisplayController.getCurrentFrame(), floatX, floatY, changeLastEdited); 1141 } 1142 1143 /** 1144 * Searches through the list of items on this frame to find one at the given 1145 * x,y coordinates. 1146 * 1147 * @param x 1148 * The x coordinate 1149 * @param y 1150 * The y coordinate 1151 * @return The Item at the given coordinates, or NULL if none is found. 1152 */ 1153 public static Item onItem(Frame toCheck, float floatX, float floatY, boolean bResetLastEdited) 1154 { 1155 // System.out.println("MouseX: " + floatX + " MouseY: " + floatY); 1156 int x = Math.round(floatX); 1157 int y = Math.round(floatY); 1158 if (toCheck == null) 1159 return null; 1160 1161 List<Item> possibles = new ArrayList<Item>(0); 1162 1163 // if the mouse is in the message area 1164 if (y >= DisplayController.getMessageBayPaintArea().getMinY()) { 1165 // check the individual message items 1166 for (Item message : MessageBay.getMessages()) { 1167 if (message != null) { 1168 if (message.contains(new Point(x, y))) { 1169 message.setOverlayPermission(UserAppliedPermission.copy); 1170 possibles.add(message); 1171 } else { 1172 // Not sure why but if the line below is removed then 1173 // several items can be highlighted at once 1174 message.setHighlightMode(Item.HighlightMode.None); 1175 message.setHighlightColorToDefault(); 1176 } 1177 } 1178 } 1179 1180 // check the link to the message frame 1181 if (MessageBay.getMessageLink() != null) { 1182 if (MessageBay.getMessageLink().contains(new Point(x, y))) { 1183 MessageBay.getMessageLink().setOverlayPermission(UserAppliedPermission.copy); 1184 possibles.add(MessageBay.getMessageLink()); 1185 } 1186 } 1187 1188 // this is taken into account in contains 1189 // y -= FrameGraphics.getMaxFrameSize().height; 1190 // otherwise, the mouse is on the frame 1191 } else { 1192 if (LastEdited != null) { 1193 if (LastEdited.contains(x, y) 1194 && !FreeItems.getInstance().contains(LastEdited) 1195 && LastEdited.getParent() == DisplayController.getCurrentFrame() 1196 && LastEdited.getParent().getItems().contains(LastEdited)) 1197 { 1198 LastEdited.setOverlayPermission(UserAppliedPermission.full); 1199 return LastEdited; 1200 } else if (bResetLastEdited) { 1201 setLastEdited(null); 1202 } 1203 } 1204 ArrayList<Item> checkList = new ArrayList<Item>(); 1205 checkList.addAll(toCheck.getInteractableItems()); 1206 checkList.add(toCheck.getNameItem()); 1207 1208 for (Item i : checkList) { 1209 1210 // do not check annotation items in audience mode 1211 //TODO: Upon hover of Rubbish Bin, Undo and Restore Widgets, flickering occurs depending on the mouse distance from a corner. Resolve this. 1212 if (i.isVisible() && !(DisplayController.isAudienceMode() && i.isAnnotation())) { 1213 if (i instanceof WidgetCorner) { 1214 WidgetCorner wc = (WidgetCorner) i; 1215 if (wc.getWidgetSource() instanceof ButtonWidget) { 1216 ButtonWidget bw = (ButtonWidget) wc.getWidgetSource(); 1217 1218 if (bw.getdropInteractableStatus() == true) { 1219 Widget iw = wc.getWidgetSource(); 1220 1221 if(iw.getBounds().contains(x, y)){ 1222 1223 if( !FreeItems.getInstance().contains(i)) 1224 { 1225 possibles.add(i); 1226 } 1227 } 1228 } 1229 } 1230 } 1231 1232 if (i.contains(new Point(x, y))){ 1233 if(!FreeItems.getInstance().contains(i)) { 1234 possibles.add(i); 1235 } 1236 } 1237 1238 } 1239 } 1240 } 1241 1242 // if there are no possible items, return null 1243 if (possibles.size() == 0) 1244 return null; 1245 1246 // if there is only one possibility, return it 1247 if (possibles.size() == 1) 1248 return possibles.get(0); 1249 1250 // return closest x,y pair to mouse 1251 Item closest = possibles.get(0); 1252 int distance = (int) Math.round(Math.sqrt(Math.pow( 1253 Math.abs(closest.getX() - x), 2) 1254 + Math.pow(Math.abs(closest.getY() - y), 2))); 1255 1256 for (Item i : possibles) { 1257 int d = (int) Math.round(Math.sqrt(Math.pow(Math.abs(i.getX() - x), 1258 2) + Math.pow(Math.abs(i.getY() - y), 2))); 1259 1260 // System.out.println(d); 1261 if (d <= distance) { 1262 distance = d; 1263 1264 // dots take precedence over lines 1265 if ((!(closest instanceof Dot && i instanceof Line)) 1266 && (!(closest instanceof Text && i instanceof Line))) 1267 closest = i; 1268 1269 } 1270 1271 } 1272 1273 return closest; 1274 } 428 1275 429 // check for an updated template... 430 for (Item i : frame.getAnnotationItems()) { 431 432 if (ItemUtils.startsWithTag(i, annotationStr)) { 433 434 matched_item = i; 435 break; 436 } 437 } 438 439 return matched_item; 440 } 441 442 protected static void doFrameTransition(Item frameTransition, Frame from, Frame to) 443 { 444 String s = frameTransition.getText(); 445 String[] s_array = s.split(":"); 446 if(s_array.length > 1){ 447 String slide_mode_method = s_array[1].trim(); 448 449 FrameTransitions.setSlideModeMethod(slide_mode_method); 450 System.out.println("Triggered on annotation: " + s); 451 FrameTransitions.setSlideTrue(); 452 FrameTransitions.setSlideModeBaseImage(FrameGraphics.getBuffer(from, false, false)); 453 } 454 else { 455 System.err.println("Warning: failed to detect frameTransition type"); 456 // TODO: print list as a result of reflection listing 457 } 458 } 459 460 /** 461 * Displays the given Frame on the display. If the current frame has changed 462 * since the last save then it will be saved before the switch is made. The 463 * caller can also dictate whether the current frame is added to the 464 * back-stack or not. 465 * 466 * @param toDisplay 467 * The Frame to display on the screen 468 * @param addToBack 469 * True if the current Frame should be added to the back-stack, 470 * False otherwise 471 */ 472 public static void DisplayFrame(Frame toDisplay, boolean addToBack, 473 boolean incrementStats) { 474 if (toDisplay == null) 475 return; 476 477 Frame current = DisplayIO.getCurrentFrame(); 478 479 // Dont need to do anything if the frame to display is already being 480 // displayed 481 if (current.equals(toDisplay)) 482 return; 483 484 // move any anchored connected items 485 if (FreeItems.itemsAttachedToCursor()) { 486 List<Item> toAdd = new ArrayList<Item>(); 487 List<Item> toCheck = new ArrayList<Item>(FreeItems.getInstance()); 488 489 while (toCheck.size() > 0) { 490 Item i = toCheck.get(0); 491 Collection<Item> connected = i.getAllConnected(); 492 493 // // Only move completely enclosed items 494 // if (!toCheck.containsAll(connected)) { 495 // connected.retainAll(FreeItems.getInstance()); 496 // FreeItems.getInstance().removeAll(connected); 497 // toCheck.removeAll(connected); 498 // FrameMouseActions.anchor(connected); 499 // } else { 500 // toCheck.removeAll(connected); 501 // } 502 503 // Anchor overlay items where they belong 504 if (i.getParent() != null && i.getParent() != current) { 505 FreeItems.getInstance().removeAll(connected); 506 toCheck.removeAll(connected); 507 FrameMouseActions.anchor(connected); 1276 /** 1277 * Checks if the mouse is currently over an item. 1278 * 1279 * @return 1280 * True if the mouse is over any item, false otherwise. 1281 */ 1282 public static boolean hasCurrentItem() 1283 { 1284 return getCurrentItem() != null; 1285 } 1286 1287 public synchronized static Item getCurrentItem() 1288 { 1289 return onItem(DisplayController.getCurrentFrame(), DisplayController.getMouseX(), DisplayController.getMouseY(), true); 1290 } 1291 1292 public static PolygonBounds getEnlosingPolygon() 1293 { 1294 Collection<Item> enclosure = getEnclosingLineEnds(); 1295 1296 if (enclosure == null || enclosure.size() == 0) return null; 1297 1298 return enclosure.iterator().next().getEnclosedShape(); 1299 } 1300 1301 /** 1302 * 1303 * @param currentItem 1304 * @return 1305 */ 1306 public static Collection<Item> getCurrentItems() 1307 { 1308 return getCurrentItems(getCurrentItem()); 1309 } 1310 1311 public static Collection<Item> getCurrentItems(Item currentItem) 1312 { 1313 Collection<Item> enclosure = getEnclosingLineEnds(); 1314 1315 if (enclosure == null || enclosure.size() == 0) return null; 1316 1317 Item firstItem = enclosure.iterator().next(); 1318 1319 Collection<Item> enclosed = getItemsEnclosedBy(DisplayController.getCurrentFrame(), firstItem.getEnclosedShape()); 1320 1321 // Brook: enclosed widgets are to be fully enclosed, never partially 1322 /* 1323 * MIKE says: but doesn't this mean that widgets are treated differently 1324 * from ALL other object which only need to be partially enclosed to be 1325 * picked up 1326 */ 1327 List<Widget> enclosedWidgets = new LinkedList<Widget>(); 1328 for (Item i : enclosed) { 1329 // Don't want to lose the highlighting from the current item 1330 if (i == currentItem || enclosure.contains(i)) { 1331 continue; 1332 } 1333 // Don't want to lose the highlighting of connected Dots 1334 // TODO: this code does nothing (perhaps the continue is meant for the outer 1335 // for loop?). cts16 1336 if (i instanceof Dot && i.getHighlightMode() == HighlightMode.Connected) { 1337 for (Line l : i.getLines()) { 1338 if (l.getOppositeEnd(i).getHighlightMode() == HighlightMode.Normal) { 1339 continue; 1340 } 1341 } 1342 } 1343 1344 if (i instanceof WidgetCorner) { 1345 if (!enclosedWidgets.contains(((WidgetCorner) i).getWidgetSource())) { 1346 enclosedWidgets.add(((WidgetCorner) i).getWidgetSource()); 1347 } 1348 } 1349 1350 i.setHighlightMode(Item.HighlightMode.None); 1351 i.setHighlightColorToDefault(); 1352 } 1353 1354 for (Widget iw : enclosedWidgets) { 1355 for (Item i : iw.getItems()) { 1356 if (!enclosed.contains(i)) { 1357 enclosed.add(i); 1358 } 1359 } 1360 } 1361 1362 return enclosed; 1363 } 1364 1365 /** 1366 * Gets the collection of Dot items that form the enclosure nearest to the current mouse position. 1367 */ 1368 public static Collection<Item> getEnclosingLineEnds() 1369 { 1370 return getEnclosingLineEnds(new Point(DisplayController.getMouseX(), DisplayController.getMouseY())); 1371 } 1372 1373 /** 1374 * Gets the collection of Dot items that form the enclosure nearest to the given position. 1375 */ 1376 public static Collection<Item> getEnclosingLineEnds(Point position) 1377 { 1378 // update enclosed shapes 1379 Frame current = DisplayController.getCurrentFrame(); 1380 if (current == null) return null; 1381 List<Item> items = current.getItems(); 1382 1383 // Remove all items that are connected to freeItems 1384 List<Item> freeItems = new ArrayList<Item>(FreeItems.getInstance()); 1385 while (freeItems.size() > 0) { 1386 Item item = freeItems.get(0); 1387 Collection<Item> connected = item.getAllConnected(); 1388 items.removeAll(connected); 1389 freeItems.removeAll(connected); 1390 } 1391 1392 List<Item> used = new ArrayList<Item>(0); 1393 1394 while (items.size() > 0) { 1395 Item i = items.get(0); 1396 items.remove(i); 1397 if (i.isEnclosed()) { 1398 PolygonBounds p = i.getEnclosedShape(); 1399 if (p.contains(position)) { 1400 used.add(i); 1401 items.removeAll(i.getEnclosingDots()); 1402 } 1403 } 1404 } 1405 1406 if (used.size() == 0) return null; 1407 1408 // if there is only one possibility, return it 1409 if (used.size() == 1) { 1410 return used.get(0).getEnclosingDots(); 1411 // otherwise, determine which polygon is closest to the cursor 508 1412 } else { 509 // Add stuff that is partially enclosed 510 // remove all the connected items from our list to check 511 toCheck.removeAll(connected); 512 // Dont add the items that are free 513 connected.removeAll(FreeItems.getInstance()); 514 toAdd.addAll(connected); 515 } 516 } 517 518 current.removeAllItems(toAdd); 519 520 boolean oldChange = toDisplay.hasChanged(); 521 toDisplay.updateIDs(toAdd); 522 toDisplay.addAllItems(toAdd); 523 toDisplay.setChanged(oldChange); 524 } 525 526 if (addToBack && current != toDisplay) { 527 FrameIO.checkTDFC(current); 528 } 529 530 // if the saving happened properly, we can continue 531 if (!LeavingFrame(current)) { 532 MessageBay.displayMessage("Navigation cancelled"); 533 return; 534 } 535 536 if (addToBack && current != toDisplay) { 537 DisplayIO.addToBack(current); 538 } 539 540 Parse(toDisplay); 541 542 if (FrameGraphics.isAudienceMode()) { 543 // Only need to worry about frame transitions when in Audience Mode 1413 Collections.sort(used, new Comparator<Item>() { 1414 public int compare(Item d1, Item d2) { 1415 PolygonBounds p1 = d1.getEnclosedShape(); 1416 PolygonBounds p2 = d2.getEnclosedShape(); 1417 1418 int closest = Integer.MAX_VALUE; 1419 int close2 = Integer.MAX_VALUE; 1420 1421 int mouseX = DisplayController.getMouseX(); 1422 int mouseY = DisplayController.getMouseY(); 1423 1424 for (int i = 0; i < p1.getPointCount(); i++) { 1425 int diff = Math.abs(p1.getPoint(i).x - mouseX) + Math.abs(p1.getPoint(i).y - mouseY); 1426 int diff2 = Integer.MAX_VALUE; 1427 1428 if (i < p2.getPointCount()) 1429 diff2 = Math.abs(p2.getPoint(i).x - mouseX) + Math.abs(p2.getPoint(i).y - mouseY); 1430 1431 if (diff < Math.abs(closest)) { 1432 close2 = closest; 1433 closest = diff; 1434 } else if (diff < Math.abs(close2)) 1435 close2 = diff; 1436 1437 if (diff2 < Math.abs(closest)) { 1438 close2 = closest; 1439 closest = -diff2; 1440 } else if (diff2 < Math.abs(close2)) 1441 close2 = diff2; 1442 } 1443 1444 if (closest > 0 && close2 > 0) 1445 return -10; 1446 1447 if (closest < 0 && close2 < 0) 1448 return 10; 1449 1450 if (closest > 0) 1451 return -10; 1452 1453 return 10; 1454 } 1455 1456 }); 1457 1458 return used.get(0).getEnclosingDots(); 1459 } 1460 } 1461 1462 // TODO Remove this method!! 1463 // Can just getItemsWithin be used? 1464 public static Collection<Item> getItemsEnclosedBy(Frame frame, PolygonBounds poly) 1465 { 1466 Collection<Item> contained = frame.getItemsWithin(poly); 1467 1468 Collection<Item> results = new LinkedHashSet<Item>(contained.size()); 1469 1470 // check for correct permissions 1471 for (Item item : contained) { 1472 // if the item is on the frame 1473 if (item.getParent() == frame || item.getParent() == null) { 1474 // item.Permission = Permission.full; 1475 results.add(item); 1476 // otherwise, it must be on an overlay frame 1477 } else { 1478 for (Overlay overlay : frame.getOverlays()) { 1479 if (overlay.Frame == item.getParent()) { 1480 item.setOverlayPermission(overlay.permission); 1481 results.add(item); 1482 break; 1483 } 1484 } 1485 } 1486 } 1487 1488 return results; 1489 } 1490 1491 /** 1492 * Fills the given Frame with default profile tags 1493 */ 1494 public static void CreateDefaultProfile(String username, Frame profile) 1495 { 1496 Text title = profile.getTitleItem(); 1497 if (username.equals(UserSettings.DEFAULT_PROFILE_NAME)) { 1498 title.setText("Default Profile Frame"); 1499 } else { 1500 // if this profile is not the default profile, copy it from the default profile instead of generating a new profile 1501 // (this allows the possibility of modifying the default profile and having any new profiles get those modifications) 1502 Frame nextDefault = FrameIO.LoadProfile(UserSettings.DEFAULT_PROFILE_NAME); 1503 if (nextDefault == null) { 1504 try { 1505 nextDefault = FrameIO.CreateNewProfile(UserSettings.DEFAULT_PROFILE_NAME); 1506 } catch (Exception e) { 1507 // TODO tell the user that there was a problem creating the 1508 // profile frame and close nicely 1509 e.printStackTrace(); 1510 } 1511 } 1512 // load profile frame and set title correctly 1513 profile.reset(); 1514 profile.removeAllItems(profile.getAllItems()); 1515 // set relative link on all items so their links will correctly point to the page on the current profile rather than on the default profile 1516 for(Item i : nextDefault.getAllItems()) { 1517 i.setRelativeLink(); 1518 } 1519 profile.addAllItems(ItemUtils.CopyItems(nextDefault.getAllItems())); 1520 profile.setTitle(username + "'s Profile Frame"); 1521 FrameIO.SaveFrame(profile); 1522 1523 Frame nextProfile = profile; 1524 MessageBay.suppressMessages(true); 1525 while((nextDefault = FrameIO.LoadNext(nextDefault)) != null) { 1526 // in case there are gaps in the frame numbering of the default profile (e.g. if a user has edited it), 1527 // we need to replicate those gaps in the copied profile so the links will work correctly 1528 while(nextProfile.getNumber() < nextDefault.getNumber()) { 1529 nextProfile = FrameIO.CreateFrame(profile.getFramesetName(), null, null); 1530 } 1531 // if the new profile has a frame number higher than the current frame number in the default profile, 1532 // the new profile must already exist, so just exit 1533 // (TODO: should we wipe the frames instead?) 1534 if(nextProfile.getNumber() > nextDefault.getNumber()) { 1535 break; 1536 } 1537 nextProfile.reset(); 1538 nextProfile.removeAllItems(nextProfile.getAllItems()); 1539 // set relative link on all items so their links will correctly point to the page on the current profile rather than on the default profile 1540 for(Item i : nextDefault.getAllItems()) { 1541 i.setRelativeLink(); 1542 } 1543 nextProfile.addAllItems(ItemUtils.CopyItems(nextDefault.getAllItems())); 1544 FrameIO.SaveFrame(nextProfile); 1545 } 1546 MessageBay.suppressMessages(false); 1547 1548 return; 1549 } 1550 1551 // int spacing = 50; 1552 final int intialYPos = 75; 1553 int xPos = 75; 1554 int yPos = intialYPos; 1555 1556 // yPos += spacing; 1557 // profile.addText(xPos, yPos, "@HomeFrame", null, profile.getName()); 1558 // yPos += spacing; 1559 // String defaultFrameName = profile.getFramesetName() + "0"; 1560 // profile.addText(xPos, yPos, "@DefaultFrame", null, defaultFrameName); 1561 // yPos += spacing; 1562 // 1563 // profile.addText(xPos, yPos, "@InitialWidth: " 1564 // + UserSettings.InitialWidth, null); 1565 // yPos += spacing; 1566 // 1567 // profile.addText(xPos, yPos, "@InitialHeight: " 1568 // + UserSettings.InitialHeight, null); 1569 // yPos += spacing; 1570 // 1571 // Text t = profile.addText(xPos, yPos, "@ItemTemplate", null); 1572 // t.setColor(null); 1573 // 1574 // yPos += spacing; 1575 // t = profile.addText(xPos, yPos, "@AnnotationTemplate", null); 1576 // t.setColor(Color.gray); 1577 // 1578 // yPos += spacing; 1579 // t = profile.addText(xPos, yPos, "@CommentTemplate", null); 1580 // t.setColor(Color.green.darker()); 1581 // 1582 // yPos += spacing; 1583 // t = profile.addText(xPos, yPos, "@StatsTemplate", null); 1584 // t.setColor(Color.BLACK); 1585 // t.setBackgroundColor(new Color(0.9F, 0.9F, 0.9F)); 1586 // t.setFamily(Text.MONOSPACED_FONT); 1587 // t.setSize(14); 1588 1589 Text t; 1590 1591 xPos = 300; 1592 // yPos = intialYPos + spacing; 1593 yPos = 100; 1594 1595 // Add documentation links 1596 File helpDirectory = new File(FrameIO.HELP_PATH); 1597 if (helpDirectory != null) { 1598 File[] helpFramesets = helpDirectory.listFiles(); 1599 if (helpFramesets != null) { 1600 1601 // Add the title for the help index 1602 Text help = profile.addText(xPos, yPos, "@Expeditee Help", null); 1603 help.setSize(25); 1604 help.setFontStyle("Bold"); 1605 help.setFamily("SansSerif"); 1606 help.setColor(TemplateSettings.ColorWheel.get()[3]); 1607 1608 xPos += 25; 1609 System.out.println("Installing frameset: "); 1610 1611 boolean first_item = true; 1612 1613 for (File helpFrameset : helpFramesets) { 1614 String framesetName = helpFrameset.getName(); 1615 if (!FrameIO.isValidFramesetName(framesetName)) { 1616 continue; 1617 } 1618 1619 if (first_item) { 1620 System.out.print(" " + framesetName); 1621 first_item = false; 1622 } 1623 else { 1624 System.out.print(", " + framesetName); 1625 } 1626 System.out.flush(); 1627 1628 Frame indexFrame = FrameIO.LoadFrame(framesetName + '1'); 1629 // Look through the folder for help index pages 1630 if (indexFrame != null 1631 && ItemUtils.FindTag(indexFrame.getItems(), 1632 "@HelpIndex") != null) { 1633 // yPos += spacing; 1634 yPos += 30; 1635 t = profile.addText(xPos, yPos, 1636 '@' + indexFrame.getFramesetName(), null); 1637 t.setLink(indexFrame.getName()); 1638 t.setColor(Colour.GREY); 1639 } 1640 } 1641 System.out.println(); 1642 } 1643 } 1644 1645 xPos = 50; 1646 yPos = 100; 1647 1648 // Populate Start Pages and Settings 1649 File framesetDirectory = new File(FrameIO.FRAME_PATH); 1650 1651 if (framesetDirectory.exists()) { 1652 File[] startpagesFramesets = framesetDirectory.listFiles(); 1653 1654 if (startpagesFramesets != null) { 1655 // Add Start Page title 1656 Text templates = profile.addText(xPos, yPos, "@Start Pages", 1657 null); 1658 templates.setSize(25); 1659 templates.setFontStyle("Bold"); 1660 templates.setFamily("SansSerif"); 1661 templates.setColor(TemplateSettings.ColorWheel.get()[3]); 1662 1663 xPos += 25; 1664 1665 // Start Pages should be the first frame in its own frameset + 1666 // frameset name should be present in FrameUtils.startPages[]. 1667 for (File startpagesFrameset : startpagesFramesets) { 1668 String framesetName = startpagesFrameset.getName(); 1669 1670 // Only add link if frameset is a startpage 1671 for (int i = 0; i < startPages.length; i++) { 1672 if (framesetName.equals(startPages[i])) { 1673 Frame indexFrame = FrameIO 1674 .LoadFrame(framesetName + '1'); 1675 1676 // Add start page link 1677 if (indexFrame != null) { 1678 yPos += 30; 1679 t = profile.addText(xPos, yPos, 1680 '@' + indexFrame.getFramesetName(), 1681 null); 1682 t.setLink(indexFrame.getName()); 1683 t.setColor(Colour.GREY); 1684 } 1685 } 1686 } 1687 } 1688 } 1689 } 1690 1691 FrameIO.SaveFrame(profile); 1692 1693 // Populate settings frameset 1694 Settings.Init(); 1695 t = profile.addText(550, 100, "@Settings", null); 1696 t.setSize((float) 25.0); 1697 t.setFamily("SansSerif"); 1698 t.setFontStyle("Bold"); 1699 t.setColor(Colour.GREY); 1700 Settings.generateSettingsTree(t); 1701 1702 FrameIO.SaveFrame(profile); 1703 } 1704 1705 private static void checkTDFCItemWaiting(Frame currentFrame) 1706 { 1707 Item tdfcItem = FrameUtils.getTdfcItem(); 1708 // if there is a TDFC Item waiting 1709 if (tdfcItem != null) { 1710 boolean change = currentFrame.hasChanged(); 1711 boolean saved = currentFrame.isSaved(); 1712 // Save the parent of the item if it has not been saved 1713 if (!change && !saved) { 1714 tdfcItem.setLink(null); 1715 tdfcItem.getParent().setChanged(true); 1716 FrameIO.SaveFrame(tdfcItem.getParent()); 1717 DisplayController.requestRefresh(true); 1718 } else { 1719 SessionStats.CreatedFrame(); 1720 } 1721 1722 setTdfcItem(null); 1723 } 1724 } 1725 1726 public static void setTdfcItem(Item _tdfcItem) 1727 { 1728 FrameUtils._tdfcItem = _tdfcItem; 1729 } 1730 1731 public static Item getTdfcItem() 1732 { 1733 return FrameUtils._tdfcItem; 1734 } 1735 1736 public static void setLastEdited(Text lastEdited) 1737 { 1738 // If the lastEdited is being changed then check if its @i 1739 Frame toReparse = null; 1740 Frame toRecalculate = null; 1741 Frame toUpdateObservers = null; 1742 1743 if (LastEdited == null) { 1744 // System.out.print("N"); 1745 } else if (LastEdited != null) { 1746 // System.out.print("T"); 1747 Frame parent = LastEdited.getParentOrCurrentFrame(); 1748 1749 if (lastEdited != LastEdited) { 1750 if (LastEdited.startsWith("@i")) { 1751 // Check if its an image that can be resized to fit a box 1752 // around it 1753 String text = LastEdited.getText(); 1754 if (text.startsWith("@i:") 1755 && !Character 1756 .isDigit(text.charAt(text.length() - 1))) { 1757 Collection<Item> enclosure = FrameUtils 1758 .getEnclosingLineEnds(LastEdited.getPosition()); 1759 if (enclosure != null) { 1760 for (Item i : enclosure) { 1761 if (i.isLineEnd() && i.isEnclosed()) { 1762 DisplayController.getCurrentFrame().removeAllItems( 1763 enclosure); 1764 AxisAlignedBoxBounds rect = i.getEnclosedBox(); 1765 LastEdited 1766 .setText(LastEdited.getText() 1767 + " " 1768 + Math.round(rect 1769 .getWidth())); 1770 LastEdited.setPosition(rect.getTopLeft()); 1771 LastEdited.setThickness(i.getThickness()); 1772 LastEdited.setBorderColor(i.getColor()); 1773 break; 1774 } 1775 } 1776 StandardGestureActions.deleteItems(enclosure, false); 1777 } 1778 } 1779 toReparse = parent; 1780 } else if (LastEdited.recalculateWhenChanged()) { 1781 toRecalculate = parent; 1782 } 1783 1784 if (parent.hasObservers()) { 1785 toUpdateObservers = parent; 1786 } 1787 // Update the formula if in XRay mode 1788 if (DisplayController.isXRayMode() && LastEdited.hasFormula()) { 1789 LastEdited.setFormula(LastEdited.getText()); 1790 } 1791 } 1792 if (lastEdited != LastEdited && LastEdited.getText().length() == 0) { 1793 parent.removeItem(LastEdited); 1794 } 1795 } 1796 LastEdited = lastEdited; 1797 1798 if (!DisplayController.isXRayMode()) { 1799 if (toReparse != null) { 1800 Parse(toReparse, false, false); 1801 } else { 1802 if (toRecalculate != null) { 1803 toRecalculate.recalculate(); 1804 } 1805 1806 if (toUpdateObservers != null) { 1807 toUpdateObservers.notifyObservers(false); 1808 } 1809 } 1810 } 1811 } 1812 1813 /** 1814 * Extracts files/folders from the assets/resources folder directly into 1815 * ${PARENT_FOLDER} (~/.expeditee) 1816 * 1817 * @param force if true, resources will be extracted even if they have already been extracted before 1818 */ 1819 public static void extractResources(boolean force) 1820 { 1821 File check = new File(FrameIO.PARENT_FOLDER + ".res"); 544 1822 545 // Test to see if frame transition specified through annotation, and perform it if one if found 546 Item frameTransition = getAnnotation(toDisplay, "@frameTransition"); 547 if (frameTransition != null) { 548 doFrameTransition(frameTransition,current,toDisplay); 549 } 550 } 551 552 DisplayIO.setCurrentFrame(toDisplay, incrementStats); 553 FrameMouseActions.updateCursor(); 554 // FrameMouseActions.getInstance().refreshHighlights(); 555 // update response timer 556 _LastResponse = ResponseTimer.getElapsedSeconds(); 557 _ResponseTimeSum += _LastResponse; 558 DisplayIO.UpdateTitle(); 559 } 560 561 /** 562 * Loads and displays the Frame with the given framename, and adds the 563 * current frame to the back-stack if required. 564 * 565 * @param framename 566 * The name of the Frame to load and display 567 * @param addToBack 568 * True if the current Frame should be added to the back-stack, 569 * false otherwise 570 */ 571 public static void DisplayFrame(String frameName, boolean addToBack, 572 boolean incrementStats) { 573 Frame newFrame = getFrame(frameName); 574 575 if (newFrame != null) 576 // display the frame 577 DisplayFrame(newFrame, addToBack, incrementStats); 578 } 579 580 /** 581 * Loads and displays the Frame with the given framename and adds the 582 * current frame to the back-stack. This is the same as calling 583 * DisplayFrame(framename, true) 584 * 585 * @param framename 586 * The name of the Frame to load and display 587 */ 588 public static void DisplayFrame(String framename) { 589 DisplayFrame(framename, true, true); 590 } 591 592 public static Frame getFrame(String frameName) { 593 // if the new frame does not exist then tell the user 594 Frame f = FrameIO.LoadFrame(frameName); 595 596 if (f == null) { 597 MessageBay.errorMessage("Frame '" + frameName 598 + "' could not be found."); 599 } 600 601 return f; 602 } 603 604 /** 605 * Creates a new Picture Item from the given Text source Item and adds it to 606 * the given Frame. 607 * 608 * @return True if the image was created successfully, false otherwise 609 */ 610 private static boolean createPicture(Frame frame, Text txt) { 611 // attempt to create the picture 612 Picture pic = ItemUtils.CreatePicture(txt, frame); 613 614 // if the picture could not be created successfully 615 if (pic == null) { 616 String imagePath = txt.getText(); 617 assert (imagePath != null); 618 imagePath = new AttributeValuePair(imagePath).getValue().trim(); 619 if (imagePath.length() == 0) { 620 return false; 621 // MessageBay.errorMessage("Expected image path after @i:"); 622 } else { 623 MessageBay.errorMessage("Image " + imagePath 624 + " could not be loaded"); 625 } 626 return false; 627 } 628 frame.addItem(pic); 629 630 return true; 631 } 632 633 /** 634 * Creates an interactive widget and adds it to a frame. If txt has no 635 * parent the parent will be set to frame. 636 * 637 * @param frame 638 * Frame to add widget to. Must not be null. 639 * 640 * @param txt 641 * Text to create the widget from. Must not be null. 642 * 643 * @return True if created/added. False if coul not create. 644 * 645 * @author Brook Novak 646 */ 647 private static boolean createWidget(Frame frame, Text txt) { 648 649 if (frame == null) 650 throw new NullPointerException("frame"); 651 if (txt == null) 652 throw new NullPointerException("txt"); 653 654 // Safety 655 if (txt.getParent() == null) 656 txt.setParent(frame); 657 658 InteractiveWidget iw = null; 659 660 try { 661 662 iw = InteractiveWidget.createWidget(txt); 663 664 } catch (InteractiveWidgetNotAvailableException e) { 665 e.printStackTrace(); 666 MessageBay.errorMessage("Cannot create iWidget: " + e.getMessage()); 667 } catch (InteractiveWidgetInitialisationFailedException e) { 668 e.printStackTrace(); 669 MessageBay.errorMessage("Cannot create iWidget: " + e.getMessage()); 670 } catch (IllegalArgumentException e) { 671 e.printStackTrace(); 672 MessageBay.errorMessage("Cannot create iWidget: " + e.getMessage()); 673 } 674 675 if (iw == null) 676 return false; 677 678 frame.removeItem(txt); 679 680 frame.addAllItems(iw.getItems()); 681 682 return true; 683 } 684 685 public static Collection<String> ParseProfile(Frame profile) { 686 Collection<String> errors = new LinkedList<String>(); 687 if (profile == null) 688 return errors; 689 690 /* 691 * Make sure the correct cursor shows when turning off the custom cursor 692 * and reparsing the profile frame 693 */ 694 FreeItems.getCursor().clear(); 695 DisplayIO.setCursor(Item.HIDDEN_CURSOR); 696 DisplayIO.setCursor(Item.DEFAULT_CURSOR); 697 698 // check for settings tags 699 for (Text item : profile.getBodyTextItems(true)) { 700 try { 701 702 AttributeValuePair avp = new AttributeValuePair(item.getText()); 703 String attributeFullCase = avp.getAttributeOrValue(); 704 705 if (attributeFullCase == null) { 706 continue; 707 } 708 String attribute = attributeFullCase.trim().toLowerCase() 709 .replaceAll("^@", ""); 710 711 if (attribute.equals("settings")) { 712 Settings.parseSettings(item); 713 } 714 715 } catch (Exception e) { 716 if (e.getMessage() != null) { 717 errors.add(e.getMessage()); 718 } else { 719 e.printStackTrace(); 720 errors.add("Error parsing [" + item.getText() + "] on " 721 + profile.getName()); 722 } 723 } 724 } 725 726 return errors; 727 } 728 729 /** 730 * Sets the first frame to be displayed. 731 * 732 * @param profile 733 */ 734 public static void loadFirstFrame(Frame profile) { 735 if (UserSettings.HomeFrame.get() == null) 736 UserSettings.HomeFrame.set(profile.getName()); 737 738 Frame firstFrame = FrameIO.LoadFrame(UserSettings.HomeFrame.get()); 739 if (firstFrame == null) { 740 MessageBay.warningMessage("Home frame not found: " 741 + UserSettings.HomeFrame); 742 UserSettings.HomeFrame.set(profile.getName()); 743 DisplayIO.setCurrentFrame(profile, true); 744 } else { 745 DisplayIO.setCurrentFrame(firstFrame, true); 746 } 747 748 } 749 750 public static Color[] getColorWheel(Frame frame) { 751 if (frame != null) { 752 List<Text> textItems = frame.getBodyTextItems(false); 753 Color[] colorList = new Color[textItems.size() + 1]; 754 for (int i = 0; i < textItems.size(); i++) { 755 colorList[i] = textItems.get(i).getColor(); 756 } 757 // Make the last item transparency or default for forecolor 758 colorList[colorList.length - 1] = null; 759 760 return colorList; 761 } 762 return new Color[] { Color.black, Color.white, null }; 763 } 764 765 public static String getLink(Item item, String alt) { 766 if (item == null || !(item instanceof Text)) 767 return alt; 768 769 AttributeValuePair avp = new AttributeValuePair(item.getText()); 770 assert (avp != null); 771 772 if (avp.hasPair() && avp.getValue().trim().length() != 0) { 773 item.setLink(avp.getValue()); 774 return avp.getValue(); 775 } else if (item.getLink() != null) { 776 return item.getAbsoluteLink(); 777 } 778 779 return alt; 780 } 781 782 public static String getDir(String name) { 783 if (name != null) { 784 File tester = new File(name); 785 if (tester.exists() && tester.isDirectory()) { 786 if (name.endsWith(File.separator)) 787 return name; 788 else 789 return name + File.separator; 790 } else { 791 throw new RuntimeException("Directory not found: " + name); 792 } 793 } 794 throw new RuntimeException("Missing value for profile attribute" + name); 795 } 796 797 public static ArrayList<String> getDirs(Item item) { 798 ArrayList<String> dirsToAdd = new ArrayList<String>(); 799 String dirListFrameName = item.getAbsoluteLink(); 800 if (dirListFrameName != null) { 801 Frame dirListFrame = FrameIO.LoadFrame(dirListFrameName); 802 if (dirListFrame != null) { 803 for (Text t : dirListFrame.getBodyTextItems(false)) { 804 String dirName = t.getText().trim(); 805 File tester = new File(dirName); 806 if (tester.exists() && tester.isDirectory()) { 807 if (dirName.endsWith(File.separator)) 808 dirsToAdd.add(dirName); 809 else 810 dirsToAdd.add(dirName + File.separator); 811 } 812 } 813 } 814 } 815 816 return dirsToAdd; 817 } 818 819 public static void Parse(Frame toParse) { 820 Parse(toParse, false); 821 } 822 823 /** 824 * Checks for any special Annotation items and updates the display as 825 * necessary. Special Items: Images, overlays, sort. 826 * 827 */ 828 public static void Parse(Frame toParse, boolean firstParse) { 829 Parse(toParse, firstParse, false); 830 } 831 832 /** 833 * 834 * @param toParse 835 * @param firstParse 836 * @param ignoreAnnotations 837 * used to prevent infinate loops such as when performing TDFC 838 * with an ao tag linked to a frame with an frameImage of a frame 839 * which also has an ao tag on it. 840 */ 841 public static void Parse(Frame toParse, boolean firstParse, 842 boolean ignoreAnnotations) { 843 // TODO check why we are getting toParse == null... when profile frame 844 // is being created and change the lines below 845 if (toParse == null) 846 return; 847 // System.out.println(firstParse); 848 if (firstParse) 849 ItemUtils.EnclosedCheck(toParse.getItems()); 850 List<Item> items = toParse.getItems(); 851 852 // if XRayMode is on, replace pictures with their underlying text 853 if (FrameGraphics.isXRayMode()) { 854 855 // BROOK: Must handle these a little different 856 List<InteractiveWidget> widgets = toParse.getInteractiveWidgets(); 857 858 for (Item i : items) { 859 if (i instanceof XRayable) { 860 toParse.removeItem(i); 861 // Show the items 862 for (Item item : ((XRayable) i).getConnected()) { 863 item.setVisible(true); 864 item.removeEnclosure(i); 865 } 866 } else if (i instanceof WidgetCorner) { 867 toParse.removeItem(i); 868 } else if (i instanceof WidgetEdge) { 869 toParse.removeItem(i); 870 } else if (i.hasFormula()) { 871 i.setText(i.getFormula()); 872 } else if (i.hasOverlay()) { 873 i.setVisible(true); 874 // int x = i.getBoundsHeight(); 875 } 876 } 877 878 for (InteractiveWidget iw : widgets) { 879 toParse.addItem(iw.getSource()); 880 } 881 } 882 883 // Text title = null; 884 // Text template = UserSettingsTemplate.copy(); 885 886 List<Overlay> overlays = new ArrayList<Overlay>(); 887 List<Vector> vectors = new ArrayList<Vector>(); 888 889 // disable reading of cached overlays if in twinframes mode 890 if (DisplayIO.isTwinFramesOn()) 891 FrameIO.SuspendCache(); 892 893 DotType pointtype = DotType.square; 894 boolean filledPoints = true; 895 896 UserAppliedPermission permission = toParse.getUserAppliedPermission(); 897 toParse.clearAnnotations(); 898 899 // check for any new overlay items 900 for (Item i : toParse.getItems()) { 901 try { 902 // reset overlay permission 903 i.setOverlayPermission(null); 904 // i.setPermission(permission); 905 if (i instanceof WidgetCorner) { 906 // TODO improve efficiency so it only updates once... using 907 // observer design pattern 908 i.update(); 909 } else if (i instanceof Text) { 910 if (i.isAnnotation()) { 911 if (ItemUtils.startsWithTag(i, ItemUtils.TAG_POINTTYPE)) { 912 Text txt = (Text) i; 913 String line = txt.getFirstLine(); 914 line = ItemUtils.StripTag(line, 915 ItemUtils.GetTag(ItemUtils.TAG_POINTTYPE)); 916 917 if (line != null) { 918 line = line.toLowerCase(); 919 if (line.indexOf(" ") > 0) { 920 String fill = line.substring(line 921 .indexOf(" ") + 1); 922 if (fill.startsWith("nofill")) 923 filledPoints = false; 924 else 925 filledPoints = true; 926 } 927 928 if (line.startsWith("circle")) 929 pointtype = DotType.circle; 930 else 931 pointtype = DotType.square; 932 } 933 }// check for new VECTOR items 934 else if (!FrameGraphics.isXRayMode() 935 && ItemUtils.startsWithTag(i, 936 ItemUtils.TAG_VECTOR) 937 && i.getLink() != null) { 938 if (!i.getAbsoluteLink().equals(toParse.getName())) 939 addVector(vectors, UserAppliedPermission.none, 940 permission, i); 941 } else if (!FrameGraphics.isXRayMode() 942 && ItemUtils.startsWithTag(i, 943 ItemUtils.TAG_ACTIVE_VECTOR) 944 && i.getLink() != null) { 945 if (!i.getAbsoluteLink().equals(toParse.getName())) 946 addVector(vectors, 947 UserAppliedPermission.followLinks, 948 permission, i); 949 } 950 // check for new OVERLAY items 951 else if (!ignoreAnnotations 952 && ItemUtils.startsWithTag(i, 953 ItemUtils.TAG_OVERLAY) 954 && i.getLink() != null) { 955 if (i.getAbsoluteLink().equalsIgnoreCase( 956 toParse.getName())) { 957 // This frame contains an active overlay which 958 // points to itself 959 MessageBay 960 .errorMessage(toParse.getName() 961 + " contains an @o which links to itself"); 962 continue; 963 } 964 965 Frame overlayFrame = FrameIO.LoadFrame(i 966 .getAbsoluteLink()); 967 // Parse(overlay); 968 if (overlayFrame != null 969 && Overlay.getOverlay(overlays, 970 overlayFrame) == null) 971 overlays.add(new Overlay(overlayFrame, 972 UserAppliedPermission.none)); 973 } 974 // check for ACTIVE_OVERLAY items 975 else if (!ignoreAnnotations 976 && ItemUtils.startsWithTag(i, 977 ItemUtils.TAG_ACTIVE_OVERLAY) 978 && i.getLink() != null) { 979 String link = i.getAbsoluteLink(); 980 if (link.equalsIgnoreCase(toParse.getName())) { 981 // This frame contains an active overlay which 982 // points to itself 983 MessageBay 984 .errorMessage(toParse.getName() 985 + " contains an @ao which links to itself"); 986 continue; 987 } 988 Frame overlayFrame = null; 989 990 Frame current = DisplayIO.getCurrentFrame(); 991 if (current != null) { 992 for (Overlay o : current.getOverlays()) { 993 if (o.Frame.getName() 994 .equalsIgnoreCase(link)) 995 overlayFrame = o.Frame; 996 } 997 } 998 if (overlayFrame == null) 999 overlayFrame = FrameIO.LoadFrame(link); 1000 1001 // get level if specified 1002 String level = new AttributeValuePair(i.getText()) 1003 .getValue(); 1004 // default permission (if none is specified) 1005 PermissionPair permissionLevel = new PermissionPair( 1006 level, UserAppliedPermission.followLinks); 1007 1008 if (overlayFrame != null) { 1009 Overlay existingOverlay = Overlay.getOverlay( 1010 overlays, overlayFrame); 1011 // If it wasn't in the list create it and add 1012 // it. 1013 if (existingOverlay == null) { 1014 Overlay newOverlay = new Overlay( 1015 overlayFrame, 1016 permissionLevel 1017 .getPermission(overlayFrame 1018 .getOwner())); 1019 i.setOverlay(newOverlay); 1020 overlays.add(newOverlay); 1021 } else { 1022 existingOverlay.Frame 1023 .setPermission(permissionLevel); 1024 } 1025 } 1026 } 1027 // check for Images and widgets 1028 else { 1029 if (!FrameGraphics.isXRayMode()) { 1030 if (ItemUtils.startsWithTag(i, 1031 ItemUtils.TAG_IMAGE, true)) { 1032 if (!i.hasEnclosures()) { 1033 createPicture(toParse, (Text) i); 1034 } 1035 // check for frame images 1036 } else if (ItemUtils.startsWithTag(i, 1037 ItemUtils.TAG_FRAME_IMAGE) 1038 && i.getLink() != null 1039 && !i.getAbsoluteLink() 1040 .equalsIgnoreCase( 1041 toParse.getName())) { 1042 XRayable image = null; 1043 if (i.hasEnclosures()) { 1044 // i.setHidden(true); 1045 // image = 1046 // i.getEnclosures().iterator().next(); 1047 // image.refresh(); 1048 } else { 1049 image = new FrameImage((Text) i, 1050 toParse, null); 1051 } 1052 // TODO Add the image when creating new 1053 // FrameImage 1054 toParse.addItem(image); 1055 } else if (ItemUtils.startsWithTag(i, 1056 ItemUtils.TAG_BITMAP_IMAGE) 1057 && i.getLink() != null 1058 && !i.getAbsoluteLink() 1059 .equalsIgnoreCase( 1060 toParse.getName())) { 1061 XRayable image = null; 1062 if (i.hasEnclosures()) { 1063 // image = 1064 // i.getEnclosures().iterator().next(); 1065 // image.refresh(); 1066 // i.setHidden(true); 1067 } else { 1068 // If a new bitmap is created for a 1069 // frame which already has a bitmap dont 1070 // recreate the bitmap 1071 image = new FrameBitmap((Text) i, 1072 toParse, null); 1073 } 1074 toParse.addItem(image); 1075 } else if (ItemUtils.startsWithTag(i, "@c")) { 1076 // Can only have a @c 1077 if (!i.hasEnclosures() 1078 && i.getLines().size() == 1) { 1079 toParse.addItem(new Circle((Text) i)); 1080 } 1081 // Check for JSItem 1082 } else if(ItemUtils.startsWithTag(i, "@js")) { 1083 toParse.addItem(new JSItem((Text) i)); 1084 // Check for interactive widgets 1085 } else if (ItemUtils.startsWithTag(i, 1086 ItemUtils.TAG_IWIDGET)) { 1087 createWidget(toParse, (Text) i); 1088 } 1089 } 1090 // TODO decide exactly what to do here!! 1091 toParse.addAnnotation((Text) i); 1092 } 1093 } else if (!FrameGraphics.isXRayMode() && i.hasFormula()) { 1094 i.calculate(i.getFormula()); 1095 } 1096 } 1097 } catch (Exception e) { 1098 Logger.Log(e); 1099 e.printStackTrace(); 1100 MessageBay.warningMessage("Exception occured when loading " 1101 + i.getClass().getSimpleName() + "(ID: " + i.getID() 1102 + ") " + e.getMessage() != null ? e.getMessage() : ""); 1103 } 1104 } 1105 1106 /* 1107 * for (Item i : items) { if (i instanceof Dot) { ((Dot) 1108 * i).setPointType(pointtype); ((Dot) i).useFilledPoints(filledPoints); 1109 * } } 1110 */ 1111 1112 FrameIO.ResumeCache(); 1113 1114 toParse.clearOverlays(); 1115 toParse.clearVectors(); 1116 toParse.addAllOverlays(overlays); 1117 toParse.addAllVectors(vectors); 1118 1119 } 1120 1121 /** 1122 * @param vectors 1123 * @param permission 1124 * @param i 1125 */ 1126 private static void addVector(List<Vector> vectors, 1127 UserAppliedPermission defaultPermission, 1128 UserAppliedPermission framePermission, Item i) { 1129 // TODO It is possible to get into an infinate loop if a 1130 // frame contains an @ao which leads to a frame with an 1131 // @v which points back to the frame with the @ao 1132 Frame vector = FrameIO.LoadFrame(i.getAbsoluteLink()); 1133 1134 // Get the permission from off the vector frame 1135 UserAppliedPermission vectorPermission = UserAppliedPermission 1136 .getPermission(vector.getAnnotationValue("permission"), 1137 defaultPermission); 1138 // If the frame permission is lower, use that 1139 vectorPermission = UserAppliedPermission.min(vectorPermission, 1140 framePermission); 1141 // Highest permissable permission for vectors is copy 1142 vectorPermission = UserAppliedPermission.min(vectorPermission, 1143 UserAppliedPermission.copy); 1144 if (vector != null) { 1145 String scaleString = new AttributeValuePair(i.getText()).getValue(); 1146 Float scale = 1F; 1147 try { 1148 scale = Float.parseFloat(scaleString); 1149 } catch (Exception e) { 1150 } 1151 Vector newVector = new Vector(vector, vectorPermission, scale, i); 1152 i.setOverlay(newVector); 1153 i.setVisible(false); 1154 vectors.add(newVector); 1155 } 1156 } 1157 1158 public static Item onItem(float floatX, float floatY, 1159 boolean changeLastEdited) { 1160 return onItem(DisplayIO.getCurrentFrame(), floatX, floatY, 1161 changeLastEdited); 1162 } 1163 1164 /** 1165 * Searches through the list of items on this frame to find one at the given 1166 * x,y coordinates. 1167 * 1168 * @param x 1169 * The x coordinate 1170 * @param y 1171 * The y coordinate 1172 * @return The Item at the given coordinates, or NULL if none is found. 1173 */ 1174 public static Item onItem(Frame toCheck, float floatX, float floatY, 1175 boolean bResetLastEdited) { 1176 // System.out.println("MouseX: " + floatX + " MouseY: " + floatY); 1177 int x = Math.round(floatX); 1178 int y = Math.round(floatY); 1179 if (toCheck == null) 1180 return null; 1181 1182 List<Item> possibles = new ArrayList<Item>(0); 1183 1184 // if the mouse is in the message area 1185 if (y > FrameGraphics.getMaxFrameSize().getHeight()) { 1186 // check the individual message items 1187 for (Item message : MessageBay.getMessages()) { 1188 if (message != null) { 1189 if (message.contains(x, y)) { 1190 message.setOverlayPermission(UserAppliedPermission.copy); 1191 possibles.add(message); 1192 } else { 1193 // Not sure why but if the line below is removed then 1194 // several items can be highlighted at once 1195 message.setHighlightMode(Item.HighlightMode.None); 1196 } 1197 } 1198 } 1199 1200 // check the link to the message frame 1201 if (MessageBay.getMessageLink() != null) { 1202 if (MessageBay.getMessageLink().contains(x, y)) { 1203 MessageBay.getMessageLink().setOverlayPermission( 1204 UserAppliedPermission.copy); 1205 possibles.add(MessageBay.getMessageLink()); 1206 } 1207 } 1208 1209 // this is taken into account in contains 1210 // y -= FrameGraphics.getMaxFrameSize().height; 1211 // otherwise, the mouse is on the frame 1212 } else { 1213 if (LastEdited != null) { 1214 if (LastEdited.contains(x, y) 1215 && !FreeItems.getInstance().contains(LastEdited) 1216 && LastEdited.getParent() == DisplayIO 1217 .getCurrentFrame() 1218 && LastEdited.getParent().getItems() 1219 .contains(LastEdited)) { 1220 LastEdited.setOverlayPermission(UserAppliedPermission.full); 1221 return LastEdited; 1222 } else if (bResetLastEdited) { 1223 setLastEdited(null); 1224 } 1225 } 1226 ArrayList<Item> checkList = new ArrayList<Item>(); 1227 checkList.addAll(toCheck.getInteractableItems()); 1228 checkList.add(toCheck.getNameItem()); 1229 1230 for (Item i : checkList) { 1231 1232 // do not check annotation items in audience mode 1233 //TODO: Upon hover of Rubbish Bin, Undo and Restore Widgets, flickering occurs depending on the mouse distance from a corner. Resolve this. 1234 if (i.isVisible() 1235 && !(FrameGraphics.isAudienceMode() && i.isAnnotation())) { 1236 if(i instanceof WidgetCorner){ 1237 WidgetCorner wc = (WidgetCorner)i; 1238 if(wc.getWidgetSource() instanceof ButtonWidget){ 1239 ButtonWidget bw = (ButtonWidget) wc.getWidgetSource(); 1240 1241 if(bw.getdropInteractableStatus() == true){ 1242 InteractiveWidget iw = wc.getWidgetSource(); 1243 1244 if(iw.getBounds().contains(x, y)){ 1245 1246 if( !FreeItems.getInstance().contains(i)) 1247 { 1248 possibles.add(i); 1249 } 1250 } 1251 } 1252 1253 } 1254 1255 } 1256 1257 if (i.contains(x, y)){ 1258 if( !FreeItems.getInstance().contains(i)) 1259 { 1260 possibles.add(i); 1261 } 1262 } 1263 1264 } 1265 } 1266 } 1267 1268 // if there are no possible items, return null 1269 if (possibles.size() == 0) 1270 return null; 1271 1272 // if there is only one possibility, return it 1273 if (possibles.size() == 1) 1274 return possibles.get(0); 1275 1276 // return closest x,y pair to mouse 1277 Item closest = possibles.get(0); 1278 int distance = (int) Math.round(Math.sqrt(Math.pow( 1279 Math.abs(closest.getX() - x), 2) 1280 + Math.pow(Math.abs(closest.getY() - y), 2))); 1281 1282 for (Item i : possibles) { 1283 int d = (int) Math.round(Math.sqrt(Math.pow(Math.abs(i.getX() - x), 1284 2) + Math.pow(Math.abs(i.getY() - y), 2))); 1285 1286 // System.out.println(d); 1287 if (d <= distance) { 1288 distance = d; 1289 1290 // dots take precedence over lines 1291 if ((!(closest instanceof Dot && i instanceof Line)) 1292 && (!(closest instanceof Text && i instanceof Line))) 1293 closest = i; 1294 1295 } 1296 1297 } 1298 1299 return closest; 1300 } 1301 1302 public synchronized static Item getCurrentItem() { 1303 return onItem(DisplayIO.getCurrentFrame(), DisplayIO.getMouseX(), 1304 FrameMouseActions.getY(), true); 1305 } 1306 1307 public static Polygon getEnlosingPolygon() { 1308 Collection<Item> enclosure = getEnclosingLineEnds(); 1309 if (enclosure == null || enclosure.size() == 0) 1310 return null; 1311 1312 return enclosure.iterator().next().getEnclosedShape(); 1313 } 1314 1315 /** 1316 * 1317 * @param currentItem 1318 * @return 1319 */ 1320 public static Collection<Item> getCurrentItems() { 1321 return getCurrentItems(getCurrentItem()); 1322 } 1323 1324 public static Collection<Item> getCurrentItems(Item currentItem) { 1325 1326 Collection<Item> enclosure = getEnclosingLineEnds(); 1327 if (enclosure == null || enclosure.size() == 0) 1328 return null; 1329 1330 Item firstItem = enclosure.iterator().next(); 1331 1332 Collection<Item> enclosed = getItemsEnclosedBy( 1333 DisplayIO.getCurrentFrame(), firstItem.getEnclosedShape()); 1334 1335 // Brook: enclosed widgets are to be fully enclosed, never partially 1336 /* 1337 * MIKE says: but doesnt this mean that widgets are treated differently 1338 * from ALL other object which only need to be partially enclosed to be 1339 * picked up 1340 */ 1341 List<InteractiveWidget> enclosedWidgets = new LinkedList<InteractiveWidget>(); 1342 for (Item i : enclosed) { 1343 // Don't want to lose the highlighting from the current item 1344 if (i == currentItem || enclosure.contains(i)) { 1345 continue; 1346 } 1347 // Don't want to lose the highlighting of connected Dots 1348 if (i instanceof Dot 1349 && i.getHighlightMode() == HighlightMode.Connected) { 1350 for (Line l : i.getLines()) { 1351 if (l.getOppositeEnd(i).getHighlightMode() == HighlightMode.Normal) { 1352 continue; 1353 } 1354 } 1355 } 1356 if (i instanceof WidgetCorner) { 1357 if (!enclosedWidgets.contains(((WidgetCorner) i) 1358 .getWidgetSource())) 1359 enclosedWidgets.add(((WidgetCorner) i).getWidgetSource()); 1360 } 1361 i.setHighlightMode(Item.HighlightMode.None); 1362 } 1363 1364 for (InteractiveWidget iw : enclosedWidgets) { 1365 for (Item i : iw.getItems()) { 1366 if (!enclosed.contains(i)) { 1367 enclosed.add(i); 1368 } 1369 } 1370 } 1371 1372 return enclosed; 1373 } 1374 1375 public static Collection<Item> getEnclosingLineEnds() { 1376 return getEnclosingLineEnds(new Point(DisplayIO.getMouseX(), 1377 FrameMouseActions.getY())); 1378 } 1379 1380 public static Collection<Item> getEnclosingLineEnds(Point position) { 1381 // update enclosed shapes 1382 Frame current = DisplayIO.getCurrentFrame(); 1383 List<Item> items = current.getItems(); 1384 1385 // Remove all items that are connected to freeItems 1386 List<Item> freeItems = new ArrayList<Item>(FreeItems.getInstance()); 1387 while (freeItems.size() > 0) { 1388 Item item = freeItems.get(0); 1389 Collection<Item> connected = item.getAllConnected(); 1390 items.removeAll(connected); 1391 freeItems.removeAll(connected); 1392 } 1393 1394 List<Item> used = new ArrayList<Item>(0); 1395 1396 while (items.size() > 0) { 1397 Item i = items.get(0); 1398 items.remove(i); 1399 if (i.isEnclosed()) { 1400 Polygon p = i.getEnclosedShape(); 1401 if (p.contains(position.x, position.y)) { 1402 used.add(i); 1403 items.removeAll(i.getEnclosingDots()); 1404 } 1405 } 1406 } 1407 1408 if (used.size() == 0) 1409 return null; 1410 1411 // if there is only one possibility, return it 1412 if (used.size() == 1) { 1413 return used.get(0).getEnclosingDots(); 1414 // otherwise, determine which polygon is closest to the cursor 1415 } else { 1416 Collections.sort(used, new Comparator<Item>() { 1417 public int compare(Item d1, Item d2) { 1418 Polygon p1 = d1.getEnclosedShape(); 1419 Polygon p2 = d2.getEnclosedShape(); 1420 1421 int closest = Integer.MAX_VALUE; 1422 int close2 = Integer.MAX_VALUE; 1423 1424 int mouseX = DisplayIO.getMouseX(); 1425 int mouseY = FrameMouseActions.getY(); 1426 1427 for (int i = 0; i < p1.npoints; i++) { 1428 int diff = Math.abs(p1.xpoints[i] - mouseX) 1429 + Math.abs(p1.ypoints[i] - mouseY); 1430 int diff2 = Integer.MAX_VALUE; 1431 1432 if (i < p2.npoints) 1433 diff2 = Math.abs(p2.xpoints[i] - mouseX) 1434 + Math.abs(p2.ypoints[i] - mouseY); 1435 1436 if (diff < Math.abs(closest)) { 1437 close2 = closest; 1438 closest = diff; 1439 } else if (diff < Math.abs(close2)) 1440 close2 = diff; 1441 1442 if (diff2 < Math.abs(closest)) { 1443 close2 = closest; 1444 closest = -diff2; 1445 } else if (diff2 < Math.abs(close2)) 1446 close2 = diff2; 1447 } 1448 1449 if (closest > 0 && close2 > 0) 1450 return -10; 1451 1452 if (closest < 0 && close2 < 0) 1453 return 10; 1454 1455 if (closest > 0) 1456 return -10; 1457 1458 return 10; 1459 } 1460 1461 }); 1462 1463 return used.get(0).getEnclosingDots(); 1464 } 1465 } 1466 1467 // TODO Remove this method!! 1468 // Can just getItemsWithin be used? 1469 public static Collection<Item> getItemsEnclosedBy(Frame frame, Polygon poly) { 1470 Collection<Item> contained = frame.getItemsWithin(poly); 1471 1472 Collection<Item> results = new LinkedHashSet<Item>(contained.size()); 1473 1474 // check for correct permissions 1475 for (Item item : contained) { 1476 // if the item is on the frame 1477 if (item.getParent() == frame || item.getParent() == null) { 1478 // item.Permission = Permission.full; 1479 results.add(item); 1480 // otherwise, it must be on an overlay frame 1481 } else { 1482 for (Overlay overlay : frame.getOverlays()) { 1483 if (overlay.Frame == item.getParent()) { 1484 item.setOverlayPermission(overlay.permission); 1485 results.add(item); 1486 break; 1487 } 1488 } 1489 } 1490 } 1491 1492 return results; 1493 } 1494 1495 /** 1496 * Fills the given Frame with default profile tags 1497 */ 1498 public static void CreateDefaultProfile(String username, Frame profile) { 1499 Text title = profile.getTitleItem(); 1500 if (username.equals(UserSettings.DEFAULT_PROFILE_NAME)) { 1501 title.setText("Default Profile Frame"); 1502 } else { 1503 // if this profile is not the default profile, copy it from the default profile instead of generating a new profile 1504 // (this allows the possibility of modifying the default profile and having any new profiles get those modifications) 1505 Frame nextDefault = FrameIO.LoadProfile(UserSettings.DEFAULT_PROFILE_NAME); 1506 if (nextDefault == null) { 1507 try { 1508 nextDefault = FrameIO.CreateNewProfile(UserSettings.DEFAULT_PROFILE_NAME); 1509 } catch (Exception e) { 1510 // TODO tell the user that there was a problem creating the 1511 // profile frame and close nicely 1512 e.printStackTrace(); 1513 } 1514 } 1515 // load profile frame and set title correctly 1516 profile.reset(); 1517 profile.removeAllItems(profile.getAllItems()); 1518 // set relative link on all items so their links will correctly point to the page on the current profile rather than on the default profile 1519 for(Item i : nextDefault.getAllItems()) { 1520 i.setRelativeLink(); 1521 } 1522 profile.addAllItems(ItemUtils.CopyItems(nextDefault.getAllItems())); 1523 profile.setTitle(username + "'s Profile Frame"); 1524 FrameIO.SaveFrame(profile); 1823 if(!force && check.exists()) return; 1525 1824 1526 Frame nextProfile = profile; 1527 MessageBay.suppressMessages(true); 1528 while((nextDefault = FrameIO.LoadNext(nextDefault)) != null) { 1529 // in case there are gaps in the frame numbering of the default profile (e.g. if a user has edited it), 1530 // we need to replicate those gaps in the copied profile so the links will work correctly 1531 while(nextProfile.getNumber() < nextDefault.getNumber()) { 1532 nextProfile = FrameIO.CreateFrame(profile.getFramesetName(), null, null); 1533 } 1534 // if the new profile has a frame number higher than the current frame number in the default profile, 1535 // the new profile must already exist, so just exit 1536 // (TODO: should we wipe the frames instead?) 1537 if(nextProfile.getNumber() > nextDefault.getNumber()) { 1538 break; 1539 } 1540 nextProfile.reset(); 1541 nextProfile.removeAllItems(nextProfile.getAllItems()); 1542 // set relative link on all items so their links will correctly point to the page on the current profile rather than on the default profile 1543 for(Item i : nextDefault.getAllItems()) { 1544 i.setRelativeLink(); 1545 } 1546 nextProfile.addAllItems(ItemUtils.CopyItems(nextDefault.getAllItems())); 1547 FrameIO.SaveFrame(nextProfile); 1548 } 1549 MessageBay.suppressMessages(false); 1825 System.out.println("Extracting/Installing resources:"); 1550 1826 1551 return;1552 }1553 1554 // int spacing = 50;1555 final int intialYPos = 75;1556 int xPos = 75;1557 int yPos = intialYPos;1558 1559 // yPos += spacing;1560 // profile.addText(xPos, yPos, "@HomeFrame", null, profile.getName());1561 // yPos += spacing;1562 // String defaultFrameName = profile.getFramesetName() + "0";1563 // profile.addText(xPos, yPos, "@DefaultFrame", null, defaultFrameName);1564 // yPos += spacing;1565 //1566 // profile.addText(xPos, yPos, "@InitialWidth: "1567 // + UserSettings.InitialWidth, null);1568 // yPos += spacing;1569 //1570 // profile.addText(xPos, yPos, "@InitialHeight: "1571 // + UserSettings.InitialHeight, null);1572 // yPos += spacing;1573 //1574 // Text t = profile.addText(xPos, yPos, "@ItemTemplate", null);1575 // t.setColor(null);1576 //1577 // yPos += spacing;1578 // t = profile.addText(xPos, yPos, "@AnnotationTemplate", null);1579 // t.setColor(Color.gray);1580 //1581 // yPos += spacing;1582 // t = profile.addText(xPos, yPos, "@CommentTemplate", null);1583 // t.setColor(Color.green.darker());1584 //1585 // yPos += spacing;1586 // t = profile.addText(xPos, yPos, "@StatsTemplate", null);1587 // t.setColor(Color.BLACK);1588 // t.setBackgroundColor(new Color(0.9F, 0.9F, 0.9F));1589 // t.setFamily(Text.MONOSPACED_FONT);1590 // t.setSize(14);1591 1592 Text t;1593 1594 xPos = 300;1595 // yPos = intialYPos + spacing;1596 yPos = 100;1597 1598 // Add documentation links1599 File helpDirectory = new File(FrameIO.HELP_PATH);1600 if (helpDirectory != null) {1601 File[] helpFramesets = helpDirectory.listFiles();1602 if (helpFramesets != null) {1603 1604 // Add the title for the help index1605 Text help = profile.addText(xPos, yPos, "@Expeditee Help", null);1606 help.setSize(25);1607 help.setFontStyle("Bold");1608 help.setFamily("SansSerif");1609 help.setColor(TemplateSettings.ColorWheel.get()[3]);1610 1611 xPos += 25;1612 System.out.println("Installing frameset: ");1613 1614 boolean first_item = true;1615 1616 for (File helpFrameset : helpFramesets) {1617 String framesetName = helpFrameset.getName();1618 if (!FrameIO.isValidFramesetName(framesetName)) {1619 continue;1620 }1621 1622 if (first_item) {1623 System.out.print(" " + framesetName);1624 first_item = false;1625 }1626 else {1627 System.out.print(", " + framesetName);1628 }1629 System.out.flush();1630 1631 Frame indexFrame = FrameIO.LoadFrame(framesetName + '1');1632 // Look through the folder for help index pages1633 if (indexFrame != null1634 && ItemUtils.FindTag(indexFrame.getItems(),1635 "@HelpIndex") != null) {1636 // yPos += spacing;1637 yPos += 30;1638 t = profile.addText(xPos, yPos,1639 '@' + indexFrame.getFramesetName(), null);1640 t.setLink(indexFrame.getName());1641 t.setColor(Color.gray);1642 }1643 }1644 System.out.println();1645 }1646 }1647 1648 xPos = 50;1649 yPos = 100;1650 1651 // Populate Start Pages and Settings1652 File framesetDirectory = new File(FrameIO.FRAME_PATH);1653 1654 if (framesetDirectory.exists()) {1655 File[] startpagesFramesets = framesetDirectory.listFiles();1656 1657 if (startpagesFramesets != null) {1658 // Add Start Page title1659 Text templates = profile.addText(xPos, yPos, "@Start Pages",1660 null);1661 templates.setSize(25);1662 templates.setFontStyle("Bold");1663 templates.setFamily("SansSerif");1664 templates.setColor(TemplateSettings.ColorWheel.get()[3]);1665 1666 xPos += 25;1667 1668 // Start Pages should be the first frame in its own frameset +1669 // frameset name should be present in FrameUtils.startPages[].1670 for (File startpagesFrameset : startpagesFramesets) {1671 String framesetName = startpagesFrameset.getName();1672 1673 // Only add link if frameset is a startpage1674 for (int i = 0; i < startPages.length; i++) {1675 if (framesetName.equals(startPages[i])) {1676 Frame indexFrame = FrameIO1677 .LoadFrame(framesetName + '1');1678 1679 // Add start page link1680 if (indexFrame != null) {1681 yPos += 30;1682 t = profile.addText(xPos, yPos,1683 '@' + indexFrame.getFramesetName(),1684 null);1685 t.setLink(indexFrame.getName());1686 t.setColor(Color.gray);1687 }1688 }1689 }1690 }1691 }1692 }1693 1694 FrameIO.SaveFrame(profile);1695 1696 // Populate settings frameset1697 Settings.Init();1698 t = profile.addText(550, 100, "@Settings", null);1699 t.setSize((float) 25.0);1700 t.setFamily("SansSerif");1701 t.setFontStyle("Bold");1702 t.setColor(Color.gray);1703 Settings.generateSettingsTree(t);1704 1705 FrameIO.SaveFrame(profile);1706 }1707 1708 private static void checkTDFCItemWaiting(Frame currentFrame) {1709 Item tdfcItem = FrameUtils.getTdfcItem();1710 // if there is a TDFC Item waiting1711 if (tdfcItem != null) {1712 boolean change = currentFrame.hasChanged();1713 boolean saved = currentFrame.isSaved();1714 // Save the parent of the item if it has not been saved1715 if (!change && !saved) {1716 tdfcItem.setLink(null);1717 tdfcItem.getParent().setChanged(true);1718 FrameIO.SaveFrame(tdfcItem.getParent());1719 FrameGraphics.Repaint();1720 } else {1721 SessionStats.CreatedFrame();1722 }1723 1724 setTdfcItem(null);1725 }1726 }1727 1728 public static void setTdfcItem(Item _tdfcItem) {1729 FrameUtils._tdfcItem = _tdfcItem;1730 }1731 1732 public static Item getTdfcItem() {1733 return FrameUtils._tdfcItem;1734 }1735 1736 private static Item _tdfcItem = null;1737 1738 public static void setLastEdited(Text lastEdited) {1739 1740 // If the lastEdited is being changed then check if its @i1741 Frame toReparse = null;1742 Frame toRecalculate = null;1743 Frame toUpdateObservers = null;1744 1745 if (LastEdited == null) {1746 // System.out.print("N");1747 } else if (LastEdited != null) {1748 // System.out.print("T");1749 Frame parent = LastEdited.getParentOrCurrentFrame();1750 1751 if (lastEdited != LastEdited) {1752 if (LastEdited.startsWith("@i")) {1753 // Check if its an image that can be resized to fit a box1754 // around it1755 String text = LastEdited.getText();1756 if (text.startsWith("@i:")1757 && !Character1758 .isDigit(text.charAt(text.length() - 1))) {1759 Collection<Item> enclosure = FrameUtils1760 .getEnclosingLineEnds(LastEdited.getPosition());1761 if (enclosure != null) {1762 for (Item i : enclosure) {1763 if (i.isLineEnd() && i.isEnclosed()) {1764 DisplayIO.getCurrentFrame().removeAllItems(1765 enclosure);1766 Rectangle rect = i.getEnclosedRectangle();1767 LastEdited1768 .setText(LastEdited.getText()1769 + " "1770 + Math.round(rect1771 .getWidth()));1772 LastEdited.setPosition(new Point(rect.x,1773 rect.y));1774 LastEdited.setThickness(i.getThickness());1775 LastEdited.setBorderColor(i.getColor());1776 break;1777 }1778 }1779 FrameMouseActions.deleteItems(enclosure, false);1780 }1781 }1782 toReparse = parent;1783 } else if (LastEdited.recalculateWhenChanged()) {1784 toRecalculate = parent;1785 }1786 1787 if (parent.hasObservers()) {1788 toUpdateObservers = parent;1789 }1790 // Update the formula if in XRay mode1791 if (FrameGraphics.isXRayMode() && LastEdited.hasFormula()) {1792 LastEdited.setFormula(LastEdited.getText());1793 }1794 }1795 if (lastEdited != LastEdited && LastEdited.getText().length() == 0) {1796 parent.removeItem(LastEdited);1797 }1798 }1799 LastEdited = lastEdited;1800 1801 if (!FrameGraphics.isXRayMode()) {1802 if (toReparse != null) {1803 Parse(toReparse, false, false);1804 } else {1805 if (toRecalculate != null) {1806 toRecalculate.recalculate();1807 }1808 1809 if (toUpdateObservers != null) {1810 toUpdateObservers.notifyObservers(false);1811 }1812 }1813 }1814 }1815 1816 /**1817 * Extracts files/folders from the assets/resources folder directly into1818 * ${PARENT_FOLDER} (~/.expeditee)1819 *1820 * @param force if true, resources will be extracted even if they have already been extracted before1821 */1822 public static void extractResources(boolean force) {1823 File check = new File(FrameIO.PARENT_FOLDER + ".res");1824 if(!force && check.exists()) {1825 return;1826 }1827 System.out.println("Extracting/Installing resources:");1828 1827 try { 1829 1828 check.getParentFile().mkdirs(); 1830 1831 1829 check.createNewFile(); 1830 1832 1831 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 1833 1832 URL docURL = classLoader.getResource("org/expeditee/assets/resources"); 1834 1833 1835 1834 // copy files from the jar file to the profile folder 1836 1835 if (docURL.getProtocol().equals("jar")) { … … 1840 1839 String res = "org/expeditee/assets/resources/"; 1841 1840 int resLength = res.length(); 1842 1841 1843 1842 ZipEntry ze; 1844 1843 1845 1844 while(jarEntries.hasMoreElements()) { 1846 1845 ze = jarEntries.nextElement(); … … 1850 1849 File out = new File(FrameIO.PARENT_FOLDER + ze.getName().substring(resLength)); 1851 1850 // System.out.println("Didn't crash here " + out.getPath()); 1852 // if(out.exists()) {1853 // continue;1854 // }1851 // if(out.exists()) { 1852 // continue; 1853 // } 1855 1854 if(ze.isDirectory()) { 1856 1855 // System.out.println(out.getPath() + " IS DIRECTORY"); … … 1881 1880 } 1882 1881 } 1883 1884 // Copy files from the source folder to the profile folder1882 1883 // Copy files from the source folder to the profile folder 1885 1884 } else if (docURL.getProtocol().equals("bundleresource")) { 1886 1885 final URLConnection urlConnection = docURL.openConnection(); … … 1899 1898 } 1900 1899 1901 private static void extractResourcesFromFolder(File folder) throws IOException { 1902 LinkedList<File> items = new LinkedList<File>(); 1903 items.addAll(Arrays.asList(folder.listFiles())); 1904 LinkedList<File> files = new LinkedList<File>(); 1905 String res = "org" + File.separator + "expeditee" + File.separator + "assets" + File.separator + "resources"; 1906 int resLength = res.length(); 1907 1908 while (items.size() > 0) { 1909 File file = items.remove(0); 1910 if(file.isFile()) { 1911 if(!file.getName().contains(".svn")) { 1912 files.add(file); 1913 } 1914 } else { 1915 if (!file.getName().contains(".svn")) { 1916 items.addAll(Arrays.asList(file.listFiles())); 1917 } 1918 } 1919 } 1920 for (File file : files) { 1921 System.out.println(file.getPath()); 1922 File out = new File(FrameIO.PARENT_FOLDER + file.getPath().substring(file.getPath().indexOf(res) + resLength)); 1923 // if(out.exists()) { 1924 // continue; 1925 // } 1926 copyFile(file, out, true); 1927 } 1928 } 1929 1930 /** 1931 * @param src 1932 * @param dst 1933 * @throws IOException 1934 */ 1935 public static void copyFile(File src, File dst, boolean overWrite) throws IOException { 1936 if(!overWrite && dst.exists()) 1937 return; 1938 dst.getParentFile().mkdirs(); 1900 private static void extractResourcesFromFolder(File folder) throws IOException 1901 { 1902 LinkedList<File> items = new LinkedList<File>(); 1903 items.addAll(Arrays.asList(folder.listFiles())); 1904 LinkedList<File> files = new LinkedList<File>(); 1905 String res = "org" + File.separator + "expeditee" + File.separator + "assets" + File.separator + "resources"; 1906 int resLength = res.length(); 1907 1908 while (items.size() > 0) { 1909 File file = items.remove(0); 1910 if(file.isFile()) { 1911 if(!file.getName().contains(".svn")) { 1912 files.add(file); 1913 } 1914 } else { 1915 if (!file.getName().contains(".svn")) { 1916 items.addAll(Arrays.asList(file.listFiles())); 1917 } 1918 } 1919 } 1920 for (File file : files) { 1921 System.out.println(file.getPath()); 1922 File out = new File(FrameIO.PARENT_FOLDER + file.getPath().substring(file.getPath().indexOf(res) + resLength)); 1923 // if(out.exists()) { 1924 // continue; 1925 // } 1926 copyFile(file, out, true); 1927 } 1928 } 1929 1930 /** 1931 * @param src 1932 * @param dst 1933 * @throws IOException 1934 */ 1935 public static void copyFile(File src, File dst, boolean overWrite) throws IOException 1936 { 1937 if(!overWrite && dst.exists()) return; 1938 1939 dst.getParentFile().mkdirs(); 1939 1940 FileOutputStream fOut = null; 1940 1941 FileInputStream fIn = null; … … 1959 1960 } 1960 1961 } 1961 } 1962 1963 public static Text getLastEdited() { 1964 return LastEdited; 1965 } 1966 1967 public static Collection<Text> getCurrentTextItems() { 1968 Collection<Text> currentTextItems = new LinkedHashSet<Text>(); 1969 Collection<Item> currentItems = getCurrentItems(null); 1970 if (currentItems != null) { 1971 for (Item i : getCurrentItems(null)) { 1972 if (i instanceof Text && !i.isLineEnd()) { 1973 currentTextItems.add((Text) i); 1974 } 1975 } 1976 } 1977 return currentTextItems; 1978 } 1962 } 1963 1964 public static Text getLastEdited() 1965 { 1966 return LastEdited; 1967 } 1968 1969 public static Collection<Text> getCurrentTextItems() 1970 { 1971 Collection<Text> currentTextItems = new LinkedHashSet<Text>(); 1972 Collection<Item> currentItems = getCurrentItems(null); 1973 if (currentItems != null) { 1974 for (Item i : getCurrentItems(null)) { 1975 if (i instanceof Text && !i.isLineEnd()) { 1976 currentTextItems.add((Text) i); 1977 } 1978 } 1979 } 1980 return currentTextItems; 1981 } 1979 1982 }
Note:
See TracChangeset
for help on using the changeset viewer.