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 }