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.acewiki.gui; 016 017 import java.util.ArrayList; 018 import java.util.List; 019 020 import nextapp.echo.app.event.ActionEvent; 021 import nextapp.echo.app.event.ActionListener; 022 import ch.uzh.ifi.attempto.acewiki.Task; 023 import ch.uzh.ifi.attempto.acewiki.Wiki; 024 import ch.uzh.ifi.attempto.acewiki.core.Article; 025 import ch.uzh.ifi.attempto.acewiki.core.Comment; 026 import ch.uzh.ifi.attempto.acewiki.core.InconsistencyException; 027 import ch.uzh.ifi.attempto.acewiki.core.LanguageHandler; 028 import ch.uzh.ifi.attempto.acewiki.core.LanguageUtils; 029 import ch.uzh.ifi.attempto.acewiki.core.Ontology; 030 import ch.uzh.ifi.attempto.acewiki.core.Sentence; 031 import ch.uzh.ifi.attempto.acewiki.core.SentenceSuggestion; 032 import ch.uzh.ifi.attempto.acewiki.core.Statement; 033 import ch.uzh.ifi.attempto.base.PredictiveParser; 034 import ch.uzh.ifi.attempto.base.TextContainer; 035 import ch.uzh.ifi.attempto.base.TextElement; 036 import ch.uzh.ifi.attempto.echocomp.MessageWindow; 037 import ch.uzh.ifi.attempto.preditor.PreditorWindow; 038 039 /** 040 * This class manages the predictive editor. It creates the editor window and handles its 041 * responses. 042 * 043 * @author Tobias Kuhn 044 */ 045 public class SentenceEditorHandler implements ActionListener { 046 047 private static final long serialVersionUID = -2083910385095284075L; 048 049 private PreditorWindow editorWindow; 050 private MessageWindow messageWindow; 051 private ArticlePage page; 052 private Wiki wiki; 053 private boolean edit; 054 private Statement statement; 055 private List<Sentence> newSentences = new ArrayList<Sentence>(); 056 private int checked = 0; 057 private SentenceSuggestion suggestion; 058 059 private SentenceEditorHandler(Statement statement, ArticlePage page, boolean edit) { 060 this.page = page; 061 this.wiki = page.getWiki(); 062 this.edit = edit; 063 this.statement = statement; 064 AceWikiMenuCreator menuCreator = new AceWikiMenuCreator( 065 wiki, 066 page.getOntologyElement(), 067 this 068 ); 069 LanguageHandler lh = wiki.getLanguageHandler(); 070 editorWindow = new PreditorWindow("Sentence Editor", lh.getPredictiveParser()); 071 editorWindow.setMenuCreator(menuCreator); 072 editorWindow.setLogger(wiki.getLogger()); 073 editorWindow.addActionListener(this); 074 editorWindow.setTextOperator(lh.getTextOperator()); 075 076 if (edit) { 077 Comment c = (Comment) statement; 078 editorWindow.addText(LanguageUtils.getPrettyPrinted(c.getText()) + " "); 079 } 080 } 081 082 /** 083 * Generates a new preditive editor window for the creation of a new sentence. 084 * 085 * @param followingStatement The statement in front of which the new sentences should be added, 086 * or null if the sentences should be added to the end of the article. 087 * @param page The host page into which the sentence should be added. 088 * @return A new preditor window. 089 */ 090 public static PreditorWindow generateCreationWindow(Statement followingStatement, 091 ArticlePage page) { 092 SentenceEditorHandler h = new SentenceEditorHandler(followingStatement, page, false); 093 return h.getWindow(); 094 } 095 096 /** 097 * Generates a new preditive editor window for editing an existing sentence. 098 * 099 * @param sentence The sentence that should be edited. 100 * @param page The host page which contains the sentence to be edited. 101 * @return A new preditor window. 102 */ 103 public static PreditorWindow generateEditWindow(Sentence sentence, ArticlePage page) { 104 SentenceEditorHandler h = new SentenceEditorHandler(sentence, page, true); 105 return h.getWindow(); 106 } 107 108 private PreditorWindow getWindow() { 109 return editorWindow; 110 } 111 112 public void actionPerformed(ActionEvent e) { 113 Object src = e.getSource(); 114 String c = e.getActionCommand(); 115 if (src == editorWindow && c.matches("OK|Enter")) { 116 Ontology o = wiki.getOntology(); 117 LanguageHandler lh = wiki.getLanguageHandler(); 118 119 for (String t : lh.getEditorController().getAutocompleteTokens()) { 120 if (editorWindow.isPossibleNextToken(t)) { 121 editorWindow.addTextElement(lh.getTextOperator().createTextElement(t)); 122 break; 123 } 124 } 125 126 PredictiveParser parser = editorWindow.getPredictiveParser(); 127 if (parser.getTokenCount() == 0) { 128 wiki.removeWindow(editorWindow); 129 } else if (parser.isComplete()) { 130 newSentences = o.getStatementFactory().extractSentences( 131 wiki.getLanguageHandler(), 132 editorWindow.getTextContainer(), 133 parser, 134 page.getArticle() 135 ); 136 checkSentence(); 137 } else if (c.equals("OK")) { 138 wiki.log("edit", "error: unfinished sentences"); 139 MessageWindow mw = new MessageWindow( 140 "Error", 141 "There are unfinished sentences.", 142 editorWindow, 143 "OK" 144 ); 145 page.getWiki().showWindow(mw); 146 } 147 } else if (src == editorWindow && c.matches("Cancel|Close|Escape")) { 148 wiki.removeWindow(editorWindow); 149 } else if (src == messageWindow && c.equals("Close")) { 150 checked = 0; 151 } else if (src == messageWindow && suggestion != null) { 152 Sentence s = suggestion.getSentence(c); 153 if (s != newSentences.get(checked)) { 154 newSentences.remove(checked); 155 newSentences.add(checked, s); 156 } 157 checked++; 158 checkSentence(); 159 } else if (src instanceof TextElement) { 160 editorWindow.addTextElement((TextElement) src); 161 } 162 } 163 164 private void checkSentence() { 165 if (checked >= newSentences.size()) { 166 assertSentences(); 167 } else { 168 suggestion = wiki.getLanguageHandler().getSuggestion(newSentences.get(checked)); 169 if (suggestion != null) { 170 messageWindow = new MessageWindow( 171 "Suggestion", 172 suggestion.getMessage(), 173 editorWindow, 174 this, 175 suggestion.getOptions() 176 ); 177 wiki.showWindow(messageWindow); 178 } else { 179 checked++; 180 checkSentence(); 181 } 182 } 183 } 184 185 private void assertSentences() { 186 final TextContainer textContainer = editorWindow.getTextContainer(); 187 final Article a = page.getArticle(); 188 189 Task task = new Task() { 190 191 boolean inconsistent = false; 192 193 public void run() { 194 try { 195 if (edit) { 196 wiki.log("edit", "sentence updated: " + textContainer.getText()); 197 a.edit(statement, new ArrayList<Statement>(newSentences)); 198 } else { 199 wiki.log("edit", "sentence created: " + textContainer.getText()); 200 a.add(statement, new ArrayList<Statement>(newSentences)); 201 } 202 } catch (InconsistencyException ex) { 203 inconsistent = true; 204 } 205 } 206 207 public void updateGUI() { 208 page.update(); 209 if (inconsistent) { 210 wiki.showWindow( 211 new MessageWindow( 212 "Conflict", 213 "The sentence is in conflict with the current knowledge. For that " + 214 "reason, it cannot be added to the knowledge base.", 215 "OK" 216 ) 217 ); 218 } 219 if (page != null) { 220 page.update(); 221 page.getWiki().update(); 222 } 223 } 224 225 }; 226 227 if (edit) { 228 wiki.enqueueStrongAsyncTask( 229 "Updating", 230 "The knowledge base is being updated...", 231 task 232 ); 233 } else { 234 wiki.enqueueStrongAsyncTask( 235 "Updating", 236 "The sentence is being added to the knowledge base...", 237 task 238 ); 239 } 240 241 wiki.removeWindow(editorWindow); 242 } 243 244 }