001: package com.salmonllc.forms;
002:
003: /////////////////////////
004: //$Archive: /SOFIA/SourceCode/com/salmonllc/forms/ListInlineEditingForm.java $
005: //$Author: Srufle $
006: //$Revision: 17 $
007: //$Modtime: 4/15/03 2:24p $
008: /////////////////////////
009:
010: import java.util.Enumeration;
011: import java.util.Vector;
012:
013: import com.salmonllc.html.*;
014: import com.salmonllc.html.events.*;
015: import com.salmonllc.properties.Props;
016: import com.salmonllc.sql.DataStore;
017: import com.salmonllc.sql.DataStoreBuffer;
018: import com.salmonllc.util.MessageLog;
019: import com.salmonllc.util.Util;
020:
021: /**
022: * This class is used for making a list form that you can add, delete ,edit
023: * and save values directly in the listing datatable
024: */
025: public class ListInlineEditingForm extends BaseListForm implements
026: ValueChangedListener {
027: /** Constant definitions for flags parameter in constructor */
028: /** constructor flags parameter: Do not create the default Save button. */
029: public static final int INIT_NO_SAVE_BUTTON = 1 << 2;
030: /** constructor flags parameter: Do not create the default Delete button. */
031: public static final int INIT_NO_DELETE_BUTTON = 1 << 3;
032:
033: /** addColumn flags parameter: Make the field an edit field */
034: public static final int MAKE_EDIT = 1 << 9;
035: /** addColumn flags parameter: Field is required. */
036: public static final int IS_REQUIRED = 1 << 10;
037: //
038: public static final int ERROR_ANY = 99;
039: /** Other */
040: protected HtmlComponent _btnSave = null;
041: protected HtmlComponent _btnDelete = null;
042: /** delete bucket */
043: public static final String _bktDelete = "_bktDelete";
044: protected String _mode;
045: private boolean _initVerifyDone = false;
046: private DataStore _dsVerify;
047:
048: /**
049: * Information on components in form is stored in a vector of objects of type
050: * FormComponent.
051: */
052: private Vector _formComponents = new Vector();
053:
054: /**
055: * Implements standard Search/List form.
056: * Default data store is created. Standard add button is included.
057: * @param page Page containing this form as a component.
058: */
059: public ListInlineEditingForm(HtmlPage page) {
060: this (page, null, 0);
061: }
062:
063: /**
064: * Implements standard Search/List form.
065: * Standard add button is included.
066: * @param page HtmlPage Page containing this form as a component.
067: * @param ds DataStore Data store object to use; if null then create one.
068: */
069: public ListInlineEditingForm(HtmlPage page, DataStore ds) {
070: this (page, ds, 0);
071: }
072:
073: /**
074: * Implements standard Search/List form.
075: * @param page HtmlPage Page containing this form as a component.
076: * @param ds DataStore Data store object to use; if null then create one.
077: * @param flags Bitwise-OR combination of INIT_NO_SAVE_BUTTON, etc.
078: */
079: public ListInlineEditingForm(HtmlPage page, DataStore ds, int flags) {
080: super (page, ds, flags);
081: _mode = "edit";
082: /** Add Save button to List display box */
083: if ((flags & INIT_NO_SAVE_BUTTON) == 0) {
084: HtmlSubmitButton b = new HtmlSubmitButton("btnSave",
085: "Save", page);
086: _boxList.addHeadingComponent(b);
087: b.addSubmitListener(this );
088: _btnSave = b;
089: }
090: if ((flags & INIT_NO_DELETE_BUTTON) == 0) {
091: HtmlSubmitButton b = new HtmlSubmitButton("btnDelete",
092: "Delete", page);
093: _boxList.addHeadingComponent(b);
094: b.addSubmitListener(this );
095: _btnDelete = b;
096: }
097:
098: /** Initialize datastore to use for primary-key verification */
099: _dsVerify = new DataStore(page.getApplicationName());
100:
101: /** As a favor to client classes, add page as listener if appropriate */
102: if (page instanceof ListInLineEditingFormListener)
103: addListener((ListInLineEditingFormListener) page);
104: }
105:
106: /**
107: * Creates a datastore bucket and corresponding display components for the search and list
108: * boxes.
109: * @param name Name of bucket
110: * @param caption Caption for search box and/or list box, or null
111: * @param type Type of datastore column, using DataStore.DATATYPE_* values
112: * @param flags Bitwise-OR combination of PRIMARY_KEY, etc. 0 = default.
113: */
114: public void addBucket(String name, String caption, int type,
115: int flags) throws Exception {
116: addBucket(name, caption, type, flags, null, null);
117: }
118:
119: /**
120: * Creates a datastore bucket and corresponding display components for the search and list
121: * boxes.
122: * @param name Name of bucket
123: * @param caption Caption for search box and/or list box, or null
124: * @param type Type of datastore column, using DataStore.DATATYPE_* values
125: * @param flags Bitwise-OR combination of PRIMARY_KEY, etc. 0 = default.
126: * @param href HREF to use in hotlink from this column in list box, else null.
127: * @param format Format used to display column in listbox (as in DataStore), else null.
128: */
129: public void addBucket(String name, String caption, int type,
130: int flags, String href, String format) throws Exception {
131: addBucket(name, caption, type, flags, href, format, null, null,
132: null);
133: }
134:
135: /**
136: * Creates a datastore bucket and corresponding display components for the search and list
137: * boxes.
138: * @param name Name of bucket
139: * @param caption Caption for search box and/or list box, or null
140: * @param type Type of datastore column, using DataStore.DATATYPE_* values
141: * @param flags Bitwise-OR combination of PRIMARY_KEY, etc. 0 = default.
142: * @param href HREF to use in hotlink from this column in list box, else null.
143: * @param format Format used to display column in listbox (as in DataStore), else null.
144: * @param propCaption HtmlTableCellProperties
145: * @param propSearch HtmlTableCellProperties
146: * @param propList HtmlTableCellProperties
147: */
148: public void addBucket(String name, String caption, int type,
149: int flags, String href, String format,
150: HtmlTableCellProperties propCaption,
151: HtmlTableCellProperties propSearch,
152: HtmlTableCellProperties propList) throws Exception {
153: if (_ds.getColumnIndex(name) == -1)
154: _ds.addBucket(name, type);
155: if ((flags & LIST_ONLY) == 0)
156: addSearchDisplay(name, caption, makeComponent(name, type),
157: flags | NO_SEARCH, propCaption, propSearch);
158: if ((flags & SEARCH_ONLY) == 0) {
159: HtmlLink hl = null;
160: HtmlPage page = getPage();
161: HtmlText ht = null;
162: HtmlTextEdit hte = null;
163: if (format == null) {
164: /** For certain data types, set format according to page properties. */
165: Props props = getPage().getPageProperties();
166: switch (type) {
167: case DataStore.DATATYPE_DATETIME:
168: format = props.getProperty(Props.DATETIME_FORMAT);
169: break;
170: case DataStore.DATATYPE_DATE:
171: format = props.getProperty(Props.DATE_FORMAT);
172: break;
173: case DataStore.DATATYPE_TIME:
174: format = props.getProperty(Props.TIME_FORMAT);
175: break;
176: }
177: }
178: if ((flags & MAKE_EDIT) != 0) {
179: hte = (HtmlTextEdit) makeComponent(name, type);
180: hte.setColumn(_ds, name);
181:
182: addListDisplay(name, caption, hte, propList);
183: addFormComponent(caption, hte, flags);
184: } else {
185: /** create a text comp */
186: ht = new HtmlText(name, page);
187:
188: /** check the format */
189: if (format != null) {
190: ht.setExpression(_ds, name, format);
191: } else {
192: ht.setExpression(_ds, name);
193: }
194:
195: /** add text comp to a link container if applicable */
196: if (Util.isFilled(href)) {
197: hl = new HtmlLink("lnk" + name, "", page);
198: hl.setHrefExpression(_ds, href);
199: hl.add(ht);
200: ht.setFont(_linkFont);
201: addListDisplay(name, caption, hl, propList);
202: } else {
203: addListDisplay(name, caption, ht, propList);
204: }
205: }
206: }
207: }
208:
209: /**
210: * Creates a datastore column and corresponding display components for the search and list
211: * boxes.
212: * @param table Name of table for datastore
213: * @param column Name of column for datastore
214: * @param caption Caption for search box and/or list box, or null
215: * @param type Type of datastore column, using DataStore.DATATYPE_* values
216: * @param flags Bitwise-OR combination of PRIMARY_KEY, etc. 0 = default.
217: */
218: public void addColumn(String table, String column, String caption,
219: int type, int flags) throws Exception {
220: addColumn(table, column, caption, type, flags, null);
221: }
222:
223: /**
224: * Creates a datastore column and corresponding display components for the search and list
225: * boxes.
226: * @param table Name of table for datastore
227: * @param column Name of column for datastore
228: * @param caption Caption for search box and/or list box, or null
229: * @param type Type of datastore column, using DataStore.DATATYPE_* values
230: * @param flags Bitwise-OR combination of PRIMARY_KEY, etc. 0 = default.
231: * @param href HREF to use in hotlink from this column in list box, else null.
232: */
233: public void addColumn(String table, String column, String caption,
234: int type, int flags, String href) throws Exception {
235: addColumn(table, column, caption, type, flags, href, null);
236: }
237:
238: /**
239: * Creates a datastore column and corresponding display components for the search and list
240: * boxes.
241: * @param table Name of table for datastore
242: * @param column Name of column for datastore
243: * @param caption Caption for search box and/or list box, or null
244: * @param type Type of datastore column, using DataStore.DATATYPE_* values
245: * @param flags Bitwise-OR combination of PRIMARY_KEY, etc. 0 = default.
246: * @param href HREF to use in hotlink from this column in list box, else null.
247: * @param format Format used to display column in listbox (as in DataStore), else null.
248: */
249: public void addColumn(String table, String column, String caption,
250: int type, int flags, String href, String format)
251: throws Exception {
252: addColumn(table, column, caption, type, flags, href, format,
253: null, null, null);
254: }
255:
256: /**
257: * Creates a datastore column and corresponding display components for the search and list
258: * boxes.
259: * @param table Name of table for datastore
260: * @param column Name of column for datastore
261: * @param caption Caption for search box and/or list box, or null
262: * @param type Type of datastore column, using DataStore.DATATYPE_* values
263: * @param flags Bitwise-OR combination of PRIMARY_KEY, etc. 0 = default.
264: * @param href HREF to use in hotlink from this column in list box, else null.
265: * @param format Format used to display column in listbox (as in DataStore), else null.
266: * @param propCaption HtmlTableCellProperties
267: * @param propSearch HtmlTableCellProperties
268: * @param propList HtmlTableCellProperties
269: */
270: public void addColumn(String table, String column, String caption,
271: int type, int flags, String href, String format,
272: HtmlTableCellProperties propCaption,
273: HtmlTableCellProperties propSearch,
274: HtmlTableCellProperties propList) throws Exception {
275: if (table == null) {
276: table = NULL_TABLE;
277: }
278: String fullColName = table + "." + column;
279:
280: /** `Don't add the same column twice to the data store. */
281: if (_ds.getColumnIndex(table + "." + column) == -1) {
282: /** changed to make all columns editable */
283: if ((flags & PRIMARY_KEY) != 0) {
284: _ds.addColumn(table, column, type, true, true);
285: } else {
286: _ds.addColumn(table, column, type, false, true);
287: }
288: }
289:
290: if ((flags & LIST_ONLY) == 0) {
291: addSearchDisplay(fullColName, caption, makeComponent(table
292: + "_" + column, type), flags, propCaption,
293: propSearch);
294: }
295: if ((flags & SEARCH_ONLY) == 0) {
296: HtmlLink hl = null;
297: HtmlPage page = getPage();
298: HtmlText ht = null;
299: HtmlTextEdit hte = null;
300: if (format == null) {
301: /** For certain data types, set format according to page properties. */
302: Props props = getPage().getPageProperties();
303: switch (type) {
304: case DataStore.DATATYPE_DATETIME:
305: format = props.getProperty(Props.DATETIME_FORMAT);
306: break;
307: case DataStore.DATATYPE_DATE:
308: format = props.getProperty(Props.DATE_FORMAT);
309: break;
310: case DataStore.DATATYPE_TIME:
311: format = props.getProperty(Props.TIME_FORMAT);
312: break;
313: }
314: }
315: if ((flags & MAKE_EDIT) != 0) {
316: hte = (HtmlTextEdit) makeComponent(
317: table + "_" + column, type);
318: hte.setColumn(_ds, fullColName);
319:
320: /** when you add a list display you will also have to call addFormComponent(caption, hte, flags); */
321: addListDisplay(fullColName, caption, hte, propList);
322: addFormComponent(caption, hte, flags);
323: } else {
324: /** create a text comp */
325: ht = new HtmlText(table + "_" + column, page);
326:
327: /** check the format */
328: if (format != null) {
329: ht.setExpression(_ds, fullColName, format);
330: } else {
331: ht.setExpression(_ds, fullColName);
332: }
333:
334: /** add text comp to a link container if applicable */
335: if (Util.isFilled(href)) {
336: hl = new HtmlLink("lnk" + column, "", page);
337: hl.setHrefExpression(_ds, href);
338: hl.add(ht);
339: ht.setFont(_linkFont);
340: addListDisplay(fullColName, caption, hl, propList);
341: } else {
342: addListDisplay(fullColName, caption, ht, propList);
343: }
344: }
345: }
346: }
347:
348: /**
349: * Adds a check box to each row so you can delete each checked row when you press the delete button.
350: */
351: public void addDeleteCheckBox() {
352: try {
353: if (_ds.getColumnIndex(_bktDelete) == -1) {
354: _ds.addBucket(_bktDelete, DataStore.DATATYPE_STRING);
355: }
356: /** create a check box */
357: HtmlCheckBox chkDelete = new HtmlCheckBox("chkDelete",
358: getPage(), "1", "0");
359: chkDelete.setColumn(_ds, _bktDelete);
360:
361: /** we may want to pass in an alignment prop */
362: addListDisplay(_bktDelete, "Delete", chkDelete, null);
363: } catch (Exception e) {
364: MessageLog.writeErrorMessage("addDeleteCheckBox", e, this );
365: }
366: }
367:
368: /**
369: * Adds a custom component to the List portion of the form.
370: * @param caption java.lang.String
371: * @param component com.salmonllc.html.HtmlComponent
372: * @param flags int
373: */
374: protected void addFormComponent(String caption,
375: HtmlComponent component, int flags) {
376:
377: HtmlText captionTextComp = new HtmlText(caption, getPage());
378: _formComponents.addElement(new FormComponent(captionTextComp,
379: component, flags));
380: addValueChangedListener(component);
381: }
382:
383: /**
384: * Adds a ListInLineEditingFormListener.
385: * @param listener ListInLineEditingFormListener
386: */
387: public void addListener(ListInLineEditingFormListener listener) {
388: /** Prevent listener from being added twice */
389: int listenersSize = _listeners.size();
390: for (int i = 0; i < listenersSize; i++)
391: if (((ListInLineEditingFormListener) _listeners
392: .elementAt(i)) == listener)
393: return;
394: _listeners.addElement(listener);
395: }
396:
397: /**
398: * Recursively adds ValueChangedListener.
399: * @param c com.salmonllc.html.HtmlComponent
400: */
401: protected void addValueChangedListener(HtmlComponent c) {
402: if (c instanceof HtmlFormComponent) {
403: ((HtmlFormComponent) c).addValueChangedListener(this );
404: } else {
405: if (c instanceof HtmlContainer) {
406: Enumeration e = ((HtmlContainer) c).getComponents();
407: while (e.hasMoreElements()) {
408: addValueChangedListener((HtmlComponent) e
409: .nextElement());
410: }
411: }
412: }
413: }
414:
415: /**
416: * Finds a component in the List Form Components
417: * @return HtmlComponent
418: * @param component HtmlComponent
419: */
420: protected HtmlComponent findFormComponent(HtmlComponent component) {
421: int rowCompSize = _tblList.getRowComponentsSize();
422: HtmlComponent comp = null;
423: for (int i = 0; i < rowCompSize; i++) {
424: comp = (HtmlComponent) _tblList.getRowComponentAt(i);
425: if ((comp == component)
426: || ((comp instanceof HtmlContainer && hasComponent(
427: (HtmlContainer) comp, component))))
428: return comp;
429: }
430: return null;
431: }
432:
433: /**
434: * Recursively determins whether a container contains a component.
435: * @return boolean
436: * @param cont com.salmonllc.html.HtmlContainer
437: * @param component com.salmonllc.html.HtmlComponent
438: */
439: protected boolean hasComponent(HtmlContainer cont,
440: HtmlComponent component) {
441: Enumeration e = cont.getComponents();
442: HtmlComponent c = null;
443: while (e.hasMoreElements()) {
444: c = (HtmlComponent) e.nextElement();
445: if (c == component)
446: return true;
447: else if (c instanceof HtmlContainer) {
448: if (hasComponent((HtmlContainer) c, component))
449: return true;
450: }
451: }
452: return false;
453: }
454:
455: /**
456: * Process a user error condition.
457: * @param code int
458: * @param caption java.lang.String
459: * @param component com.salmonllc.html.HtmlComponent
460: * @param row int
461: * @return boolean If true, continue event processing.
462: */
463: protected boolean processError(int code, String caption,
464: HtmlComponent component, int row) {
465: int listenersSize = _listeners.size();
466: if (listenersSize == 0)
467: return true;
468: String text = null;
469: switch (code) {
470: case DetailFormListener.ERROR_DUPLICATE_ROW:
471: text = "Row in database already exists with same primary key on row "
472: + (row + 1);
473: break;
474: case DetailFormListener.ERROR_EMPTY_FIELD:
475: if ((component instanceof HtmlDropDownList)
476: || (component instanceof HtmlRadioButtonGroup))
477: text = "Please select a value on row " + (row + 1);
478: else
479: text = "Please enter a value on row " + (row + 1);
480: break;
481: case DetailFormListener.ERROR_INVALID_ENTRY:
482: text = "Please enter a valid value on row " + (row + 1);
483: break;
484: }
485: if (text == null)
486: text = caption;
487: else if (caption != null)
488: text += " for " + caption;
489: if (text != null)
490: text += ".";
491: for (int i = 0; i < listenersSize; i++)
492: if (!((ListInLineEditingFormListener) _listeners
493: .elementAt(i)).onListError(code, text, component,
494: row))
495: return false;
496: return true;
497: }
498:
499: /**
500: * Replaces default delete button (if any) with a submit image
501: * @param img - HtmlSubmitImage to use for the delete button.
502: */
503: public void setDeleteImage(HtmlSubmitImage img) {
504: /** Delete Button */
505: if (_btnDelete != null) {
506: _boxList.removeHeadingComponent(_btnDelete);
507: }
508: img.addSubmitListener(this );
509: _boxList.addHeadingComponent(_btnDelete = img);
510: }
511:
512: /**
513: * Replaces default delete button (if any) with an image button
514: * @param imageUrl URL of image.
515: */
516: public void setDeleteImage(String imageUrl) {
517: /** Delete Button */
518: if (_btnDelete != null) {
519: _boxList.removeHeadingComponent(_btnDelete);
520: }
521: HtmlSubmitImage i = new HtmlSubmitImage("btnDelete", imageUrl,
522: getPage());
523: i.addSubmitListener(this );
524: _boxList.addHeadingComponent(_btnDelete = i);
525: }
526:
527: /**
528: * Replaces default save button (if any) with a submit image
529: * @param img - SumbitImage to use for the save button.
530: */
531: public void setSaveImage(HtmlSubmitImage img) {
532: /** Save Button */
533: if (_btnSave != null) {
534: _boxList.removeHeadingComponent(_btnSave);
535: }
536: img.addSubmitListener(this );
537: _boxList.addHeadingComponent(_btnSave = img);
538: }
539:
540: /**
541: * Replaces default save button (if any) with an image button
542: * @param imageUrl URL of image.
543: */
544: public void setSaveImage(String imageUrl) {
545: /** Save Button */
546: if (_btnSave != null) {
547: _boxList.removeHeadingComponent(_btnSave);
548: }
549: HtmlSubmitImage i = new HtmlSubmitImage("btnSave", imageUrl,
550: getPage());
551: i.addSubmitListener(this );
552: _boxList.addHeadingComponent(_btnSave = i);
553: }
554:
555: /**
556: * Sets the vivibility of the default Delete button.
557: * @param visible boolean
558: */
559: public void showDeleteButton(boolean visible) {
560: _btnDelete.setVisible(visible);
561: }
562:
563: /**
564: * Sets the vivibility of the default Save button.
565: * @param visible boolean
566: */
567: public void showSaveButton(boolean visible) {
568: _btnSave.setVisible(visible);
569: }
570:
571: /**
572: * Inherited abstract method.
573: * @return boolean
574: * @param e com.salmonllc.html.events.SubmitEvent
575: */
576: public boolean submitPerformed(SubmitEvent e) throws Exception {
577: super .submitPerformed(e);
578:
579: MessageLog.writeDebugMessage(" submitPerformed(SubmitEvent e)",
580: this );
581: HtmlComponent c = e.getComponent();
582:
583: int listenersSize = _listeners.size();
584: if (c == _btnAddListForm) {
585: /** do preListAdd */
586:
587: for (int i = 0; i < listenersSize; i++) {
588: if (!((ListFormListener) _listeners.elementAt(i))
589: .preListAdd()) {
590: return false;
591: }
592: }
593: /** add a row to the data store */
594: _ds.insertRow();
595: _mode = "add";
596:
597: /** do postListAdd */
598: for (int i = 0; i < listenersSize; i++) {
599: ((ListFormListener) _listeners.elementAt(i))
600: .postListAdd();
601: }
602: return true;
603: }
604: if (c == _btnDelete) {
605:
606: /** first delete any rows that are flagged */
607: for (int i = 0; i < listenersSize; i++) {
608: if (!((ListInLineEditingFormListener) _listeners
609: .elementAt(i)).preListDelete()) {
610: return false;
611: }
612: }
613: /** you have to go from the bottom up for it to work */
614: int rowCount = _ds.getRowCount() - 1;
615: for (int i = rowCount; i >= 0; i--) {
616: String data = _ds.getString(i, _bktDelete);
617: int status = _ds.getRowStatus(i);
618: /** Delete row if necessary */
619: if (data != null) {
620: if (data.equals("1")) {
621: switch (status) {
622: case DataStore.STATUS_NOT_MODIFIED:
623: case DataStore.STATUS_MODIFIED:
624: if (!_ds.deleteRow(i)) {
625: return false;
626: }
627: break;
628: case DataStore.STATUS_NEW:
629: case DataStore.STATUS_NEW_MODIFIED:
630: _ds.removeRow(i);
631: break;
632: }
633: }
634: }
635: }
636: _ds.update();
637: for (int i = 0; i < listenersSize; i++) {
638: ((ListInLineEditingFormListener) _listeners
639: .elementAt(i)).postListDelete();
640: }
641: doRetrieve();
642: return true;
643: }
644: if (c == _btnSave) {
645:
646: /** Verification passed, go ahead with update */
647: for (int i = 0; i < listenersSize; i++) {
648: if (!((ListInLineEditingFormListener) _listeners
649: .elementAt(i)).preListSave()) {
650: return false;
651: }
652: }
653:
654: /** you have to go from the bottom up for it to work */
655: int rowCount = _ds.getRowCount() - 1;
656: for (int i = rowCount; i >= 0; i--) {
657: int status = _ds.getRowStatus(i);
658: switch (status) {
659: case DataStore.STATUS_NEW_MODIFIED:
660: case DataStore.STATUS_MODIFIED:
661: if (!validateRow(i)) {
662: return false;
663: }
664: }
665: }
666: _ds.update();
667: _mode = "edit";
668: for (int i = 0; i < listenersSize; i++) {
669: ((ListInLineEditingFormListener) _listeners
670: .elementAt(i)).postListSave();
671: }
672: return true;
673: }
674: return true;
675: }
676:
677: /**
678: * Perform validation recursively on a component.
679: * @return boolean
680: * @param comp com.salmonllc.html.HtmlComponent
681: * @param row int
682: */
683: protected boolean validateComponent(HtmlComponent comp, int row) {
684: if (comp instanceof HtmlFormComponent) {
685: HtmlFormComponent hfc = (HtmlFormComponent) comp;
686: if (hfc.getValue() == null) {
687: if (!processError(DetailFormListener.ERROR_EMPTY_FIELD,
688: null, hfc, row))
689: return false;
690: }
691: if (!hfc.isValid()) {
692: if (!processError(
693: DetailFormListener.ERROR_INVALID_ENTRY, null,
694: hfc, row))
695: return false;
696: }
697: } else if (comp instanceof HtmlContainer) {
698: Enumeration e = ((HtmlContainer) comp).getComponents();
699: while (e.hasMoreElements())
700: if (!validateComponent((HtmlComponent) e.nextElement(),
701: row))
702: return false;
703: }
704: return true;
705: }
706:
707: /**
708: * Validates entry fields according to current mode.
709: * @param row int
710: * @return True if validation was successful.
711: */
712: public boolean validateRow(int row) throws Exception {
713: String mode = null;
714: if (_mode == null) {
715: mode = "";
716: } else {
717: mode = _mode;
718: }
719: //
720: if (mode.equals("add")) {
721: /** Verify row with duplicate primary key combination does not exist */
722: CriteriaString cr = new CriteriaString();
723:
724: int colCount = _ds.getColumnCount();
725: String name = null;
726:
727: for (int colIndex = 0; colIndex < colCount; colIndex++) {
728: if (!_ds.isPrimaryKey(colIndex))
729: continue;
730: name = _ds.getColumnName(colIndex);
731: switch (_ds.getColumnDataType(colIndex)) {
732: case DataStore.DATATYPE_STRING:
733: cr.and(name + "='" + _ds.getString(row, colIndex)
734: + "'");
735: break;
736: case DataStore.DATATYPE_INT:
737: cr.and(name + "=" + _ds.getInt(row, colIndex));
738: break;
739: case DataStore.DATATYPE_DOUBLE:
740: cr.and(name + "=" + _ds.getDouble(row, colIndex));
741: break;
742: case DataStore.DATATYPE_DATETIME:
743: cr.and(name + "='" + _ds.getDateTime(row, colIndex)
744: + "'");
745: break;
746: default:
747: throw new FormException("Unknown datatype");
748: }
749: if (!_initVerifyDone) {
750: /** Copy an arbirary column into _dsVerify so we can do a retrieve on it. */
751: int dot = name.indexOf('.');
752: /** Check for table.column form even thought it should always be OK */
753: if (dot != -1) {
754: _dsVerify.addColumn(name.substring(0, dot),
755: name.substring(dot + 1), _ds
756: .getColumnDataType(colIndex),
757: _ds.isPrimaryKey(colIndex), false);
758: _initVerifyDone = true;
759: }
760: }
761: }
762: String s = cr.toString();
763: /**
764: * problem: with multiple rows we have to validate each new row
765: * when this was in detailform there was only one row
766: */
767:
768: if ((s != null) && _initVerifyDone) {
769: _dsVerify.retrieve(s);
770: if (_dsVerify.gotoNext()) {
771: if (!processError(
772: DetailFormListener.ERROR_DUPLICATE_ROW,
773: null, null, row))
774: return false;
775: }
776: }
777: }
778:
779: /** Verify all required fields */
780: if (mode.equals("edit")) {
781:
782: int formComponentsSize = _formComponents.size();
783: FormComponent fc = null;
784: HtmlComponent c = null;
785: for (int i = 0; i < formComponentsSize; i++) {
786: fc = (FormComponent) _formComponents.elementAt(i);
787: if ((fc.getFlags() & IS_REQUIRED) == 0)
788: continue;
789: c = fc.getFormComponent();
790: if ((c != null)
791: && !validateComponent((HtmlComponent) c, row)) {
792: return false;
793: }
794: }
795: }
796: return true;
797: }
798:
799: /**
800: * Tests that data entered in the edit components passes simple validation.
801: * @return boolean
802: * @param e com.salmonllc.html.events.ValueChangedEvent
803: */
804: public boolean valueChanged(ValueChangedEvent e) throws Exception {
805: DataStoreBuffer ds = e.getDataStore();
806: if (ds == null) {
807: return true;
808: }
809: if (!ds.isFormattedStringValid(e.getColumn(), e.getNewValue())) {
810: String msg = "Invalid value entered";
811: HtmlComponent comp = findFormComponent(e.getComponent());
812: if (comp != null)
813: msg += " for column " + (e.getColumn() + 1) + " row "
814: + (e.getRow() + 1);
815: if (!processError(ERROR_ANY, msg, e.getComponent(), e
816: .getRow())) {
817: e
818: .setAcceptValue(ValueChangedEvent.PROCESSING_NOTENTERED);
819: return false;
820: } else {
821: return true;
822: }
823: } else {
824: return true;
825: }
826: }
827: }
|