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