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.gui.editor;
016    
017    import nextapp.echo2.app.Alignment;
018    import nextapp.echo2.app.Column;
019    import nextapp.echo2.app.Component;
020    import nextapp.echo2.app.ContentPane;
021    import nextapp.echo2.app.Extent;
022    import nextapp.echo2.app.Font;
023    import nextapp.echo2.app.Grid;
024    import nextapp.echo2.app.Insets;
025    import nextapp.echo2.app.ResourceImageReference;
026    import nextapp.echo2.app.Row;
027    import nextapp.echo2.app.event.ActionEvent;
028    import nextapp.echo2.app.event.ActionListener;
029    import nextapp.echo2.app.layout.GridLayoutData;
030    import ch.uzh.ifi.attempto.acewiki.Wiki;
031    import ch.uzh.ifi.attempto.acewiki.core.ontology.OntologyElement;
032    import ch.uzh.ifi.attempto.acewiki.core.text.OntologyTextElement;
033    import ch.uzh.ifi.attempto.acewiki.core.text.TextElemFactory;
034    import ch.uzh.ifi.attempto.echocomp.GeneralButton;
035    import ch.uzh.ifi.attempto.echocomp.Label;
036    import ch.uzh.ifi.attempto.echocomp.MessageWindow;
037    import ch.uzh.ifi.attempto.echocomp.SolidLabel;
038    import ch.uzh.ifi.attempto.echocomp.TextField;
039    import ch.uzh.ifi.attempto.echocomp.WindowPane;
040    
041    /**
042     * This abstract class contains the basic structure for forms to create and modify words
043     * (represented by ontology elements).
044     * 
045     * @author Tobias Kuhn
046     */
047    public abstract class FormPane extends ContentPane implements ActionListener {
048    
049            private Wiki wiki;
050            private ActionListener actionListener;
051            
052            private Column column;
053            private WindowPane window;
054            private Grid iconRow;
055            private GeneralButton okButton;
056            private GeneralButton cancelButton;
057            
058            /**
059             * Initializes the form pane.
060             * 
061             * @param window The host window.
062             * @param wiki The wiki instance.
063             * @param actionListener The actionlistener.
064             */
065            protected FormPane(WindowPane window, Wiki wiki, ActionListener actionListener) {
066                    this.window = window;
067                    this.wiki = wiki;
068                    this.actionListener = actionListener;
069                    
070                    Grid grid = new Grid(1);
071                    grid.setRowHeight(0, new Extent(330));
072                    grid.setRowHeight(1, new Extent(30));
073                    
074                    column = new Column();
075                    column.setInsets(new Insets(10, 20, 0, 0));
076                    column.setCellSpacing(new Extent(10));
077                    GridLayoutData gridLayout = new GridLayoutData();
078                    gridLayout.setAlignment(new Alignment(Alignment.LEFT, Alignment.TOP));
079                    column.setLayoutData(gridLayout);
080                    grid.add(column);
081                    
082                    iconRow = new Grid(2);
083                    iconRow.setRowHeight(0, new Extent(110));
084                    iconRow.setColumnWidth(0, new Extent(100));
085                    iconRow.setInsets(new Insets(0, 0, 10, 20));
086                    column.add(iconRow);
087                    
088                    Row footerRow = new Row();
089                    footerRow.setInsets(new Insets(10, 0, 0, 0));
090                    footerRow.add(new Label("* required field", Font.ITALIC, 11));
091                    grid.add(footerRow);
092                    
093                    Row buttonBar = new Row();
094                    buttonBar.setAlignment(new Alignment(Alignment.RIGHT, Alignment.CENTER));
095                    buttonBar.setInsets(new Insets(10, 10, 10, 10));
096                    buttonBar.setCellSpacing(new Extent(5));
097                    okButton = new GeneralButton("OK", 70, this);
098                    buttonBar.add(okButton);
099                    cancelButton = new GeneralButton("Cancel", 70, this);
100                    buttonBar.add(cancelButton);
101                    grid.add(buttonBar);
102                    
103                    add(grid);
104            }
105            
106            /**
107             * Returns the wiki instance.
108             * 
109             * @return The wiki instance.
110             */
111            protected Wiki getWiki() {
112                    return wiki;
113            }
114            
115            /**
116             * This method should try to save the word with the current properties and should show
117             * error messages if this is not successful. In the case of success, one of the
118             * finished-methods has to be called.
119             * 
120             * @see #finished(OntologyElement)
121             * @see #finished(OntologyElement, int)
122             */
123            protected abstract void save();
124            
125            /**
126             * This method should be called when the saving process is finished successfully.
127             * 
128             * @param el The created or modified ontology element.
129             */
130            protected void finished(OntologyElement el) {
131                    finished(el, 0);
132            }
133            
134            /**
135             * This method should be called when the saving process is finished successfully.
136             * 
137             * @param el The created or modified ontology element.
138             * @param wordNumber The word form id.
139             */
140            protected void finished(OntologyElement el, int wordNumber) {
141                    window.setVisible(false);
142                    dispose();
143                    
144                    // a text element is used to store the ontology element and the word number in one object:
145                    OntologyTextElement te = TextElemFactory.createTextElement(el, wordNumber);
146                    actionListener.actionPerformed(new ActionEvent(te, ""));
147            }
148            
149            /**
150             * Adds a new row to the form.
151             * 
152             * @param labelText The text for the label shown on the left hand side of the component.
153             * @param component The component, i.e. a text field.
154             * @param explanation An explanation text shown under the component.
155             * @param required Defines whether the component should be marked as required.
156             */
157            protected void addRow(String labelText, Component component, String explanation, boolean required) {
158                    Grid grid = new Grid(3);
159                    grid.setInsets(new Insets(0, 0, 5, 0));
160                    grid.setColumnWidth(0, new Extent(120));
161                    grid.add(new SolidLabel(labelText, Font.ITALIC));
162                    if (component instanceof TextField) {
163                            ((TextField) component).setWidth(new Extent(550));
164                    }
165                    grid.add(component);
166                    if (required) {
167                            grid.add(new Label("*", Font.ITALIC, 11));
168                    } else {
169                            grid.add(new Label());
170                    }
171                    grid.add(new Label());
172                    grid.add(new Label(explanation, Font.ITALIC, 11));
173                    column.add(grid);
174            }
175            
176            /**
177             * Sets the icon row. The icon row is shown at the top of the form and shows an icon of the
178             * ontological structure that is represented by the word. On the right hand side of the icon,
179             * an explanatory text is shown.
180             * 
181             * @param iconName The name of the icon, one of "individual", "concept", or "role".
182             * @param text The explanatory text.
183             */
184            protected void setIconRow(String iconName, String text) {
185                    iconRow.removeAll();
186                    iconRow.add(new Label(new ResourceImageReference("ch/uzh/ifi/attempto/acewiki/gui/img/" + iconName + ".png")));
187                    iconRow.add(new Label(text, Font.ITALIC));
188            }
189            
190            /**
191             * Shows an error message.
192             * 
193             * @param text The error text.
194             */
195            protected void showErrorMessage(String text) {
196                    wiki.showWindow(new MessageWindow("Error", text, window, "OK"));
197            }
198            
199            public void actionPerformed(ActionEvent e) {
200                    if (e.getSource() == okButton) {
201                            save();
202                    } else if (e.getSource() == cancelButton) {
203                            window.setVisible(false);
204                            dispose();
205                    }
206            }
207            
208            /**
209             * Normalizes the string. All white spaces are replaced by underscores. Afterwards, leading and
210             * trailing underscores are removed and successive underscores are replaced by just one underscore.
211             * 
212             * @param s The string to be normalized.
213             * @return The normalized string.
214             */
215            protected static String normalize(String s) {
216                    return s.replaceAll("\\s", "_").replaceAll("(_)+", "_").replaceAll("^_", "").replaceAll("_$", "");
217            }
218            
219            /**
220             * Returns true if the string is a valid to be used as a word form. The first character must be
221             * one of a-z, A-Z. The following characters have to be one of a-z, A-Z, 0-9, -, _.
222             * 
223             * @param s The string to be checked for validity.
224             * @return true if the string is valid.
225             */
226            protected static boolean isValidString(String s) {
227                    if (s.length() == 0) return true;
228                    boolean first = true;
229                    for (byte b : s.getBytes()) {
230                            if (first) {
231                                    first = false;
232                                    if (b >= 'a' && b <= 'z') continue;
233                                    if (b >= 'A' && b <= 'Z') continue;
234                                    return false;
235                            } else {
236                                    if (b >= 'a' && b <= 'z') continue;
237                                    if (b >= 'A' && b <= 'Z') continue;
238                                    if (b >= '0' && b <= '9') continue;
239                                    if (b == '-') continue;
240                                    if (b == '_') continue;
241                                    return false;
242                            }
243                    }
244                    return true;
245            }
246    
247    }