// 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;
}
}
}