001: /*
002: * Copyright (c) 2003-2007 JGoodies Karsten Lentzsch. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JGoodies Karsten Lentzsch nor the names of
015: * its contributors may be used to endorse or promote products derived
016: * from this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package com.jgoodies.validation.tutorial.validator;
032:
033: import java.awt.event.ActionEvent;
034: import java.text.DateFormat;
035: import java.util.Date;
036:
037: import javax.swing.*;
038:
039: import com.jgoodies.forms.builder.DefaultFormBuilder;
040: import com.jgoodies.forms.builder.PanelBuilder;
041: import com.jgoodies.forms.factories.ButtonBarFactory;
042: import com.jgoodies.forms.layout.CellConstraints;
043: import com.jgoodies.forms.layout.FormLayout;
044: import com.jgoodies.forms.layout.RowSpec;
045: import com.jgoodies.validation.Validatable;
046: import com.jgoodies.validation.ValidationResult;
047: import com.jgoodies.validation.tutorial.basics.SimpleDomainValidationExample;
048: import com.jgoodies.validation.tutorial.shared.Order;
049: import com.jgoodies.validation.tutorial.util.TutorialUtils;
050: import com.jgoodies.validation.util.ValidationUtils;
051:
052: /**
053: * A view that validates its GUI state. On OK pressed the GUI state is
054: * validated, and a modal dialog shows the errors and warnings - if any.
055: * The domain model will be updated only, if the GUI state has no errors
056: * - though it may have warnings.<p>
057: *
058: * This class exists for learning and demonstration purposes only.
059: * Typically you won't validate the GUI state, but validate
060: * the domain object properties or the presentation model state.
061: * See the {@link SimpleDomainValidationExample} for a similar example
062: * that validates the domain object, not the GUI state.
063: *
064: * @author Karsten Lentzsch
065: * @version $Revision: 1.14 $
066: *
067: * @see SimpleDomainValidationExample
068: */
069: public final class ValidatingOrderEditor implements Validatable {
070:
071: private Order order;
072:
073: private JTextField orderNoField;
074: private JFormattedTextField orderDateField;
075: private JFormattedTextField deliveryDateField;
076: private JTextArea deliveryNotesArea;
077: private JButton okButton;
078: private JButton closeButton;
079:
080: /**
081: * Launches this example: creates a JFrame, adds the built
082: * example panel, packs the frame and finally makes it visible.
083: *
084: * @param args runtime arguments (ignored)
085: */
086: public static void main(String[] args) {
087: try {
088: UIManager
089: .setLookAndFeel("com.jgoodies.looks.plastic.PlasticXPLookAndFeel");
090: } catch (Exception e) {
091: // Likely Plastic is not in the classpath; ignore it.
092: }
093: JFrame frame = new JFrame();
094: frame.setTitle("Validator :: GUI State Validation");
095: frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
096: JComponent panel = new ValidatingOrderEditor().buildPanel();
097: frame.getContentPane().add(panel);
098: frame.pack();
099: TutorialUtils.locateOnOpticalScreenCenter(frame);
100: frame.setVisible(true);
101: }
102:
103: // Instance Creation ******************************************************
104:
105: private void init() {
106: order = new Order();
107: }
108:
109: // Component Creation and Initialization **********************************
110:
111: /**
112: * Creates and initializes the UI components.
113: */
114: protected void initComponents() {
115: orderNoField = new JTextField();
116: DateFormat dateFormat = DateFormat
117: .getDateInstance(DateFormat.SHORT);
118: orderDateField = new JFormattedTextField(dateFormat);
119: deliveryDateField = new JFormattedTextField(dateFormat);
120: deliveryNotesArea = new JTextArea();
121:
122: okButton = new JButton(new OKAction());
123: closeButton = new JButton(TutorialUtils.getCloseAction());
124: }
125:
126: // Building ***************************************************************
127:
128: /**
129: * Builds the whole editor.
130: *
131: * @return the editor panel with a report area at the bottom
132: */
133: public JComponent buildPanel() {
134: init();
135: initComponents();
136: updateView();
137: return buildPanelWithReportInBottom();
138: }
139:
140: /**
141: * Builds the whole editor.
142: *
143: * @return the editor panel with a report area at the bottom
144: */
145: private JComponent buildPanelWithReportInBottom() {
146: FormLayout layout = new FormLayout("fill:default:grow",
147: "pref, 6dlu:grow, pref");
148:
149: PanelBuilder builder = new PanelBuilder(layout);
150: builder.setDefaultDialogBorder();
151:
152: CellConstraints cc = new CellConstraints();
153: builder.add(buildEditorPanel(), cc.xy(1, 1));
154: builder.add(buildButtonBar(), cc.xy(1, 3));
155: return builder.getPanel();
156: }
157:
158: private JComponent buildEditorPanel() {
159: FormLayout layout = new FormLayout(
160: "right:pref, 4dlu, 40dlu, 2dlu, 40dlu, 82dlu:grow");
161:
162: DefaultFormBuilder builder = new DefaultFormBuilder(layout);
163: builder.setRowGroupingEnabled(true);
164:
165: CellConstraints cc = new CellConstraints();
166:
167: builder.appendSeparator("Order");
168: builder.append("Order No", orderNoField, 3);
169: builder.append("Order-/Delivery Date", orderDateField,
170: deliveryDateField);
171: builder.nextLine();
172:
173: builder.append("Notes");
174: builder.appendRow(new RowSpec("17dlu")); // Assumes line is 14, gap is 3
175: builder.add(new JScrollPane(deliveryNotesArea), cc.xywh(builder
176: .getColumn(), builder.getRow(), 4, 2));
177:
178: // Append a small gap at the bottom so the overlay icon is visible
179: builder.nextLine();
180: builder.appendRow(new RowSpec("2px"));
181:
182: return builder.getPanel();
183: }
184:
185: private JComponent buildButtonBar() {
186: return ButtonBarFactory.buildOKCancelBar(okButton, closeButton);
187: }
188:
189: // Synchronizing Model and View *******************************************
190:
191: private void updateView() {
192: orderNoField.setText(getOrder().getOrderNo());
193: orderDateField.setValue(getOrder().getOrderDate());
194: deliveryDateField.setValue(getOrder().getDeliveryDate());
195: deliveryNotesArea.setText(getOrder().getDeliveryNotes());
196: }
197:
198: private void updateModel() {
199: getOrder().setOrderNo(orderNoField.getText());
200: getOrder().setOrderDate((Date) orderDateField.getValue());
201: getOrder().setDeliveryDate((Date) deliveryDateField.getValue());
202: getOrder().setDeliveryNotes(deliveryNotesArea.getText());
203: }
204:
205: private Order getOrder() {
206: return order;
207: }
208:
209: // Validation *************************************************************
210:
211: /**
212: * Validates the order and returns a ValidationResult.
213: *
214: * @return the ValidationResult of the pure order validation
215: */
216: public ValidationResult validate() {
217: ValidationResult result = new ValidationResult();
218:
219: String orderNo = orderNoField.getText();
220: if (ValidationUtils.isBlank(orderNo)) {
221: result.addError("Order No is mandatory");
222: } else if (!ValidationUtils.hasMinimumLength(orderNo, 5)
223: || !ValidationUtils.hasMaximumLength(orderNo, 10)) {
224: result.addError("Order No length must be in [5, 10]");
225: }
226:
227: Date orderDate = (Date) orderDateField.getValue();
228: Date deliveryDate = (Date) deliveryDateField.getValue();
229: if (orderDate == null) {
230: result.addError("Order Date is mandatory");
231: }
232:
233: if (orderDate != null && deliveryDate != null
234: && orderDate.after(deliveryDate)) {
235: result
236: .addWarning("Delivery Date shall be after the order date");
237: }
238:
239: String deliveryNotes = deliveryNotesArea.getText();
240: if (deliveryNotes != null
241: && !ValidationUtils.hasMaximumLength(deliveryNotes, 30)) {
242: result.addWarning("Notes length shall be in [0, 30]");
243: }
244:
245: return result;
246: }
247:
248: // Event Handling *********************************************************
249:
250: /**
251: * Validates the GUI state and updates the model only,
252: * if the GUI state has no errors (it may have warnings).
253: */
254: private final class OKAction extends AbstractAction {
255:
256: OKAction() {
257: super ("OK");
258: }
259:
260: public void actionPerformed(ActionEvent e) {
261: ValidationResult validationResult = validate();
262: if (validationResult.hasErrors()) {
263: TutorialUtils.showValidationMessage(e,
264: "To save the order, fix the following errors:",
265: validationResult);
266: return;
267: }
268: if (validationResult.hasWarnings()) {
269: TutorialUtils.showValidationMessage(e,
270: "Note: some order fields are invalid.",
271: validationResult);
272: }
273: updateModel();
274: System.out.println("Data saved");
275: }
276:
277: }
278:
279: }
|