// This file is part of AceWiki. // Copyright 2008-2013, AceWiki developers. // // AceWiki is free software: you can redistribute it and/or modify it under the terms of the GNU // Lesser General Public License as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // AceWiki is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License along with AceWiki. If // not, see http://www.gnu.org/licenses/. package ch.uzh.ifi.attempto.acewiki; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.Random; import java.util.Stack; import javax.servlet.http.Cookie; import nextapp.echo.app.Alignment; import nextapp.echo.app.ApplicationInstance; import nextapp.echo.app.Color; import nextapp.echo.app.Column; import nextapp.echo.app.Component; import nextapp.echo.app.ContentPane; import nextapp.echo.app.Extent; import nextapp.echo.app.Font; import nextapp.echo.app.Insets; import nextapp.echo.app.ResourceImageReference; import nextapp.echo.app.Row; import nextapp.echo.app.SplitPane; import nextapp.echo.app.TaskQueueHandle; import nextapp.echo.app.WindowPane; import nextapp.echo.app.event.ActionEvent; import nextapp.echo.app.event.ActionListener; import nextapp.echo.app.layout.ColumnLayoutData; import nextapp.echo.webcontainer.ContainerContext; import ch.uzh.ifi.attempto.acewiki.core.AceWikiConfig; import ch.uzh.ifi.attempto.acewiki.core.AceWikiDataExporter; import ch.uzh.ifi.attempto.acewiki.core.AceWikiEngine; import ch.uzh.ifi.attempto.acewiki.core.AceWikiGrammarEditor; import ch.uzh.ifi.attempto.acewiki.core.AceWikiStorage; import ch.uzh.ifi.attempto.acewiki.core.GrammarEditorResult; import ch.uzh.ifi.attempto.acewiki.core.LanguageHandler; import ch.uzh.ifi.attempto.acewiki.core.LexiconTableExporter; import ch.uzh.ifi.attempto.acewiki.core.Ontology; import ch.uzh.ifi.attempto.acewiki.core.OntologyElement; import ch.uzh.ifi.attempto.acewiki.core.OntologyExportManager; import ch.uzh.ifi.attempto.acewiki.core.OntologyExporter; import ch.uzh.ifi.attempto.acewiki.core.OntologyTextElement; import ch.uzh.ifi.attempto.acewiki.core.Sentence; import ch.uzh.ifi.attempto.acewiki.core.Statement; import ch.uzh.ifi.attempto.acewiki.core.StatementTableExporter; import ch.uzh.ifi.attempto.acewiki.core.User; import ch.uzh.ifi.attempto.acewiki.core.UserBase; import ch.uzh.ifi.attempto.acewiki.core.UserProvider; import ch.uzh.ifi.attempto.acewiki.gui.AboutPage; import ch.uzh.ifi.attempto.acewiki.gui.ArticlePage; import ch.uzh.ifi.attempto.acewiki.gui.ExportWindow; import ch.uzh.ifi.attempto.acewiki.gui.FormPane; import ch.uzh.ifi.attempto.acewiki.gui.GrammarPage; import ch.uzh.ifi.attempto.acewiki.gui.IconButton; import ch.uzh.ifi.attempto.acewiki.gui.IndexPage; import ch.uzh.ifi.attempto.acewiki.gui.LexiconEditorPage; import ch.uzh.ifi.attempto.acewiki.gui.ListItem; import ch.uzh.ifi.attempto.acewiki.gui.LoginWindow; import ch.uzh.ifi.attempto.acewiki.gui.SearchPage; import ch.uzh.ifi.attempto.acewiki.gui.SentencePage; import ch.uzh.ifi.attempto.acewiki.gui.StartPage; import ch.uzh.ifi.attempto.acewiki.gui.Title; import ch.uzh.ifi.attempto.acewiki.gui.UserWindow; import ch.uzh.ifi.attempto.acewiki.gui.WikiPage; import ch.uzh.ifi.attempto.base.LoggerContext; import ch.uzh.ifi.attempto.echocomp.EchoThread; import ch.uzh.ifi.attempto.echocomp.HSpace; import ch.uzh.ifi.attempto.echocomp.Label; import ch.uzh.ifi.attempto.echocomp.LocaleResources; import ch.uzh.ifi.attempto.echocomp.MessageWindow; import ch.uzh.ifi.attempto.echocomp.SimpleErrorMessageWindow; import ch.uzh.ifi.attempto.echocomp.SmallButton; import ch.uzh.ifi.attempto.echocomp.SolidLabel; import ch.uzh.ifi.attempto.echocomp.Style; import ch.uzh.ifi.attempto.echocomp.TextAreaWindow; import ch.uzh.ifi.attempto.echocomp.TextField; import ch.uzh.ifi.attempto.echocomp.VSpace; import ch.uzh.ifi.attempto.preditor.PreditorWindow; import ch.uzh.ifi.attempto.preditor.WordEditorWindow; import echopoint.externalevent.ExternalEvent; import echopoint.externalevent.ExternalEventListener; import echopoint.externalevent.ExternalEventMonitor; // TODO Move this class to gui package? /** * This class represents an AceWiki wiki instance (including its graphical user interface). * There is such a wiki object for every wiki user. * The actions handled by this class refer to the wiki as a whole. * * @author Tobias Kuhn * @author Kaarel Kaljurand */ public class Wiki implements UserProvider, ActionListener, ExternalEventListener { private static final long serialVersionUID = 2777443689044226043L; private AceWikiConfig config; private final Ontology ontology; private final AceWikiEngine engine; private String language; private User user; private OntologyExportManager ontologyExportManager; private AceWikiStorage storage; private WikiPage currentPage; private Column pageCol; private ContentPane contentPane = new ContentPane(); private Row navigationButtons; private final LoggerContext loggerContext; private final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(this.getClass()); private SplitPane wikiPane; private Row loginBackground; private IconButton backButton, forwardButton, refreshButton, userButton, logoutButton, searchButton; private TextField searchTextField = new TextField(170, this); private Label userLabel; private SmallButton homeButton, indexButton, searchButton2, aboutButton, randomButton, newButton, exportButton, rebuildGrammarButton; private SmallButton grammarButton; private SmallButton lexiconEditorButton; private List<SmallButton> languageButtons; private StartPage startPage; private Stack<WikiPage> history = new Stack<WikiPage>(); private Stack<WikiPage> forward = new Stack<WikiPage>(); private TaskQueueHandle taskQueue; private MessageWindow waitWindow; private List<Task> strongTasks = new ArrayList<Task>(); private List<Task> weakTasks = new ArrayList<Task>(); private ExternalEventMonitor externalEventMonitor; private AceWikiApp application; private static Properties properties; private boolean disposed = false; private boolean locked = false; private ActionListener lockedListener; /** * Creates a new wiki instance. * * @param backend The backend object. * @param parameters The configuration parameters. * @param sessionId The session id. */ Wiki(Backend backend, Map<String, String> parameters, int sessionId) { this.config = new AceWikiConfig(parameters, this); storage = backend.getStorage(); ontology = backend.getOntology(); engine = ontology.getEngine(); loggerContext = new LoggerContext(ontology.getName(), "anon", String.valueOf(sessionId)); loggerContext.propagateWithinThread(); application = (AceWikiApp) EchoThread.getActiveApplication(); taskQueue = application.createTaskQueue(); language = config.getParameter("language"); if (language == null || language.equals("")) { language = engine.getLanguages()[0]; } log("syst", "language set to " + language); if (config.isLanguageSwitchingEnabled()) { String showLang = getURLParameterValue("showlang"); if (showLang != null && Arrays.asList(engine.getLanguages()).contains(showLang)) { language = showLang; } } application.setLocale(getLocale()); ontologyExportManager = new OntologyExportManager(ontology); for (OntologyExporter o : engine.getExporters()) { ontologyExportManager.addExporter(o); } ontologyExportManager.addExporter(new LexiconTableExporter()); ontologyExportManager.addExporter(new StatementTableExporter()); ontologyExportManager.addExporter(new AceWikiDataExporter()); userLabel = new SolidLabel(getGUIText("acewiki_anonymoususer_name"), Font.ITALIC); userLabel.setForeground(Color.DARKGRAY); buildContentPane(); logoutButton.setVisible(false); startPage = new StartPage(this); // auto login if (config.isLoginEnabled()) { String userName = getCookie("lastusername"); boolean stayLoggedIn = getCookie("stayloggedin").equals("true"); if (getUserBase().containsUser(userName) && stayLoggedIn) { String clientToken = getCookie("stayloggedintoken"); if (clientToken.length() > 0) { log("syst", "try auto login..."); user = getUserBase().autoLogin(userName, clientToken); if (user != null) { log("syst", "auto login successful: " + user.getName()); setUser(user); } else { log("syst", "auto login failed: " + userName); clearCookie("stayloggedintoken"); } } } } String showpage = getURLParameterValue("showpage"); if (showpage != null && ontology.getElement(showpage) != null) { setCurrentPage(ArticlePage.create(ontology.getElement(showpage), this)); } else { setCurrentPage(startPage); } // This thread checks regularly for pending tasks and executes them. Strong tasks take // precedence over weak ones. EchoThread asyncThread = new EchoThread() { public ApplicationInstance getApplication() { return application; } public void run() { while (true) { try { sleep(500); } catch (InterruptedException ex) {} if (disposed) { break; } Task task = null; if (strongTasks.size() > 0) { task = strongTasks.remove(0); } else if (weakTasks.size() > 0) { task = weakTasks.remove(0); } final Task fTask = task; if (fTask != null) { task.run(); application.enqueueTask(taskQueue, new Runnable() { public synchronized void run() { fTask.updateGUI(); if (waitWindow != null) { removeWindow(waitWindow); waitWindow = null; } } }); } } } }; asyncThread.setPriority(Thread.MIN_PRIORITY); asyncThread.start(); update(); } private void buildContentPane() { if (loginBackground != null) return; contentPane.removeAll(); SplitPane splitPane1 = new SplitPane(SplitPane.ORIENTATION_VERTICAL_TOP_BOTTOM); splitPane1.setSeparatorPosition(new Extent(50)); splitPane1.setSeparatorHeight(new Extent(0)); SplitPane splitPane2 = new SplitPane(SplitPane.ORIENTATION_HORIZONTAL_RIGHT_LEFT); splitPane2.setSeparatorPosition(new Extent(215)); splitPane2.setSeparatorWidth(new Extent(0)); navigationButtons = new Row(); navigationButtons.setInsets(new Insets(5)); navigationButtons.setBackground(Style.shadedBackground); backButton = new IconButton("back", this); forwardButton = new IconButton("forward", this); refreshButton = new IconButton("refresh", this); userButton = new IconButton("user", this); logoutButton = new IconButton("logout", this); searchButton = new IconButton("search", this); navigationButtons.add(backButton); navigationButtons.add(new HSpace(5)); navigationButtons.add(forwardButton); navigationButtons.add(new HSpace(5)); navigationButtons.add(refreshButton); navigationButtons.add(new HSpace(30)); Row userRow = new Row(); userRow.add(userButton); userRow.add(new HSpace(3)); userRow.add(userLabel); userRow.add(logoutButton); userRow.setVisible(config.isLoginEnabled()); navigationButtons.add(userRow); ContentPane menuBar = new ContentPane(); menuBar.setBackground(Style.shadedBackground); menuBar.add(navigationButtons); Row searchRow = new Row(); searchRow.setInsets(new Insets(5)); searchRow.setBackground(Style.shadedBackground); searchRow.add(searchButton); searchRow.add(new HSpace(5)); searchRow.add(searchTextField); ContentPane searchBar = new ContentPane(); searchBar.setBackground(Style.shadedBackground); searchBar.add(searchRow); wikiPane = new SplitPane( SplitPane.ORIENTATION_HORIZONTAL_LEFT_RIGHT, new Extent(145) ); wikiPane.setSeparatorHeight(new Extent(0)); SplitPane sideBar = new SplitPane( SplitPane.ORIENTATION_VERTICAL_TOP_BOTTOM, new Extent(170) ); sideBar.setSeparatorHeight(new Extent(0)); sideBar.setBackground(Style.shadedBackground); Column iconCol = new Column(); iconCol.setInsets(new Insets(10, 10, 10, 0)); iconCol.setCellSpacing(new Extent(1)); Label logo = new Label(new ResourceImageReference( "ch/uzh/ifi/attempto/acewiki/gui/img/AceWikiLogoSmall.png" )); iconCol.add(logo); iconCol.add(new VSpace(10)); ColumnLayoutData layout = new ColumnLayoutData(); layout.setAlignment(Alignment.ALIGN_CENTER); String title = config.getParameter("title"); if (title != null && title.length() > 0) { Label titleLabel = new Label(title, Font.ITALIC, 14); iconCol.add(titleLabel); titleLabel.setLayoutData(layout); iconCol.add(new VSpace(5)); } if (config.isReadOnly()) { String s = "— " + getGUIText("acewiki_state_readonly") + " —"; SolidLabel rolabel = new SolidLabel(s, Font.ITALIC); rolabel.setFont(new Font(Style.fontTypeface, Font.ITALIC, new Extent(10))); rolabel.setLayoutData(layout); iconCol.add(rolabel); } sideBar.add(iconCol); Column sideCol = new Column(); sideCol.setInsets(new Insets(10, 0, 0, 10)); sideCol.setCellSpacing(new Extent(1)); SolidLabel label = new SolidLabel(getGUIText("acewiki_sidemenu_navigation"), Font.ITALIC); label.setFont(new Font(Style.fontTypeface, Font.ITALIC, new Extent(10))); sideCol.add(label); homeButton = new SmallButton(getGUIText("acewiki_page_main"), this, 12); indexButton = new SmallButton(getGUIText("acewiki_page_index"), this, 12); searchButton2 = new SmallButton(getGUIText("acewiki_page_search"), this, 12); aboutButton = new SmallButton(getGUIText("acewiki_page_about"), this, 12); grammarButton = new SmallButton(getGUIText("acewiki_page_grammar"), this, 12); lexiconEditorButton = new SmallButton(getGUIText("acewiki_page_lexicon"), this, 12); randomButton = new SmallButton(getGUIText("acewiki_page_random"), this, 12); sideCol.add(new ListItem(homeButton)); sideCol.add(new ListItem(indexButton)); sideCol.add(new ListItem(searchButton2)); sideCol.add(new ListItem(aboutButton)); if (config.isGrammarIntegrationEnabled()) { sideCol.add(new ListItem(grammarButton)); sideCol.add(new ListItem(lexiconEditorButton)); } sideCol.add(new ListItem(randomButton)); sideCol.add(new VSpace(10)); label = new SolidLabel(getGUIText("acewiki_sidemenu_actions"), Font.ITALIC); label.setFont(new Font(Style.fontTypeface, Font.ITALIC, new Extent(10))); sideCol.add(label); newButton = new SmallButton(getGUIText("acewiki_action_new"), this, 12); exportButton = new SmallButton(getGUIText("acewiki_action_export"), this, 12); if (!config.isReadOnly() && getEngine().getLexicalTypes().length > 0) { sideCol.add(new ListItem(newButton)); } AceWikiGrammarEditor grammarEditor = getEngine().getGrammarEditor(); if (grammarEditor != null && grammarEditor.isEditable()) { rebuildGrammarButton = new SmallButton(getGUIText("acewiki_action_rebuild_grammar"), this, 12); sideCol.add(new ListItem(rebuildGrammarButton)); } sideCol.add(new ListItem(exportButton)); languageButtons = new ArrayList<SmallButton>(); if (isMultilingual() && config.isLanguageSwitchingEnabled()) { // show language switcher sideCol.add(new VSpace(10)); label = new SolidLabel(getGUIText("acewiki_sidemenu_languages"), Font.ITALIC); label.setFont(new Font(Style.fontTypeface, Font.ITALIC, new Extent(10))); sideCol.add(label); for (String lang : engine.getLanguages()) { String n = engine.getLanguageHandler(lang).getLanguageName(); SmallButton b = new SmallButton(n, this, 12); if (lang.equals(language)) b.setEnabled(false); languageButtons.add(b); sideCol.add(new ListItem(b)); } } if (externalEventMonitor != null) { externalEventMonitor.removeExternalEventListener(this); externalEventMonitor.dispose(); } externalEventMonitor = new ExternalEventMonitor(); externalEventMonitor.addExternalEventListener(this); sideCol.add(externalEventMonitor); //sideCol.add(new VSpace(20)); //sideCol.add(new ItalicLabel("Session ID: " + sessionId)); sideBar.add(sideCol); SplitPane splitPane3 = new SplitPane(SplitPane.ORIENTATION_HORIZONTAL_LEFT_RIGHT); splitPane3.setSeparatorWidth(new Extent(1)); splitPane3.setSeparatorColor(Color.BLACK); splitPane3.setSeparatorPosition(new Extent(0)); splitPane3.add(new Label()); SplitPane splitPane4 = new SplitPane(SplitPane.ORIENTATION_VERTICAL_TOP_BOTTOM); splitPane4.setSeparatorHeight(new Extent(1)); splitPane4.setSeparatorColor(Color.BLACK); splitPane4.setSeparatorPosition(new Extent(0)); splitPane4.add(new Label()); splitPane3.add(splitPane4); pageCol = new Column(); splitPane4.add(pageCol); splitPane2.add(searchBar); splitPane2.add(menuBar); splitPane1.add(splitPane2); splitPane1.add(splitPane3); wikiPane.add(sideBar); wikiPane.add(splitPane1); contentPane.add(wikiPane); } /** * Returns the content pane containing the wiki GUI. * * @return The content pane. */ public ContentPane getContentPane() { return contentPane; } /** * Returns the application instance object of this wiki. * * @return The application instance. */ public ApplicationInstance getApplication() { return application; } public AceWikiConfig getConfig() { return config; } /** * Returns whether the wiki is in the current situation editable. This depends on the fact * whether a user is logged in and whether login is required for editing the wiki data. * * @return true if the wiki is editable. */ public boolean isEditable() { return (user != null || !config.isLoginRequiredForEditing()); } public boolean isRetractReassertActivated() { if (!config.hasParameter("retractreassert")) { return getEngine().getReasoner() != null; } else { return config.isRetractReassertEnabled(); } } public boolean isTranslationsPageActivated() { if (!isMultilingual()) return false; return config.isTranslationsPageEnabled(); } /** * Shows the window. * * @param window The window to be shown. */ public void showWindow(WindowPane window) { cleanWindows(); if (window instanceof WordEditorWindow || window instanceof PreditorWindow || window instanceof TextAreaWindow) { int c = getContentPane().getComponentCount() - 1; window.setPositionX(new Extent(50 + (c % 5)*40)); window.setPositionY(new Extent(50 + (c % 5)*20)); } getContentPane().add(window); } /** * Shows a word editor window. * * @param element The ontology element to be edited. */ public void showEditorWindow(OntologyElement element) { WordEditorWindow editorWindow = new WordEditorWindow(getGUIText("acewiki_wordeditor_title")); editorWindow.addTab(new FormPane(element, editorWindow, this)); showWindow(editorWindow); } /** * Shows a word creator window for the given word type and number. * * @param type The word type. * @param wordNumber The word number. * @param actionListener The actionlistener. */ public void showCreatorWindow(String type, int wordNumber, ActionListener actionListener) { WordEditorWindow creatorWindow = new WordEditorWindow(getGUIText("acewiki_wordeditor_creatortitle")); creatorWindow.addTab(new FormPane(type, wordNumber, creatorWindow, this, actionListener)); showWindow(creatorWindow); } /** * Removes the window. * * @param window The window to be removed. */ public void removeWindow(WindowPane window) { window.setVisible(false); window.dispose(); cleanWindows(); } private void cleanWindows() { for (Component c : getContentPane().getComponents()) { if (!c.isVisible()) { getContentPane().remove(c); } } } /** * Shows the login window. */ public void showLoginWindow() { if (config.isLoginRequiredForViewing()) { getContentPane().removeAll(); loginBackground = new Row(); loginBackground.setInsets(new Insets(10, 10)); loginBackground.setCellSpacing(new Extent(30)); Label loginBgLogo = new Label(getImage("AceWikiLogoSmall.png")); loginBackground.add(loginBgLogo); loginBackground.add(new Title(config.getParameter("title"), true)); loginBackground.add(externalEventMonitor); getContentPane().add(loginBackground); getContentPane().setBackground(new Color(230, 230, 230)); } showWindow(new LoginWindow(this)); } /** * Switches to the given page. * * @param page The page to switch to. */ public void showPage(WikiPage page) { if (!currentPage.equals(page)) { history.push(currentPage); if (history.size() > 20) history.remove(0); forward.clear(); } setCurrentPage(page); log("navi", "goto: " + page); update(); } /** * Switches to the page of the given ontology element. * * @param e The ontology element the page of which should be shown. */ public void showPage(OntologyElement e) { showPage(ArticlePage.create(e, this)); } /** * Go to the previous page in the history. */ public void back() { if (history.isEmpty()) return; forward.push(currentPage); if (forward.size() > 20) forward.remove(0); WikiPage page = history.pop(); setCurrentPage(page); log("navi", "back: " + page); update(); } /** * Go to the next page in the history. */ public void forward() { if (forward.isEmpty()) return; history.push(currentPage); if (history.size() > 20) history.remove(0); WikiPage page = forward.pop(); setCurrentPage(page); log("navi", "forw: " + page); update(); } /** * Show the start page. */ public void showStartPage() { showPage(startPage); } /** * Show the index page. */ public void showIndexPage() { showPage(new IndexPage(this)); } /** * Show the search page. */ public void showSearchPage() { showPage(new SearchPage(this, "")); } /** * Show the about page. */ public void showAboutPage() { showPage(new AboutPage(this)); } /** * Show the grammar page. */ public void showGrammarPage() { showPage(new GrammarPage(this)); } /** * Show the lexicon editor page. */ public void showLexiconEditorPage() { showPage(new LexiconEditorPage(this)); } /** * Returns the ontology; * * @return The ontology. */ public Ontology getOntology() { return ontology; } /** * Returns the ontology export manager. * * @return The ontology export manager. */ public OntologyExportManager getOntologyExportManager() { return ontologyExportManager; } /** * Returns the user base for this wiki. * * @return The user base. */ public UserBase getUserBase() { return storage.getUserBase(ontology); } /** * Returns all ontology elements. The list is a copy of the internal list. * * @return A list of all ontology elements. */ public List<OntologyElement> getOntologyElements() { return ontology.getOntologyElements(); } /** * Updates the GUI. */ public void update() { pageCol.removeAll(); pageCol.add(currentPage); removeExpiredPages(history); removeExpiredPages(forward); backButton.setEnabled(!history.isEmpty()); forwardButton.setEnabled(!forward.isEmpty()); // The commented-out code below checks at every GUI update whether the ontology is consistent or not. // If not, a red AceWiki logo is shown. Usually, this case should never occur because we check for // consistency after every new statement. //if (ontology.isConsistent()) { // logo.setIcon(new ResourceImageReference("ch/uzh/ifi/attempto/acewiki/gui/img/AceWikiLogoSmall.png")); //} else { // logo.setIcon(new ResourceImageReference("ch/uzh/ifi/attempto/acewiki/gui/img/AceWikiLogoSmallRed.png")); //} } private void removeExpiredPages(Stack<WikiPage> stack) { WikiPage previousPage = null; for (WikiPage page : new ArrayList<WikiPage>(stack)) { if (page.isExpired() || page.equals(previousPage)) { stack.remove(page); } else { previousPage = page; } } if (stack.size() > 0 && currentPage.equals(stack.peek())) { stack.pop(); } } public void updateStatement(Statement oldStatement, List<Statement> newStatements) { Statement newStatement = null; if (newStatements.size() == 1) { newStatement = newStatements.get(0); } updateStatement(oldStatement, newStatement); } public void updateStatement(Statement oldStatement, Statement newStatement) { if (!(newStatement instanceof Sentence)) return; Sentence newSentence = (Sentence) newStatement; List<WikiPage> pages = new ArrayList<>(); pages.addAll(history); pages.add(currentPage); pages.addAll(forward); for (WikiPage page : pages) { if (!(page instanceof SentencePage)) continue; SentencePage sp = (SentencePage) page; if (sp.getSentence() == oldStatement) { sp.setSentence(newSentence); } } } private void setCurrentPage(WikiPage currentPage) { this.currentPage = currentPage; refresh(); } /** * Refreshes the current page. */ public void refresh() { currentPage.update(); } public void actionPerformed(ActionEvent e) { Object src = e.getSource(); String c = e.getActionCommand(); if (locked) { if (lockedListener != null) { lockedListener.actionPerformed(new ActionEvent(this, "locked")); } return; } if (src == backButton) { log("page", "pressed: back"); back(); } else if (src == forwardButton) { log("page", "pressed: forward"); forward(); } else if (src == indexButton) { log("page", "pressed: index"); showIndexPage(); } else if (src == aboutButton) { log("page", "pressed: about"); showAboutPage(); } else if (src == grammarButton) { log("page", "pressed: about grammar"); showGrammarPage(); } else if (src == lexiconEditorButton) { log("page", "pressed: lexicon editor"); showLexiconEditorPage(); } else if (src == homeButton) { log("page", "pressed: main page"); showStartPage(); } else if (src == randomButton) { log("page", "pressed: random page"); List<OntologyElement> elements = ontology.getOntologyElements(); if (elements.size() > 0) { int r = (new Random()).nextInt(elements.size()); showPage(elements.get(r)); } else { showStartPage(); } } else if (src == refreshButton) { log("page", "pressed: refresh"); buildContentPane(); update(); refresh(); } else if (src == newButton) { log("page", "pressed: new word"); if (!isEditable()) { showLoginWindow(); } else { WordEditorWindow w = new WordEditorWindow(getGUIText("acewiki_wordeditor_creatortitle")); for (String t : getEngine().getLexicalTypes()) { w.addTab(new FormPane(t, w, this)); } showWindow(w); } } else if (src == searchButton || src == searchTextField || src == searchButton2) { log("page", "pressed: search '" + searchTextField.getText() + "'"); String s = searchTextField.getText(); searchTextField.setText(""); OntologyElement el = ontology.getElement(s.replace(' ', '_')); if (el == null) { showPage(new SearchPage(this, s)); } else { showPage(el); } } else if (src == exportButton) { showWindow(new ExportWindow(this)); } else if (src == rebuildGrammarButton) { if (!isEditable()) { showLoginWindow(); } else { rebuildGrammar(getEngine().getGrammarEditor()); } } else if (src == logoutButton) { showWindow(new MessageWindow( "acewiki_message_logouttitle", "acewiki_message_logout", null, this, "general_action_yes", "general_action_no" )); } else if (src == userButton) { if (user == null) { showLoginWindow(); } else { showWindow(new UserWindow(this)); } } else if (src instanceof MessageWindow && c.equals("general_action_yes")) { logout(); } else if (src instanceof OntologyTextElement) { // for newly generated elements OntologyTextElement te = (OntologyTextElement) src; log("edit", "new word: " + te.getOntologyElement().getWord()); showPage(te.getOntologyElement()); } else if (languageButtons.contains(src)) { String language = engine.getLanguages()[languageButtons.indexOf(src)]; log("page", "pressed: " + language); switchLanguage(language); } } public void externalEvent(ExternalEvent e) { String p = e.getParameter("page"); if (p != null) { OntologyElement oe = ontology.getElement(e.getParameter("page")); if (oe != null) showPage(oe); } p = e.getParameter("lang"); if (p != null &&Arrays.asList(engine.getLanguages()).contains(p)) { log("syst", "external: lang to " + p); switchLanguage(p); } } /** * Writes the log entry to the log file. * * @param type The type of the log entry. * @param text The text of the log entry. */ public void log(String type, String text) { loggerContext.propagateWithinThread(); org.slf4j.MDC.put("type", type); log.info(text); } /** * Logs in the given user. * * @param user The user to log in. * @param stayLoggedIn Defines whether the user should stay logged in or not. */ public void login(User user, boolean stayLoggedIn) { log("syst", "login"); user.setUserData("stayloggedin", stayLoggedIn + ""); setCookie("stayloggedin", stayLoggedIn + ""); String stayloggedintoken; if (stayLoggedIn) { stayloggedintoken = (new Random()).nextLong() + ""; } else { stayloggedintoken = ""; } user.setUserData("stayloggedintoken", stayloggedintoken); setCookie("stayloggedintoken", stayloggedintoken); setUser(user); refresh(); update(); } /** * Logs out the current user. */ public void logout() { log("syst", "logout"); user.setUserData("stayloggedintoken", ""); setCookie("stayloggedintoken", ""); application.logout(); } /** * Returns the user of this wiki object. * * @return The user. */ public User getUser() { return user; } public boolean hasUserRight(String right) { if (user == null) return false; return user.hasRight(right); } /** * Sets the user. * * @param user The user. */ private void setUser(User user) { this.user = user; loggerContext.setUsername(user.getName()); userLabel.setForeground(Color.BLACK); userLabel.setText(user.getName()); logoutButton.setVisible(true); if (loginBackground != null) { loginBackground = null; buildContentPane(); getContentPane().removeAll(); getContentPane().add(wikiPane); getContentPane().setBackground(Color.WHITE); update(); refresh(); } setCookie("lastusername", user.getName()); } /** * Sets a cookie on the client. * * @param name The name of the cookie. * @param value The value of the cookie. */ public void setCookie(String name, String value) { Cookie cookie = new Cookie(name, value); cookie.setMaxAge(1000000000); getContainerContext().addCookie(cookie); } /** * Clears the given cookie on the client. * * @param name The name of the cookie. */ public void clearCookie(String name) { getContainerContext().addCookie(new Cookie(name, null)); } /** * Returns the value of the cookie on the client, or "" if there is no such cookie. * * @param name The name of the cookie. * @return The value of the cookie. */ public String getCookie(String name) { for (Cookie cookie : getContainerContext().getCookies()) { if ((name + "").equals(cookie.getName())) { String value = cookie.getValue(); if (value == null) return ""; return value; } } return ""; } private ContainerContext getContainerContext() { return (ContainerContext) application.getContextProperty( ContainerContext.CONTEXT_PROPERTY_NAME ); } /** * Returns the AceWiki engine. * * @return The AceWiki engine. */ public AceWikiEngine getEngine() { return engine; } /** * Returns the language of this wiki instance. * * @return The name of the language. */ public String getLanguage() { return language; } /** * Returns the locale of this wiki instance. * * @return The locale. */ public Locale getLocale() { return getLanguageHandler().getLocale(); // for locale testing: //return new Locale("de", "DE"); } /** * Switches to another language. * * @param language The new language. */ public void switchLanguage(String language) { log("syst", "change language to " + language); this.language = language; String[] languages = engine.getLanguages(); for (int i = 0 ; i < languages.length ; i++) { String l = languages[i]; languageButtons.get(i).setEnabled(!l.equals(language)); } application.setLocale(getLocale()); buildContentPane(); update(); refresh(); } /** * Returns the language handler. * * @return The language handler. */ public LanguageHandler getLanguageHandler() { return engine.getLanguageHandler(language); } /** * Returns whether the wiki is multilingual, i.e. has more than one language. * * @return true if multilingual. */ public boolean isMultilingual() { return engine.getLanguages().length > 1; } /** * Returns the logger context object. * * @return The logger context object. */ public LoggerContext getLoggerContext() { return loggerContext; } /** * Runs the task without showing a wait window while it is executed. * * @param task The task. */ public void enqueueTask(Runnable task) { application.enqueueTask(taskQueue, task); } /** * Runs the task in an asynchronous way and shows a wait window while it is executed. The task * is treated as a strong task that takes precedence over weak tasks. * * @param title The title of the wait window. * @param message The message of the wait window. * @param task The task. */ public void enqueueStrongAsyncTask(String title, String message, Task task) { waitWindow = new MessageWindow( title, new ResourceImageReference("ch/uzh/ifi/attempto/acewiki/gui/img/wait.gif"), message, null, null ); waitWindow.setClosable(false); showWindow(waitWindow); strongTasks.add(task); } /** * Runs the task in an asynchronous way without showing a wait window. The task is treated as a * weak task that can be overtaken by strong tasks. * * @param task The task. */ public void enqueueWeakAsyncTask(Task task) { weakTasks.add(task); } /** * Returns information about AceWiki, like the version number and the release date. This * information is read from the file "acewiki.properties". * * @param key The key string. * @return The value for the given key. */ public static String getInfo(String key) { if (properties == null) { String f = "ch/uzh/ifi/attempto/acewiki/acewiki.properties"; InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(f); properties = new Properties(); try { properties.load(in); } catch (Exception ex) { ex.printStackTrace(); } } return properties.getProperty(key); } /** * Cleans up when the object is no longer used. */ public void dispose() { disposed = true; externalEventMonitor.removeExternalEventListener(this); externalEventMonitor.dispose(); } /** * This methods locks the general buttons of the wiki interface. When one of these buttons * is pressed, the locked-listener is called. * * @param lockedListener The listener to be called when one of the buttons is pressed. */ public void lock(ActionListener lockedListener) { if (locked) return; locked = true; this.lockedListener = lockedListener; } /** * Unlocks the wiki interface, if it has been locked before. */ public void unlock() { locked = false; } /** * Returns an image reference for a file in the AceWiki image directory with the given file * name. * * @param fileName The name of the image file. * @return The image reference. */ public static ResourceImageReference getImage(String fileName) { return Style.getImage("ch/uzh/ifi/attempto/acewiki/gui/img/" + fileName); } /** * Returns the GUI text for the current locale. * * @param key The key of the GUI text item. * @return The localized string. */ public static String getGUIText(String key) { String text = LocaleResources.getString(key); if (text == null) text = key; return text; } private String getURLParameterValue(String name) { String v = null; try { ContainerContext cc = getContainerContext(); String[] values = (String[]) cc.getInitialRequestParameterMap().get(name); v = values[0]; } catch (Exception ex) {} return v; } // TODO: localize private void rebuildGrammar(AceWikiGrammarEditor grammarEditor) { try { // TODO: this blocks, do it in the background GrammarEditorResult result = grammarEditor.update(getOntology()); // TODO: if these make sense only together then put them into a private method if (result.isSuccess()) { update(); refresh(); showWindow(new MessageWindow("Success", "Grammar rebuilt successfully.")); } else { showWindow(new SimpleErrorMessageWindow(getGUIText("acewiki_error_title"), result.getResultCode() + ": " + result.getMessage() + " (" + result.getCommand() + ")")); } } catch (Exception ex) { showWindow(new SimpleErrorMessageWindow(getGUIText("acewiki_error_title"), ex.getMessage())); return; } } }