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 }