View Javadoc

1   /*
2    * Copyright (c) 2003, Andreas Pataki 
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions are
7    * met:
8    *
9    * Redistributions of source code must retain the above copyright notice,
10   * this list of conditions and the following disclaimer.
11   * 
12   * Redistributions in binary form must reproduce the above copyright notice,
13   * this list of conditions and the following disclaimer in the documentation
14   * and/or other materials provided with the distribution.
15   * 
16   * Neither the name of the author nor the names of its contributors
17   * may be used to endorse or promote products derived from this software
18   * without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS
21   * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   */
32  
33  package net.sf.tm.plugin.ui;
34  
35  import java.io.IOException;
36  import java.util.ArrayList;
37  import java.util.Arrays;
38  import java.util.List;
39  
40  import net.sf.tm.plugin.ContextManagerPlugin;
41  import net.sf.tm.plugin.Logger;
42  import net.sf.tm.tomcat.TomcatServer;
43  
44  import org.apache.commons.lang.StringUtils;
45  import org.eclipse.jface.dialogs.DialogSettings;
46  import org.eclipse.jface.dialogs.IDialogConstants;
47  import org.eclipse.jface.dialogs.IDialogSettings;
48  import org.eclipse.jface.dialogs.TitleAreaDialog;
49  import org.eclipse.swt.SWT;
50  import org.eclipse.swt.events.ModifyEvent;
51  import org.eclipse.swt.events.ModifyListener;
52  import org.eclipse.swt.layout.GridData;
53  import org.eclipse.swt.layout.GridLayout;
54  import org.eclipse.swt.widgets.Button;
55  import org.eclipse.swt.widgets.Combo;
56  import org.eclipse.swt.widgets.Composite;
57  import org.eclipse.swt.widgets.Control;
58  import org.eclipse.swt.widgets.Group;
59  import org.eclipse.swt.widgets.Shell;
60  import org.eclipse.swt.widgets.Text;
61  
62  /***
63   * Base class for all server dialogs. Provides the panel with the input
64   * fields needed to edit a server.
65   * 
66   * @author Andreas Pataki
67   * @version $Id: AbstractServerDialog.java,v 1.8 2004/03/28 16:21:35 apataki Exp $
68   */
69  public abstract class AbstractServerDialog extends TitleAreaDialog {
70  
71      /***
72       * Lenght for all editable combo boxes  
73       */
74      private static final int COMBO_HISTORY_LENGTH = 5;
75      /***
76       * History filename
77       */
78      private static final String HISTORY_FILENAME = "dialog-history.xml";
79      /***
80       * History key for host
81       */
82      private static final String HISTORY_HOST = "Server.host";
83      /***
84       * History key for the port
85       */
86      private static final String HISTORY_PORT = "Server.port";
87      /***
88       * History key for the manager
89       */
90      private static final String HISTORY_MANAGER = "Server.manager";
91      /***
92       * History key for the user
93       */
94      private static final String HISTORY_USER = "Server.user";
95  
96      /***
97       * Private instance for the history settings storage
98       */
99      private IDialogSettings historySettings = null;
100 
101     /***
102      * Server instance
103      */
104     private TomcatServer server;
105     /***
106      * Input field for the name
107      */
108     private Text name;
109     /***
110      * Input field for the host
111      */
112     private Combo host;
113     /***
114      * Input field for the port. Port is an Integer.
115      */
116     private Combo port;
117     /***
118      * Input field for the manager
119      */
120     private Combo managerContext;
121     /***
122      * Input field for the user
123      */
124     private Combo user;
125     /***
126      * Input field for the password
127      */
128     private Text password;
129 
130     /***
131      * @param parentShell shell
132      * @param server The server which should be edited.
133      */
134     public AbstractServerDialog(TomcatServer server, Shell parentShell) {
135         super(parentShell);
136         this.server = server;
137     }
138 
139     /***
140      * @return The edited server data.
141      */
142     public TomcatServer getServer() {
143         return this.server;
144     }
145 
146     /***
147      * @see org.eclipse.jface.dialogs.TitleAreaDialog#createDialogArea(org.eclipse.swt.widgets.Composite)
148      */
149     protected Control createDialogArea(Composite parent) {
150         Composite composite = (Composite) super.createDialogArea(parent);
151 
152         setDialogText();
153 
154         createAndLayoutFields(composite);
155         initializeValues();
156         registerActions();
157 
158         return composite;
159     }
160 
161     /***
162      * This method must be overwritten by the impementing server dialog to 
163      * set the text which should be displayed in the text area of the dialog.
164      */
165     public abstract void setDialogText();
166 
167     /***
168      * @see org.eclipse.jface.dialogs.Dialog#createButtonBar(org.eclipse.swt.widgets.Composite)
169      */
170     protected Control createButtonBar(Composite parent) {
171         Control control = super.createButtonBar(parent);
172         updateStatus();
173         return control;
174     }
175 
176     /***
177      * Registers a modify listener.
178      */
179     private void registerActions() {
180 
181         // create a new modify listener which update the
182         // status on field changes
183         ModifyListener listener = new ModifyListener() {
184 
185             public void modifyText(ModifyEvent event) {
186                 updateStatus();
187             }
188 
189         };
190 
191         // register listener to fields
192         name.addModifyListener(listener);
193         host.addModifyListener(listener);
194         port.addModifyListener(listener);
195         managerContext.addModifyListener(listener);
196         user.addModifyListener(listener);
197         password.addModifyListener(listener);
198 
199     }
200 
201     /***
202      * @see org.eclipse.jface.dialogs.Dialog#okPressed()
203      */
204     protected void okPressed() {
205 
206         // set changed server data
207         server.setName(name.getText());
208         server.setHost(host.getText());
209         server.setPort(Integer.parseInt(port.getText()));
210         server.setManager(managerContext.getText());
211         server.setUser(user.getText());
212         server.setPassword(password.getText());
213 
214         saveWidgetValues();
215 
216         super.okPressed();
217     }
218 
219     /***
220      * Makes some validations and displays an error message if the input 
221      * was wrong. If everything is OK the OK button gets enabled.
222      */
223     private void updateStatus() {
224         boolean complete = false;
225 
226         if (StringUtils.isNotEmpty(port.getText()) && !validatePort()) {
227             // port has wrong format
228             setErrorMessage(localizeString("dialog.server.error.portFormat"));
229 
230         } else if (
231             // manager context has wrong format
232         StringUtils.isNotEmpty(
233             managerContext.getText())
234                 && !validateManagerContext()) {
235 
236             setErrorMessage(
237                 localizeString("dialog.server.error.managerContext"));
238 
239         } else { // no validation errors, clear error
240             setErrorMessage(null);
241 
242             if (checkMandatory()) {
243                 // everything seems OK
244                 complete = true;
245             }
246         }
247 
248         Button okButton = getButton(IDialogConstants.OK_ID);
249 
250         if (okButton != null) {
251             okButton.setEnabled(complete);
252         }
253     }
254 
255     /***
256      * Checks if all mandatory fields are filled
257      * @return true if all are filled
258      */
259     private boolean checkMandatory() {
260         return StringUtils.isNotEmpty(name.getText())
261             && StringUtils.isNotEmpty(host.getText())
262             && StringUtils.isNotEmpty(port.getText())
263             && StringUtils.isNotEmpty(managerContext.getText())
264             && StringUtils.isNotEmpty(user.getText())
265             && StringUtils.isNotEmpty(password.getText());
266     }
267 
268     /***
269      * Validates the server port. The port must be an integer value.
270      * 
271      * @return true if valid.
272      */
273     private boolean validatePort() {
274         return StringUtils.isNumeric(port.getText());
275     }
276 
277     /***
278      * Validates the manager entry of the server. A valid entry must start
279      * with a /
280      * 
281      * @return true if valid.
282      */
283     private boolean validateManagerContext() {
284         return (managerContext.getText().startsWith("/"));
285     }
286 
287     /***
288      * Creates all fields and labels and layout them on the panel.
289      * 
290      * @param composite the parent 
291      */
292     private void createAndLayoutFields(Composite parent) {
293         WidgetFactory factory = new WidgetFactory();
294 
295         GridLayout layout = new GridLayout();
296         layout.marginHeight =
297             convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
298         layout.marginWidth =
299             convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
300         layout.verticalSpacing =
301             convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
302         layout.horizontalSpacing =
303             convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
304         layout.numColumns = 2;
305 
306         Composite contents = new Composite(parent, SWT.NONE);
307         contents.setLayout(layout);
308         contents.setLayoutData(new GridData(GridData.FILL_BOTH));
309         contents.setFont(parent.getFont());
310 
311         factory.createLabel(
312             contents,
313             localizeString("dialog.server.label.name"));
314         name = factory.createTextField(contents);
315         name.setText(createStringForSetText(server.getName()));
316 
317         // create group for server informations
318         Group g =
319             factory.createGroup(
320                 contents,
321                 localizeString("dialog.server.group.server"));
322 
323         // host 
324         factory.createLabel(g, localizeString("dialog.server.label.host"));
325         host = factory.createEditableCombo(g);
326         host.setText(createStringForSetText(server.getHost()));
327 
328         // port
329         factory.createLabel(g, localizeString("dialog.server.label.port"));
330         port = factory.createEditableCombo(g);
331         port.setTextLimit(10);
332         port.setText(createStringForSetText(String.valueOf(server.getPort())));
333 
334         // manager
335         factory.createLabel(g, localizeString("dialog.server.label.manager"));
336         managerContext = factory.createEditableCombo(g);
337         managerContext.setText(createStringForSetText(server.getManager()));
338 
339         // group for authentication informations
340         g =
341             factory.createGroup(
342                 contents,
343                 localizeString("dialog.server.group.authentication"));
344 
345         // user
346         factory.createLabel(g, localizeString("dialog.server.label.user"));
347         user = factory.createEditableCombo(g);
348         user.setText(createStringForSetText(server.getUser()));
349 
350         // password
351         factory.createLabel(g, localizeString("dialog.server.label.password"));
352         password = factory.createTextField(g);
353         password.setText(createStringForSetText(server.getPassword()));
354         password.setEchoChar('*');
355 
356     }
357 
358     /***
359      * Adds an entry to a history, while taking care of duplicate history items
360      * and excessively long histories.  The assumption is made that all histories
361      * should be of length <code>COMBO_HISTORY_LENGTH</code>.
362      *
363      * @param history the current history
364      * @param newEntry the entry to add to the history
365      * @return the history with the new entry appended
366      */
367     protected String[] addToHistory(String[] history, String newEntry) {
368         ArrayList l = new ArrayList(Arrays.asList(history));
369         addToHistory(l, newEntry);
370         String[] r = new String[l.size()];
371         l.toArray(r);
372         return r;
373     }
374 
375     /***
376      * Adds an entry to a history, while taking care of duplicate history items
377      * and excessively long histories.  The assumption is made that all histories
378      * should be of length <code>COMBO_HISTORY_LENGTH</code>.
379      *
380      * @param history the current history
381      * @param newEntry the entry to add to the history
382      */
383     protected void addToHistory(List history, String newEntry) {
384         history.remove(newEntry);
385         history.add(0, newEntry);
386 
387         // since only one new item was added, we can be over the limit
388         // by at most one item
389         if (history.size() > COMBO_HISTORY_LENGTH) {
390             history.remove(COMBO_HISTORY_LENGTH);
391         }
392     }
393 
394     /***
395      * Saves the widget values
396      */
397     private void saveWidgetValues() {
398         // Update history
399         IDialogSettings settings = getDialogSettings();
400         if (settings != null) {
401             saveWidgetValues(settings, HISTORY_HOST, host);
402             saveWidgetValues(settings, HISTORY_PORT, port);
403             saveWidgetValues(settings, HISTORY_MANAGER, managerContext);
404             saveWidgetValues(settings, HISTORY_USER, user);
405 
406             // save
407             try {
408                 settings.save(
409                     ContextManagerPlugin
410                         .getDefault()
411                         .getStateLocation()
412                         .append(HISTORY_FILENAME)
413                         .toString());
414             } catch (IOException e) {
415                 Logger.error("error saving " + HISTORY_FILENAME, e);
416             }
417         }
418 
419     }
420 
421     /***
422      * Method for saving the history combo values of a single combo field.
423      * 
424      * @param settings the current settings file
425      * @param key the key of the setting section
426      * @param combo the combo field
427      */
428     private void saveWidgetValues(
429         IDialogSettings settings,
430         String key,
431         Combo combo) {
432 
433         String[] locations = settings.getArray(key);
434         if (locations == null) {
435             locations = new String[0];
436         }
437         locations = addToHistory(locations, combo.getText());
438         settings.put(key, locations);
439     }
440 
441     /***
442      * Initializes states of the controls.
443      */
444     private void initializeValues() {
445         IDialogSettings settings = getDialogSettings();
446         if (settings != null) {
447             initializeValues(settings, HISTORY_HOST, host);
448             initializeValues(settings, HISTORY_PORT, port);
449             initializeValues(settings, HISTORY_MANAGER, managerContext);
450             initializeValues(settings, HISTORY_USER, user);
451         }
452     }
453 
454     /***
455      * Method for setting the history combo values of a single combo field.
456      *  
457      * @param settings the current settings file
458      * @param key the key of the setting section
459      * @param combo the combo field
460      */
461     private void initializeValues(
462         IDialogSettings settings,
463         String key,
464         Combo combo) {
465 
466         String[] locations = settings.getArray(key);
467         if (locations != null) {
468             for (int i = 0; i < locations.length; i++) {
469                 combo.add(locations[i]);
470             }
471         }
472 
473     }
474 
475     /***
476      * Gets the current dialog history settings. If no one exists a new one
477      * will be created.
478      * 
479      * @return
480      */
481     private IDialogSettings getDialogSettings() {
482         if (historySettings == null) {
483             historySettings = new DialogSettings("history");
484             try {
485                 historySettings.load(
486                     ContextManagerPlugin
487                         .getDefault()
488                         .getStateLocation()
489                         .append(HISTORY_FILENAME)
490                         .toString());
491             } catch (IOException e) {
492                 Logger.error("error loading " + HISTORY_FILENAME, e);
493             }
494         }
495         return historySettings;
496     }
497 
498     //---------------- helper methods
499 
500     /***
501      * Helper method for calling the 
502      * {@link ContextManagerPlugin#getLocalizedString(String)} method
503      * in the {@link ContextManagerPlugin} class.
504      */
505     protected String localizeString(String key) {
506         return ContextManagerPlugin.getDefault().getLocalizedString(key);
507     }
508 
509     /***
510      * @param original text
511      * @return A String. If the input was null an emtpy String is returned. 
512      */
513     private String createStringForSetText(String original) {
514         return (original != null) ? original : "";
515     }
516 
517 }