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.Category; 022 import ch.uzh.ifi.attempto.chartparser.ChartParser; 023 import ch.uzh.ifi.attempto.chartparser.Terminal; 024 import ch.uzh.ifi.attempto.preditor.text.RefTextElement; 025 import ch.uzh.ifi.attempto.preditor.text.RefableTextElement; 026 import ch.uzh.ifi.attempto.preditor.text.TextContainer; 027 import ch.uzh.ifi.attempto.preditor.text.TextElement; 028 import ch.uzh.ifi.attempto.preditor.text.VarTextElement; 029 030 /** 031 * This abstract class is used for the predictive editor to create menus on the basis of categories of the grammar. 032 * 033 * @author Tobias Kuhn 034 */ 035 public abstract class MenuCreator { 036 037 private HashMap<String, MenuBlockContent> contentsMap = new HashMap<String, MenuBlockContent>(); 038 private List<MenuBlockContent> contentsList = new ArrayList<MenuBlockContent>(); 039 private ChartParser parser; 040 private TextContainer textContainer; 041 042 /** 043 * Initializes a new menu creator object. 044 */ 045 public MenuCreator() { 046 } 047 048 /** 049 * An implementation of this abstract method should process the category by calling {@link #addMenuItem addMenuItem} 050 * and/or {@link #addMenuEntry addMenuEntry}. 051 * 052 * @param category The category of the grammar to be processed. 053 */ 054 protected abstract void processCategory(Terminal category); 055 056 /** 057 * This abstract method is called when the predictive editor is refreshed (before the first call of 058 * {@link #processCategory processCategory}). This is a good place for calling {@link #prepareMenuBlock prepareMenuBlock}. 059 */ 060 public abstract void initMenuCreation(); 061 062 /** 063 * Prepares a new menu block (if there is no such menu block already with the same name). The menu blocks are 064 * shown in the predictive editor in the same order as they have been prepared. 065 * 066 * @param menuBlockName The name of the menu block. 067 */ 068 public void prepareMenuBlock(String menuBlockName) { 069 prepareMenuBlock(menuBlockName, false); 070 } 071 072 /** 073 * Prepares a new menu block (if there is no such menu block already with the same name). The second parameter 074 * defines whether the items of the menu block should be sorted. The menu blocks are 075 * shown in the predictive editor in the same order as they have been prepared. 076 * 077 * @param menuBlockName The name of the menu block. 078 * @param doSort true if the items should be sorted. 079 */ 080 public void prepareMenuBlock(String menuBlockName, boolean doSort) { 081 if (contentsMap.containsKey(menuBlockName)) { 082 return; 083 } 084 MenuBlockContent menuBlockContent = new MenuBlockContent(menuBlockName, doSort); 085 contentsMap.put(menuBlockName, menuBlockContent); 086 contentsList.add(menuBlockContent); 087 } 088 089 /** 090 * Adds the menu item to the given menu block. If no menu block of this name has been prepared at this point then 091 * the preparation is done first. 092 * 093 * @param menuBlockName The name of the menu block. 094 * @param menuItem The menu item to be added to the menu block. 095 */ 096 public void addMenuItem(String menuBlockName, MenuItem menuItem) { 097 if (!contentsMap.containsKey(menuBlockName)) { 098 prepareMenuBlock(menuBlockName); 099 } 100 contentsMap.get(menuBlockName).addItem(menuItem); 101 } 102 103 /** 104 * Adds a new menu entry containing the text element to the menu block. If no menu block of this name has been 105 * prepared at this point then the preparation is done first. 106 * 107 * @param menuBlockName The name of the menu block. 108 * @param textElement The text element of the menu entry that is created and then added to the menu block. 109 */ 110 public void addMenuEntry(String menuBlockName, TextElement textElement) { 111 if (!contentsMap.containsKey(menuBlockName)) { 112 prepareMenuBlock(menuBlockName); 113 } 114 contentsMap.get(menuBlockName).addEntry(textElement); 115 } 116 117 /** 118 * Adds a new menu entry containing the text element to the menu block. If no menu block of this name has been 119 * prepared at this point then the preparation is done first. The menu entry is only added if the category of 120 * the text element is subsumed by the restriction category. 121 * 122 * @param menuBlockName The name of the menu block. 123 * @param textElement The text element of the menu entry that is created and then added to the menu block. 124 * @param restriction The restriction category. 125 */ 126 public void addMenuEntry(String menuBlockName, TextElement textElement, Category restriction) { 127 if (restriction.subsumes(textElement.getCategory())) { 128 addMenuEntry(menuBlockName, textElement); 129 } 130 } 131 132 /** 133 * This method looks for referenceable text elements earlier in the token list, given the category of the next 134 * token. For each of those text elements, a new reference text element is created and added to the menu block. 135 * 136 * @param menuBlockName The name of the menu block. 137 * @param categoryName The category name for which the previous tokens should be checked for referenceability. 138 * @see #getAccessibleTextElements(String) 139 * @see RefableTextElement 140 * @see RefTextElement 141 */ 142 public void addReferenceEntries(String menuBlockName, String categoryName) { 143 ArrayList<String> refStrings = new ArrayList<String>(); 144 for (TextElement el : getAccessibleTextElements(categoryName)) { 145 if (!(el instanceof RefableTextElement)) continue; 146 147 RefableTextElement refEl = (RefableTextElement) el; 148 boolean isOverridden = false; 149 String refText = refEl.getReferenceText(); 150 for (String s : refStrings) { 151 if (s.equals(refText) || s.startsWith(refText + " ")) { 152 isOverridden = true; 153 break; 154 } 155 } 156 if (!isOverridden) { 157 refStrings.add(refText); 158 addMenuEntry(menuBlockName, new RefTextElement(refEl, categoryName)); 159 } 160 } 161 } 162 163 /** 164 * This method adds text elements that contain variables (in the form of "X", "Y", "Z", "X1", "Y1", "Z1", "X2", and so on) 165 * to the menu block. 166 * 167 * @param menuBlockName The name of the menu block. 168 * @param num Variables are created up to this number. 169 * @param categoryName The category name of the variable tokens. 170 * @see VarTextElement 171 */ 172 public void addVariableEntries(String menuBlockName, int num, String categoryName) { 173 ArrayList<String> varNames = new ArrayList<String>(); 174 varNames.add("X"); 175 varNames.add("Y"); 176 varNames.add("Z"); 177 for (int i=1; i<=num; i++) { 178 varNames.add("X" + i); 179 varNames.add("Y" + i); 180 varNames.add("Z" + i); 181 } 182 for (TextElement el : textContainer.getTextElements()) { 183 if (!(el instanceof VarTextElement)) continue; 184 varNames.remove(((VarTextElement) el).getText()); 185 } 186 for (String s : varNames) { 187 addMenuEntry(menuBlockName, new VarTextElement(s, categoryName)); 188 } 189 } 190 191 /** 192 * This method returns all text elements that are accessible for the given next token. 193 * 194 * @param nextToken The next token. 195 * @return A list of all accessible text elements. 196 */ 197 public List<TextElement> getAccessibleTextElements(String nextToken) { 198 List<TextElement> elements = new ArrayList<TextElement>(); 199 200 boolean[] pos = parser.getAccessiblePositions(nextToken); 201 for (int i=pos.length-1 ; i >= 0 ; i--) { 202 if (!pos[i]) continue; 203 TextElement el = textContainer.getTextElements().get(i); 204 elements.add(el); 205 } 206 207 return elements; 208 } 209 210 List<MenuBlockContent> createMenu(ChartParser parser, TextContainer textContainer) { 211 this.parser = parser; 212 this.textContainer = textContainer; 213 contentsMap.clear(); 214 contentsList.clear(); 215 216 initMenuCreation(); 217 218 for (Terminal t : parser.nextTokens()) { 219 processCategory(t); 220 } 221 222 return new ArrayList<MenuBlockContent>(contentsList); 223 } 224 225 }