Changeset 975


Ignore:
Timestamp:
11/24/15 11:17:31 (8 years ago)
Author:
bln4
Message:

When attempting to run a action and finding multiple potential matches (overloaded methods) it now attempts to match the candidate with the most parameters without going over.

For example: running the action "RunJava 100"
-with available actions RunJava() and RunJava(String)
-will now reliably run RunJava(String)

However; some potential confusion still exists; take the same example: running the action "RunJava 100"
-but this time has available actions RunJava(), RunJava(String) and RunJava(Integer)
-whichever it sees first; either the String or the Integer variant will get run
-furthermore it appears nondeterministic over which it will find first. on any given run of Expeditee it will consistently find the same one; however a restart may produce varying results.
-as this behaviour was not noticed for some time my current theory is that it has something to do with the order things get compiled; it was scala code (SpIDER) that first exhibited this problem. Scala compilation does things with inner classes. More investigation needed if we want a answer as to 'why'

Location:
trunk/src/org/expeditee
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/expeditee/actions/Actions.java

    r919 r975  
    2020
    2121import java.awt.GraphicsEnvironment;
    22 import java.io.File;
    23 import java.io.IOException;
    2422import java.lang.reflect.Constructor;
    2523import java.lang.reflect.Method;
    2624import java.lang.reflect.Modifier;
    27 import java.net.URL;
    28 import java.net.URI;
    29 import java.net.URLDecoder;
    30 import java.net.JarURLConnection;
    3125import java.rmi.UnexpectedException;
    32 import java.util.ArrayList;
    3326import java.util.Collection;
    34 import java.util.Enumeration;
     27import java.util.Comparator;
    3528import java.util.HashMap;
    3629import java.util.LinkedList;
    3730import java.util.List;
    3831import java.util.Set;
    39 import java.util.jar.JarEntry;
    40 import java.util.jar.JarFile;
    41 import java.util.zip.ZipEntry;
    4232
    4333import org.expeditee.agents.Agent;
     
    5444import org.expeditee.items.Text;
    5545import org.expeditee.reflection.PackageLoader;
    56 import org.expeditee.settings.UserSettings;
    5746import org.expeditee.simple.SString;
    5847import org.expeditee.stats.Logger;
     
    6150 * The Action class is used to launch Actions and Agents.
    6251 *
    63  * This class checks all class files in the same directory, and reads in and adds all the methods from them. The methods
    64  * are stored in a Hashtable so that the lowercase method names can be mapped to the correctly capatilized method names
    65  * (to provide case-insensitivity)
     52 * This class checks all class files in the same directory, and reads in and
     53 * adds all the methods from them. The methods are stored in a Hashtable so that
     54 * the lowercase method names can be mapped to the correctly capatilized method
     55 * names (to provide case-insensitivity)
    6656 *
    67  * When adding an action to a class in the actions folder the following must be considered: <li>If the first parameter
    68  * is of type Frame, the current frame will be passed as a parameter. <li>If the next param is of type Item the item on
    69  * the end of the cursor will be passed or the item that was clicked to execute the action if nothing is on the end of
    70  * the cursor. current frame or item.</li> <li>If there are multiple overloads for the same method they should be
    71  * declared in order of the methods with the most parameteres to least parameters.</li>
     57 * When adding an action to a class in the actions folder the following must be
     58 * considered: <li>If the first parameter is of type Frame, the current frame
     59 * will be passed as a parameter. <li>If the next param is of type Item the item
     60 * on the end of the cursor will be passed or the item that was clicked to
     61 * execute the action if nothing is on the end of the cursor. current frame or
     62 * item.</li> <li>If there are multiple overloads for the same method they
     63 * should be declared in order of the methods with the most parameteres to least
     64 * parameters.</li>
    7265 */
    7366public class Actions {
     
    9992        public static final String WIDGET_PACKAGE = ROOT_PACKAGE + "items.widgets.";
    10093
    101         public static final String CHARTS_PACKAGE = ROOT_PACKAGE + "items.widgets.charts.";
    102 
    103         public static final String NAVIGATIONS_CLASS = ROOT_PACKAGE + "actions.NavigationActions";
     94        public static final String CHARTS_PACKAGE = ROOT_PACKAGE
     95                        + "items.widgets.charts.";
     96
     97        public static final String NAVIGATIONS_CLASS = ROOT_PACKAGE
     98                        + "actions.NavigationActions";
    10499
    105100        // public static Class[] getClasses(String pckgname)
     
    213208
    214209        /**
    215          * Clears out the Action and JAG Hashtables and refills them. Normally this is only called once when the system
    216          * starts.
    217          *
    218          * @return a warning message if there were any problems loading agents or actions.
     210         * Clears out the Action and JAG Hashtables and refills them. Normally this
     211         * is only called once when the system starts.
     212         *
     213         * @return a warning message if there were any problems loading agents or
     214         *         actions.
    219215         */
    220216        public static Collection<String> Init() {
     
    232228                        }
    233229
    234                        
    235230                        classes = PackageLoader.getClassesNew(WIDGET_PACKAGE);
    236231
     
    241236                        }
    242237
    243                        
    244238                        classes = PackageLoader.getClassesNew(CHARTS_PACKAGE);
    245239
     
    282276
    283277        /**
    284          * Temporary, if a plugin system is devised then this would porbably become redundant. For now this allows external
    285          * agents to be included.
     278         * Temporary, if a plugin system is devised then this would porbably become
     279         * redundant. For now this allows external agents to be included.
    286280         *
    287281         * @param fullClassNames
    288          *            A set of full class names, that is, the class package and name. For
    289          *            example" "org.myplugin.agents.SerializedSearch"
    290          *
    291          * @return A collection of classes their were omitted because either there was a name clash with existing agents or
    292          *         did not exist. i.e. is completely successful this will be empty. Never null.
     282         *            A set of full class names, that is, the class package and
     283         *            name. For example" "org.myplugin.agents.SerializedSearch"
     284         *
     285         * @return A collection of classes their were omitted because either there
     286         *         was a name clash with existing agents or did not exist. i.e. is
     287         *         completely successful this will be empty. Never null.
    293288         *
    294289         * @throws NullPointerException
     
    335330
    336331        /**
    337          * Loads all the Methods that meet the requirements checked by MethodCheck into the hashtable.
     332         * Loads all the Methods that meet the requirements checked by MethodCheck
     333         * into the hashtable.
    338334         *
    339335         * @param c
     
    365361
    366362        /**
    367          * Checks if the given Method corresponds to the restrictions of Action commands, namely: Declared (not inherited),
    368          * Public, and Static, with a void return type.
     363         * Checks if the given Method corresponds to the restrictions of Action
     364         * commands, namely: Declared (not inherited), Public, and Static, with a
     365         * void return type.
    369366         *
    370367         * @param m
     
    392389
    393390        /**
    394          * Performs the given action command. The source Frame and Item are given because they are required by some actions.
    395          * Note that the source frame does not have to be the Item's parent Frame.
     391         * Performs the given action command. The source frame and item are given
     392         * because they are required by some actions. Note that the source frame
     393         * does not ahve to be the items parent frame.
     394         *
     395         * If multiple actions exist with the name command.takeWhile(_ != ' ') then
     396         * it attempts to find candidate that best matches the arguments passed in.
     397         * (arguments are command.dropWhile(_ != ' ') or is floating)
    396398         *
    397399         * @param source
    398          *            The Frame that the action should apply to
     400         *            The frame that the action should apply to
    399401         * @param launcher
    400          *            The Item that has the action assigned to it
     402         *            The item that has the action assigned to it
    401403         * @param command
    402404         *            The action to perform
    403          */
    404         public static Object PerformAction(Frame source, Item launcher, String command) throws Exception {
    405                 // if (!command.equalsIgnoreCase("Restore"))
    406                 // FrameIO.SaveFrame(source, false);
    407                 // TODO make restore UNDO the changes made by the last action
    408 
    409                 // separate method name and parameter names
    410                 String mname = getName(command);
    411                 command = command.substring(mname.length()).trim();
    412                 // If no params are provided get them from a text item on the cursor
    413                 if (command.length() == 0 && launcher instanceof Text && launcher.isFloating()) {
    414                         command = launcher.getText();
    415                 }
    416 
    417                 // Strip off the @ from annotation items
    418                 if (mname.startsWith("@"))
    419                         mname = mname.substring(1);
    420 
    421                 mname = mname.trim();
    422                 String lowercaseName = mname.toLowerCase();
    423                 // check for protection on frame
    424                 if (ItemUtils.ContainsTag(source.getItems(), "@No" + mname)) {
    425                         throw new RuntimeException("Frame is protected by @No" + mname + " tag.");
    426                 }
    427 
    428                 // retrieve methods that match the name
    429                 Method toRun = _Actions.get(lowercaseName);
    430 
    431                 // if this is not the name of a method, it may be the name of an agent
    432                 if (toRun == null) {
    433                         LaunchAgent(mname, command, source, launcher);
     405         * @return
     406         * @throws Exception
     407         */
     408        public static Object PerformAction(final Frame source, final Item launcher,
     409                        final String command) throws Exception {
     410                System.err.println("Running action: " + command + " with floating: " + launcher);
     411                final String actionName = getName(command);
     412                final String parameters = command.substring(actionName.length()).trim();
     413
     414                // Check for protection on frame.
     415                if (ItemUtils.ContainsTag(source.getItems(), "@No" + actionName)) {
     416                        final String errorMsg = "Frame is protected by @No" + actionName
     417                                        + " tag.";
     418                        MessageBay.errorMessage(errorMsg);
     419                        throw new RuntimeException(errorMsg);
     420                }
     421
     422                // Find all canditates. Sort by quantity of arguments.
     423                final String lowercaseName = actionName.toLowerCase();
     424                final Method firstCanditate = _Actions.get(lowercaseName);
     425                //      if this is not the name of a method, it may be the name of an agent
     426                if (firstCanditate == null) {
     427                        LaunchAgent(actionName, command, source, launcher);
    434428                        return null;
    435429                }
    436 
    437                 // Need to save the frame if we are navigating away from it so we dont
    438                 // loose changes
    439                 if (toRun.getDeclaringClass().getName().equals(NAVIGATIONS_CLASS)) {
     430                //      need to save the frame if we are navigating away from it so we dont
     431                //      loose changes
     432                if (firstCanditate.getDeclaringClass().getName().equals(NAVIGATIONS_CLASS)) {
    440433                        FrameIO.SaveFrame(DisplayIO.getCurrentFrame());
    441434                }
    442 
    443                 // if there are duplicate methods with the same name
    444                 List<Method> possibles = new LinkedList<Method>();
    445                 possibles.add(toRun);
     435                final List<Method> canditates = new LinkedList<Method>();
     436                canditates.add(firstCanditate);
    446437                int i = 0;
    447                 while (_Actions.containsKey(lowercaseName + i)) {
    448                         possibles.add(_Actions.get(lowercaseName + i));
    449                         i++;
    450                 }
    451 
    452                 for (Method possible : possibles) {
    453                         // try first with the launching item as a parameter
    454 
    455                         // run method
     438                while (_Actions.containsKey(lowercaseName + i))
     439                        canditates.add(_Actions.get(lowercaseName + i++));
     440                canditates.sort(new Comparator<Method>() {
     441                        @Override
     442                        public int compare(final Method m1, final Method m2) {
     443                                return m2.getParameterCount() - m1.getParameterCount();
     444                        }
     445                });
     446
     447                // Find best candidate. Start searching with the candidate with most
     448                // arguments.
     449                for (final Method canditate : canditates) {
     450                        final Object[] paramObjects = CreateObjects(canditate, source,
     451                                        launcher, parameters);
    456452                        try {
    457                                 // convert parameters to objects and get the method to invoke
    458                                 Object[] parameters = CreateObjects(possible, source, launcher, command);
    459                                 // Check that there are the same amount of params
    460                                 if (parameters == null) {
    461                                         continue;
    462                                 }
    463 
    464                                 return possible.invoke(null, parameters);
    465                         } catch (Exception e) {
     453                                if (paramObjects != null)
     454                                        return canditate.invoke(null, paramObjects);
     455                        } catch (final Exception e) {
    466456                                Logger.Log(e);
    467457                                e.printStackTrace();
    468458                        }
    469459                }
    470                 // If the actions was not found... then it is run as an agent
    471                 assert (possibles.size() > 0);
    472                 throw new RuntimeException("Incorrect parameters for " + mname);
    473         }
     460                assert (canditates.size() > 0);
     461                final String nl = System.getProperty("line.separator");
     462                final StringBuilder errorBuilder = new StringBuilder(
     463                                "Incorrect parameters for " + actionName + nl + "Canditates: ");
     464                for (final Method canditate : canditates)
     465                        errorBuilder.append(canditate + nl);
     466                throw new RuntimeException(errorBuilder.toString());
     467        }
     468
     469        // /**
     470        // * Performs the given action command. The source Frame and Item are given
     471        // because they are required by some actions.
     472        // * Note that the source frame does not have to be the Item's parent Frame.
     473        // *
     474        // * @param source
     475        // * The Frame that the action should apply to
     476        // * @param launcher
     477        // * The Item that has the action assigned to it
     478        // * @param command
     479        // * The action to perform
     480        // */
     481        // public static Object PerformAction(Frame source, Item launcher, String
     482        // command) throws Exception {
     483        // // if (!command.equalsIgnoreCase("Restore"))
     484        // // FrameIO.SaveFrame(source, false);
     485        // // TODO make restore UNDO the changes made by the last action
     486        //
     487        // // separate method name and parameter names
     488        // String mname = getName(command);
     489        // command = command.substring(mname.length()).trim();
     490        // // If no params are provided get them from a text item on the cursor
     491        // if (command.length() == 0 && launcher instanceof Text &&
     492        // launcher.isFloating()) {
     493        // command = launcher.getText();
     494        // }
     495        //
     496        // // Strip off the @ from annotation items
     497        // if (mname.startsWith("@"))
     498        // mname = mname.substring(1);
     499        //
     500        // mname = mname.trim();
     501        // String lowercaseName = mname.toLowerCase();
     502        // // check for protection on frame
     503        // if (ItemUtils.ContainsTag(source.getItems(), "@No" + mname)) {
     504        // throw new RuntimeException("Frame is protected by @No" + mname +
     505        // " tag.");
     506        // }
     507        //
     508        // // retrieve methods that match the name
     509        // Method toRun = _Actions.get(lowercaseName);
     510        //
     511        // // if this is not the name of a method, it may be the name of an agent
     512        // if (toRun == null) {
     513        // LaunchAgent(mname, command, source, launcher);
     514        // return null;
     515        // }
     516        //
     517        // // Need to save the frame if we are navigating away from it so we dont
     518        // // loose changes
     519        // if (toRun.getDeclaringClass().getName().equals(NAVIGATIONS_CLASS)) {
     520        // FrameIO.SaveFrame(DisplayIO.getCurrentFrame());
     521        // }
     522        //
     523        // // if there are duplicate methods with the same name
     524        // List<Method> possibles = new LinkedList<Method>();
     525        // possibles.add(toRun);
     526        // int i = 0;
     527        // while (_Actions.containsKey(lowercaseName + i)) {
     528        // possibles.add(_Actions.get(lowercaseName + i));
     529        // i++;
     530        // }
     531        //
     532        // for (Method possible : possibles) {
     533        // // try first with the launching item as a parameter
     534        //
     535        // // run method
     536        // try {
     537        // // convert parameters to objects and get the method to invoke
     538        // Object[] parameters = CreateObjects(possible, source, launcher, command);
     539        // // Check that there are the same amount of params
     540        // if (parameters == null) {
     541        // continue;
     542        // }
     543        //
     544        // return possible.invoke(null, parameters);
     545        // } catch (Exception e) {
     546        // Logger.Log(e);
     547        // e.printStackTrace();
     548        // }
     549        // }
     550        // // If the actions was not found... then it is run as an agent
     551        // assert (possibles.size() > 0);
     552        // throw new RuntimeException("Incorrect parameters for " + mname);
     553        // }
    474554
    475555        /**
     
    483563         *            The starting Frame that the JAG is being launched on
    484564         */
    485         private static void LaunchAgent(String name, String parameters, Frame source, Item clicked) throws Exception {
     565        private static void LaunchAgent(String name, String parameters,
     566                        Frame source, Item clicked) throws Exception {
    486567                // Use the correct case version for printing error messages
    487568                String nameWithCorrectCase = name;
     
    495576                                fullClassName = _JAGs.get(name);
    496577                        } else if (name.endsWith("tree")) {
    497                                 parameters = name.substring(0, name.length() - "tree".length()) + " " + parameters;
     578                                parameters = name.substring(0, name.length() - "tree".length())
     579                                                + " " + parameters;
    498580                                fullClassName = AGENTS_PACKAGE + "writetree";
    499581
    500582                        } else if (name.endsWith("frame")) {
    501                                 parameters = name.substring(0, name.length() - "frame".length()) + " " + parameters;
     583                                parameters = name
     584                                                .substring(0, name.length() - "frame".length())
     585                                                + " "
     586                                                + parameters;
    502587                                fullClassName = AGENTS_PACKAGE + "writeframe";
    503588                        }
     
    520605                                        String[] paramStrings = parameters.split("\\s+");
    521606                                        /**
    522                                          * Any extra parameters will be treated as the rest of the string if the last param is a string
     607                                         * Any extra parameters will be treated as the rest of the
     608                                         * string if the last param is a string
    523609                                         */
    524610                                        if (paramCount > paramStrings.length) {
     
    527613
    528614                                        /**
    529                                          * If there are extra parameters the last param must be a String
     615                                         * If there are extra parameters the last param must be a
     616                                         * String
    530617                                         */
    531618                                        int lastParam = paramTypes.length - 1;
    532619
    533                                         if (paramCount < paramStrings.length && !paramTypes[lastParam].equals(String.class)) {
     620                                        if (paramCount < paramStrings.length
     621                                                        && !paramTypes[lastParam].equals(String.class)) {
    534622                                                continue;
    535623                                        }
     
    539627                                                        SString nextParam = new SString(paramStrings[i]);
    540628                                                        params[i] = null;
    541                                                         if (paramTypes[i].equals(int.class) || paramTypes[i].equals(Integer.class)) {
     629                                                        if (paramTypes[i].equals(int.class)
     630                                                                        || paramTypes[i].equals(Integer.class)) {
    542631                                                                params[i] = nextParam.integerValue().intValue();
    543                                                         } else if (paramTypes[i].equals(long.class) || paramTypes[i].equals(Long.class)) {
     632                                                        } else if (paramTypes[i].equals(long.class)
     633                                                                        || paramTypes[i].equals(Long.class)) {
    544634                                                                params[i] = nextParam.integerValue();
    545                                                         } else if (paramTypes[i].equals(double.class) || paramTypes[i].equals(Double.class)) {
     635                                                        } else if (paramTypes[i].equals(double.class)
     636                                                                        || paramTypes[i].equals(Double.class)) {
    546637                                                                params[i] = nextParam.doubleValue();
    547                                                         } else if (paramTypes[i].equals(float.class) || paramTypes[i].equals(Float.class)) {
    548                                                                 params[i] = nextParam.doubleValue().floatValue();
    549                                                         } else if (paramTypes[i].equals(boolean.class) || paramTypes[i].equals(Boolean.class)) {
     638                                                        } else if (paramTypes[i].equals(float.class)
     639                                                                        || paramTypes[i].equals(Float.class)) {
     640                                                                params[i] = nextParam.doubleValue()
     641                                                                                .floatValue();
     642                                                        } else if (paramTypes[i].equals(boolean.class)
     643                                                                        || paramTypes[i].equals(Boolean.class)) {
    550644                                                                params[i] = nextParam.booleanValue();
    551645                                                        } else if (paramTypes[i].equals(String.class)) {
    552646                                                                params[i] = nextParam.stringValue();
    553647                                                        } else {
    554                                                                 throw new UnexpectedException("Unexpected type " + paramTypes[i].getClass().toString());
     648                                                                throw new UnexpectedException(
     649                                                                                "Unexpected type "
     650                                                                                                + paramTypes[i].getClass()
     651                                                                                                                .toString());
    555652                                                        }
    556653                                                }
     
    562659
    563660                                                /**
    564                                                  * Append extra params on the end of the last string param
     661                                                 * Append extra params on the end of the last string
     662                                                 * param
    565663                                                 */
    566664                                                String s = params[lastParam].toString();
     
    581679                        // if there is no constructor, return
    582680                        if (con == null) {
    583                                 throw new RuntimeException(INVALID_PARAMETERS_ERROR + nameWithCorrectCase);
     681                                throw new RuntimeException(INVALID_PARAMETERS_ERROR
     682                                                + nameWithCorrectCase);
    584683                        }
    585684
     
    591690                } catch (ClassNotFoundException cnf) {
    592691                        _Agent = null;
    593                         throw new RuntimeException("'" + nameWithCorrectCase + "' is not an action or agent.");
    594                 }
    595         }
    596 
    597         public static void LaunchAgent(String name, String parameters, Frame source) throws Exception {
     692                        throw new RuntimeException("'" + nameWithCorrectCase
     693                                        + "' is not an action or agent.");
     694                }
     695        }
     696
     697        public static void LaunchAgent(String name, String parameters, Frame source)
     698                        throws Exception {
    598699                LaunchAgent(name, parameters, source, null);
    599700        }
     
    630731
    631732                        Thread.UncaughtExceptionHandler h = new Thread.UncaughtExceptionHandler() {
    632                             public void uncaughtException(Thread th, Throwable ex) {
    633                          
    634                                 MessageBay.errorMessage("Error occurred in Action: " + th.getName());
    635                                 ex.printStackTrace();
    636 
    637                                 stopAgent();
    638                                 _Agent = null;
    639                             }
     733                                public void uncaughtException(Thread th, Throwable ex) {
     734
     735                                        MessageBay.errorMessage("Error occurred in Action: "
     736                                                        + th.getName());
     737                                        ex.printStackTrace();
     738
     739                                        stopAgent();
     740                                        _Agent = null;
     741                                }
    640742                        };
    641                        
    642                         Thread t = new Thread(_Agent,nameWithCorrectCase);
    643                
     743
     744                        Thread t = new Thread(_Agent, nameWithCorrectCase);
     745
    644746                        t.setPriority(Thread.MIN_PRIORITY);
    645747                        t.setUncaughtExceptionHandler(h);
    646                        
     748
    647749                        if (FreeItems.textOnlyAttachedToCursor()) {
    648750                                itemParam = FreeItems.getItemAttachedToCursor();
     
    652754                        if (!_Agent.initialise(source, itemParam)) {
    653755                                _Agent = null;
    654                                 throw new RuntimeException("Error initialising agent: " + nameWithCorrectCase);
     756                                throw new RuntimeException("Error initialising agent: "
     757                                                + nameWithCorrectCase);
    655758                        }
    656759
     
    658761                        // TODO make this nicer... ie. make Format an action rather than an
    659762                        // agent and save frames only before running agents
    660                         if (!nameWithCorrectCase.equalsIgnoreCase("format") && !nameWithCorrectCase.equalsIgnoreCase("sort")) {
     763                        if (!nameWithCorrectCase.equalsIgnoreCase("format")
     764                                        && !nameWithCorrectCase.equalsIgnoreCase("sort")) {
    661765                                FrameUtils.LeavingFrame(source);
    662766                        }
     
    667771                                t.run();
    668772                                if (_Agent != null) {
    669                                     String result = _Agent.toString();
    670                                     // Attach the result to the cursor
    671                                     if (FreeItems.textOnlyAttachedToCursor()) {
    672                                         Item resultItem = FreeItems.getItemAttachedToCursor();
    673                                         resultItem.setText(result);
    674                                     }
    675                                     // if there is a completion frame, then display it to the user
     773                                        String result = _Agent.toString();
     774                                        // Attach the result to the cursor
     775                                        if (FreeItems.textOnlyAttachedToCursor()) {
     776                                                Item resultItem = FreeItems.getItemAttachedToCursor();
     777                                                resultItem.setText(result);
     778                                        }
     779                                        // if there is a completion frame, then display it to the
     780                                        // user
    676781                                }
    677782                        } else {
     
    687792                        _Agent = null;
    688793                        e.printStackTrace();
    689                         throw new RuntimeException("Error creating Agent: '" + nameWithCorrectCase + "'");
     794                        throw new RuntimeException("Error creating Agent: '"
     795                                        + nameWithCorrectCase + "'");
    690796                }
    691797                FrameGraphics.refresh(false);
     
    705811
    706812        /**
    707          * Stops the currently running Agent (If there is one) by calling Agent.stop(). Note: This may not stop the Agent
    708          * immediately, but the Agent should terminate as soon as it is safe to do so.
     813         * Stops the currently running Agent (If there is one) by calling
     814         * Agent.stop(). Note: This may not stop the Agent immediately, but the
     815         * Agent should terminate as soon as it is safe to do so.
    709816         */
    710817        public static void stopAgent() {
     
    725832         *
    726833         * @param launcher
    727          *            The Item used to launch the action, it may be required as a parameter
     834         *            The Item used to launch the action, it may be required as a
     835         *            parameter
    728836         * @param values
    729837         *            A list of space separated String values to convert to objects
    730838         * @return The created array of Objects
    731839         */
    732         public static Object[] CreateObjects(Method method, Frame source, Item launcher, String values) {
     840        public static Object[] CreateObjects(Method method, Frame source,
     841                        Item launcher, String values) {
    733842                // The parameter types that should be created from the given String
    734843                Class<?>[] paramTypes = method.getParameterTypes();
     
    743852
    744853                /*
    745                  * if the first class in the list is a frame or item, it is the source or launcher length must be at least one
    746                  * if we are still running
     854                 * if the first class in the list is a frame or item, it is the source
     855                 * or launcher length must be at least one if we are still running
    747856                 */
    748857                if (paramTypes[ind] == Frame.class) {
     
    792901
    793902        /**
    794          * Returns a string containing the remaining params after ignoring the first one.
     903         * Returns a string containing the remaining params after ignoring the first
     904         * one.
    795905         *
    796906         * @param params
     
    824934
    825935        /**
    826          * Returns the first value in the space separated String of parameters passed in. Strings are enclosed in double
    827          * quotes.
     936         * Returns the first value in the space separated String of parameters
     937         * passed in. Strings are enclosed in double quotes.
    828938         *
    829939         * @param params
     
    854964
    855965        /**
    856          * Separates the name of the given command from any parameters and returns them
     966         * Separates the name of the given command from any parameters and returns
     967         * them Also deals with leading '@'s and leading and tailing whitespace.
    857968         *
    858969         * @param command
     
    861972         */
    862973        private static String getName(String command) {
     974                command = command.trim();
     975                if (command.startsWith("@"))
     976                        command = command.substring(1);
    863977                if (command.indexOf(" ") < 0)
    864978                        return command;
     
    868982
    869983        /**
    870          * Gets an uncapitalized font name and returns the capitalized font name. The capitalized form can be used with the
    871          * Font.decoded method to get a corresponding Font object.
     984         * Gets an uncapitalized font name and returns the capitalized font name.
     985         * The capitalized form can be used with the Font.decoded method to get a
     986         * corresponding Font object.
    872987         *
    873988         * @param fontName
     
    8861001        private static void initFonts() {
    8871002                if (_Fonts.size() == 0) {
    888                         String[] availableFonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
     1003                        String[] availableFonts = GraphicsEnvironment
     1004                                        .getLocalGraphicsEnvironment()
     1005                                        .getAvailableFontFamilyNames();
    8891006                        for (String s : availableFonts) {
    8901007                                _Fonts.put(s.toLowerCase(), s);
     
    8981015        }
    8991016
    900         public static Object PerformActionCatchErrors(Frame current, Item launcher, String command) {
     1017        public static Object PerformActionCatchErrors(Frame current, Item launcher,
     1018                        String command) {
    9011019                try {
    9021020                        return PerformAction(current, launcher, command);
     
    9061024                } catch (Exception e) {
    9071025                        e.printStackTrace();
    908                         MessageBay.errorMessage("Action failed: " + e.getClass().getSimpleName());
     1026                        MessageBay.errorMessage("Action failed: "
     1027                                        + e.getClass().getSimpleName());
    9091028                }
    9101029                return null;
  • trunk/src/org/expeditee/io/flowlayout/XGroupItem.java

    r972 r975  
    3737import org.expeditee.items.Text;
    3838
    39 
    40 public class XGroupItem extends XItem
    41 {
    42         public static final Text GROUPSEP_END = new Text('2' + ""); //ASCII '2' is start of text
    43 
    44         public static final Text GROUPSEP_START = new Text('3' + ""); //ASCII '3' is end of text
    45        
    46         enum FlowType { in_flow, out_of_flow_original, out_of_flow_faked_position };
    47        
     39public class XGroupItem extends XItem {
     40        public static final Text GROUPSEP_END = new Text('2' + ""); // ASCII '2' is
     41                                                                                                                                // start of text
     42
     43        public static final Text GROUPSEP_START = new Text('3' + ""); // ASCII '3'
     44                                                                                                                                        // is end of
     45                                                                                                                                        // text
     46
     47        enum FlowType {
     48                in_flow, out_of_flow_original, out_of_flow_faked_position
     49        };
     50
    4851        public static boolean doImplicitBoxing = true;
    49        
    50         class MultiArrowHeadComparable implements Comparator<Item>{
    51                  
    52             @Override
    53             public int compare(Item o1, Item o2)
    54             {
    55                 int o1y = o1.getY();
    56                 int o2y = o2.getY();
    57                
    58                 int order = 0; // default to assume they are identical
    59                
    60                 if (o1y<o2y) {
    61                         order = -1; // done, o1 is higher up the frame than o2 => our definition of 'before'
    62                 }
    63                 else if (o2y<o1y) {
    64                         order = +1; // also done, o1 is lower down the frame than o2 => our definition of 'after'
    65                        
    66                 }
    67                 else {
    68                         // have identical 'y' values, so look to 'x' to tie-break
    69                        
    70                         int o1x = o1.getX();
    71                         int o2x = o2.getX();
    72                        
    73                         if (o1x<o2x) {
    74                                 order = -1; // done, o1 is to the left of o2 => our definition of 'before'
    75                         }
    76                         else if (o2x<o1x) {
    77                                 order = +1; // also done, o1 is to the right of o2  => our definition of 'after'
    78                         }
    79                 }
    80                        
    81                 return order;
    82             }
    83         }
    84        
     52
     53        class MultiArrowHeadComparable implements Comparator<Item> {
     54
     55                @Override
     56                public int compare(Item o1, Item o2) {
     57                        int o1y = o1.getY();
     58                        int o2y = o2.getY();
     59
     60                        int order = 0; // default to assume they are identical
     61
     62                        if (o1y < o2y) {
     63                                order = -1; // done, o1 is higher up the frame than o2 => our
     64                                                        // definition of 'before'
     65                        } else if (o2y < o1y) {
     66                                order = +1; // also done, o1 is lower down the frame than o2 =>
     67                                                        // our definition of 'after'
     68
     69                        } else {
     70                                // have identical 'y' values, so look to 'x' to tie-break
     71
     72                                int o1x = o1.getX();
     73                                int o2x = o2.getX();
     74
     75                                if (o1x < o2x) {
     76                                        order = -1; // done, o1 is to the left of o2 => our
     77                                                                // definition of 'before'
     78                                } else if (o2x < o1x) {
     79                                        order = +1; // also done, o1 is to the right of o2 => our
     80                                                                // definition of 'after'
     81                                }
     82                        }
     83
     84                        return order;
     85                }
     86        }
     87
    8588        Frame frame;
    86        
     89
    8790        protected int y_span_height;
    8891        protected YOverlappingItemsSpan[] yitems_span_array;
    89        
     92
    9093        List<Text> raw_text_item_list;
    9194        List<XGroupItem> grouped_item_list;
    9295        List<Item> remaining_item_list;
    93        
     96
    9497        FlowType out_of_flow;
    95        
    96         protected XGroupItem()
    97         {
     98
     99        protected XGroupItem() {
    98100                frame = null;
    99                
     101
    100102                y_span_height = 0;
    101103                yitems_span_array = null;
    102                
     104
    103105                raw_text_item_list = null;
    104106                grouped_item_list = null;
    105107                remaining_item_list = null;
    106                
     108
    107109                out_of_flow = FlowType.in_flow;
    108110        }
    109        
    110         public XGroupItem(Frame frame, List<Item> y_ordered_items, Polygon enclosing_polygon)
    111         {
     111
     112        public XGroupItem(Frame frame, List<Item> y_ordered_items,
     113                        Polygon enclosing_polygon) {
    112114                this.frame = frame;
    113                 this.out_of_flow = FlowType.in_flow;;
    114                
     115                this.out_of_flow = FlowType.in_flow;
     116                ;
     117
    115118                if (enclosing_polygon == null) {
    116                         // e.g. when the top-level case, with no enclosing polygon at this stage
     119                        // e.g. when the top-level case, with no enclosing polygon at this
     120                        // stage
    117121                        // => generate one based on the bounding box of the y_ordered_items
    118                         enclosing_polygon = DimensionExtent.boundingBoxPolygon(y_ordered_items);
    119                 }
    120                
    121                 Rectangle enclosing_bounding_rect = enclosing_polygon.getBounds();
     122                        enclosing_polygon = DimensionExtent
     123                                        .boundingBoxPolygon(y_ordered_items);
     124                }
     125
     126                Rectangle enclosing_bounding_rect = enclosing_polygon.getBounds();
    122127                initSpanArray(enclosing_bounding_rect);
    123                
    124                 // Step 1: Separate out the raw-text-items, the grouped-items and 'remaining' (e.g. points and lines)
    125                
     128
     129                // Step 1: Separate out the raw-text-items, the grouped-items and
     130                // 'remaining' (e.g. points and lines)
     131
    126132                raw_text_item_list = new ArrayList<Text>();
    127133                grouped_item_list = new ArrayList<XGroupItem>();
    128134                remaining_item_list = new ArrayList<Item>();
    129                
    130                 separateYOverlappingItems(frame, y_ordered_items, enclosing_polygon, raw_text_item_list, grouped_item_list, remaining_item_list);
    131                
    132        
     135
     136                separateYOverlappingItems(frame, y_ordered_items, enclosing_polygon,
     137                                raw_text_item_list, grouped_item_list, remaining_item_list);
     138
    133139                // Step 2: Add in the raw-text items
    134140                for (Text text_item : raw_text_item_list) {
    135                        
     141
    136142                        XRawItem x_raw_item = new XRawItem(text_item, this);
    137                         // overspill can occur (and is acceptable) when raw-text item spills out of enclosing shape (such as a rectangle)
     143                        // overspill can occur (and is acceptable) when raw-text item spills
     144                        // out of enclosing shape (such as a rectangle)
    138145                        mapInItem(x_raw_item);
    139146                }
    140                
    141         }
    142        
    143         public XGroupItem(Frame frame, List<Item> y_ordered_items)
    144         {
    145                 this(frame,y_ordered_items,null);
    146         }
    147        
    148         protected XGroupItem(XGroupItem imprint, Rectangle copy_to_bounding_rect)
    149         {
     147
     148        }
     149
     150        public XGroupItem(Frame frame, List<Item> y_ordered_items) {
     151                this(frame, y_ordered_items, null);
     152        }
     153
     154        protected XGroupItem(XGroupItem imprint, Rectangle copy_to_bounding_rect) {
    150155                super();
    151                
    152                 // Implement a shallow copy => share references to frame, and item list, and y-span
    153                 // Only the bounding box is changed => set to the 'copy_to_bounding_rect' passed in
    154                
     156
     157                // Implement a shallow copy => share references to frame, and item list,
     158                // and y-span
     159                // Only the bounding box is changed => set to the
     160                // 'copy_to_bounding_rect' passed in
     161
    155162                this.frame = imprint.frame;
    156                
     163
    157164                y_span_height = imprint.y_span_height;
    158165                yitems_span_array = imprint.yitems_span_array;
    159                
    160                 this.raw_text_item_list  = imprint.raw_text_item_list;
    161                 this.grouped_item_list   = imprint.grouped_item_list;
    162                
    163 //              int offX = imprint.getBoundingRect().x - copy_to_bounding_rect.x;
    164 //              int offY = imprint.getBoundingRect().y - copy_to_bounding_rect.y;
    165 //              this.grouped_item_list  = new ArrayList<XGroupItem>();
    166 //              for(XGroupItem newChild : imprint.grouped_item_list) {
    167 //                      Rectangle newRect = newChild.getBoundingRect();
    168 //                      newRect.x -= offX;
    169 //                      newRect.y -= offY;
    170 //                      this.grouped_item_list.add(new XGroupItem(newChild, newRect));
    171 //              }
     166
     167                this.raw_text_item_list = imprint.raw_text_item_list;
     168                this.grouped_item_list = imprint.grouped_item_list;
     169
     170                // int offX = imprint.getBoundingRect().x - copy_to_bounding_rect.x;
     171                // int offY = imprint.getBoundingRect().y - copy_to_bounding_rect.y;
     172                // this.grouped_item_list = new ArrayList<XGroupItem>();
     173                // for(XGroupItem newChild : imprint.grouped_item_list) {
     174                // Rectangle newRect = newChild.getBoundingRect();
     175                // newRect.x -= offX;
     176                // newRect.y -= offY;
     177                // this.grouped_item_list.add(new XGroupItem(newChild, newRect));
     178                // }
    172179                this.remaining_item_list = imprint.remaining_item_list;
    173                
    174                 this.out_of_flow = imprint.out_of_flow; // Or perhaps set it to FlowType.out_of_flow_fake_position straight away?
    175                
    176                 this.bounding_rect = new Rectangle(copy_to_bounding_rect); // deep copy to be on the safe side
    177         }
    178        
    179        
    180         protected void initSpanArray(Rectangle bounding_rect)
    181         {
     180
     181                this.out_of_flow = imprint.out_of_flow; // Or perhaps set it to
     182                                                                                                // FlowType.out_of_flow_fake_position
     183                                                                                                // straight away?
     184
     185                this.bounding_rect = new Rectangle(copy_to_bounding_rect); // deep copy
     186                                                                                                                                        // to be on
     187                                                                                                                                        // the safe
     188                                                                                                                                        // side
     189        }
     190
     191        protected void initSpanArray(Rectangle bounding_rect) {
    182192                this.bounding_rect = bounding_rect;
    183                
     193
    184194                int y_top = getBoundingYTop();
    185195                int y_bot = getBoundingYBot();
    186                
    187                 if (y_top<=y_bot) {
     196
     197                if (y_top <= y_bot) {
    188198                        // => have non-trivial span
    189                
    190                         y_span_height = (y_bot - y_top) + 2;  // Polygon in Java excludes right and bottom sides so need extra "+1" in calc
    191                
    192                         yitems_span_array = new YOverlappingItemsSpan[y_span_height];
    193                 }
    194                 else {
     199
     200                        y_span_height = (y_bot - y_top) + 2; // Polygon in Java excludes
     201                                                                                                        // right and bottom sides so
     202                                                                                                        // need extra "+1" in calc
     203
     204                        yitems_span_array = new YOverlappingItemsSpan[y_span_height];
     205                } else {
    195206                        y_span_height = 0;
    196207                        yitems_span_array = null;
    197208                }
    198209        }
    199        
     210
    200211        public YOverlappingItemsSpan getSpanItemAt(int index) {
    201             return yitems_span_array[index];
    202         }
    203        
    204         public void setOutOfFlow(FlowType flow_type)
    205         {
     212                return yitems_span_array[index];
     213        }
     214
     215        public void setOutOfFlow(FlowType flow_type) {
    206216                out_of_flow = flow_type;
    207217        }
    208        
    209         public FlowType getFlowItem()
    210         {
     218
     219        public FlowType getFlowItem() {
    211220                return out_of_flow;
    212221        }
    213        
    214         public boolean isOriginalOutOfFlowItem()
    215         {
     222
     223        public boolean isOriginalOutOfFlowItem() {
    216224                return out_of_flow == FlowType.out_of_flow_original;
    217225        }
    218        
    219         public boolean isFakedOutOfFlowItem()
    220         {
     226
     227        public boolean isFakedOutOfFlowItem() {
    221228                return out_of_flow == FlowType.out_of_flow_faked_position;
    222229        }
    223230
    224        
    225         public List<Text> getRawTextItemList()
    226         {
     231        public List<Text> getRawTextItemList() {
    227232                return raw_text_item_list;
    228233        }
    229        
     234
    230235        public List<Text[]> getRawTextLines() {
    231236                final List<Text> rawText = getRawTextItemList();
    232237                final List<Text> lineStarts = new LinkedList<Text>();
    233                 for(final YOverlappingItemsSpan span : this.yitems_span_array) {
    234                         if(span instanceof YOverlappingItemsTopEdge) {
     238                for (final YOverlappingItemsSpan span : this.yitems_span_array) {
     239                        if (span instanceof YOverlappingItemsTopEdge) {
    235240                                final YOverlappingItemsTopEdge topEdge = (YOverlappingItemsTopEdge) span;
    236                                 final List<XItem> xLine = topEdge.getXOrderedLine().getXItemList();
    237                                 for(final XItem xitem : xLine) {
    238                                         if(xitem instanceof XRawItem) {
    239                                                 final Text item = (Text)((XRawItem) xitem).getItem();
     241                                final List<XItem> xLine = topEdge.getXOrderedLine()
     242                                                .getXItemList();
     243                                for (final XItem xitem : xLine) {
     244                                        if (xitem instanceof XRawItem) {
     245                                                final Text item = (Text) ((XRawItem) xitem).getItem();
    240246                                                lineStarts.add(item);
    241247                                                break;
     
    245251                }
    246252                final List<Integer> indexes = new LinkedList<Integer>();
    247                 for(final Text lineStart : lineStarts)
     253                for (final Text lineStart : lineStarts)
    248254                        indexes.add(rawText.indexOf(lineStart));
    249255                final List<Text[]> ret = new LinkedList<Text[]>();
    250256                int rangeEnd = indexes.get(0);
    251257                int last = rangeEnd;
    252                 for(int i = 1; i < indexes.size(); i++) {
     258                for (int i = 1; i < indexes.size(); i++) {
    253259                        rangeEnd = indexes.get(i);
    254                         final List<Text> part = new LinkedList<Text>(rawText.subList(0, rangeEnd - last));
     260                        final List<Text> part = new LinkedList<Text>(rawText.subList(0,
     261                                        rangeEnd - last));
    255262                        last = rangeEnd;
    256263                        rawText.removeAll(part);
    257                         part.toArray(new Text[]{});
    258                         ret.add(part.toArray(new Text[]{}));
    259                 }
    260                 ret.add(rawText.toArray(new Text[]{}));
     264                        part.toArray(new Text[] {});
     265                        ret.add(part.toArray(new Text[] {}));
     266                }
     267                ret.add(rawText.toArray(new Text[] {}));
    261268                return ret;
    262269        }
    263        
    264         public List<XGroupItem> getGroupedItemList()
    265         {
     270
     271        public List<XGroupItem> getGroupedItemList() {
    266272                return grouped_item_list;
    267273        }
    268        
    269         public List<Item> getRemainingItemList()
    270         {
     274
     275        public List<Item> getRemainingItemList() {
    271276                return remaining_item_list;
    272277        }
    273        
     278
    274279        public int getItemSpanLength() {
    275280                return yitems_span_array.length;
    276281        }
    277        
    278         public YOverlappingItemsSpan getYOverlappingItemsSpan(int y)
    279         {
     282
     283        public YOverlappingItemsSpan getYOverlappingItemsSpan(int y) {
    280284                int y_index = y - getBoundingYTop();
    281                
    282                 if ((y_index<0) || (y_index>=yitems_span_array.length)) {
     285
     286                if ((y_index < 0) || (y_index >= yitems_span_array.length)) {
    283287                        int y_top = getBoundingYTop();
    284                         int y_bot = y_top + yitems_span_array.length -1;
    285 
    286                         System.err.println("Error in getYOverlappingItemsSpan(): index out of bounds for value " + y);
    287                         System.err.println("  => Operation mapped into local array: y-top=" + y_top + ", y-bot=" + y_bot);
    288                  
    289                     return null;
     288                        int y_bot = y_top + yitems_span_array.length - 1;
     289
     290                        System.err
     291                                        .println("Error in getYOverlappingItemsSpan(): index out of bounds for value "
     292                                                        + y);
     293                        System.err.println("  => Operation mapped into local array: y-top="
     294                                        + y_top + ", y-bot=" + y_bot);
     295
     296                        return null;
    290297                }
    291298                return yitems_span_array[y_index];
    292299        }
    293        
     300
    294301        protected int cropToTop(int y) {
    295302                int y_index = y - getBoundingYTop();
    296                
    297                 if (y_index<0) {
     303
     304                if (y_index < 0) {
    298305                        y = getBoundingYTop();
    299306                }
    300                
     307
    301308                return y;
    302309        }
    303        
     310
    304311        protected int cropToBot(int y) {
    305312                int y_index = y - getBoundingYTop();
    306        
    307                 if (y_index>=yitems_span_array.length) {
     313
     314                if (y_index >= yitems_span_array.length) {
    308315                        y = getBoundingYBot();
    309316                }
    310                
     317
    311318                return y;
    312319        }
    313        
    314         public void setYOverlappingItemsSpan(int y,YOverlappingItemsSpan yitems_span)
    315         {
     320
     321        public void setYOverlappingItemsSpan(int y,
     322                        YOverlappingItemsSpan yitems_span) {
    316323                int y_index = y - getBoundingYTop();
    317324
    318                 if ((y_index<0) || (y_index>=yitems_span_array.length)) {
    319        
     325                if ((y_index < 0) || (y_index >= yitems_span_array.length)) {
     326
    320327                        int y_top = getBoundingYTop();
    321                         int y_bot = y_top + yitems_span_array.length -1;
    322 
    323                         System.err.println("Error in setYOverlappingItemsSpan(): index out of bounds for value " + y);
    324                         System.err.println("  => Operation mapped into local array: y-top=" + y_top + ", y-bot=" + y_bot);
    325 
    326                     return;
     328                        int y_bot = y_top + yitems_span_array.length - 1;
     329
     330                        System.err
     331                                        .println("Error in setYOverlappingItemsSpan(): index out of bounds for value "
     332                                                        + y);
     333                        System.err.println("  => Operation mapped into local array: y-top="
     334                                        + y_top + ", y-bot=" + y_bot);
     335
     336                        return;
    327337                }
    328338                yitems_span_array[y_index] = yitems_span;
    329339        }
    330        
    331        
    332         protected List<Item> followLinesToArrowHeads(Collection<Item> visited, Item anchor_item, List<Line>used_in_lines)
    333         {
     340
     341        protected List<Item> followLinesToArrowHeads(Collection<Item> visited,
     342                        Item anchor_item, List<Line> used_in_lines) {
    334343                List<Item> arrow_head_endpoints = new ArrayList<Item>();
    335                
    336                 for (Line line: used_in_lines) {
    337                        
     344
     345                for (Line line : used_in_lines) {
     346
    338347                        Item start_item = line.getStartItem();
    339                        
     348
    340349                        if (start_item == anchor_item) {
    341350                                // the line we're considering is heading in the right direction
    342                                
     351
    343352                                Item end_item = line.getEndItem();
    344353
     
    348357
    349358                                        List<Line> follow_lines = end_item.getLines();
    350                                        
    351                                         if (follow_lines.size()==1) {
     359
     360                                        if (follow_lines.size() == 1) {
    352361                                                // reached an end-point
    353362                                                if (end_item.hasVisibleArrow()) {
    354363                                                        arrow_head_endpoints.add(end_item);
    355364                                                }
    356                                         }
    357                                         else if (follow_lines.size()>1) {
    358                                                
    359                                                 List<Item> followed_arrow_heads = followLinesToArrowHeads(visited,end_item,follow_lines);
     365                                        } else if (follow_lines.size() > 1) {
     366
     367                                                List<Item> followed_arrow_heads = followLinesToArrowHeads(
     368                                                                visited, end_item, follow_lines);
    360369                                                arrow_head_endpoints.addAll(followed_arrow_heads);
    361370                                        }
    362371                                }
    363372                        }
    364                        
     373
    365374                }
    366375                return arrow_head_endpoints;
    367376        }
    368        
    369 
    370         protected XGroupItem innermostXGroup(Item arrow_head, List<XGroupItem> grouped_item_list)
    371         {
     377
     378        protected XGroupItem innermostXGroup(Item arrow_head,
     379                        List<XGroupItem> grouped_item_list) {
    372380                XGroupItem innermost_item = null;
    373                
    374                 for (XGroupItem xgroup_item: grouped_item_list) {
     381
     382                for (XGroupItem xgroup_item : grouped_item_list) {
    375383                        if (xgroup_item.containsItem(arrow_head)) {
    376                                
     384
    377385                                innermost_item = xgroup_item;
    378                                
     386
    379387                                // Now see if it is in any of the nested ones?
    380                                
     388
    381389                                List<XGroupItem> nested_group_item_list = xgroup_item.grouped_item_list;
    382                                
    383                                 XGroupItem potentially_better_item = innermostXGroup(arrow_head,nested_group_item_list);
    384                                                
     390
     391                                XGroupItem potentially_better_item = innermostXGroup(
     392                                                arrow_head, nested_group_item_list);
     393
    385394                                if (potentially_better_item != null) {
    386395                                        innermost_item = potentially_better_item;
     
    388397                                break;
    389398                        }
    390                        
    391                 }
    392                
     399
     400                }
     401
    393402                return innermost_item;
    394403        }
    395        
    396         protected void removeXGroupItem(XGroupItem remove_item, List<XGroupItem> grouped_item_list)
    397         {
    398                
    399                 for (XGroupItem xgroup_item: grouped_item_list) {
    400                        
     404
     405        protected void removeXGroupItem(XGroupItem remove_item,
     406                        List<XGroupItem> grouped_item_list) {
     407
     408                for (XGroupItem xgroup_item : grouped_item_list) {
     409
    401410                        if (xgroup_item == remove_item) {
    402411                                grouped_item_list.remove(xgroup_item);
    403412                                return;
    404                         }
    405                         else {
     413                        } else {
    406414                                List<XGroupItem> nested_group_item_list = xgroup_item.grouped_item_list;
    407                                 removeXGroupItem(remove_item,nested_group_item_list);
    408                                
    409                         }
    410                 }
    411         }
    412        
    413         protected boolean daisyChainContainsLoop(final XGroupItem toplevel_xgroup, final Item exitingDot, Collection<XGroupItem> groupsSeen) {
     415                                removeXGroupItem(remove_item, nested_group_item_list);
     416
     417                        }
     418                }
     419        }
     420
     421        protected boolean daisyChainContainsLoop(final XGroupItem toplevel_xgroup,
     422                        final Item exitingDot, Collection<XGroupItem> groupsSeen) {
    414423                final Item start_item = exitingDot;
    415424                final Item end_item = start_item.getLines().get(0).getEndItem();
    416                 final XGroupItem xgroup = innermostXGroup(end_item,toplevel_xgroup.getGroupedItemList());
     425                final XGroupItem xgroup = innermostXGroup(end_item,
     426                                toplevel_xgroup.getGroupedItemList());
    417427               
    418                 if(groupsSeen.contains(xgroup)) return true;
    419                
     428                if(xgroup == null) return false;
     429
     430                if (groupsSeen.contains(xgroup))
     431                        return true;
     432
    420433                groupsSeen.add(xgroup);
    421                
    422                 for(final Item i : xgroup.remaining_item_list) {
     434
     435                for (final Item i : xgroup.remaining_item_list) {
    423436                        final List<Line> lines = i.getLines();
    424                         if(lines.size() == 1 && lines.get(0).getStartItem() == i) {
     437                        if (lines.size() == 1 && lines.get(0).getStartItem() == i) {
    425438                                return daisyChainContainsLoop(toplevel_xgroup, i, groupsSeen);
    426439                        }
    427440                }
    428                
    429                 return false;                   
    430         }
    431        
    432         protected void repositionOutOfFlowGroupsFollowLine(XGroupItem toplevel_xgroup, Item remaining_item, Collection<XGroupItem> out_of_flow)
    433         {
     441                return false;
     442        }
     443
     444        protected void repositionOutOfFlowGroupsFollowLine(
     445                        XGroupItem toplevel_xgroup, Item remaining_item,
     446                        Collection<XGroupItem> out_of_flow) {
    434447                // See if this item is the start of a line
    435448                // Follow it if it is
    436                 // For each end of the line (potentially a multi-split poly-line) that has an arrow head:
    437                 //   See if the arrow-head falls inside an XGroup area
    438                 //   => Ignore endings that are in the same XGroupItem as the line started in
     449                // For each end of the line (potentially a multi-split poly-line) that
     450                // has an arrow head:
     451                // See if the arrow-head falls inside an XGroup area
     452                // => Ignore endings that are in the same XGroupItem as the line started
     453                // in
    439454                List<Line> used_in_lines = remaining_item.getLines();
    440                 if (used_in_lines.size()==1) {
     455                if (used_in_lines.size() == 1) {
    441456                        // at the start (or end) of a line
    442                        
     457
    443458                        Item start_item = used_in_lines.get(0).getStartItem();
    444459
     
    446461
    447462                                // found the start of a line
    448                                
     463
    449464                                Collection<Item> visited = new HashSet<Item>();
    450465                                visited.add(remaining_item);
    451466
    452                                 List<Item> arrow_head_endpoints = followLinesToArrowHeads(visited,remaining_item,used_in_lines);
    453 
    454                                 //System.out.println("**** For Xgroup " + this + " with dot starting at " + remaining_item + " has " + arrow_head_endpoints.size() + " arrow head endpoints");
    455 
    456                                 Collections.sort(arrow_head_endpoints, new MultiArrowHeadComparable());
    457                                                                
    458                                 for (Item arrow_head: arrow_head_endpoints) {
     467                                List<Item> arrow_head_endpoints = followLinesToArrowHeads(
     468                                                visited, remaining_item, used_in_lines);
     469
     470                                // System.out.println("**** For Xgroup " + this +
     471                                // " with dot starting at " + remaining_item + " has " +
     472                                // arrow_head_endpoints.size() + " arrow head endpoints");
     473
     474                                Collections.sort(arrow_head_endpoints,
     475                                                new MultiArrowHeadComparable());
     476
     477                                for (Item arrow_head : arrow_head_endpoints) {
    459478                                        // find the inner-most group it falls within
    460                                        
    461                                         List<XGroupItem> toplevel_grouped_item_list = toplevel_xgroup.getGroupedItemList();
    462                                        
    463                                         XGroupItem xgroup_item = innermostXGroup(arrow_head,toplevel_grouped_item_list);
    464                                        
     479
     480                                        List<XGroupItem> toplevel_grouped_item_list = toplevel_xgroup
     481                                                        .getGroupedItemList();
     482
     483                                        XGroupItem xgroup_item = innermostXGroup(arrow_head,
     484                                                        toplevel_grouped_item_list);
     485
    465486                                        if (xgroup_item != null) {
    466                                                
    467                                                 // Ignore if the found 'xgroup_item' is 'this'
    468                                                 // (i.e. the found arrow head is at the same XGroupItem level we are currently processing)
    469                                                
     487
     488                                                // Ignore if the found 'xgroup_item' is 'this'
     489                                                // (i.e. the found arrow head is at the same XGroupItem
     490                                                // level we are currently processing)
     491
    470492                                                if (xgroup_item != this) {
    471                                                
    472                                                         if(/*out_of_flow.contains(xgroup_item) &&*/ daisyChainContainsLoop(toplevel_xgroup, start_item, new ArrayList<XGroupItem>())) {
    473                                                                 System.err.println("#Found infinite loop; not following.");
     493
     494                                                        if (/* out_of_flow.contains(xgroup_item) && */daisyChainContainsLoop(
     495                                                                        toplevel_xgroup, start_item,
     496                                                                        new ArrayList<XGroupItem>())) {
     497                                                                System.err.println("#Found infinite loop; not following.  On frame: " +
     498                                                                        start_item.getParent().getName() + " At position: " +
     499                                                                                start_item.getPosition());
    474500                                                                continue;
    475501                                                        }
    476                                                        
    477 
    478                                                        
    479                                                         if(!out_of_flow.contains(xgroup_item)) {
    480                                                                 for (Item remaining_item_deeper: xgroup_item.getRemainingItemList()) {
    481                                                                         xgroup_item.repositionOutOfFlowGroupsFollowLine(toplevel_xgroup,remaining_item_deeper,out_of_flow);
     502
     503                                                        if (!out_of_flow.contains(xgroup_item)) {
     504                                                                for (Item remaining_item_deeper : xgroup_item
     505                                                                                .getRemainingItemList()) {
     506                                                                        xgroup_item
     507                                                                                        .repositionOutOfFlowGroupsFollowLine(
     508                                                                                                        toplevel_xgroup,
     509                                                                                                        remaining_item_deeper,
     510                                                                                                        out_of_flow);
    482511                                                                }
    483512                                                        }
    484513
    485                                                         out_of_flow.add(xgroup_item);                                                   
    486                                                        
    487                                                        
    488                                                         // Can't delete here, as it causes a concurrent exception => add to 'out_of_flow' hashmap and perform removal later
    489                                                        
    490                                                         //System.out.println("**** innermost XGroupItem = " + xgroup_item);
    491 
    492                                                         // Artificially rework its (x,y) org and dimension to make it appear where the start of the arrow is
    493 
    494                                                         Rectangle start_rect = start_item.getArea().getBounds();
    495                                                        
    496                                                         XGroupItem xgroup_item_shallow_copy = new XGroupItem(xgroup_item,start_rect);
    497                                                        
    498                                                         // Perhaps the following two lines should be moved to inside the constructor??
    499                                                        
    500                                                         xgroup_item.setOutOfFlow(FlowType.out_of_flow_original);
    501                                                         xgroup_item_shallow_copy.setOutOfFlow(FlowType.out_of_flow_faked_position);
    502                                                        
    503                                                        
    504                                                         //xgroup_item.setBoundingRect(start_rect);
    505                                                         //xgroup_item.setOutOfFlow();
    506                                                        
    507                                                         // Finally add it in
    508                                                         //mapInItem(xgroup_item);
     514                                                        out_of_flow.add(xgroup_item);
     515
     516                                                        // Can't delete here, as it causes a concurrent
     517                                                        // exception => add to 'out_of_flow' hashmap and
     518                                                        // perform removal later
     519
     520                                                        // System.out.println("**** innermost XGroupItem = "
     521                                                        // + xgroup_item);
     522
     523                                                        // Artificially rework its (x,y) org and dimension
     524                                                        // to make it appear where the start of the arrow is
     525
     526                                                        Rectangle start_rect = start_item.getArea()
     527                                                                        .getBounds();
     528
     529                                                        XGroupItem xgroup_item_shallow_copy = new XGroupItem(
     530                                                                        xgroup_item, start_rect);
     531
     532                                                        // Perhaps the following two lines should be moved
     533                                                        // to inside the constructor??
     534
     535                                                        xgroup_item
     536                                                                        .setOutOfFlow(FlowType.out_of_flow_original);
     537                                                        xgroup_item_shallow_copy
     538                                                                        .setOutOfFlow(FlowType.out_of_flow_faked_position);
     539
     540                                                        // xgroup_item.setBoundingRect(start_rect);
     541                                                        // xgroup_item.setOutOfFlow();
     542
     543                                                        // Finally add it in
     544                                                        // mapInItem(xgroup_item);
    509545                                                        mapInItem(xgroup_item_shallow_copy);
    510546                                                }
     
    515551                }
    516552        }
    517        
    518         /**     
    519           *     Look for any 'out-of-flow' XGroup boxes, signalled by the user drawing an arrow line to it
    520           *      => force an artificial change to such boxes so its dimensions becomes the starting point
    521           *         of the arrow line.  This will make it sort to the desired spot in the YOverlapping span
    522           */
    523        
    524         public void repositionOutOfFlowGroupsRecursive(XGroupItem toplevel_xgroup, Collection<XGroupItem> out_of_flow)
    525         {
     553
     554        /**
     555         * Look for any 'out-of-flow' XGroup boxes, signalled by the user drawing an
     556         * arrow line to it => force an artificial change to such boxes so its
     557         * dimensions becomes the starting point of the arrow line. This will make
     558         * it sort to the desired spot in the YOverlapping span
     559         */
     560
     561        public void repositionOutOfFlowGroupsRecursive(XGroupItem toplevel_xgroup,
     562                        Collection<XGroupItem> out_of_flow) {
    526563                // Map in all the items in the given list:
    527                 for (Item remaining_item: remaining_item_list) {
    528 
    529                         repositionOutOfFlowGroupsFollowLine(toplevel_xgroup,remaining_item,out_of_flow);
    530                 }       
    531 
    532                 // Now recursively work through each item's nested x-groups
    533                 for (XGroupItem xgroup_item: grouped_item_list) {
     564                for (Item remaining_item : remaining_item_list) {
     565
     566                        repositionOutOfFlowGroupsFollowLine(toplevel_xgroup,
     567                                        remaining_item, out_of_flow);
     568                }
     569
     570                // Now recursively work through each item's nested x-groups
     571                for (XGroupItem xgroup_item : grouped_item_list) {
    534572
    535573                        if (!out_of_flow.contains(xgroup_item)) {
    536                                 xgroup_item.repositionOutOfFlowGroupsRecursive(toplevel_xgroup,out_of_flow);
    537                         }
    538                 }       
    539         }
    540        
    541        
    542         public void repositionOutOfFlowGroups(XGroupItem toplevel_xgroup)
    543         {
    544 //              Collection<XGroupItem> out_of_flow = new HashSet<XGroupItem>();
     574                                xgroup_item.repositionOutOfFlowGroupsRecursive(toplevel_xgroup,
     575                                                out_of_flow);
     576                        }
     577                }
     578        }
     579
     580        public void repositionOutOfFlowGroups(XGroupItem toplevel_xgroup) {
     581                // Collection<XGroupItem> out_of_flow = new HashSet<XGroupItem>();
    545582                Collection<XGroupItem> out_of_flow = new ArrayList<XGroupItem>();
    546583
    547                 repositionOutOfFlowGroupsRecursive(toplevel_xgroup,out_of_flow);
    548                
    549 //              List<XGroupItem >toplevel_grouped_item_list = toplevel_xgroup.getGroupedItemList();
     584                repositionOutOfFlowGroupsRecursive(toplevel_xgroup, out_of_flow);
     585
     586                // List<XGroupItem >toplevel_grouped_item_list =
     587                // toplevel_xgroup.getGroupedItemList();
    550588
    551589                // ****
    552                
    553                 // Want to remove the original "out-of-position" blocks that were found, as (for each arrow
    554                 // point to such an original) shallow-copies now exist with 'faked' positions that correspond
     590
     591                // Want to remove the original "out-of-position" blocks that were found,
     592                // as (for each arrow
     593                // point to such an original) shallow-copies now exist with 'faked'
     594                // positions that correspond
    555595                // to where the arrows start.
    556                
    557                
    558                 // No longer remove them from the nested grouped structure, rather, rely on these items being
    559                 // tagged "isOutOfFLow()" to be skipped by subsequent traversal calls (e.g., to generate
     596
     597                // No longer remove them from the nested grouped structure, rather, rely
     598                // on these items being
     599                // tagged "isOutOfFLow()" to be skipped by subsequent traversal calls
     600                // (e.g., to generate
    560601                // the normal "in-flow" nested blocks)
    561                
    562                 // Structuring things this way, means that it is now possible to have multiple arrows
    563                 // pointing to the same block of code, and both "out-of-flow" arrows will be honoured,
    564                 // replicating the code at their respective start points
    565                
     602
     603                // Structuring things this way, means that it is now possible to have
     604                // multiple arrows
     605                // pointing to the same block of code, and both "out-of-flow" arrows
     606                // will be honoured,
     607                // replicating the code at their respective start points
     608
    566609                /*
    567                 for (XGroupItem xgroup_item: out_of_flow) {
    568                         removeXGroupItem(xgroup_item,toplevel_grouped_item_list);
    569                 }
    570                
    571         */
    572                
    573         }
    574        
     610                 * for (XGroupItem xgroup_item: out_of_flow) {
     611                 * removeXGroupItem(xgroup_item,toplevel_grouped_item_list); }
     612                 */
     613
     614        }
     615
    575616        /**
    576          * Focusing only on enclosures that fit within the given polygon *and* have this item
    577          * in it, the method finds the largest of these enclosures and
     617         * Focusing only on enclosures that fit within the given polygon *and* have
     618         * this item in it, the method finds the largest of these enclosures and
    578619         * returns all the items it contains
    579620         *
    580621         * @return
    581622         */
    582         public Collection<Item> getItemsInNestedEnclosure(Item given_item, AreaPolygon outer_polygon)
    583         {
     623        public Collection<Item> getItemsInNestedEnclosure(Item given_item,
     624                        AreaPolygon outer_polygon) {
    584625                Collection<Item> sameEnclosure = null;
    585626                Collection<Item> seen = new HashSet<Item>();
    586                
     627
    587628                double enclosureArea = 0.0;
    588        
     629
    589630                for (Item i : frame.getItems()) {
    590                        
    591                          // Go through all the enclosures ...
    592                          
     631
     632                        // Go through all the enclosures ...
     633
    593634                        if (!seen.contains(i) && i.isEnclosed()) {
    594                                
     635
    595636                                Collection<Item> i_enclosing_dots_coll = i.getEnclosingDots();
    596                                 List<Item> i_enclosing_dots = new ArrayList<Item>(i_enclosing_dots_coll); // Change to List of items
    597                                
     637                                List<Item> i_enclosing_dots = new ArrayList<Item>(
     638                                                i_enclosing_dots_coll); // Change to List of items
     639
    598640                                seen.addAll(i_enclosing_dots);
    599                                
     641
    600642                                Polygon i_polygon = new Polygon();
    601                                 for (int di=0; di<i_enclosing_dots.size(); di++) {
     643                                for (int di = 0; di < i_enclosing_dots.size(); di++) {
    602644                                        Item d = i_enclosing_dots.get(di);
    603                                        
     645
    604646                                        i_polygon.addPoint(d.getX(), d.getY());
    605647                                }
    606                                
    607                                 // ... looking for one that is completely contained in the 'outer_polygon' and ...
     648
     649                                // ... looking for one that is completely contained in the
     650                                // 'outer_polygon' and ...
    608651                                if (outer_polygon.completelyContains(i_polygon)) {
    609652
    610653                                        Collection<Item> enclosed = i.getEnclosedItems();
    611                                        
    612                                         // ... includes this item 
     654
     655                                        // ... includes this item
    613656                                        if (enclosed.contains(given_item)) {
    614657
    615                                                 // Remember it if it is larger than anything we've encountered before
     658                                                // Remember it if it is larger than anything we've
     659                                                // encountered before
    616660                                                if ((i.getEnclosedArea() > enclosureArea)) {
    617661                                                        enclosureArea = i.getEnclosedArea();
     
    620664                                        }
    621665                                }
    622                                
     666
    623667                        }
    624668                }
     
    629673                return sameEnclosure;
    630674        }
    631        
    632        
    633         public void separateYOverlappingItems(Frame frame, List<Item> item_list, Polygon enclosing_polygon,
    634                          List<Text> raw_text_item_list, List<XGroupItem> grouped_item_list, List<Item> remaining_item_list)
    635         {
     675
     676        public void separateYOverlappingItems(Frame frame, List<Item> item_list,
     677                        Polygon enclosing_polygon, List<Text> raw_text_item_list,
     678                        List<XGroupItem> grouped_item_list, List<Item> remaining_item_list) {
    636679                final List<Item> origonal_item_list = new ArrayList<Item>(item_list);
    637680                // raw_text_items_list => all the non-enclosed text items
    638                 // grouped_items_list  => list of all enclosures containing text items
    639                 // remaining_item_list => whatever is left: mostly dots that form part of lines/polylines/polygons
     681                // grouped_items_list => list of all enclosures containing text items
     682                // remaining_item_list => whatever is left: mostly dots that form part
     683                // of lines/polylines/polygons
    640684
    641685                AreaPolygon area_enclosing_polygon = new AreaPolygon(enclosing_polygon);
    642                
     686
    643687                List<AreaPolygon> area_enclosed_polygon_list = new ArrayList<AreaPolygon>();
    644688
    645                 while (item_list.size()>0) {
     689                while (item_list.size() > 0) {
    646690                        Item item = item_list.remove(0); // shift
    647691
    648692                        if (item instanceof Text) {
    649                                 Text text = (Text)item;
    650 
    651                                 Collection<Item> items_in_nested_enclosure_coll = getItemsInNestedEnclosure(text,area_enclosing_polygon);
    652                                 List<Item>  items_in_nested_enclosure = new ArrayList<Item>(items_in_nested_enclosure_coll); // Change to handling it as a list
    653                                
    654                                 if (items_in_nested_enclosure.size()==0) {
    655 //                                      if(text.getPixelBoundsUnion().x >= this.getBoundingXLeft() && text.getPixelBoundsUnion().y >= this.getBoundingYTop())
    656 //                                              raw_text_item_list.add(text);
    657 //                                      else remaining_item_list.add(text);
     693                                Text text = (Text) item;
     694
     695                                Collection<Item> items_in_nested_enclosure_coll = getItemsInNestedEnclosure(
     696                                                text, area_enclosing_polygon);
     697                                List<Item> items_in_nested_enclosure = new ArrayList<Item>(
     698                                                items_in_nested_enclosure_coll); // Change to handling
     699                                                                                                                        // it as a list
     700
     701                                if (items_in_nested_enclosure.size() == 0) {
     702                                        // if(text.getPixelBoundsUnion().x >=
     703                                        // this.getBoundingXLeft() && text.getPixelBoundsUnion().y
     704                                        // >= this.getBoundingYTop())
     705                                        // raw_text_item_list.add(text);
     706                                        // else remaining_item_list.add(text);
    658707                                        raw_text_item_list.add(text);
    659                                 }
    660                                 else {
    661                                
     708                                } else {
     709
    662710                                        // Something other than just this text-item is around
    663                                        
    664                                         while (items_in_nested_enclosure.size()>0) {
    665                                                
    666                                                 Item enclosure_item = items_in_nested_enclosure.remove(0); // shift
    667                                                                
    668                                                 Polygon enclosed_polygon = enclosure_item.getEnclosedShape();
    669                                                
    670                                                 if (enclosed_polygon!=null) {
    671                                                         // Got a group
     711
     712                                        while (items_in_nested_enclosure.size() > 0) {
     713
     714                                                Item enclosure_item = items_in_nested_enclosure
     715                                                                .remove(0); // shift
     716
     717                                                Polygon enclosed_polygon = enclosure_item
     718                                                                .getEnclosedShape();
     719
     720                                                if (enclosed_polygon != null) {
     721                                                        // Got a group
    672722                                                        // => Remove any items-in-nested-enclosure from:
    673723                                                        //
    674                                                         //     'item_list' (so we don't waste our time discovering and processing again these related items)
    675                                                         //   and
    676                                                         //      'raw_text_item_list' and 'remaining_item_lst' (as we now know they are part of the nested enclosed group)
    677                                                        
    678                                                         AreaPolygon area_enclosed_polygon = new AreaPolygon(enclosed_polygon);
    679                                                         area_enclosed_polygon_list.add(area_enclosed_polygon);
     724                                                        // 'item_list' (so we don't waste our time
     725                                                        // discovering and processing again these related
     726                                                        // items)
     727                                                        // and
     728                                                        // 'raw_text_item_list' and 'remaining_item_lst' (as
     729                                                        // we now know they are part of the nested enclosed
     730                                                        // group)
     731
     732                                                        AreaPolygon area_enclosed_polygon = new AreaPolygon(
     733                                                                        enclosed_polygon);
     734                                                        area_enclosed_polygon_list
     735                                                                        .add(area_enclosed_polygon);
    680736
    681737                                                        item_list.remove(enclosure_item);
    682                                                         item_list.removeAll(items_in_nested_enclosure); 
    683                                                        
     738                                                        item_list.removeAll(items_in_nested_enclosure);
     739
    684740                                                        raw_text_item_list.remove(enclosure_item);
    685                                                         raw_text_item_list.removeAll(items_in_nested_enclosure);
    686                                                        
     741                                                        raw_text_item_list
     742                                                                        .removeAll(items_in_nested_enclosure);
     743
    687744                                                        remaining_item_list.remove(enclosure_item);
    688                                                         remaining_item_list.removeAll(items_in_nested_enclosure);
    689                                                        
    690                                                         // Now remove any of the just used enclosed-items if they formed part of the perimeter
     745                                                        remaining_item_list
     746                                                                        .removeAll(items_in_nested_enclosure);
     747
     748                                                        // Now remove any of the just used enclosed-items if
     749                                                        // they formed part of the perimeter
    691750                                                        List<Item> items_on_perimeter = new ArrayList<Item>();
    692                                                        
    693                                                         Iterator<Item> item_iterator = items_in_nested_enclosure.iterator();
     751
     752                                                        Iterator<Item> item_iterator = items_in_nested_enclosure
     753                                                                        .iterator();
    694754                                                        while (item_iterator.hasNext()) {
    695755                                                                Item item_to_check = item_iterator.next();
    696                                                                 Point pt_to_check = new Point(item_to_check.getX(),item_to_check.getY());
    697                                                                
    698                                                                 if (area_enclosed_polygon.isPerimeterPoint(pt_to_check)) {
     756                                                                Point pt_to_check = new Point(
     757                                                                                item_to_check.getX(),
     758                                                                                item_to_check.getY());
     759
     760                                                                if (area_enclosed_polygon
     761                                                                                .isPerimeterPoint(pt_to_check)) {
    699762                                                                        items_on_perimeter.add(item_to_check);
    700763                                                                }
    701764                                                        }
    702                                                
    703                                                         items_in_nested_enclosure.removeAll(items_on_perimeter);
     765
     766                                                        items_in_nested_enclosure
     767                                                                        .removeAll(items_on_perimeter);
    704768                                                }
    705                                                
     769
    706770                                                else {
    707771                                                        // Text or single point (with no enclosure)
    708                                                
     772
    709773                                                        // This item doesn't feature at this level
    710                                                         // => will be subsequently capture by the group polygon below
    711                                                         //    and processed by the recursive call
    712                                                        
     774                                                        // => will be subsequently capture by the group
     775                                                        // polygon below
     776                                                        // and processed by the recursive call
     777
    713778                                                        item_list.remove(enclosure_item);
    714779                                                }
    715780                                        }
    716                                        
     781
    717782                                }
    718783
     
    726791
    727792                // Sort areas, smallest to largest
    728                 Collections.sort(area_enclosed_polygon_list, new Comparator<AreaPolygon>() {
    729 
    730                         public int compare(AreaPolygon ap1, AreaPolygon ap2) {
    731                                 Double ap1_area = ap1.getArea();
    732                                 Double ap2_area = ap2.getArea();
    733 
    734                                 return ap2_area.compareTo(ap1_area);
    735                         }
    736                 });
    737 
    738                 // Remove any enclosed polygon areas that are completely contained in a larger one
    739 
    740                 for (int ri=0; ri<area_enclosed_polygon_list.size(); ri++) {
     793                Collections.sort(area_enclosed_polygon_list,
     794                                new Comparator<AreaPolygon>() {
     795
     796                                        public int compare(AreaPolygon ap1, AreaPolygon ap2) {
     797                                                Double ap1_area = ap1.getArea();
     798                                                Double ap2_area = ap2.getArea();
     799
     800                                                return ap2_area.compareTo(ap1_area);
     801                                        }
     802                                });
     803
     804                // Remove any enclosed polygon areas that are completely contained in a
     805                // larger one
     806
     807                for (int ri = 0; ri < area_enclosed_polygon_list.size(); ri++) {
    741808                        // ri = remove index pos
    742809
    743810                        AreaPolygon rpoly = area_enclosed_polygon_list.get(ri);
    744811
    745                         for (int ci=ri+1; ci<area_enclosed_polygon_list.size(); ci++) {
     812                        for (int ci = ri + 1; ci < area_enclosed_polygon_list.size(); ci++) {
    746813                                // ci = check index pos
    747814                                AreaPolygon cpoly = area_enclosed_polygon_list.get(ci);
     
    753820                        }
    754821                }
    755                
    756 
    757                 // By this point, guaranteed that the remaining polygons are the largest ones
     822
     823                // By this point, guaranteed that the remaining polygons are the largest
     824                // ones
    758825                // that capture groups of items
    759826                //
    760                 // There may be sub-groupings within them, which is the reason for the recursive call below
    761                
    762 
    763                 for (AreaPolygon area_polygon: area_enclosed_polygon_list) {
    764 
    765                         Collection<Item> enclosed_items = FrameUtils.getItemsEnclosedBy(frame, area_polygon);
    766                         List<Item> enclosed_item_list = new ArrayList<Item>(enclosed_items);
    767                        
    768                         int i=0;
    769                         while (i<enclosed_item_list.size()) {
     827                // There may be sub-groupings within them, which is the reason for the
     828                // recursive call below
     829
     830                for (AreaPolygon area_polygon : area_enclosed_polygon_list) {
     831
     832                        Collection<Item> enclosed_items = FrameUtils.getItemsEnclosedBy(
     833                                        frame, area_polygon);
     834                        List<Item> enclosed_item_list = new ArrayList<Item>(enclosed_items);
     835
     836                        int i = 0;
     837                        while (i < enclosed_item_list.size()) {
    770838                                Item enclosed_item = enclosed_item_list.get(i);
    771                                
    772                                 // Filter out enclosed-items points that are part of the polygon's perimeter
     839
     840                                // Filter out enclosed-items points that are part of the
     841                                // polygon's perimeter
    773842                                if (area_polygon.isPerimeterPoint(enclosed_item.getPosition())) {
    774843                                        enclosed_item_list.remove(i);
    775                                         //Don't include items the user hasn't asked us to.
    776                                 }
    777                                 //Only include items the user has asked to to include.
    778                                 else if(!origonal_item_list.contains(enclosed_item)) enclosed_item_list.remove(i);
     844                                        // Don't include items the user hasn't asked us to.
     845                                }
     846                                // Only include items the user has asked to to include.
     847                                else if (!origonal_item_list.contains(enclosed_item))
     848                                        enclosed_item_list.remove(i);
    779849                                else {
    780850                                        i++;
    781851                                }
    782852                        }
    783                        
     853
    784854                        // Recursively work on the identified sub-group
    785                        
    786                         XGroupItem xgroup_item = new XGroupItem(frame, enclosed_item_list, area_polygon);
     855
     856                        XGroupItem xgroup_item = new XGroupItem(frame, enclosed_item_list,
     857                                        area_polygon);
    787858
    788859                        grouped_item_list.add(xgroup_item);
     
    790861        }
    791862
    792        
    793        
    794         protected void castShadowIntoEmptySpace(YOverlappingItemsTopEdge y_item_span_top_edge, int yt, int yb)
    795         {
     863        protected void castShadowIntoEmptySpace(
     864                        YOverlappingItemsTopEdge y_item_span_top_edge, int yt, int yb) {
    796865                // Assumes that all entries cast into are currently null
    797                 // => Use the more general castShadow() below, if this is not guaranteed to be the case
    798                
    799                 YOverlappingItemsShadow y_span_shadow = new YOverlappingItemsShadow(y_item_span_top_edge);
    800                
    801                 for (int y=yt; y<=yb; y++) {
    802 
    803                         setYOverlappingItemsSpan(y,y_span_shadow);
    804                 }
    805         }
    806        
    807         protected void castShadow(YOverlappingItemsTopEdge y_item_span_top_edge, int yt, int yb)
    808         {
    809                 // Cast shadows only in places where there are currently no shadow entries
    810                
    811                 YOverlappingItemsShadow y_span_shadow = new YOverlappingItemsShadow(y_item_span_top_edge);
    812                
    813                 int y=yt;
    814                
    815                 while (y<=yb) {
     866                // => Use the more general castShadow() below, if this is not guaranteed
     867                // to be the case
     868
     869                YOverlappingItemsShadow y_span_shadow = new YOverlappingItemsShadow(
     870                                y_item_span_top_edge);
     871
     872                for (int y = yt; y <= yb; y++) {
     873
     874                        setYOverlappingItemsSpan(y, y_span_shadow);
     875                }
     876        }
     877
     878        protected void castShadow(YOverlappingItemsTopEdge y_item_span_top_edge,
     879                        int yt, int yb) {
     880                // Cast shadows only in places where there are currently no shadow
     881                // entries
     882
     883                YOverlappingItemsShadow y_span_shadow = new YOverlappingItemsShadow(
     884                                y_item_span_top_edge);
     885
     886                int y = yt;
     887
     888                while (y <= yb) {
    816889                        YOverlappingItemsSpan y_item_span = getYOverlappingItemsSpan(y);
    817                        
    818                         if (y_item_span==null) {
    819                                 setYOverlappingItemsSpan(y,y_span_shadow);
     890
     891                        if (y_item_span == null) {
     892                                setYOverlappingItemsSpan(y, y_span_shadow);
    820893                                y++;
    821                         }
    822                         else if (y_item_span instanceof YOverlappingItemsTopEdge) {
    823                                 // Our shadow has run into another top-edged zone
    824                                 //   => need to extend the shadow to include this zone as well
    825                                 //      (making this encountered top-edge obsolete)
    826                                
     894                        } else if (y_item_span instanceof YOverlappingItemsTopEdge) {
     895                                // Our shadow has run into another top-edged zone
     896                                // => need to extend the shadow to include this zone as well
     897                                // (making this encountered top-edge obsolete)
     898
    827899                                // Merge the newly encountered top-line in with the current one
    828900                                // and change all its shadow references to our (dominant) one
    829                                
    830                                 XOrderedLine dominant_x_line = y_item_span_top_edge.getXOrderedLine();
    831                                
    832                                 YOverlappingItemsTopEdge obsolete_top_edge = (YOverlappingItemsTopEdge)y_item_span;
    833                                 XOrderedLine obsolete_x_line = obsolete_top_edge.getXOrderedLine();
    834                                
    835                                 for (XItem xitem: obsolete_x_line.getXItemList()) {
    836                                        
     901
     902                                XOrderedLine dominant_x_line = y_item_span_top_edge
     903                                                .getXOrderedLine();
     904
     905                                YOverlappingItemsTopEdge obsolete_top_edge = (YOverlappingItemsTopEdge) y_item_span;
     906                                XOrderedLine obsolete_x_line = obsolete_top_edge
     907                                                .getXOrderedLine();
     908
     909                                for (XItem xitem : obsolete_x_line.getXItemList()) {
     910
    837911                                        dominant_x_line.orderedMergeItem(xitem);
    838912                                }
    839                                
     913
    840914                                while (y_item_span != null) {
    841                                        
    842                                         setYOverlappingItemsSpan(y,y_span_shadow);
    843                                        
     915
     916                                        setYOverlappingItemsSpan(y, y_span_shadow);
     917
    844918                                        y++;
    845                                        
    846                                         if (y<=yb) {
     919
     920                                        if (y <= yb) {
    847921                                                y_item_span = getYOverlappingItemsSpan(y);
    848                                         }
    849                                         else {
     922                                        } else {
    850923                                                y_item_span = null;
    851924                                        }
    852925                                }
    853                         }
    854                         else {
     926                        } else {
    855927                                y++;
    856928                        }
    857929                }
    858930        }
    859        
    860         protected int autocropToTop(XItem xitem)
    861         {
    862                 // top-edge over-spill can occur (and is acceptable) when (for example) the given xitem is a raw-text item
    863                 // that doesn't neatly fit in an enclosed area (i,e., is poking out the top of an enclosing rectangle) 
     931
     932        protected int autocropToTop(XItem xitem) {
     933                // top-edge over-spill can occur (and is acceptable) when (for example)
     934                // the given xitem is a raw-text item
     935                // that doesn't neatly fit in an enclosed area (i,e., is poking out the
     936                // top of an enclosing rectangle)
    864937                // => cut down to the top of 'this' xgroupitem
    865                
     938
    866939                int yt = xitem.getBoundingYTop();
    867                                
    868                
     940
    869941                yt = cropToTop(yt); // Only changes yt if in an over-spill situation
    870                
     942
    871943                return yt;
    872                
    873         }
    874        
    875         protected int autocropToBot(XItem xitem)
    876         {
    877                
    878                 // similar to autocropToTop(), bottom-edge over-spill can occur (and is acceptable) with
    879                 // a less than precise placed raw-text item 
    880                
     944
     945        }
     946
     947        protected int autocropToBot(XItem xitem) {
     948
     949                // similar to autocropToTop(), bottom-edge over-spill can occur (and is
     950                // acceptable) with
     951                // a less than precise placed raw-text item
     952
    881953                int yb = xitem.getBoundingYBot();
    882                
     954
    883955                yb = cropToBot(yb); // Only changes yb if in an over-spill situation
    884                
     956
    885957                return yb;
    886958        }
    887        
    888         protected boolean yExtentIntersection(XGroupItem xgroup_item1, XGroupItem xgroup_item2)
    889         {
     959
     960        protected boolean yExtentIntersection(XGroupItem xgroup_item1,
     961                        XGroupItem xgroup_item2) {
    890962                // Computation applied to y-extent of each rectangle
    891                
    892                 // To intersect, either a point in item1 falls inside item2,
    893                 // or else item2 is completely within item1
    894                
    895        
     963
     964                // To intersect, either a point in item1 falls inside item2,
     965                // or else item2 is completely within item1
     966
    896967                int yt1 = xgroup_item1.getBoundingYTop();
    897968                int yb1 = xgroup_item1.getBoundingYBot();
    898                
     969
    899970                int yt2 = xgroup_item2.getBoundingYTop();
    900                
     971
    901972                // yt1 insides item2?
    902973                if (xgroup_item2.containedInYExtent(yt1)) {
    903974                        return true;
    904975                }
    905                
     976
    906977                // yb1 inside item2?
    907978                if (xgroup_item2.containedInYExtent(yb1)) {
    908979                        return true;
    909980                }
    910                
     981
    911982                // item2 completely inside item1?
    912983                //
     
    914985                // by checking only one of the values is inside.
    915986                // Doesn't matter which => choose yt2
    916                
     987
    917988                if (xgroup_item1.containedInYExtent(yt2)) {
    918989                        return true;
    919990                }
    920                
     991
    921992                // Get to here if there is no intersection
    922993                return false;
    923                
    924         }
    925         protected ArrayList<XGroupItem> calcXGroupYExtentIntersection(XGroupItem xgroup_pivot_item, List<XGroupItem> xgroup_item_list)
    926         {
     994
     995        }
     996
     997        protected ArrayList<XGroupItem> calcXGroupYExtentIntersection(
     998                        XGroupItem xgroup_pivot_item, List<XGroupItem> xgroup_item_list) {
    927999                ArrayList<XGroupItem> intersect_list = new ArrayList<XGroupItem>();
    928                
    929                 for (XGroupItem xgroup_item: xgroup_item_list) {
     1000
     1001                for (XGroupItem xgroup_item : xgroup_item_list) {
    9301002
    9311003                        if (xgroup_item == xgroup_pivot_item) {
     
    9341006                        }
    9351007
    936                         if (yExtentIntersection(xgroup_pivot_item,xgroup_item)) {
     1008                        if (yExtentIntersection(xgroup_pivot_item, xgroup_item)) {
    9371009                                intersect_list.add(xgroup_item);
    9381010                        }
    9391011                }
    940        
     1012
    9411013                return intersect_list;
    9421014        }
    943        
    944         protected ArrayList<YOverlappingItemsTopEdge> calcYSpanOverlap(XItem xitem)
    945         {
     1015
     1016        protected ArrayList<YOverlappingItemsTopEdge> calcYSpanOverlap(XItem xitem) {
    9461017                int yt = autocropToTop(xitem);
    9471018                int yb = autocropToBot(xitem);
    948                
    949                
     1019
    9501020                ArrayList<YOverlappingItemsTopEdge> top_edge_list = new ArrayList<YOverlappingItemsTopEdge>();
    951                
    952                 for (int y=yt; y<=yb; y++) {
     1021
     1022                for (int y = yt; y <= yb; y++) {
    9531023
    9541024                        YOverlappingItemsSpan item_span = getYOverlappingItemsSpan(y);
     
    9581028                                if (item_span instanceof YOverlappingItemsTopEdge) {
    9591029
    960                                         YOverlappingItemsTopEdge y_item_span_top_edge = (YOverlappingItemsTopEdge)item_span;
    961                                        
     1030                                        YOverlappingItemsTopEdge y_item_span_top_edge = (YOverlappingItemsTopEdge) item_span;
     1031
    9621032                                        top_edge_list.add(y_item_span_top_edge);
    9631033                                }
     
    9651035
    9661036                }
    967                
     1037
    9681038                return top_edge_list;
    9691039        }
    970        
    971        
    972         protected boolean multipleYSpanOverlap(XItem xitem)
    973         {
     1040
     1041        protected boolean multipleYSpanOverlap(XItem xitem) {
    9741042                return calcYSpanOverlap(xitem).size() > 0;
    9751043        }
    976        
    977         public void mapInItem(XItem xitem)
    978         {
    979                
     1044
     1045        public void mapInItem(XItem xitem) {
     1046
    9801047                int yt = autocropToTop(xitem);
    9811048                int yb = autocropToBot(xitem);
    9821049                /*
    983                 int yt = xitem.getBoundingYTop();
    984                 int yb = xitem.getBoundingYBot();
    985                                
    986                 // top-edge over-spill can occur (and is acceptable) when (for example) the given xitem is a raw-text item
    987                 // that doesn't neatly fit in an enclosed area (i,e., is poking out the top of an enclosing rectangle) 
    988                 yt = cropToTop(yt); // Only changes yt if in an over-spill situation
    989        
    990                 // similarly, bottom-edge over-spill can occur (and is acceptable) with a less than precise placed raw-text item
    991                 yb = cropToBot(yb); // Only changes yb if in an over-spill situation
    992                         */
    993                
    994                 // Merge into 'items_span' checking for overlaps (based on xitem's y-span)
    995                                
     1050                 * int yt = xitem.getBoundingYTop(); int yb = xitem.getBoundingYBot();
     1051                 *
     1052                 * // top-edge over-spill can occur (and is acceptable) when (for
     1053                 * example) the given xitem is a raw-text item // that doesn't neatly
     1054                 * fit in an enclosed area (i,e., is poking out the top of an enclosing
     1055                 * rectangle) yt = cropToTop(yt); // Only changes yt if in an over-spill
     1056                 * situation
     1057                 *
     1058                 * // similarly, bottom-edge over-spill can occur (and is acceptable)
     1059                 * with a less than precise placed raw-text item yb = cropToBot(yb); //
     1060                 * Only changes yb if in an over-spill situation
     1061                 */
     1062
     1063                // Merge into 'items_span' checking for overlaps (based on xitem's
     1064                // y-span)
     1065
    9961066                boolean merged_item = false;
    997                 for (int y=yt; y<=yb; y++) {
     1067                for (int y = yt; y <= yb; y++) {
    9981068
    9991069                        YOverlappingItemsSpan item_span = getYOverlappingItemsSpan(y);
     
    10061076
    10071077                                        // Need to:
    1008                                         //   1. *Required*      Insert new item into current x-ordered line
    1009                                         //   2. *Conditionally* Move entire x-ordered line up to higher 'y' top edge
    1010                                         //   3. *Required*      Cast shadow for new item
     1078                                        // 1. *Required* Insert new item into current x-ordered line
     1079                                        // 2. *Conditionally* Move entire x-ordered line up to
     1080                                        // higher 'y' top edge
     1081                                        // 3. *Required* Cast shadow for new item
    10111082
    10121083                                        // Note for Step 2:
    1013                                         // i)  No need to do the move if y == yt
    1014                                         //      (the case when the new top edge is exactly the same height as the existing one)
    1015                                         // ii) If moving top-edge (the case when y > yt) then no need to recalculate the top edge for existing shadows, as
    1016                                         //       this 'connection' is stored as a reference
    1017 
     1084                                        // i) No need to do the move if y == yt
     1085                                        // (the case when the new top edge is exactly the same
     1086                                        // height as the existing one)
     1087                                        // ii) If moving top-edge (the case when y > yt) then no
     1088                                        // need to recalculate the top edge for existing shadows, as
     1089                                        // this 'connection' is stored as a reference
    10181090
    10191091                                        // Step 1: insert into existing top-edge
    10201092
    1021                                         YOverlappingItemsTopEdge y_item_span_top_edge = (YOverlappingItemsTopEdge)item_span;
    1022                                         XOrderedLine xitem_span = y_item_span_top_edge.getXOrderedLine();
    1023 
    1024                                         xitem_span.orderedMergeItem(xitem.getBoundingXLeft(),xitem);
    1025 
    1026                                         // Step 2: if our new top-edge is higher than the existing one, then need to move existing top-edge
    1027                                         if (y>yt) {
     1093                                        YOverlappingItemsTopEdge y_item_span_top_edge = (YOverlappingItemsTopEdge) item_span;
     1094                                        XOrderedLine xitem_span = y_item_span_top_edge
     1095                                                        .getXOrderedLine();
     1096
     1097                                        xitem_span
     1098                                                        .orderedMergeItem(xitem.getBoundingXLeft(), xitem);
     1099
     1100                                        // Step 2: if our new top-edge is higher than the existing
     1101                                        // one, then need to move existing top-edge
     1102                                        if (y > yt) {
    10281103
    10291104                                                // Move to new position
     
    10311106
    10321107                                                // Old position needs to become a shadow reference
    1033                                                 YOverlappingItemsShadow y_span_shadow = new YOverlappingItemsShadow(y_item_span_top_edge);
    1034                                                 setYOverlappingItemsSpan(y,y_span_shadow);
     1108                                                YOverlappingItemsShadow y_span_shadow = new YOverlappingItemsShadow(
     1109                                                                y_item_span_top_edge);
     1110                                                setYOverlappingItemsSpan(y, y_span_shadow);
    10351111                                        }
    10361112
    1037 
    10381113                                        // Step 3: Cast shadow
    1039                                         castShadow(y_item_span_top_edge, yt+1, yb);
    1040 
    1041                                 }
    1042                                 else {
    1043                                         // Top edge to our new item has hit a shadow entry (straight off)
    1044                                         // => Look up what the shadow references, and then add in to that
    1045 
    1046                                         // Effectively after the shadow reference lookup this is the same
    1047                                         // as the above, without the need to worry about Step 2 (as no move is needed)
    1048 
    1049                                         YOverlappingItemsShadow y_item_span_shadow = (YOverlappingItemsShadow)item_span;
    1050                                         YOverlappingItemsTopEdge y_item_span_top_edge = y_item_span_shadow.getTopEdge();
    1051 
    1052                                         XOrderedLine xitem_span = y_item_span_top_edge.getXOrderedLine();
     1114                                        castShadow(y_item_span_top_edge, yt + 1, yb);
     1115
     1116                                } else {
     1117                                        // Top edge to our new item has hit a shadow entry (straight
     1118                                        // off)
     1119                                        // => Look up what the shadow references, and then add in to
     1120                                        // that
     1121
     1122                                        // Effectively after the shadow reference lookup this is the
     1123                                        // same
     1124                                        // as the above, without the need to worry about Step 2 (as
     1125                                        // no move is needed)
     1126
     1127                                        YOverlappingItemsShadow y_item_span_shadow = (YOverlappingItemsShadow) item_span;
     1128                                        YOverlappingItemsTopEdge y_item_span_top_edge = y_item_span_shadow
     1129                                                        .getTopEdge();
     1130
     1131                                        XOrderedLine xitem_span = y_item_span_top_edge
     1132                                                        .getXOrderedLine();
    10531133
    10541134                                        // merge with this item list, preserving x ordering
    1055                                         xitem_span.orderedMergeItem(xitem.getBoundingXLeft(),xitem);
     1135                                        xitem_span
     1136                                                        .orderedMergeItem(xitem.getBoundingXLeft(), xitem);
    10561137
    10571138                                        // Now Cast shadow
    1058                                         castShadow(y_item_span_top_edge, yt+1, yb);
     1139                                        castShadow(y_item_span_top_edge, yt + 1, yb);
    10591140                                }
    10601141
     
    10661147                }
    10671148
    1068                 // Having checked all the y-location's ('yt' to 'yb') of this x-item, if all y-span entries were found to be null
     1149                // Having checked all the y-location's ('yt' to 'yb') of this x-item, if
     1150                // all y-span entries were found to be null
    10691151                // => 'merged_item' is still false
    1070                
     1152
    10711153                if (!merged_item) {
    1072                         // xitem didn't intersect with any existing y-spans
    1073                         // => simple case for add (i.e. all entries affected by map are currently null)
    1074 
    1075                         // Start up a new x-ordered-line (consisting of only 'xitem'), add in top edge and cast shadow
    1076                        
     1154                        // xitem didn't intersect with any existing y-spans
     1155                        // => simple case for add (i.e. all entries affected by map are
     1156                        // currently null)
     1157
     1158                        // Start up a new x-ordered-line (consisting of only 'xitem'), add
     1159                        // in top edge and cast shadow
     1160
    10771161                        XOrderedLine xitem_line = new XOrderedLine(xitem);
    1078                        
    1079                         YOverlappingItemsTopEdge y_item_span_top_edge = new YOverlappingItemsTopEdge(xitem_line);
    1080                
    1081                         setYOverlappingItemsSpan(yt,y_item_span_top_edge);
    1082 
    1083                         castShadowIntoEmptySpace(y_item_span_top_edge, yt+1, yb);
    1084                 }
    1085 
    1086 
    1087         }
    1088        
    1089         private ArrayList<DimensionExtent> calcXGroupXGaps(XGroupItem xgroup_pivot_item, List<XGroupItem> xgroup_item_list)
    1090         {
     1162
     1163                        YOverlappingItemsTopEdge y_item_span_top_edge = new YOverlappingItemsTopEdge(
     1164                                        xitem_line);
     1165
     1166                        setYOverlappingItemsSpan(yt, y_item_span_top_edge);
     1167
     1168                        castShadowIntoEmptySpace(y_item_span_top_edge, yt + 1, yb);
     1169                }
     1170
     1171        }
     1172
     1173        private ArrayList<DimensionExtent> calcXGroupXGaps(
     1174                        XGroupItem xgroup_pivot_item, List<XGroupItem> xgroup_item_list) {
    10911175                // 'xgroup_pivot_item' current not used!!
    1092                
     1176
    10931177                int enclosing_xl = getBoundingXLeft();
    10941178                int enclosing_xr = getBoundingXRight();
    1095                
    1096                 int enclosing_x_dim = enclosing_xr - enclosing_xl +1;
    1097                 boolean is_x_shadow[] = new boolean[enclosing_x_dim]; // defaults all values to false
    1098                
     1179
     1180                int enclosing_x_dim = enclosing_xr - enclosing_xl + 1;
     1181                boolean is_x_shadow[] = new boolean[enclosing_x_dim]; // defaults all
     1182                                                                                                                                // values to
     1183                                                                                                                                // false
     1184
    10991185                ArrayList<DimensionExtent> x_gap_list = new ArrayList<DimensionExtent>();
    1100                
    1101                 for (XGroupItem xgroup_item: xgroup_item_list) {
     1186
     1187                for (XGroupItem xgroup_item : xgroup_item_list) {
    11021188                        int xl = xgroup_item.getBoundingXLeft();
    11031189                        int xr = xgroup_item.getBoundingXRight();
    1104                        
    1105                         for (int x=xl; x<=xr; x++) {
     1190
     1191                        for (int x = xl; x <= xr; x++) {
    11061192                                int x_offset = x - enclosing_xl;
    11071193                                is_x_shadow[x_offset] = true;
    11081194                        }
    11091195                }
    1110                
    1111                 // New find where the contiguous runs of 'false' are, as they point to the gaps
    1112                
     1196
     1197                // New find where the contiguous runs of 'false' are, as they point to
     1198                // the gaps
     1199
    11131200                int x = 1;
    11141201                int start_x_gap = enclosing_xl;
    11151202                boolean in_gap = true;
    1116                
     1203
    11171204                while (x < is_x_shadow.length) {
    1118                         boolean prev_is_shadow = is_x_shadow[x-1];
     1205                        boolean prev_is_shadow = is_x_shadow[x - 1];
    11191206                        boolean this_is_shadow = is_x_shadow[x];
    11201207
     
    11231210                                start_x_gap = enclosing_xl + x;
    11241211                                in_gap = true;
    1125                         }
    1126                         else if (!prev_is_shadow && this_is_shadow) {
     1212                        } else if (!prev_is_shadow && this_is_shadow) {
    11271213                                // reached the end of a gap, record it
    1128                                 int end_x_gap = enclosing_xl + x -1;
    1129                                 DimensionExtent de = new DimensionExtent(start_x_gap,end_x_gap);
     1214                                int end_x_gap = enclosing_xl + x - 1;
     1215                                DimensionExtent de = new DimensionExtent(start_x_gap, end_x_gap);
    11301216                                x_gap_list.add(de);
    11311217                                in_gap = false;
     
    11331219                        x++;
    11341220                }
    1135                
     1221
    11361222                if (in_gap) {
    1137                         int end_x_gap = enclosing_xl + x -1;
    1138                         DimensionExtent de = new DimensionExtent(start_x_gap,end_x_gap);
     1223                        int end_x_gap = enclosing_xl + x - 1;
     1224                        DimensionExtent de = new DimensionExtent(start_x_gap, end_x_gap);
    11391225                        x_gap_list.add(de);
    11401226                }
    1141                
     1227
    11421228                return x_gap_list;
    11431229        }
    11441230
    1145         protected void boxMultipleXRawItemsInGaps(XGroupItem xgroup_pivot_item, ArrayList<DimensionExtent> x_text_gap_list)
    1146         {
     1231        protected void boxMultipleXRawItemsInGaps(XGroupItem xgroup_pivot_item,
     1232                        ArrayList<DimensionExtent> x_text_gap_list) {
    11471233                ArrayList<YOverlappingItemsTopEdge> y_span_overlap = calcYSpanOverlap(xgroup_pivot_item);
    1148                
    1149                 // work out where continuous runs of raw-text items intersect with the gaps occurring between boxed items
    1150                
    1151                 // foreach x-gap,
    1152                 //    foreach y-span's list of x-sorted objects,
    1153                 //      => see how many raw-text items fit into it
    1154                
    1155                
     1234
     1235                // work out where continuous runs of raw-text items intersect with the
     1236                // gaps occurring between boxed items
     1237
     1238                // foreach x-gap,
     1239                // foreach y-span's list of x-sorted objects,
     1240                // => see how many raw-text items fit into it
     1241
    11561242                ArrayList<ArrayList<XRawItem>> implicit_box_list = new ArrayList<ArrayList<XRawItem>>();
    1157                
    1158                 for (DimensionExtent de_gap: x_text_gap_list) {
    1159                        
     1243
     1244                for (DimensionExtent de_gap : x_text_gap_list) {
     1245
    11601246                        int deg_xl = de_gap.min;
    11611247                        int deg_xr = de_gap.max;
    1162                        
     1248
    11631249                        ArrayList<XRawItem> grouped_raw_text_list = new ArrayList<XRawItem>();
    1164                        
     1250
    11651251                        int y_span_line_count = 0;
    1166                        
    1167                         for (YOverlappingItemsTopEdge y_top_edge: y_span_overlap) {
    1168                                
     1252
     1253                        for (YOverlappingItemsTopEdge y_top_edge : y_span_overlap) {
     1254
    11691255                                List<XItem> x_item_list = y_top_edge.x_items.getXItemList();
    11701256
    11711257                                boolean used_x_raw_text = false;
    1172                                
    1173                                 for (XItem x_item: x_item_list) {
    1174                                
     1258
     1259                                for (XItem x_item : x_item_list) {
     1260
    11751261                                        if (x_item instanceof XRawItem) {
    1176                                                 XRawItem x_raw_item = (XRawItem)x_item;
    1177                                                
     1262                                                XRawItem x_raw_item = (XRawItem) x_item;
     1263
    11781264                                                int xri_xl = x_raw_item.getBoundingXLeft();
    11791265                                                int xri_xr = x_raw_item.getBoundingXRight();
    1180                                                
    1181                                                 if ((xri_xl>=deg_xl) && (xri_xr<=deg_xr)) {
     1266
     1267                                                if ((xri_xl >= deg_xl) && (xri_xr <= deg_xr)) {
    11821268                                                        grouped_raw_text_list.add(x_raw_item);
    11831269                                                        used_x_raw_text = true;
     
    11851271                                        }
    11861272                                }
    1187                                
     1273
    11881274                                if (used_x_raw_text) {
    11891275                                        y_span_line_count++;
    11901276                                }
    11911277                        }
    1192                        
    1193                         // Only interested in implicitly boxing if the formed group is used over 2 or more y-span lines
    1194                         if (y_span_line_count>=2) {
     1278
     1279                        // Only interested in implicitly boxing if the formed group is used
     1280                        // over 2 or more y-span lines
     1281                        if (y_span_line_count >= 2) {
    11951282                                implicit_box_list.add(grouped_raw_text_list);
    11961283                        }
    11971284                }
    1198                
    1199                 //System.err.println("*** Number of implicit groups found: " + implicit_box_list.size());
    1200                
     1285
     1286                // System.err.println("*** Number of implicit groups found: " +
     1287                // implicit_box_list.size());
     1288
    12011289                for (ArrayList<XRawItem> implicit_x_item_list : implicit_box_list) {
    1202                        
    1203                         for (YOverlappingItemsTopEdge y_top_edge: y_span_overlap) {
    1204                                
    1205                                 List<XItem> yspan_x_item_list = y_top_edge.x_items.getXItemList();
    1206                                
     1290
     1291                        for (YOverlappingItemsTopEdge y_top_edge : y_span_overlap) {
     1292
     1293                                List<XItem> yspan_x_item_list = y_top_edge.x_items
     1294                                                .getXItemList();
     1295
    12071296                                // Remove all the XRawItems from the current y-span
    12081297                                yspan_x_item_list.removeAll(implicit_x_item_list);
    1209                        
    1210                         }
    1211                        
     1298
     1299                        }
     1300
    12121301                        // Create a list of original Text items
    12131302                        // (OK that they are not y-ordered)
    1214                         ArrayList<Item> implicit_item_list= new ArrayList<Item>();
    1215                         for (XRawItem x_raw_item: implicit_x_item_list) {
     1303                        ArrayList<Item> implicit_item_list = new ArrayList<Item>();
     1304                        for (XRawItem x_raw_item : implicit_x_item_list) {
    12161305                                Item item = (Text) x_raw_item.item;
    12171306                                implicit_item_list.add(item);
     
    12191308
    12201309                        // Now insert them as their own boxed up items
    1221                         XGroupItem implicit_xgroup = new XGroupItem(frame,implicit_item_list);
     1310                        XGroupItem implicit_xgroup = new XGroupItem(frame,
     1311                                        implicit_item_list);
    12221312                        this.mapInItem(implicit_xgroup);
    12231313                }
    1224                
    1225         }
    1226        
    1227         protected void implicitBoxing(XGroupItem xgroup_pivot_item,List<XGroupItem> xgroup_item_list) {
    1228                
    1229                 // Implicit boxing is needed if there are two or more raw-text items
     1314
     1315        }
     1316
     1317        protected void implicitBoxing(XGroupItem xgroup_pivot_item,
     1318                        List<XGroupItem> xgroup_item_list) {
     1319
     1320                // Implicit boxing is needed if there are two or more raw-text items
    12301321                // that overlap in y-span-map of the given xgroup_item
    1231                
     1322
    12321323                // First establish if there is any kind of multiple overlap
    12331324                if (multipleYSpanOverlap(xgroup_pivot_item)) {
    1234                        
    1235                         // Overlap could be with other boxed items, so need to investigate further
    1236                        
    1237                         // Do this by working out if there are any raw-text items lurking between the pivot xgroup_item
    1238                         // and the list of other xgroup_items
    1239                        
    1240                         // Step 1: Get list intersection (y-dim) of this group item, with any
    1241                         //         other group items in xgroup_item_list
    1242                         ArrayList<XGroupItem> y_overlapping_xgroup_item_list = calcXGroupYExtentIntersection(xgroup_pivot_item,xgroup_item_list);
    1243                        
    1244                         // Step 2: Work out where the gaps are between the y-overlapping boxes in the x-dimension
    1245                         ArrayList<DimensionExtent> x_text_gap_list = calcXGroupXGaps(xgroup_pivot_item,y_overlapping_xgroup_item_list);
    1246                        
    1247                         // Step 3: Remove any sequences of raw-text items that fall in the gaps from YSpan, box them up, and reinsert
    1248                         boxMultipleXRawItemsInGaps(xgroup_pivot_item,x_text_gap_list);
    1249                        
    1250                 }
    1251         }
    1252        
    1253        
    1254 
    1255         public void mapInXGroupItemsRecursive(List<XGroupItem> xgroup_item_list)
    1256         {
    1257                
     1325
     1326                        // Overlap could be with other boxed items, so need to investigate
     1327                        // further
     1328
     1329                        // Do this by working out if there are any raw-text items lurking
     1330                        // between the pivot xgroup_item
     1331                        // and the list of other xgroup_items
     1332
     1333                        // Step 1: Get list intersection (y-dim) of this group item, with
     1334                        // any
     1335                        // other group items in xgroup_item_list
     1336                        ArrayList<XGroupItem> y_overlapping_xgroup_item_list = calcXGroupYExtentIntersection(
     1337                                        xgroup_pivot_item, xgroup_item_list);
     1338
     1339                        // Step 2: Work out where the gaps are between the y-overlapping
     1340                        // boxes in the x-dimension
     1341                        ArrayList<DimensionExtent> x_text_gap_list = calcXGroupXGaps(
     1342                                        xgroup_pivot_item, y_overlapping_xgroup_item_list);
     1343
     1344                        // Step 3: Remove any sequences of raw-text items that fall in the
     1345                        // gaps from YSpan, box them up, and reinsert
     1346                        boxMultipleXRawItemsInGaps(xgroup_pivot_item, x_text_gap_list);
     1347
     1348                }
     1349        }
     1350
     1351        public void mapInXGroupItemsRecursive(List<XGroupItem> xgroup_item_list) {
     1352
    12581353                // Map in all the items in the given list:
    1259                 for (XGroupItem xgroup_item: xgroup_item_list) {
     1354                for (XGroupItem xgroup_item : xgroup_item_list) {
    12601355                        if (!xgroup_item.isOriginalOutOfFlowItem()) {
    1261                                
     1356
    12621357                                // See if any implicit boxing of raw-text items is needed
    12631358                                if (doImplicitBoxing) {
    1264                                         implicitBoxing(xgroup_item,xgroup_item_list);
     1359                                        implicitBoxing(xgroup_item, xgroup_item_list);
    12651360                                }
    12661361                                mapInItem(xgroup_item); // Map in this x-group-item
    12671362                        }
    1268                 }       
    1269 
    1270                 // Now recursively work through each item's nested x-groups
    1271                 for (XGroupItem xgroup_item: xgroup_item_list) {
    1272                                
    1273                         List<XGroupItem> nested_xgroup_item_list = xgroup_item.getGroupedItemList();
    1274 
    1275                         if (nested_xgroup_item_list.size() >0) {
     1363                }
     1364
     1365                // Now recursively work through each item's nested x-groups
     1366                for (XGroupItem xgroup_item : xgroup_item_list) {
     1367
     1368                        List<XGroupItem> nested_xgroup_item_list = xgroup_item
     1369                                        .getGroupedItemList();
     1370
     1371                        if (nested_xgroup_item_list.size() > 0) {
    12761372                                xgroup_item.mapInXGroupItemsRecursive(nested_xgroup_item_list);
    12771373                        }
    1278                 }       
    1279         }
    1280        
     1374                }
     1375        }
     1376
    12811377        public List<Item[]> getYXOverlappingItemListLines() {
    12821378                final List<XRawItem> yxOverlappingXRawItemList = getYXOverlappingXRawItemList(true);
    12831379                final List<Item[]> lines = new ArrayList<Item[]>();
    12841380                final List<XRawItem> currentLineXItem = new ArrayList<XRawItem>();
    1285                 for(final XRawItem xitem : yxOverlappingXRawItemList) {
    1286                         if(xitem.getItem() == GROUPSEP_START) continue;
    1287                         else if(xitem.getItem() == GROUPSEP_END) {
    1288                                 if(currentLineXItem.isEmpty()) continue;
     1381                for (final XRawItem xitem : yxOverlappingXRawItemList) {
     1382                        if (xitem.getItem() == GROUPSEP_START)
     1383                                continue;
     1384                        else if (xitem.getItem() == GROUPSEP_END) {
     1385                                if (currentLineXItem.isEmpty())
     1386                                        continue;
    12891387                                else {
    12901388                                        final List<Item> ln = new ArrayList<Item>();
    1291                                         for(final XRawItem xrawitem : currentLineXItem) ln.add(xrawitem.getItem());
    1292                                         lines.add(ln.toArray(new Item[]{}));
     1389                                        for (final XRawItem xrawitem : currentLineXItem)
     1390                                                ln.add(xrawitem.getItem());
     1391                                        lines.add(ln.toArray(new Item[] {}));
    12931392                                        currentLineXItem.clear();
    12941393                                }
    12951394                        } else {
    1296                                 if(currentLineXItem.isEmpty()) currentLineXItem.add(xitem);
     1395                                if (currentLineXItem.isEmpty())
     1396                                        currentLineXItem.add(xitem);
    12971397                                else {
    1298                                         final YOverlappingItemsSpan[] itemSpanArray = xitem.getGroup().yitems_span_array;
    1299                                         final int index = xitem.getBoundingYTop() - xitem.getGroup().getBoundingYTop();
     1398                                        final YOverlappingItemsSpan[] itemSpanArray = xitem
     1399                                                        .getGroup().yitems_span_array;
     1400                                        final int index = xitem.getBoundingYTop()
     1401                                                        - xitem.getGroup().getBoundingYTop();
    13001402                                        final YOverlappingItemsSpan itemSpan = itemSpanArray[index];
    1301                                         final List<XItem> xOrderedList = itemSpan instanceof YOverlappingItemsTopEdge ?
    1302                                                         ((YOverlappingItemsTopEdge)itemSpan).getXOrderedLine().getXItemList() :
    1303                                                                 ((YOverlappingItemsShadow)itemSpan).getTopEdge().getXOrderedLine().getXItemList();
    1304                                         if(!xOrderedList.contains(currentLineXItem.get(0))) {
    1305                                                 if(!currentLineXItem.isEmpty()) {
     1403                                        final List<XItem> xOrderedList = itemSpan instanceof YOverlappingItemsTopEdge ? ((YOverlappingItemsTopEdge) itemSpan)
     1404                                                        .getXOrderedLine().getXItemList()
     1405                                                        : ((YOverlappingItemsShadow) itemSpan).getTopEdge()
     1406                                                                        .getXOrderedLine().getXItemList();
     1407                                        if (!xOrderedList.contains(currentLineXItem.get(0))) {
     1408                                                if (!currentLineXItem.isEmpty()) {
    13061409                                                        final List<Item> ln = new ArrayList<Item>();
    1307                                                         for(final XRawItem xrawitem : currentLineXItem) ln.add(xrawitem.getItem());
    1308                                                         lines.add(ln.toArray(new Item[]{}));
     1410                                                        for (final XRawItem xrawitem : currentLineXItem)
     1411                                                                ln.add(xrawitem.getItem());
     1412                                                        lines.add(ln.toArray(new Item[] {}));
    13091413                                                        currentLineXItem.clear();
    13101414                                                }
     
    13161420                        }
    13171421                }
    1318                 if(!currentLineXItem.isEmpty()) {
     1422                if (!currentLineXItem.isEmpty()) {
    13191423                        final List<Item> ln = new ArrayList<Item>();
    1320                         for(final XRawItem xrawitem : currentLineXItem) ln.add(xrawitem.getItem());
    1321                         lines.add(ln.toArray(new Item[]{}));
     1424                        for (final XRawItem xrawitem : currentLineXItem)
     1425                                ln.add(xrawitem.getItem());
     1426                        lines.add(ln.toArray(new Item[] {}));
    13221427                        currentLineXItem.clear();
    13231428                }
     
    13281433                final List<XRawItem> yxOverlappingXItemList = getYXOverlappingXRawItemList(separateGroups);
    13291434                final ArrayList<Item> yxOverlappingItemList = new ArrayList<Item>();
    1330                 for(final XRawItem xitem : yxOverlappingXItemList) yxOverlappingItemList.add(xitem.getItem());
     1435                for (final XRawItem xitem : yxOverlappingXItemList)
     1436                        yxOverlappingItemList.add(xitem.getItem());
    13311437                return yxOverlappingItemList;
    13321438        }
    1333        
    1334         public List<XRawItem> getYXOverlappingXRawItemList(final boolean separateGroups) {
     1439
     1440        public List<XRawItem> getYXOverlappingXRawItemList(
     1441                        final boolean separateGroups) {
    13351442                ArrayList<XRawItem> overlapping_y_ordered_items = new ArrayList<XRawItem>();
    13361443
     
    13501457                                                if (xspan instanceof XRawItem) {
    13511458                                                        XRawItem xitem_span = (XRawItem) xspan;
    1352 //                                                      Item item = xitem_span.getItem();
    1353 //
    1354 //                                                      overlapping_y_ordered_items.add(item);
     1459                                                        // Item item = xitem_span.getItem();
     1460                                                        //
     1461                                                        // overlapping_y_ordered_items.add(item);
    13551462                                                        overlapping_y_ordered_items.add(xitem_span);
    13561463                                                } else {
     
    13621469                                                                        .getYXOverlappingXRawItemList(separateGroups);
    13631470                                                        if (separateGroups) {
    1364                                                                 overlapping_y_ordered_items.add(new XRawItem(GROUPSEP_START, this));
     1471                                                                overlapping_y_ordered_items.add(new XRawItem(
     1472                                                                                GROUPSEP_START, this));
    13651473                                                        }
    13661474                                                        overlapping_y_ordered_items
    13671475                                                                        .addAll(nested_overlapping_items);
    13681476                                                        if (separateGroups) {
    1369                                                                 overlapping_y_ordered_items.add(new XRawItem(GROUPSEP_END, this));
     1477                                                                overlapping_y_ordered_items.add(new XRawItem(
     1478                                                                                GROUPSEP_END, this));
    13701479                                                        }
    13711480                                                }
     
    13771486                return overlapping_y_ordered_items;
    13781487        }
    1379        
     1488
    13801489        public ArrayList<Item> getYXOverlappingItemList() {
    13811490                return getYXOverlappingItemList(false);
    13821491        }
    1383        
     1492
    13841493        public String toString() {
    13851494                return "XGroupItem";
    13861495        }
    13871496}
    1388 
Note: See TracChangeset for help on using the changeset viewer.