001    // This file is part of the Attempto Java Packages.
002    // Copyright 2008-2009, Attempto Group, University of Zurich (see http://attempto.ifi.uzh.ch).
003    //
004    // The Attempto Java Packages is free software: you can redistribute it and/or modify it under the
005    // terms of the GNU Lesser General Public License as published by the Free Software Foundation,
006    // either version 3 of the License, or (at your option) any later version.
007    //
008    // The Attempto Java Packages is distributed in the hope that it will be useful, but WITHOUT ANY
009    // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
010    // PURPOSE. See the GNU Lesser General Public License for more details.
011    //
012    // You should have received a copy of the GNU Lesser General Public License along with the Attempto
013    // Java Packages. If not, see http://www.gnu.org/licenses/.
014    
015    package ch.uzh.ifi.attempto.preditor;
016    
017    import java.util.ArrayList;
018    import java.util.HashMap;
019    import java.util.List;
020    
021    import ch.uzh.ifi.attempto.chartparser.ChartParser;
022    import ch.uzh.ifi.attempto.chartparser.Restriction;
023    import ch.uzh.ifi.attempto.chartparser.Terminal;
024    import ch.uzh.ifi.attempto.preditor.text.TextElement;
025    
026    /**
027     * This abstract class is used for the predictive editor to create menus on the basis of categories of the grammar.
028     *  
029     * @author Tobias Kuhn
030     */
031    public abstract class MenuCreator {
032            
033            private HashMap<String, MenuBlockContent> contentsMap = new HashMap<String, MenuBlockContent>();
034            private List<MenuBlockContent> contentsList = new ArrayList<MenuBlockContent>();
035            private Restriction restriction;
036            private int id;
037            
038            /**
039             * Initializes a new menu creator object.
040             */
041            public MenuCreator() {
042            }
043            
044            /**
045             * An implementation of this abstract method should add menu items that comply with the given restriction.
046             * This should be done by calling {@link #addMenuItem addMenuItem} and/or {@link #addMenuEntry addMenuEntry}.
047             * 
048             * @param restriction The restriction for the menu items.
049             */
050            protected abstract void addMenuItems(Restriction restriction);
051            
052            /**
053             * This abstract method is called when the predictive editor is refreshed (before the first call of
054             * {@link #addMenuItems addMenuItems}). This is a good place for calling {@link #prepareMenuBlock(String) prepareMenuBlock}.
055             */
056            public abstract void initMenuCreation();
057            
058            /**
059             * Prepares a new menu block (if there is no such menu block already with the same name). The menu blocks are
060             * shown in the predictive editor in the same order as they have been prepared.
061             * 
062             * @param menuBlockName The name of the menu block.
063             */
064            public void prepareMenuBlock(String menuBlockName) {
065                    prepareMenuBlock(menuBlockName, false);
066            }
067    
068            /**
069             * Prepares a new menu block (if there is no such menu block already with the same name). The second parameter
070             * defines whether the items of the menu block should be sorted. The menu blocks are
071             * shown in the predictive editor in the same order as they have been prepared.
072             * 
073             * @param menuBlockName The name of the menu block.
074             * @param doSort true if the items should be sorted.
075             */
076            public void prepareMenuBlock(String menuBlockName, boolean doSort) {
077                    if (contentsMap.containsKey(menuBlockName)) {
078                            return;
079                    }
080                    MenuBlockContent menuBlockContent = new MenuBlockContent(menuBlockName, doSort);
081                    contentsMap.put(menuBlockName, menuBlockContent);
082                    contentsList.add(menuBlockContent);
083            }
084            
085            /**
086             * Adds the menu item to the given menu block. If no menu block of this name has been prepared at this point then
087             * the preparation is done first.
088             * 
089             * @param menuBlockName The name of the menu block.
090             * @param menuItem The menu item to be added to the menu block.
091             */
092            public void addMenuItem(String menuBlockName, MenuItem menuItem) {
093                    if (menuItem instanceof MenuEntry) {
094                            MenuEntry me = (MenuEntry) menuItem;
095                            me.getTextElement().setID(id);
096                            boolean restrFulfilled = me.getTextElement().applyRestriction(restriction);
097                            if (!restrFulfilled) return;
098                    }
099                    if (!contentsMap.containsKey(menuBlockName)) {
100                            prepareMenuBlock(menuBlockName);
101                    }
102                    contentsMap.get(menuBlockName).addItem(menuItem);
103            }
104            
105            /**
106             * Adds a new menu entry containing the text element to the menu block. If no menu block of this name has been
107             * prepared at this point then the preparation is done first.
108             * 
109             * @param menuBlockName The name of the menu block.
110             * @param textElement The text element of the menu entry that is created and then added to the menu block.
111             */
112            public void addMenuEntry(String menuBlockName, TextElement textElement) {
113                    textElement.setID(id);
114                    boolean restrFulfilled = textElement.applyRestriction(restriction);
115                    if (!restrFulfilled) return;
116                    if (!contentsMap.containsKey(menuBlockName)) {
117                            prepareMenuBlock(menuBlockName);
118                    }
119                    contentsMap.get(menuBlockName).addEntry(textElement);
120            }
121            
122            synchronized List<MenuBlockContent> createMenu(ChartParser parser) {
123                    contentsMap.clear();
124                    contentsList.clear();
125                    
126                    initMenuCreation();
127                    
128                    for (Restriction r : parser.getNextTokenRestrictions()) {
129                            restriction = r;
130                            id = parser.getTokens().size();
131                            addMenuItems(r);
132                    }
133                    
134                    return new ArrayList<MenuBlockContent>(contentsList);
135            }
136            
137            /**
138             * Adds menu entries that stand for variables in the form of "X", "Y", "Z", "X1", "Y1", and so on.
139             * 
140             * @param menuBlockName The name of the menu block into which the entries should be added.
141             * @param num The number upto which the variables should be enumerated.
142             * @param categoryName The category name of the entries.
143             */
144            public void addVariableEntries(String menuBlockName, int num, String categoryName) {
145                    ArrayList<String> varNames = new ArrayList<String>();
146                    varNames.add("X");
147                    varNames.add("Y");
148                    varNames.add("Z");
149                    for (int i=1; i<=num; i++) {
150                            varNames.add("X" + i);
151                            varNames.add("Y" + i);
152                            varNames.add("Z" + i);
153                    }
154                    for (String s : varNames) {
155                            Terminal t = new Terminal(categoryName);
156                            t.setFeature("text", s);
157                            addMenuEntry(menuBlockName, new TextElement(s, t));
158                    }
159            }
160    
161    }