001 // This file is part of the Attempto Java Packages.
002 // Copyright 2008, 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.acewiki;
016
017 import java.io.IOException;
018 import java.io.InputStream;
019 import java.io.OutputStream;
020 import java.util.ArrayList;
021 import java.util.Collection;
022 import java.util.Properties;
023 import java.util.Random;
024 import java.util.Stack;
025
026 import nextapp.echo2.app.ApplicationInstance;
027 import nextapp.echo2.app.Color;
028 import nextapp.echo2.app.Column;
029 import nextapp.echo2.app.ContentPane;
030 import nextapp.echo2.app.Extent;
031 import nextapp.echo2.app.Font;
032 import nextapp.echo2.app.Insets;
033 import nextapp.echo2.app.ResourceImageReference;
034 import nextapp.echo2.app.Row;
035 import nextapp.echo2.app.SplitPane;
036 import nextapp.echo2.app.TaskQueueHandle;
037 import nextapp.echo2.app.event.ActionEvent;
038 import nextapp.echo2.app.event.ActionListener;
039 import nextapp.echo2.app.filetransfer.Download;
040 import nextapp.echo2.app.filetransfer.DownloadProvider;
041 import ch.uzh.ifi.attempto.acewiki.core.grammar.StandardGrammar;
042 import ch.uzh.ifi.attempto.acewiki.core.ontology.Individual;
043 import ch.uzh.ifi.attempto.acewiki.core.ontology.NounConcept;
044 import ch.uzh.ifi.attempto.acewiki.core.ontology.OfRole;
045 import ch.uzh.ifi.attempto.acewiki.core.ontology.Ontology;
046 import ch.uzh.ifi.attempto.acewiki.core.ontology.OntologyElement;
047 import ch.uzh.ifi.attempto.acewiki.core.ontology.TrAdjRole;
048 import ch.uzh.ifi.attempto.acewiki.core.ontology.VerbRole;
049 import ch.uzh.ifi.attempto.acewiki.core.text.OntologyTextElement;
050 import ch.uzh.ifi.attempto.acewiki.gui.ListItem;
051 import ch.uzh.ifi.attempto.acewiki.gui.editor.NounForm;
052 import ch.uzh.ifi.attempto.acewiki.gui.editor.NounOfForm;
053 import ch.uzh.ifi.attempto.acewiki.gui.editor.ProperNameForm;
054 import ch.uzh.ifi.attempto.acewiki.gui.editor.TrAdjForm;
055 import ch.uzh.ifi.attempto.acewiki.gui.editor.VerbForm;
056 import ch.uzh.ifi.attempto.acewiki.gui.editor.WordEditorWindow;
057 import ch.uzh.ifi.attempto.acewiki.gui.page.ArticlePage;
058 import ch.uzh.ifi.attempto.acewiki.gui.page.IndexPage;
059 import ch.uzh.ifi.attempto.acewiki.gui.page.SearchPage;
060 import ch.uzh.ifi.attempto.acewiki.gui.page.StartPage;
061 import ch.uzh.ifi.attempto.acewiki.gui.page.WikiPage;
062 import ch.uzh.ifi.attempto.chartparser.Grammar;
063 import ch.uzh.ifi.attempto.echocomp.GeneralButton;
064 import ch.uzh.ifi.attempto.echocomp.Label;
065 import ch.uzh.ifi.attempto.echocomp.MessageWindow;
066 import ch.uzh.ifi.attempto.echocomp.SmallButton;
067 import ch.uzh.ifi.attempto.echocomp.SolidLabel;
068 import ch.uzh.ifi.attempto.echocomp.Style;
069 import ch.uzh.ifi.attempto.echocomp.VSpace;
070 import ch.uzh.ifi.attempto.echocomp.WindowPane;
071 import ch.uzh.ifi.attempto.preditor.PreditorWindow;
072
073 /**
074 * This class represents an AceWiki wiki.
075 *
076 * @author Tobias Kuhn
077 */
078 public class Wiki implements ActionListener {
079
080 private static final long serialVersionUID = 2777443689044226043L;
081
082 private final Ontology ontology;
083
084 private WikiPage currentPage;
085 private ContentPane mainPane = new ContentPane();
086 private ContentPane contentPane = new ContentPane();
087 private Row navigationButtons = new Row();
088 private Logger logger;
089
090 private GeneralButton backButton = new GeneralButton("<Back", this);
091 private GeneralButton forwardButton = new GeneralButton("Forward>", this);
092 private GeneralButton refreshButton = new GeneralButton("Refresh", this);
093
094 private SmallButton indexButton = new SmallButton("Index", this, 12);
095 private SmallButton homeButton = new SmallButton("Main Page", this, 12);
096 private SmallButton randomButton = new SmallButton("Random Article", this, 12);
097 private SmallButton searchButton = new SmallButton("Search", this, 12);
098 private SmallButton newButton = new SmallButton("New Word...", this, 12);
099 private SmallButton exportButton = new SmallButton("Export", this, 12);
100 private SmallButton logoutButton = new SmallButton("Logout", this, 12);
101 private ListItem logoutListItem;
102 private Label logo;
103
104 private StartPage startPage;
105
106 private Stack<WikiPage> history = new Stack<WikiPage>();
107 private Stack<WikiPage> forward = new Stack<WikiPage>();
108
109 private ArrayList<WindowPane> windows = new ArrayList<WindowPane>();
110
111 private Grammar grammar = new StandardGrammar();
112
113 private TaskQueueHandle taskQueue;
114
115 private ApplicationInstance application;
116
117 private static Properties properties;
118
119 /**
120 * Creates a new wiki instance.
121 *
122 * @param ontology The ontology that is loaded into the wiki.
123 * @param title The title of the wiki.
124 * @param description The description of the wiki.
125 * @param sessionID The session id.
126 */
127 Wiki(Ontology ontology, String title, String description, int sessionID) {
128 this.ontology = ontology;
129
130 logger = new Logger(ontology.getName(), sessionID);
131 application = ApplicationInstance.getActive();
132 taskQueue = application.createTaskQueue();
133
134 SplitPane splitPane1 = new SplitPane(SplitPane.ORIENTATION_VERTICAL_TOP_BOTTOM);
135 splitPane1.setSeparatorPosition(new Extent(50));
136 splitPane1.setSeparatorHeight(new Extent(0));
137
138 navigationButtons.setInsets(new Insets(5, 5, 5, 26));
139 navigationButtons.setCellSpacing(new Extent(5));
140 navigationButtons.setBackground(new Color(230, 230, 230));
141
142 navigationButtons.add(backButton);
143 navigationButtons.add(forwardButton);
144 navigationButtons.add(refreshButton);
145
146 ContentPane menuBar = new ContentPane();
147 menuBar.add(navigationButtons);
148
149 SplitPane splitPane2 = new SplitPane(SplitPane.ORIENTATION_HORIZONTAL_LEFT_RIGHT, new Extent(145));
150 splitPane2.setSeparatorHeight(new Extent(0));
151
152 ContentPane sideBar = new ContentPane();
153 sideBar.setBackground(new Color(230, 230, 230));
154 Column sideCol = new Column();
155 sideCol.setInsets(new Insets(10, 10));
156
157 logo = new Label();
158 sideCol.add(logo);
159
160 sideCol.add(new VSpace(30));
161
162 SolidLabel label1 = new SolidLabel("Navigation:", Font.ITALIC);
163 label1.setFont(new Font(Style.fontTypeface, Font.ITALIC, new Extent(10)));
164 sideCol.add(label1);
165 sideCol.add(new ListItem(homeButton));
166 sideCol.add(new ListItem(indexButton));
167 sideCol.add(new ListItem(randomButton));
168 sideCol.add(new ListItem(searchButton));
169
170 sideCol.add(new VSpace(10));
171
172 SolidLabel label2 = new SolidLabel("Actions:", Font.ITALIC);
173 label2.setFont(new Font(Style.fontTypeface, Font.ITALIC, new Extent(10)));
174 sideCol.add(label2);
175 sideCol.add(new ListItem(newButton));
176 sideCol.add(new ListItem(exportButton));
177 logoutListItem = new ListItem(logoutButton);
178 logoutButton.setWidth(new Extent(110));
179 logoutListItem.setVisible(false);
180 sideCol.add(logoutListItem);
181
182 //sideCol.add(new VSpace(20));
183 //sideCol.add(new ItalicLabel("Session ID: " + sessionID));
184
185 sideBar.add(sideCol);
186
187 SplitPane splitPane3 = new SplitPane(SplitPane.ORIENTATION_HORIZONTAL_LEFT_RIGHT);
188 splitPane3.setSeparatorWidth(new Extent(1));
189 splitPane3.setSeparatorColor(Color.BLACK);
190 splitPane3.setSeparatorPosition(new Extent(0));
191 splitPane3.add(new Label());
192
193 SplitPane splitPane4 = new SplitPane(SplitPane.ORIENTATION_VERTICAL_TOP_BOTTOM);
194 splitPane4.setSeparatorHeight(new Extent(1));
195 splitPane4.setSeparatorColor(Color.BLACK);
196 splitPane4.setSeparatorPosition(new Extent(0));
197 splitPane4.add(new Label());
198
199 splitPane3.add(splitPane4);
200 splitPane4.add(mainPane);
201
202 splitPane1.add(menuBar);
203 splitPane1.add(splitPane3);
204
205 splitPane2.add(sideBar);
206 splitPane2.add(splitPane1);
207
208 contentPane.add(splitPane2);
209
210 startPage = new StartPage(this, title, description);
211
212 setCurrentPage(startPage);
213 update();
214 }
215
216 /**
217 * Returns the content pane containing the wiki GUI.
218 *
219 * @return The content pane.
220 */
221 public ContentPane getContentPane() {
222 return contentPane;
223 }
224
225 /**
226 * Displays the window in the wiki.
227 *
228 * @param window The window to be shown.
229 */
230 public void showWindow(WindowPane window) {
231 if (window instanceof WordEditorWindow || window instanceof PreditorWindow) {
232 ArrayList<WindowPane> windowsNew = new ArrayList<WindowPane>();
233 for (WindowPane wp : windows) {
234 if (wp.isVisible()) windowsNew.add(wp);
235 }
236 windows = windowsNew;
237 int c = windows.size();
238 window.setPositionX(new Extent(50 + (c % 5)*40));
239 window.setPositionY(new Extent(50 + (c % 5)*20));
240 windows.add(window);
241 }
242 getContentPane().add(window);
243 }
244
245 /**
246 * Switches to the given page.
247 *
248 * @param page The page to switch to.
249 */
250 public void showPage(WikiPage page) {
251 if (!currentPage.equals(page)) {
252 history.push(currentPage);
253 forward.clear();
254 }
255 setCurrentPage(page);
256 log("navi", "goto: " + page);
257 update();
258 }
259
260 /**
261 * Switches to the page of the given ontology element.
262 *
263 * @param e The ontology element the page of which should be shown.
264 */
265 public void showPage(OntologyElement e) {
266 showPage(ArticlePage.create(e, this));
267 }
268
269 /**
270 * Go to the previous page in the history.
271 */
272 public void back() {
273 if (history.isEmpty()) return;
274 forward.push(currentPage);
275 WikiPage page = history.pop();
276 setCurrentPage(page);
277 log("navi", "back: " + page);
278 update();
279 }
280
281 /**
282 * Go to the next page in the history.
283 */
284 public void forward() {
285 if (forward.isEmpty()) return;
286 history.push(currentPage);
287 WikiPage page = forward.pop();
288 setCurrentPage(page);
289 log("navi", "forw: " + page);
290 update();
291 }
292
293 /**
294 * Show the start page.
295 */
296 public void showStartPage() {
297 showPage(startPage);
298 }
299
300 /**
301 * Show the index page.
302 */
303 public void showIndexPage() {
304 showPage(new IndexPage(this));
305 }
306
307 /**
308 * Show the search page.
309 */
310 public void showSearchPage() {
311 showPage(new SearchPage(this));
312 }
313
314 /**
315 * Returns the ontology;
316 *
317 * @return The ontology.
318 */
319 public Ontology getOntology() {
320 return ontology;
321 }
322
323 /**
324 * Returns all ontology elements.
325 *
326 * @return A collection of all ontology elements.
327 */
328 public Collection<OntologyElement> getOntologyElements() {
329 return ontology.getOntologyElements();
330 }
331
332 /**
333 * Updates the GUI.
334 */
335 public void update() {
336 mainPane.removeAll();
337 mainPane.add(currentPage);
338
339 backButton.setEnabled(!history.isEmpty());
340 forwardButton.setEnabled(!forward.isEmpty());
341
342 if (ontology.isConsistent()) {
343 logo.setIcon(new ResourceImageReference("ch/uzh/ifi/attempto/acewiki/gui/img/AceWikiLogoSmall.png"));
344 } else {
345 logo.setIcon(new ResourceImageReference("ch/uzh/ifi/attempto/acewiki/gui/img/AceWikiLogoSmallRed.png"));
346 }
347 }
348
349 private void setCurrentPage(WikiPage currentPage) {
350 this.currentPage = currentPage;
351 refresh();
352 }
353
354 /**
355 * Refreshes the current page.
356 */
357 public void refresh() {
358 currentPage.update();
359 }
360
361 public void actionPerformed(ActionEvent e) {
362 if (e.getSource() == backButton) {
363 log("page", "pressed: back");
364 back();
365 } else if (e.getSource() == forwardButton) {
366 log("page", "pressed: forward");
367 forward();
368 } else if (e.getSource() == indexButton) {
369 log("page", "pressed: index");
370 showIndexPage();
371 } else if (e.getSource() == homeButton) {
372 log("page", "pressed: main page");
373 showStartPage();
374 } else if (e.getSource() == randomButton) {
375 log("page", "pressed: random page");
376 ArrayList<OntologyElement> elements = new ArrayList<OntologyElement>(ontology.getOntologyElements());
377 if (elements.size() > 0) {
378 int r = (new Random()).nextInt(elements.size());
379 showPage(elements.get(r));
380 } else {
381 showStartPage();
382 }
383 } else if (e.getSource() == refreshButton) {
384 log("page", "pressed: refresh");
385 update();
386 refresh();
387 } else if (e.getSource() == newButton) {
388 log("page", "pressed: new word");
389 WordEditorWindow w = WordEditorWindow.createCreatorWindow();
390 w.addTab(new ProperNameForm(new Individual(), w, this, this));
391 w.addTab(new NounForm(new NounConcept(), 0, w, this, this));
392 w.addTab(new NounOfForm(new OfRole(), w, this, this));
393 w.addTab(new VerbForm(new VerbRole(), 0, w, this, this));
394 w.addTab(new TrAdjForm(new TrAdjRole(), w, this, this));
395 showWindow(w);
396 } else if (e.getSource() == searchButton) {
397 log("page", "pressed: search");
398 showSearchPage();
399 } else if (e.getSource() == exportButton) {
400 final String f = ontology.getOWLOntologyAsXML();
401 DownloadProvider provider = new DownloadProvider() {
402
403 public String getContentType() {
404 return "application/owl+xml";
405 }
406
407 public String getFileName() {
408 return ontology.getName() + ".owl";
409 }
410
411 public int getSize() {
412 return f.length();
413 }
414
415 public void writeFile(OutputStream out) throws IOException {
416 out.write(f.getBytes());
417 out.close();
418 }
419
420 };
421 application.enqueueCommand(new Download(provider, true));
422 } else if (e.getSource() == logoutButton) {
423 showWindow(new MessageWindow("Logout", "Do you really want to log out?", null, this, "Yes", "No"));
424 } else if (e.getSource() instanceof MessageWindow && e.getActionCommand().equals("Yes")) {
425 ((AceWikiApp) ApplicationInstance.getActive()).logout();
426 } else if (e.getSource() instanceof OntologyTextElement) {
427 // for newly generated elements
428 OntologyTextElement te = (OntologyTextElement) e.getSource();
429 log("edit", "new word: " + te.getOntologyElement().getWord());
430 showPage(te.getOntologyElement());
431 }
432 }
433
434 /**
435 * Writes the log entry to the log file.
436 *
437 * @param type The type of the log entry.
438 * @param text The text of the log entry.
439 */
440 public void log(String type, String text) {
441 logger.log(type, text);
442 }
443
444 /**
445 * Sets the user name.
446 *
447 * @param username The user name.
448 */
449 public void setUsername(String username) {
450 logger.setUsername(username);
451 logoutButton.setText("Logout: " + username);
452 logoutListItem.setVisible(true);
453 }
454
455 /**
456 * Returns the grammar to be used for this wiki.
457 *
458 * @return The grammar.
459 */
460 public Grammar getGrammar() {
461 return grammar;
462 }
463
464 /**
465 * Runs the task without showing a wait window while it is executed.
466 *
467 * @param task The task.
468 */
469 public void enqueueTask(Runnable task) {
470 application.enqueueTask(taskQueue, task);
471 }
472
473 /**
474 * Runs the task and shows a wait window while it is executed.
475 *
476 * @param title The title of the wait window.
477 * @param message The message of the wait window.
478 * @param task The task.
479 */
480 public void enqueueTaskShowingWaitWindow(String title, String message, final Task task) {
481 final MessageWindow waitWindow = new MessageWindow(
482 title,
483 new ResourceImageReference("ch/uzh/ifi/attempto/acewiki/gui/img/wait.gif"),
484 message,
485 null,
486 null
487 );
488 waitWindow.setClosable(false);
489 showWindow(waitWindow);
490
491 Thread thread = new Thread() {
492 public void run() {
493 task.run();
494 application.enqueueTask(taskQueue, new Runnable() {
495 public synchronized void run() {
496 waitWindow.setVisible(false);
497 task.updateGUI();
498 }
499 });
500 }
501 };
502 thread.start();
503 }
504
505 public static String getInfo(String key) {
506 if (properties == null) {
507 String f = "ch/uzh/ifi/attempto/acewiki/acewiki.properties";
508 InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(f);
509 properties = new Properties();
510 try {
511 properties.load(in);
512 } catch (Exception ex) {
513 ex.printStackTrace();
514 }
515 }
516
517 return properties.getProperty(key);
518 }
519
520 }