package ch.uzh.ifi.attempto.acewiki.gui; import nextapp.echo.app.Color; import nextapp.echo.app.Column; import nextapp.echo.app.Component; import nextapp.echo.app.Extent; import nextapp.echo.app.Font; import nextapp.echo.app.Grid; import nextapp.echo.app.Insets; import nextapp.echo.app.Row; import nextapp.echo.app.event.ActionEvent; import ch.uzh.ifi.attempto.acewiki.Wiki; import ch.uzh.ifi.attempto.acewiki.core.Comment; import ch.uzh.ifi.attempto.acewiki.core.ModuleElement; import ch.uzh.ifi.attempto.acewiki.core.ModuleElement.InvalidSyntaxException; import ch.uzh.ifi.attempto.acewiki.core.OntologyElement; import ch.uzh.ifi.attempto.acewiki.gf.GfEngine; import ch.uzh.ifi.attempto.acewiki.gf.TypeGfModule; import ch.uzh.ifi.attempto.echocomp.GeneralButton; import ch.uzh.ifi.attempto.echocomp.HSpace; import ch.uzh.ifi.attempto.echocomp.MessageWindow; import ch.uzh.ifi.attempto.echocomp.SimpleErrorMessageWindow; import ch.uzh.ifi.attempto.echocomp.SolidLabel; import ch.uzh.ifi.attempto.echocomp.Style; import ch.uzh.ifi.attempto.echocomp.VSpace; import ch.uzh.ifi.attempto.gfservice.GfModule; import ch.uzh.ifi.attempto.gfservice.GfServiceException; import com.google.common.base.Splitter; /** * TODO: localize strings * * @author Kaarel Kaljurand * @author Tobias Kuhn */ public class ModulePage extends ArticlePage { private static final long serialVersionUID = -5592272938081004472L; private static final String ACTION_EDIT = "Edit module"; private static final String ACTION_CHECK = "Check module"; public final static Splitter SPLITTER_NL = Splitter.on('\n'); private final ModuleElement mElement; private final Wiki mWiki; private Row mFormattedModuleContent; public ModulePage(ModuleElement element, Wiki wiki) { super(wiki, element); mElement = element; mWiki = wiki; getTitle().setColor(Style.specialForeground); } public OntologyElement getOntologyElement() { return mElement; } public void actionPerformed(ActionEvent e) { super.actionPerformed(e); if (ACTION_EDIT.equals(e.getActionCommand())) { if (!getWiki().isEditable()) { getWiki().showLoginWindow(); } else { EditorDialog.Builder editor = new EditorDialog.Builder(mElement.getModuleContent(), this) .setTitle("Module Editor") .setSize(600, 600) .setFont(new Font(Font.MONOSPACE, Font.PLAIN, new Extent(12))) .setPositiveButton(new Executable() { @Override public void execute(Object... args) { boolean success = parse(); // If there were no syntax errors then push the grammar to the server. if (success) { GfEngine engine = (GfEngine) mWiki.getEngine(); try { engine.getGfGrammar().upload( new GfModule(mElement.getWord(), mElement.getModuleContent().getText())); } catch (GfServiceException e) { mWiki.showWindow(new MessageWindow("Error", "Push to server failed.")); e.printStackTrace(); } } } }); mWiki.showWindow(editor.create()); } } else if (ACTION_CHECK.equals(e.getActionCommand())) { if (!getWiki().isEditable()) { getWiki().showLoginWindow(); } else { boolean success = parse(); if (success) { mWiki.showWindow(new MessageWindow("Success", "There are no syntax errors.")); } } } } protected void doUpdate() { setTabRow(TabRow.getEmptyTabRow()); Column textColumn = getTextColumn(); textColumn.removeAll(); Grid referencesGrid = new Grid(5); referencesGrid.setInsets(new Insets(0, 2, 8, 2)); for (ModuleElement oe : mWiki.getOntology().getOntologyElements(ModuleElement.class)) { if (oe != mElement && oe.references(mElement)) { referencesGrid.add(new WikiLink(oe, oe.getWord(), mWiki, false)); } } Row buttonRow = new Row(); buttonRow.setCellSpacing(new Extent(10)); buttonRow.add(new GeneralButton(ACTION_EDIT, this)); buttonRow.add(new GeneralButton(ACTION_CHECK, this)); textColumn.add(referencesGrid); textColumn.add(new VSpace(20)); textColumn.add(buttonRow); textColumn.add(new VSpace(20)); Comment grammarContent = mElement.getModuleContent(); if (grammarContent == null || grammarContent.getText().isEmpty()) { mElement.replaceModuleContent(mElement.getDefaultContent()); grammarContent = mElement.getModuleContent(); } mFormattedModuleContent = getModuleColumn(grammarContent.getText()); textColumn.add(mFormattedModuleContent); getTitle().setText(mElement.getWord()); } private boolean parse() { // TODO: this blocks, do it in the background try { mElement.parse(); } catch (InvalidSyntaxException iex) { Integer l = iex.getLine(); Integer c = iex.getColumn(); mWiki.showWindow(new SimpleErrorMessageWindow( "Error at line/column = " + (l == null ? "?" : l) + "/" + (c == null ? "?" : c), iex.getText())); if (l != null) highlightSyntaxError(l); return false; } catch (Exception ex) { mWiki.showWindow(new SimpleErrorMessageWindow("Error", ex.getMessage())); return false; } return true; } private void highlightSyntaxError(int nth1) { if (mFormattedModuleContent != null && mFormattedModuleContent.getComponent(0) != null && nth1 <= mFormattedModuleContent.getComponent(0).getComponentCount()) { mFormattedModuleContent.getComponent(0).getComponent(nth1 - 1).setBackground(Color.PINK); } } private Row getModuleColumn(String text) { Column colNumbers = new Column(); Column colLines = new Column(); int lineNumber = 0; for (String s : SPLITTER_NL.split(text)) { lineNumber++; Row rowNumber = new Row(); rowNumber.add(makeLineNumber(lineNumber)); colNumbers.add(rowNumber); Row rowLine = new Row(); rowLine.add(markupLine(s)); colLines.add(rowLine); } Row row = new Row(); row.add(colNumbers); row.add(new HSpace(20)); row.add(colLines); return row; } private Component markupLine(String text) { StringBuilder sb = new StringBuilder(); Row row = new Row(); for (String s : TypeGfModule.tokenizeText(text)) { // Check if the element is in the ontology OntologyElement oe = mWiki.getOntology().getElement(s); // TODO: reuse the references set from the statement if (oe == null) { sb.append(s); } else { if (sb.length() > 0) { row.add(makePlainText(sb.toString())); sb.setLength(0); } row.add(new HSpace()); row.add(new WikiLink(oe, s, mWiki, false)); row.add(new HSpace()); } } row.add(makePlainText(sb.toString())); return row; } /** * Turns the given string into a label. * Empty strings also get a representation, otherwise they would not create a row. */ private static Component makePlainText(String s) { if (s.isEmpty()) { s = "\u00A0"; } SolidLabel label = new SolidLabel(s, Font.PLAIN); label.setForeground(Style.darkForeground); label.setFont(new Font(Font.MONOSPACE, Font.PLAIN, new Extent(12))); label.setFormatWhitespace(true); // TODO: maybe this should be part of any SolidLabel return label; } private static SolidLabel makeLineNumber(int lineNumber) { SolidLabel label = new SolidLabel(String.format("%4d", lineNumber), Font.PLAIN); label.setForeground(new Color(120, 120, 120)); label.setFont(new Font(Font.MONOSPACE, Font.PLAIN, new Extent(12))); label.setFormatWhitespace(true); // TODO: maybe this should be part of any SolidLabel return label; } }