001    // This file is part of AceWiki.
002    // Copyright 2008-2012, AceWiki developers.
003    // 
004    // AceWiki is free software: you can redistribute it and/or modify it under the terms of the GNU
005    // Lesser General Public License as published by the Free Software Foundation, either version 3 of
006    // the License, or (at your option) any later version.
007    // 
008    // AceWiki is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
009    // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
010    // Lesser General Public License for more details.
011    // 
012    // You should have received a copy of the GNU Lesser General Public License along with AceWiki. If
013    // not, see http://www.gnu.org/licenses/.
014    
015    package ch.uzh.ifi.attempto.preditor;
016    
017    import java.util.Comparator;
018    import java.util.HashSet;
019    import java.util.Set;
020    
021    /**
022     * This class represents the default comparator to sort menu items in the menus of the predictive
023     * editor. Prefixes can be set that are ignored for comparison. By default, these prefixes are
024     * "the ", "a " and "and " plus their capizalized versions.
025     * 
026     * @author Tobias Kuhn
027     */
028    public class DefaultMenuItemComparator implements Comparator<MenuItem> {
029            
030            private Set<String> prefixes = new HashSet<String>();
031            
032            /**
033             * Creates a new default comparator for menu items.
034             */
035            public DefaultMenuItemComparator() {
036                    prefixes.add("the ");
037                    prefixes.add("The ");
038                    prefixes.add("a ");
039                    prefixes.add("A ");
040                    prefixes.add("an ");
041                    prefixes.add("An ");
042            }
043    
044            public int compare(MenuItem m1, MenuItem m2) {
045                    String s1 = m1.getText();
046                    String s2 = m2.getText();
047                    
048                    // Special menu items come before other items:
049                    if (m1 instanceof SpecialMenuItem && !(m2 instanceof SpecialMenuItem)) {
050                            return -1;
051                    } else if (!(m1 instanceof SpecialMenuItem) && m2 instanceof SpecialMenuItem) {
052                            return 1;
053                    }
054                    
055                    // Highlighted items come before others:
056                    if (m1.isHighlighted() && !m2.isHighlighted()) {
057                            return -1;
058                    } else if (!m1.isHighlighted() && m2.isHighlighted()) {
059                            return 1;
060                    }
061                    
062                    // Special menu items are not examined further:
063                    if (m1 instanceof SpecialMenuItem && m2 instanceof SpecialMenuItem) {
064                            return s1.compareToIgnoreCase(s2);
065                    }
066                    
067                    // Certain prefixes are ignored for comparison:
068                    String s1n = null;
069                    String s2n = null;
070                    String p1 = "";
071                    String p2 = "";
072                    for (String p : prefixes) {
073                            if (s1.startsWith(p)) {
074                                    if (s1n == null || s1n.length() > s1.length() - p.length()) {
075                                            p1 = s1.substring(0, p.length());
076                                            s1n = s1.substring(p.length());
077                                    }
078                            }
079                            if (s2.startsWith(p)) {
080                                    if (s2n == null || s2n.length() > s2.length() - p.length()) {
081                                            p2 = s2.substring(0, p.length());
082                                            s2n = s2.substring(p.length());
083                                    }
084                            }
085                    }
086                    if (s1n != null) s1 = s1n;
087                    if (s2n != null) s2 = s2n;
088                    
089                    int comp;
090                    
091                    // For items that are equal apart from trailing digits, the integer value of these trailing
092                    // digits is used for comparison:
093                    if (s1.replaceFirst("[0-9]*$", "").equals(s2.replaceFirst("[0-9]*$", ""))) {
094                            int i1 = 0;
095                            int i2 = 0;
096                            try {
097                                    i1 = Integer.parseInt(s1.replaceFirst("^.*?([0-9]*)$", "$1"));
098                            } catch (NumberFormatException ex) {}
099                            try {
100                                    i2 = Integer.parseInt(s2.replaceFirst("^.*?([0-9]*)$", "$1"));
101                            } catch (NumberFormatException ex) {}
102                            comp = i1 - i2;
103                    } else {
104                            comp = s1.compareToIgnoreCase(s2);
105                    }
106                    
107                    if (comp == 0) {
108                            return p1.compareToIgnoreCase(p2);
109                    } else {
110                            return comp;
111                    }
112            }
113            
114            /**
115             * Adds a prefix.
116             * 
117             * @param prefix The prefix to be added.
118             */
119            public void addPrefix(String prefix) {
120                    prefixes.add(prefix);
121            }
122            
123            /**
124             * Sets the prefixes.
125             * 
126             * @param prefixes The set of prefixes.
127             */
128            public void setPrefixes(Set<String> prefixes) {
129                    this.prefixes.clear();
130                    this.prefixes.addAll(prefixes);
131            }
132    
133    }