source: trunk/src/org/expeditee/gui/Frame.java@ 56

Last change on this file since 56 was 56, checked in by davidb, 16 years ago

Fixed bug with widgets movement and scaling

File size: 31.5 KB
Line 
1package org.expeditee.gui;
2
3import java.awt.Color;
4import java.awt.Dimension;
5import java.awt.Image;
6import java.awt.Polygon;
7import java.awt.image.ImageObserver;
8import java.awt.image.VolatileImage;
9import java.util.ArrayList;
10import java.util.Collection;
11import java.util.Collections;
12import java.util.LinkedList;
13import java.util.List;
14import java.util.Stack;
15
16import org.expeditee.io.Conversion;
17import org.expeditee.io.Logger;
18import org.expeditee.items.Dot;
19import org.expeditee.items.InteractiveWidget;
20import org.expeditee.items.Item;
21import org.expeditee.items.ItemParentStateChangedEvent;
22import org.expeditee.items.ItemUtils;
23import org.expeditee.items.Line;
24import org.expeditee.items.Text;
25import org.expeditee.items.WidgetCorner;
26
27/**
28 * Represents a KMS Frame that is displayed on the screen. Also is a registered
29 * MouseListener on the Browser, and processes any MouseEvents directly.
30 *
31 * @author jdm18
32 *
33 */
34public class Frame implements ImageObserver {
35
36 public static final Color[] COLOR_WHEEL = { Color.BLACK, Color.GRAY,
37 new Color(235, 235, 235), new Color(225, 225, 255),
38 new Color(195, 255, 255), new Color(225, 255, 225),
39 new Color(255, 255, 195), new Color(255, 225, 225),
40 new Color(255, 195, 255), null };
41
42 // The various attributes of this Frame
43 /**
44 * TODO: Change these to non-string attributes (where applicable). All
45 * processing to\from Java types should be done in KMSReader and KMSWriter.
46 */
47 private String _frameset = null;
48
49 private int _number = -1;
50
51 private int _version = 1;
52
53 private int _fversion = -1;
54
55 private String _protection = null;
56
57 private String _owner = null;
58
59 private String _creationDate = null;
60
61 private String _modifiedUser = null;
62
63 private String _modifiedDate = null;
64
65 private String _frozenDate = null;
66
67 private Color _background;
68
69 private Color _foreground;
70
71 public String path;
72
73 private boolean _sorted = true;
74
75 // The items contained in this Frame
76
77 // records whether a change has been made to this Frame (for saving
78 // purposes).
79 private boolean _change = false;
80
81 private boolean _saved = false;
82
83 // list of deleted items that can be restored
84 private Stack<Item> _undo = new Stack<Item>();
85
86 // basically just a list of smaller objects?
87 // maybe a hashtable (id -> item?)
88 // Note: Needs to be able to be iterated through (for painting)
89 private List<Item> _body = new ArrayList<Item>();
90
91 public static List<Item> FreeItems = new ArrayList<Item>();
92
93 // for drawing purposes
94 private List<InteractiveWidget> _iWidgets = new ArrayList<InteractiveWidget>();
95
96 private int _lineCount = 0;
97
98 private int _itemCount = 1;
99
100 // The frameName to display on the screen
101 private Text _frameName = null;
102
103 // private Text _template = UserSettings.ItemTemplate.copy();
104
105 private List<Overlay> _overlays = new ArrayList<Overlay>();
106
107 private VolatileImage _buffer = null;
108
109 private boolean _validBuffer = true;
110
111 /**
112 * Default constructor, nothing is set.
113 */
114 public Frame() {
115 // _template.setParent(this);
116 }
117
118 public VolatileImage getBuffer() {
119 return _buffer;
120 }
121
122 public void setBuffer(VolatileImage newBuffer) {
123 _buffer = newBuffer;
124 // setBufferValid(true);
125 }
126
127 public boolean isBufferValid() {
128 if (_buffer != null && _buffer.contentsLost())
129 return false;
130
131 return _validBuffer;
132 }
133
134 public void setBufferValid(boolean newValue) {
135 _validBuffer = newValue;
136 }
137
138 public int getNextItemID() {
139 return ++_itemCount;
140 }
141
142 public void updateIDs(List<Item> items) {
143 for (Item i : items)
144 if (!(i instanceof Line))
145 i.setID(getNextItemID());
146 else
147 i.setID(++_lineCount);
148 }
149
150 /**
151 *
152 * @return The interactive widgets that are currently ancored in this frame.
153 * Hence it exlcudes free-widgets. Returns a copy
154 */
155 public List<InteractiveWidget> getInteractiveWidgets() {
156 LinkedList<InteractiveWidget> clone = new LinkedList<InteractiveWidget>();
157 clone.addAll(this._iWidgets);
158 return clone;
159 }
160
161 /**
162 * Returns whether this Frame has been changed and required saving to disk.
163 *
164 * @return True if this Frame has been altered, false otherwise.
165 */
166 public boolean hasChanged() {
167 // virtual frames are never saved
168 if (_number == -1)
169 return false;
170
171 return _change;
172 }
173
174 /**
175 * Sets whether this Frame should be saved to disk.
176 *
177 * @param value
178 * False if this Frame should be saved to disk, False otherwise.
179 */
180 public void setChanged(boolean value) {
181 _change = value;
182
183 if (_change){
184 setBufferValid(false);
185 _saved = false;
186 }
187 }
188
189 // indicates the frame has changed
190 public void change() {
191 setChanged(true);
192 }
193
194 /**
195 * Returns an ArrayList of all Items currently on the Frame (excludes Items
196 * attached to the cursor).
197 *
198 * @return The list of Item objects that are on this Frame.
199 */
200 public List<Item> getItems() {
201
202 if (!_sorted) {
203 Collections.sort(_body);
204 _sorted = true;
205 }
206
207 List<Item> visibleItems = new ArrayList<Item>();
208
209 for(Item i: _body) {
210 if (i.isVisible())
211 visibleItems.add(i);
212 }
213
214 return visibleItems;
215 }
216
217 /**
218 * @param i Item to check if contained in this frame
219 * @return True if this frame contains i.
220 */
221 public boolean containsItem(Item i) {
222 if (i == null) throw new NullPointerException("i");
223 return _body.contains(i);
224 }
225
226 /**
227 * Returns a list of all the non annotation text items on the frame which
228 * are not the title or frame name.
229 *
230 * @return the list of body text items.
231 */
232 public List<Text> getBodyTextItems(boolean includeAnnotations) {
233 List<Text> bodyTextItems = new ArrayList<Text>();
234 for (Item i : getItems()) {
235 // only add up normal body text items
236 if ((i instanceof Text) &&
237 (includeAnnotations || !i.isAnnotation())) {
238 bodyTextItems.add((Text) i);
239 }
240 }
241 bodyTextItems.remove(getTitle());
242
243 return bodyTextItems;
244 }
245
246 /**
247 * Gets the last item on the frame that is a non annotation item but is also
248 * text.
249 *
250 * @return the last non annotation text item.
251 */
252 public Text getLastNonAnnotationTextItem() {
253 List<Item> items = getItems();
254
255 // find the last non-annotation text item
256 for (int i = (items.size() - 1); i >= 0; i--) {
257 Item it = items.get(i);
258
259 if (it instanceof Text && !it.isAnnotation()) {
260 return (Text) it;
261 }
262 }
263 return null;
264 }
265
266 /**
267 * Iterates through the list of items on the frame, and returns one with the
268 * given id if one exists, otherwise returns null.
269 *
270 * @param id
271 * The id to search for in the list of items
272 * @return The item on this frame with the given ID, or null if one is not
273 * found.
274 */
275 public Item getItemWithID(int id) {
276 for (Item i : _body)
277 if (i.getID() == id)
278 return i;
279
280 return null;
281 }
282
283 /**
284 * Sets this Frame's Title which is displayed in the top left corner.
285 *
286 * @param title
287 * The title to assign to this Frame
288 */
289 public void setTitle(String title) {
290 if (title == null || title == "")
291 return;
292
293 boolean oldchange = _change;
294
295 // remove any numbering this title has
296 title = title.replaceAll("^\\d*[.] *", "");
297 Text frameTitle = getTitle();
298
299 if (frameTitle == null) {
300 if (UserSettings.TitleTemplate == null) {
301 frameTitle = new Text(getNextItemID(), title);
302 frameTitle.setPosition(Item.MARGIN_LEFT
303 + org.expeditee.io.Conversion.X_ADJUST,
304 org.expeditee.io.Conversion.Y_ADJUST);
305 } else {
306 frameTitle = UserSettings.TitleTemplate.copy();
307 frameTitle.setID(this.getNextItemID());
308 frameTitle.setText(title);
309 }
310 addItem(frameTitle);
311 } else {
312 frameTitle.setText(title);
313 title = ItemUtils.StripTagSymbol(title);
314 String autoBulletText = FrameKeyboardActions.getAutoBullet(title);
315 if (autoBulletText.length() > 0)
316 frameTitle.stripFirstWord();
317 }
318 //TODO Widgets... check this out
319 // Brook: Cannot figure what is going on above... widget annot titles should be stripped always
320 if (ItemUtils.isTag(frameTitle, ItemUtils.GetTag(ItemUtils.TAG_IWIDGET))) {
321 frameTitle.stripFirstWord();
322 }
323
324 FrameUtils.Parse(this);
325
326 // do not save if this is the only change
327 setChanged(oldchange);
328 }
329
330 public Text getTitle() {
331 List<Item> items = getItems();
332 for (Item i : items) {
333 if (i instanceof Text)
334 return (Text) i;
335 }
336
337 return null;
338 }
339
340 public Text getFrameNameItem() {
341 return _frameName;
342 }
343
344 public Text getItemTemplate() {
345 Text t = UserSettings.ItemTemplate;
346
347 // check for an updated template...
348 for (Item i : this.getItems()) {
349 if (ItemUtils.isTag(i, ItemUtils.TAG_ITEM_TEMPLATE)) {
350 t = (Text) i;
351 break;
352 }
353 }
354
355 // If the item is linked apply any attribute pairs on the child frame
356 String link = t.getAbsoluteLink();
357 // need to get link first because copy doesnt copy the link
358 t = t.copy();
359 if (link != null) {
360 t.setLink(null);
361 Frame childFrame = FrameIO.LoadFrame(link);
362 if (childFrame != null) {
363 // read in attribute value pairs
364 for (Text attribute : childFrame.getBodyTextItems(false)) {
365 AttributeUtils.SetAttribute(t, attribute);
366 }
367 }
368 }
369
370 return t;
371 }
372
373 public Text getAnnotationTemplate() {
374 Text t = null;
375 // check for an updated template...
376 for (Item i : this.getItems()) {
377 if (ItemUtils.isTag(i, ItemUtils.TAG_ANNOTATION_TEMPLATE)) {
378 t = (Text) i;
379 break;
380 }
381 }
382
383 if (t == null) {
384 if (UserSettings.AnnotationTemplate != null)
385 t = UserSettings.AnnotationTemplate;
386 else
387 t = getItemTemplate();
388 }
389
390 return t.copy();
391 }
392
393 public Text getCodeCommentTemplate() {
394 Text t = null;
395
396 // check for an updated template...
397 for (Item i : this.getItems()) {
398 if (ItemUtils.isTag(i, ItemUtils.TAG_CODE_COMMENT_TEMPLATE)) {
399 t = (Text) i;
400 break;
401 }
402 }
403
404 if (t == null) {
405 if (UserSettings.CodeCommentTemplate != null)
406 t = UserSettings.CodeCommentTemplate;
407 else
408 t = getItemTemplate();
409 }
410
411 return t.copy();
412 }
413
414 /**
415 * Returns any items on this frame that are within the given Shape. Also
416 * returns any Items on overlay frames that are within the Shape.
417 *
418 * @param shape
419 * The Shape to search for Items in
420 * @return All Items on this Frame or overlayed Frames for which
421 * Item.intersects(shape) return true.
422 */
423 public List<Item> getItemsWithin(Polygon poly) {
424 ArrayList<Item> results = new ArrayList<Item>();
425
426 for (Item i : _body)
427 if (i.isVisible() /*&& i != _frameName*/ && i.intersects(poly)) {
428 if (!results.contains(i))
429 results.add(i);
430 }
431
432 for (Overlay o : _overlays)
433 results.addAll(o.Frame.getItemsWithin(poly));
434
435 return results;
436 }
437
438 /**
439 * Sets the name of this Frame to the given String, to be displayed in the
440 * upper right corner.
441 *
442 * @param name
443 * The name to use for this Frame.
444 */
445 public void setFrameset(String name) {
446 _frameset = name;
447 }
448
449 public void setFrameName(String framename) {
450 int num = Conversion.getFrameNumber(framename);
451 String frameset = Conversion.getFrameset(framename, false);
452
453 setFrameset(frameset);
454 setFrameNumber(num);
455 }
456
457 /**
458 * Sets the frame number of this Frame to the given integer
459 *
460 * @param number
461 * The number to set as the frame number
462 */
463 public void setFrameNumber(int number) {
464 _number = number;
465 boolean oldchange = _change;
466
467 int id;
468
469 if (_frameName != null) {
470 id = _frameName.getID();
471 } else{
472 id = -1 * getNextItemID();
473 }
474 _frameName = new Text(id);
475 _frameName.setParent(this);
476 _frameName.setMaxSize(FrameGraphics.getMaxFrameSize());
477 _frameName.setText(getFramesetName() + _number);
478 _frameName.setPosition(FrameGraphics.getMaxFrameSize().width
479 - _frameName.getBoundsWidth() - Item.MARGIN_RIGHT
480 - org.expeditee.io.Conversion.X_ADJUST,
481 org.expeditee.io.Conversion.Y_ADJUST);
482 setChanged(oldchange);
483 }
484
485 /**
486 * Returns the number of this Frame.
487 *
488 * @return The Frame number of this Frame or -1 if it is not set.
489 */
490 public int getFrameNumber() {
491 return _number;
492 }
493
494 /**
495 * Sets the version of this Frame to the given String.
496 *
497 * @param version
498 * The version to use for this Frame.
499 */
500 public void setVersion(int version) {
501 _version = version;
502 }
503
504 /**
505 * Sets the format version of this Frame to the given String.
506 *
507 * @param version
508 * The format version to use for this Frame.
509 */
510 public void setFormatVersion(int version) {
511 _fversion = version;
512 }
513
514 /**
515 * Sets the protection of this Frame to the given String.
516 *
517 * @param protection
518 * The protection to use for this Frame.
519 */
520 public void setProtection(String protection) {
521 _protection = protection;
522 }
523
524 /**
525 * Sets the owner of this Frame to the given String.
526 *
527 * @param owner
528 * The owner to use for this Frame.
529 */
530 public void setOwner(String owner) {
531 _owner = owner;
532 }
533
534 /**
535 * Sets the created date of this Frame to the given String.
536 *
537 * @param date
538 * The date to use for this Frame.
539 */
540 public void setDateCreated(String date) {
541 _creationDate = date;
542 _modifiedDate = date;
543 for (Item i : _body) {
544 i.setDateCreated(date);
545 }
546 }
547
548 public void resetDateCreated() {
549 setDateCreated(Logger.EasyDateFormat("ddMMMyyyy:HHmm"));
550 }
551
552 /**
553 * Sets the last modifying user of this Frame to the given String.
554 *
555 * @param user
556 * The user to set as the last modifying user.
557 */
558 public void setLastModifyUser(String user) {
559 _modifiedUser = user;
560 }
561
562 /**
563 * Sets the last modified date of this Frame to the given String.
564 *
565 * @param date
566 * The date to set as the last modified date.
567 */
568 public void setLastModifyDate(String date) {
569 _modifiedDate = date;
570 }
571
572 /**
573 * Sets the last frozen date of this Frame to the given String.
574 *
575 * @param date
576 * The date to set as the last frozen date.
577 */
578 public void setFrozenDate(String date) {
579 _frozenDate = date;
580 }
581
582 public void setResort(boolean value) {
583 _sorted = !value;
584 }
585
586 /**
587 * Adds the given Item to the body of this Frame.
588 *
589 * @param item
590 * The Item to add to this Frame.
591 */
592 public void addItem(Item item) {
593 if (item != null) {
594 if (_body.contains(item)) {
595 //System.out.println("Item (" + item.getClass().getSimpleName()
596 // + ") with ID " + item.getID() + " already in body.");
597 return;
598 }
599
600 if (item instanceof Line)
601 _lineCount++;
602
603 _itemCount = Math.max(_itemCount, item.getID());
604
605 _body.add(item);
606 item.setParent(this);
607
608 _sorted = false;
609
610 item.setMaxSize(FrameGraphics.getMaxFrameSize());
611 //add widget items to the list of widgets
612 if (item instanceof WidgetCorner) {
613 InteractiveWidget iw = ((WidgetCorner)item).getWidgetSource();
614 if (!this._iWidgets.contains(iw)) { // A set would have been best
615 _iWidgets.add(iw);
616 }
617 }
618
619 item.onParentStateChanged(new ItemParentStateChangedEvent(
620 this, ItemParentStateChangedEvent.EVENT_TYPE_ADDED));
621
622 change();
623 }
624 }
625
626 public void setMaxSize(Dimension max) {
627 if (max == null)
628 return;
629
630 for (Item i : _body)
631 i.setMaxSize(max);
632
633 _frameName.setPosition(FrameGraphics.getMaxFrameSize().width
634 - _frameName.getBoundsWidth() - Item.MARGIN_RIGHT
635 - org.expeditee.io.Conversion.X_ADJUST,
636 org.expeditee.io.Conversion.Y_ADJUST);
637 }
638
639 public void addAllItems(Collection<Item> toAdd) {
640 for (Item i : toAdd)
641 addItem(i);
642 }
643
644 public void removeAllItems(Collection<Item> toRemove) {
645 for (Item i : toRemove)
646 removeItem(i);
647 }
648
649 public void removeItem(Item item) {
650 if (_body.remove(item))
651 change();
652
653 // Remove widgets from the widget list
654 if (item != null) {
655 item.onParentStateChanged(new ItemParentStateChangedEvent(
656 this, ItemParentStateChangedEvent.EVENT_TYPE_REMOVED));
657 if (item instanceof WidgetCorner) {
658 _iWidgets.remove(((WidgetCorner)item).getWidgetSource());
659 }
660 }
661
662 }
663
664 /**
665 * Adds the given list of Items to the undo stack. This is the same as
666 * calling addToUndo() for each Item in the list.
667 *
668 * @param items
669 * The List of Items to add to the undo stack.
670 */
671 public void addAllToUndo(List<Item> items) {
672 if (items.size() < 1)
673 return;
674
675 String id = "" + _undo.size();
676
677 for (Item i : items) {
678 i.setData(id);
679 _undo.push(i);
680 }
681 }
682
683 public void addToUndo(Item item) {
684 if (item == null)
685 return;
686
687 item.setData("" + _undo.size());
688 _undo.push(item);
689 }
690
691 public void undo() {
692 Item undo = null;
693
694 if (_undo.size() <= 0)
695 return;
696
697 undo = _undo.pop();
698
699 // if the change was to characteristics
700 if (undo.isVisible() && _body.contains(undo)) {
701 Item old = _body.get(_body.indexOf(undo));
702 _body.set(_body.indexOf(old), undo);
703 // the item was deleted
704 } else {
705 List<Item> toRestore = new LinkedList<Item>();
706 toRestore.add(undo);
707
708 // remove any connected items at the top of the stack
709 while (_undo.size() > 0) {
710 Item next = _undo.peek();
711 // if this item was connected to one already picked up, remove
712 // it from the stack
713 if (toRestore.contains(next))
714 _undo.pop();
715 // else, if this item should be restored (deleted in an enclosed
716 // set)
717 else if (next.getData().equals(undo.getData())) {
718 _undo.pop();
719 toRestore.add(next);
720 // otherwise, we are done
721 } else
722 break;
723 }
724
725 // if these items were deleted from a frame, add them
726 addAllItems(toRestore);
727
728 for (Item i : toRestore) {
729 if (i instanceof Line) {
730 Line line = (Line) i;
731 line.getStartItem().addLine(line);
732 line.getEndItem().addLine(line);
733 } else {
734 i.setOffset(0, 0);
735 }
736 }
737 }
738
739 change();
740 FrameGraphics.Repaint();
741 ItemUtils.EnclosedCheck(_body);
742 }
743
744 /**
745 * Returns the frameset of this Frame
746 *
747 * @return The name of this Frame's frameset.
748 */
749 public String getFramesetName() {
750 return _frameset;
751 }
752
753 public String getFrameName() {
754 return getFramesetName() + _number;
755 }
756
757 /**
758 * Returns the format version of this Frame
759 *
760 * @return The version of this Frame.
761 */
762 public int getVersion() {
763 return _version;
764 }
765
766 public int getFormatVersion() {
767 return _fversion;
768 }
769
770 public String getProtection() {
771 return _protection;
772 }
773
774 public String getOwner() {
775 return _owner;
776 }
777
778 public String getDateCreated() {
779 return _creationDate;
780 }
781
782 public String getLastModifyUser() {
783 return _modifiedUser;
784 }
785
786 public String getLastModifyDate() {
787 return _modifiedDate;
788 }
789
790 public String getFrozenDate() {
791 return _frozenDate;
792 }
793
794 public void setBackgroundColor(Color back) {
795 _background = back;
796 change();
797 FrameGraphics.Repaint();
798 }
799
800 public Color getBackgroundColor() {
801 return _background;
802 }
803
804 public Color getPaintBackgroundColor() {
805 if (_background == null)
806 return DisplayIO.DEFAULT_BACKGROUND;
807
808 return _background;
809 }
810
811 public void setForegroundColor(Color front) {
812 _foreground = front;
813 change();
814 FrameGraphics.Repaint();
815 }
816
817 public Color getForegroundColor() {
818 return _foreground;
819 }
820
821 public Color getPaintForegroundColor() {
822 final int GRAY = 127;
823 final int THRESHOLD = 10;
824
825 if (_foreground == null) {
826 Color back = getPaintBackgroundColor();
827 if (Math.abs(back.getRed() - GRAY) < THRESHOLD
828 && Math.abs(back.getBlue() - GRAY) < THRESHOLD
829 && Math.abs(back.getGreen() - GRAY) < THRESHOLD)
830 return Color.WHITE;
831
832 Color fore = new Color(Math.abs(255 - back.getRed()), Math
833 .abs(255 - back.getGreen()), Math.abs(255 - back.getBlue()));
834 return fore;
835 // return Item.DEFAULT_FOREGROUND;
836 }
837
838 return _foreground;
839 }
840
841 public String toString() {
842 String s = "";
843 s += "Name: " + _frameset + _number + "\n";
844 s += "Version: " + _version + "\n";
845 s += "Format Version: " + _fversion + "\n";
846 s += "Protection: " + _protection + "\n";
847 s += "Owner: " + _owner + "\n";
848 s += "Date Created: " + _creationDate + "\n";
849 s += "Last Mod. User: " + _modifiedUser + "\n";
850 s += "Last Mod. Date: " + _modifiedDate + "\n";
851 s += "Last Froz. Date: " + _frozenDate + "\n";
852
853 s += "\n";
854 s += "\n";
855
856 s += "Items: " + _body.size() + "\n";
857
858 return s;
859 }
860
861 public Item getItemAbove(Item current) {
862 int ind = _body.indexOf(current);
863 if (ind == -1)
864 return null;
865
866 // loop through all items above this one, return the first match
867 for (int i = ind - 1; i >= 0; i--) {
868 Item check = _body.get(i);
869 if (check.isVisible() && FrameUtils.inSameColumn(check, current))
870 return check;
871 }
872
873 return null;
874 }
875
876 /**
877 * Updates any Images that require it from their ImageObserver (Principally
878 * Animated GIFs)
879 */
880 public boolean imageUpdate(Image img, int infoflags, int x, int y,
881 int width, int height) {
882 FrameGraphics.ForceRepaint();
883
884 if (DisplayIO.getCurrentFrame() == this)
885 return true;
886
887 return false;
888 }
889
890 /**
891 * Gets the text items that are in the same column and below a specified
892 * item. Frame title and name are excluded from the column list.
893 *
894 * @param from
895 * The Item to get the column for.
896 */
897 public List<Item> getColumn(Item from) {
898 // Check that this item is on the current frame
899 if (!_body.contains(from))
900 return null;
901
902 // Make sure the items are sorted
903 Collections.sort(_body);
904
905 if (from == null) {
906 from = getLastNonAnnotationTextItem();
907 }
908
909 if (from == null)
910 return null;
911
912 /**
913 * TODO: Check
914 */
915
916 List<Item> column = new ArrayList<Item>();
917
918 // Create a list of items consisting of the item 'from' and all the
919 // items below it which are also in the same column as it
920 for (int i = _body.indexOf(from); i < _body.size(); i++) {
921 Item item = _body.get(i);
922 if (item.isVisible() && isNormalTextItem(item)) {
923 if (FrameUtils.inSameColumn(from, item))
924 column.add(item);
925 }
926 }
927
928 return column;
929 }
930
931 /**
932 * Adds the given Frame to the list of overlays Frames being drawn with this
933 * Frame.
934 *
935 * @param overlay
936 * The Frame to add
937 *
938 * @throws NullPointerException
939 * If overlay is null.
940 */
941 public void addOverlay(Overlay overlay) {
942 if (overlay == null) throw new NullPointerException("overlay");
943 if (_overlays.contains(overlay)) return;
944
945 _overlays.add(overlay);
946
947 // Items must be notified that they have been added to this frame via the overlay...
948 List<Item> items = new LinkedList<Item>();
949 FrameGraphics.AddAllOverlayItems(items, overlay.Frame, new LinkedList<Frame>());
950 for (Item i : items) {
951 i.onParentStateChanged(new ItemParentStateChangedEvent(
952 this,
953 ItemParentStateChangedEvent.EVENT_TYPE_ADDED_VIA_OVERLAY,
954 overlay.Level));
955 }
956 }
957
958 /**
959 * Removes the given overlay from the list of overlays being drawn with this Frame.
960 *
961 * @param overlay
962 * The overlay to remove
963 *
964 * @throws NullPointerException
965 * If overlay is null.
966 */
967 public void removeOverlay(Overlay overlay) {
968 if (overlay == null) throw new NullPointerException("overlay");
969
970 this._overlays.remove(overlay);
971
972 // Items must be notified that they have been removed from this frame via the overlay...
973 List<Item> items = new LinkedList<Item>();
974 FrameGraphics.AddAllOverlayItems(items, overlay.Frame, new LinkedList<Frame>());
975 for (Item i : items) {
976 i.onParentStateChanged(new ItemParentStateChangedEvent(
977 this,
978 ItemParentStateChangedEvent.EVENT_TYPE_REMOVED_VIA_OVERLAY,
979 overlay.Level));
980 }
981 }
982
983 /**
984 * Removes the given Frame from the list of overlayed Frames being drawn with
985 * this Frame.
986 *
987 * @param overlayedFrame
988 * The Frame to remove
989 *
990 * @throws NullPointerException
991 * If overlayedFrame is null.
992 */
993 public void removeOverlay(Frame overlayedFrame) {
994 if (overlayedFrame == null) throw new NullPointerException("overlay");
995
996 // Locate the oveylay(s) that match this
997 List<Overlay> overlaysToRemove = new LinkedList<Overlay>();
998 for (Overlay o : _overlays) {
999 if (overlayedFrame.equals(o.Frame)) overlaysToRemove.add(o);
1000 }
1001 for (Overlay o : overlaysToRemove) { // must be enumerated seperate to above...
1002 removeOverlay(o);
1003 }
1004
1005 }
1006
1007 public List<Overlay> getOverlays() {
1008 List<Overlay> l = new LinkedList<Overlay>();
1009 l.addAll(_overlays);
1010 return l;
1011 }
1012
1013 /**
1014 * @return All overlays seen by this frame (including its overlays' overlays).
1015 */
1016 public List<Overlay> getOverlaysDeep() {
1017 List<Overlay> l = new LinkedList<Overlay>();
1018 getOverlaysDeep(l, this, new LinkedList<Frame>());
1019 return l;
1020 }
1021
1022 private boolean getOverlaysDeep(List<Overlay> overlays, Frame overlay, List<Frame> seenOverlays) {
1023
1024 if (seenOverlays.contains(overlay))
1025 return false;
1026
1027 seenOverlays.add(overlay);
1028
1029 for (Overlay o : overlay.getOverlays()) {
1030 if (getOverlaysDeep(overlays, o.Frame, seenOverlays)) {
1031 overlays.add(o);
1032 }
1033 }
1034
1035 return true;
1036 }
1037
1038 /**
1039 * Gets the overlay on this frame which owns the given item.
1040 * @param item The item - must not be null.
1041 * @return The overlay that contains the itm. Null if no overlay owns the item.
1042 */
1043 public Overlay getOverlayOwner(Item item) {
1044 if (item == null) throw new NullPointerException("item");
1045 List<Overlay> overlays = getOverlaysDeep();
1046 for (Overlay l : overlays) {
1047 //if (l.Frame.containsItem(item)) return l;
1048 if (item.getParent() == l.Frame) return l;
1049 }
1050
1051 return null;
1052 }
1053
1054 public void clearOverlays() {
1055 while (!_overlays.isEmpty()) {
1056 removeOverlay(_overlays.get(0)); // centralise removing
1057 }
1058 }
1059
1060 public void addAllOverlays(List<Overlay> overlays) {
1061 for (Overlay o : overlays) {
1062 addOverlay(o); // centralise adding
1063 }
1064 }
1065
1066 @Override
1067 public boolean equals(Object o) {
1068 if (o instanceof String) {
1069 return (String.CASE_INSENSITIVE_ORDER.compare((String) o,
1070 getFrameName()) == 0);
1071 }
1072
1073 if (o instanceof Frame) {
1074 return getFrameName().equals(((Frame) o).getFrameName());
1075 }
1076
1077 return super.equals(o);
1078 }
1079
1080 /**
1081 * Merge one frames contents into another.
1082 *
1083 * @param toMergeWith
1084 */
1085 private void merge(Frame toMergeWith) {
1086 if (toMergeWith == null)
1087 return;
1088
1089 List<Item> copies = ItemUtils.CopyItems(toMergeWith.getItems());
1090 copies.remove(toMergeWith.getFrameNameItem());
1091
1092 for (Item i : copies) {
1093 if (i.getID() >= 0) {
1094 i.setID(this.getNextItemID());
1095 addItem(i);
1096 }
1097 }
1098 }
1099
1100 /**
1101 * TODO document what this method is actually doing and why Merge text?!?!
1102 *
1103 * @param toMerge
1104 * @return the items that cant be merged?!?!
1105 */
1106 public List<Item> merge(List<Item> toMerge) {
1107 ArrayList<Item> remain = new ArrayList<Item>(0);
1108
1109 for (Item i : toMerge) {
1110 if (!(i instanceof Text))
1111 remain.add(i);
1112 else {
1113 if (!AttributeUtils.SetAttribute(this, (Text) i)) {
1114 if (i.getLink() != null)
1115 merge(FrameIO.LoadFrame(i.getAbsoluteLink()));
1116 else if (FrameIO
1117 .isValidFrameName(((Text) i).getFirstLine())) {
1118 // If we get hear we are merging frames
1119 merge(FrameIO.LoadFrame(((Text) i).getFirstLine()));
1120 }
1121 }
1122 }
1123 }
1124
1125 return remain;
1126 }
1127
1128 /**
1129 * Removes all non-title non-annotation items from this Frame. All removed
1130 * items are added to the backup-stack.
1131 */
1132 public void clear() {
1133 List<Item> newBody = new ArrayList<Item>(0);
1134 for (Item i : _body)
1135 if (i.isAnnotation() || i == getFrameNameItem() || i == getTitle())
1136 newBody.add(i);
1137
1138 _body.removeAll(newBody);
1139 addAllToUndo(_body);
1140 _body = newBody;
1141 }
1142
1143 /**
1144 * Creates a new text item with the given text.
1145 * @param text
1146 * @return
1147 */
1148 public Text createNewText(String text) {
1149 Text t = createBlankText(text);
1150 t.setText(text);
1151 return t;
1152 }
1153
1154 /**
1155 * Creates a new Text Item with no text. The newly created Item is a copy
1156 * the ItemTemplate if one is present, and inherits all the attributes of
1157 * the Template
1158 *
1159 * @return The newly created Text Item
1160 */
1161 public Text createBlankText(String templateType) {
1162 Text t;
1163 if (templateType.length() == 0)
1164 t = getItemTemplate().copy();
1165 else
1166 t = getItemTemplate(templateType.charAt(0));
1167
1168 // reset attributes
1169 t.setID(getNextItemID());
1170 t.setMaxSize(FrameGraphics.getMaxFrameSize());
1171 t.setPosition(DisplayIO.getMouseX(), DisplayIO.getMouseY());
1172 t.setText("");
1173 t.setParent(this);
1174 return t;
1175 }
1176
1177 private Text getItemTemplate(char firstChar) {
1178 switch (firstChar) {
1179 case '@':
1180 return getAnnotationTemplate();
1181 case '/':
1182 case '#':
1183 return getCodeCommentTemplate();
1184 default:
1185 return getItemTemplate();
1186 }
1187 }
1188
1189 public Text createNewText() {
1190 return createNewText("");
1191 }
1192
1193 public Text addText(int x, int y, String text, String action) {
1194 Text t = createNewText(text);
1195 t.setPosition(x, y);
1196 t.addAction(action);
1197
1198 addItem(t);
1199 return t;
1200 }
1201
1202 public Text addText(int x, int y, String text, String action, String link) {
1203 Text t = addText(x, y, text, action);
1204 t.setLink(link);
1205 return t;
1206 }
1207
1208 public Dot addDot(int x, int y) {
1209 Dot d = new Dot(x, y, getNextItemID());
1210 addItem(d);
1211 return d;
1212 }
1213
1214 public boolean isSaved() {
1215 return _saved;
1216 }
1217
1218 public void setSaved() {
1219 _saved = true;
1220 _change = false;
1221 }
1222
1223 public static boolean rubberbandingLine() {
1224 return FreeItems.size() == 2
1225 && (FreeItems.get(0) instanceof Line || FreeItems.get(1) instanceof Line);
1226 }
1227
1228 public static boolean itemAttachedToCursor() {
1229 return FreeItems.size() > 0;
1230 }
1231
1232 public static boolean textItemAttachedToCursor() {
1233 return itemAttachedToCursor() && FreeItems.get(0) instanceof Text;
1234 }
1235
1236 public static Item getItemAttachedToCursor() {
1237 if (itemAttachedToCursor())
1238 return FreeItems.get(0);
1239
1240 return null;
1241 }
1242
1243 /**
1244 * Tests if an item is a non title, non frame name, non special annotation
1245 * text item.
1246 *
1247 * @param it
1248 * the item to be tested
1249 * @return true if the item is a normal text item
1250 */
1251 public boolean isNormalTextItem(Item it) {
1252 if (it instanceof Text && it != getTitle() && it != _frameName
1253 && !((Text) it).isSpecialAnnotation()) {
1254 return true;
1255 }
1256
1257 return false;
1258 }
1259
1260 /**
1261 * Moves the mouse to the end of the text item with a specified index.
1262 *
1263 * @param index
1264 */
1265 public boolean moveMouseToTextItem(int index) {
1266 List<Item> items = getItems();
1267 int itemsFound = 0;
1268 for (int i = 0; i < items.size(); i++) {
1269 Item it = items.get(i);
1270 if (isNormalTextItem(it))
1271 itemsFound++;
1272 if (itemsFound > index) {
1273 DisplayIO.setCursorPosition(((Text) it)
1274 .getEndParagraphPosition().x, it.getY());
1275 DisplayIO.resetCursorOffset();
1276 FrameGraphics.Repaint();
1277 return true;
1278 }
1279 }
1280
1281 return false;
1282 }
1283
1284 /*
1285 * public boolean moveMouseToNextTextItem(int index) { List<Item> items =
1286 * getItems(); int itemsFound = 0; for (int i = 0; i < items.size(); i++) {
1287 * Item it = items.get(i); if ( isNormalTextItem(it)) itemsFound++; if
1288 * (itemsFound > index) {
1289 * DisplayIO.setCursorPosition(((Text)it).getEndParagraphPosition().x,
1290 * it.getY()); DisplayIO.resetCursorOffset(); FrameGraphics.Repaint();
1291 * return true; } }
1292 *
1293 * return false; }
1294 */
1295
1296 /**
1297 * Searches for an annotation item called start to be used as the default
1298 * cursor location when TDFC occurs.
1299 */
1300 public boolean moveMouseToDefaultLocation() {
1301 List<Item> items = getItems();
1302
1303 for (Item it : items) {
1304 if (it instanceof Text) {
1305 Text t = (Text) it;
1306 if (t.getTextNoList().toLowerCase().startsWith("@start")
1307 || t.getTextNoList().toLowerCase().equals("@start:")) {
1308 t.stripFirstWord();
1309
1310 if (t.getTextNoList().equals(""))
1311 DisplayIO.getCurrentFrame().removeItem(t);
1312 if (!Frame.itemAttachedToCursor()) {
1313 DisplayIO.setCursorPosition(((Text) it)
1314 .getEndParagraphPosition());
1315 DisplayIO.resetCursorOffset();
1316 }
1317 FrameGraphics.Repaint();
1318 return true;
1319 }
1320 }
1321 }
1322
1323 return false;
1324 }
1325
1326 /**
1327 * Gets the file name that actions should use to export files created by
1328 * running actions from this frame.
1329 *
1330 * @return the fileName if the frame contains an '@file' tag. Returns the
1331 * name of the frame if the tag isnt on the frame.
1332 */
1333 public String getExportFileName() {
1334 Text tag = ItemUtils.FindTag(getItems(), "@file:");
1335 if (tag != null) {
1336 String file = ItemUtils.StripTag(tag.getFirstLine(), "@file:");
1337 file = file.trim();
1338 if (file.length() > 0)
1339 return file;
1340 }
1341
1342 return _frameName.getTextNoList();
1343 }
1344
1345 public void toggleBackgroundColor() {
1346 setBackgroundColor(ColorUtils.getNextColor(_background,
1347 Frame.COLOR_WHEEL));
1348 }
1349}
Note: See TracBrowser for help on using the repository browser.