Ignore:
Timestamp:
05/10/18 16:04:51 (6 years ago)
Author:
davidb
Message:

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/expeditee/gui/FrameUtils.java

    r1064 r1102  
    1919package org.expeditee.gui;
    2020
    21 import java.awt.Color;
    22 import java.awt.Point;
    23 import java.awt.Polygon;
    24 import java.awt.Rectangle;
    2521import java.io.File;
    2622import java.io.FileInputStream;
     
    4440import java.util.zip.ZipEntry;
    4541
     42import org.expeditee.core.Colour;
     43import org.expeditee.core.Point;
     44import org.expeditee.core.bounds.AxisAlignedBoxBounds;
     45import org.expeditee.core.bounds.PolygonBounds;
     46import org.expeditee.gio.EcosystemManager;
     47import org.expeditee.gio.gesture.StandardGestureActions;
    4648import org.expeditee.items.Circle;
    4749import org.expeditee.items.Dot;
     
    6062import org.expeditee.items.XRayable;
    6163import org.expeditee.items.widgets.ButtonWidget;
    62 import org.expeditee.items.widgets.InteractiveWidget;
     64import org.expeditee.items.widgets.Widget;
    6365import org.expeditee.items.widgets.InteractiveWidgetInitialisationFailedException;
    6466import org.expeditee.items.widgets.InteractiveWidgetNotAvailableException;
     
    7375public class FrameUtils {
    7476
    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
    260654                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)
    411670                        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        }
    4281275       
    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
    5081412                } 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");
    5441822               
    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;
    15251824               
    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:");
    15501826               
    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 links
    1599         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 index
    1605                 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 pages
    1633                     if (indexFrame != null
    1634                             && 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 Settings
    1652         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 title
    1659                 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 startpage
    1674                     for (int i = 0; i < startPages.length; i++) {
    1675                         if (framesetName.equals(startPages[i])) {
    1676                             Frame indexFrame = FrameIO
    1677                                     .LoadFrame(framesetName + '1');
    1678 
    1679                             // Add start page link
    1680                             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 frameset
    1697         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 waiting
    1711         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 saved
    1715             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 @i
    1741         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 box
    1754                     // around it
    1755                     String text = LastEdited.getText();
    1756                     if (text.startsWith("@i:")
    1757                             && !Character
    1758                                     .isDigit(text.charAt(text.length() - 1))) {
    1759                         Collection<Item> enclosure = FrameUtils
    1760                                 .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                                     LastEdited
    1768                                             .setText(LastEdited.getText()
    1769                                                     + " "
    1770                                                     + Math.round(rect
    1771                                                             .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 mode
    1791                 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 into
    1818      * ${PARENT_FOLDER} (~/.expeditee)
    1819      *
    1820      * @param force if true, resources will be extracted even if they have already been extracted before
    1821      */
    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:");
    18281827                try     {
    18291828                        check.getParentFile().mkdirs();
    1830                 check.createNewFile();
    1831                
     1829                        check.createNewFile();
     1830
    18321831                        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    18331832                        URL docURL = classLoader.getResource("org/expeditee/assets/resources");
    1834                        
     1833
    18351834                        // copy files from the jar file to the profile folder
    18361835                        if (docURL.getProtocol().equals("jar")) {
     
    18401839                                String res = "org/expeditee/assets/resources/";
    18411840                                int resLength = res.length();
    1842                                
     1841
    18431842                                ZipEntry ze;
    1844                                
     1843
    18451844                                while(jarEntries.hasMoreElements()) {
    18461845                                        ze = jarEntries.nextElement();
     
    18501849                                        File out = new File(FrameIO.PARENT_FOLDER + ze.getName().substring(resLength));
    18511850                                        // System.out.println("Didn't crash here " + out.getPath());
    1852 //                                      if(out.exists()) {
    1853 //                                              continue;
    1854 //                                      }
     1851                                        //                                      if(out.exists()) {
     1852                                        //                                              continue;
     1853                                        //                                      }
    18551854                                        if(ze.isDirectory()) {
    18561855                                                // System.out.println(out.getPath() + " IS DIRECTORY");
     
    18811880                                        }
    18821881                                }
    1883                                
    1884                         // Copy files from the source folder to the profile folder
     1882
     1883                                // Copy files from the source folder to the profile folder
    18851884                        } else if (docURL.getProtocol().equals("bundleresource")) {
    18861885                                final URLConnection urlConnection = docURL.openConnection();
     
    18991898        }
    19001899
    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();
    19391940                FileOutputStream fOut = null;
    19401941                FileInputStream fIn = null;
     
    19591960                        }
    19601961                }
    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        }
    19791982}
Note: See TracChangeset for help on using the changeset viewer.