0001: //** Copyright Statement ***************************************************
0002: //The Salmon Open Framework for Internet Applications (SOFIA)
0003: // Copyright (C) 1999 - 2002, Salmon LLC
0004: //
0005: // This program is free software; you can redistribute it and/or
0006: // modify it under the terms of the GNU General Public License version 2
0007: // as published by the Free Software Foundation;
0008: //
0009: // This program is distributed in the hope that it will be useful,
0010: // but WITHOUT ANY WARRANTY; without even the implied warranty of
0011: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0012: // GNU General Public License for more details.
0013: //
0014: // You should have received a copy of the GNU General Public License
0015: // along with this program; if not, write to the Free Software
0016: // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
0017: //
0018: // For more information please visit http://www.salmonllc.com
0019: //** End Copyright Statement ***************************************************
0020: package com.salmonllc.jsp;
0021:
0022: import java.io.IOException;
0023: import java.sql.SQLException;
0024: import java.util.Enumeration;
0025:
0026: import javax.servlet.http.HttpServletRequest;
0027:
0028: import com.salmonllc.html.HtmlCheckBox;
0029: import com.salmonllc.html.HtmlFormComponent;
0030: import com.salmonllc.html.HtmlLink;
0031: import com.salmonllc.html.HtmlPage;
0032: import com.salmonllc.html.HtmlScriptGenerator;
0033: import com.salmonllc.html.HtmlSubmitButton;
0034: import com.salmonllc.html.HtmlText;
0035: import com.salmonllc.html.HtmlValidatorText;
0036: import com.salmonllc.html.events.PageEvent;
0037: import com.salmonllc.html.events.PageListener;
0038: import com.salmonllc.html.events.SubmitEvent;
0039: import com.salmonllc.html.events.SubmitListener;
0040: import com.salmonllc.localizer.LanguagePreferences;
0041: import com.salmonllc.localizer.LanguageResourceFinder;
0042: import com.salmonllc.properties.Props;
0043: import com.salmonllc.sql.BeanDataStore;
0044: import com.salmonllc.sql.DSDataRow;
0045: import com.salmonllc.sql.DataStore;
0046: import com.salmonllc.sql.DataStoreBuffer;
0047: import com.salmonllc.sql.DataStoreEvaluator;
0048: import com.salmonllc.sql.DataStoreException;
0049: import com.salmonllc.sql.DataStoreExpression;
0050: import com.salmonllc.sql.DirtyDataException;
0051: import com.salmonllc.sql.ModelChangedEvent;
0052: import com.salmonllc.sql.ModelChangedListener;
0053: import com.salmonllc.sql.QBEBuilder;
0054: import com.salmonllc.util.MessageLog;
0055: import com.salmonllc.util.Util;
0056:
0057: /**
0058: * An extended version of the display box with addional functionality for building list forms
0059: *
0060: */
0061: public class JspListFormDisplayBox extends JspFormDisplayBox implements
0062: SubmitListener {
0063: public static final int MODE_EDIT = 0;
0064: public static final int MODE_DISPLAY_MULTI_PAGE = 1;
0065: public static final int MODE_DISPLAY_SINGLE_PAGE = 2;
0066:
0067: private int _mode;
0068:
0069: private String _validatorName, _detailFormName, _searchFormName;
0070: private JspDetailFormDisplayBox _detailForm;
0071: private JspSearchFormDisplayBox _searchForm;
0072: private JspDataTable _datatable;
0073: private DataStoreBuffer _ds;
0074: private HtmlSubmitButton _addButton, _saveButton;
0075: private String _deleteBucketName;
0076: private Object _deleteBucketValue;
0077: private boolean _autoCreateLink = true;
0078: private String _detailPageURL;
0079: private HtmlLink _editLink;
0080: private String _saveButtonAccessKey, _addButtonAccessKey,
0081: _saveButtonCaption, _addButtonCaption;
0082: private int _rowToEdit;
0083: private String _rowHighlightColor;
0084: private int _maxRows = -1;
0085: private String _maxRowsErrorMessage = "These selections will retrieve more data rows then the maximum allowed. Please enter some additional selection criteria.";
0086: private HtmlSubmitButton _undoButton;
0087: private String _dirtyDataDeleteError = "Can't do save. A row you deleted has been modified by another user. Press \"Undo\" and then \"Save\" again to undo the delete and allow other changes to be saved. Press \"Search\" to reload the data so this row can be deleted. ";
0088: private String _dirtyDataUpdateError = "Can't do save. The highlighted row has already been modified by another user. Press \"Undo\" and then \"Save\" again to undo the changes and save other changed rows. Press \"Search\" to reload the data so this row can be changed and saved. ";
0089: private DataStoreEvaluator _lookupReturnEval;
0090: private DataStoreExpression _lookupReturnExp;
0091: private DataStoreEvaluator _lookupReturnDescEval;
0092: private DataStoreExpression _lookupReturnDescExp;
0093:
0094: private String _lookupReturnExpString, _lookupReturnDescExpString;
0095:
0096: private class SkipRowExpression implements DataStoreExpression {
0097: public Object evaluateExpression(DataStoreBuffer dsBuf, int row)
0098: throws DataStoreException {
0099: if (dsBuf.getRowStatus(row) == DataStoreBuffer.STATUS_NEW)
0100: return Boolean.TRUE;
0101: if (_deleteBucketName != null && _deleteBucketValue != null) {
0102: Object val = dsBuf.getAny(row, _deleteBucketName);
0103: if (val != null && val.equals(_deleteBucketValue))
0104: return Boolean.TRUE;
0105: }
0106: return Boolean.FALSE;
0107: }
0108: }
0109:
0110: private class DataStoreSortListener implements ModelChangedListener {
0111: DSDataRow _oldRow;
0112:
0113: public void modelChanged(ModelChangedEvent evt) {
0114: if (evt.getType() == ModelChangedEvent.TYPE_DATA_SORTING) {
0115: if (evt.getDataStore().getRow() > -1) {
0116: try {
0117: _oldRow = evt.getDataStore().getDataStoreRow(
0118: evt.getDataStore().getRow(),
0119: DataStoreBuffer.BUFFER_STANDARD)
0120: .getDSDataRow();
0121: } catch (DataStoreException e) {
0122: }
0123: }
0124: } else if (evt.getType() == ModelChangedEvent.TYPE_DATA_SORTED) {
0125: if (_oldRow != null) {
0126: DataStoreBuffer ds = evt.getDataStore();
0127: for (int i = 0; i < ds.getRowCount(); i++) {
0128: try {
0129: if (ds.getDataStoreRow(i,
0130: DataStoreBuffer.BUFFER_STANDARD)
0131: .getDSDataRow() == _oldRow) {
0132: ds.gotoRow(i);
0133: if (_rowToEdit > -1)
0134: _rowToEdit = i;
0135: break;
0136: }
0137: } catch (DataStoreException e) {
0138: }
0139: }
0140:
0141: }
0142: }
0143: }
0144: }
0145:
0146: private class SelectRowExpression implements DataStoreExpression {
0147: public Object evaluateExpression(DataStoreBuffer dsBuf, int row)
0148: throws DataStoreException {
0149: if (_mode == MODE_DISPLAY_MULTI_PAGE)
0150: return null;
0151: else if (_mode == MODE_EDIT) {
0152: if (_validator == null)
0153: return null;
0154: else
0155: return (_validator.isErrorOnLastPass() && row == dsBuf
0156: .getRow()) ? _rowHighlightColor : null;
0157: } else {
0158: if (row == dsBuf.getRow())
0159: return _rowHighlightColor;
0160: else
0161: return null;
0162: }
0163: }
0164: }
0165:
0166: private class DirtyDataUndoAction implements SubmitListener {
0167: int _row = -1;
0168: int _buffer = -1;
0169:
0170: public void setRowAndBuffer(int buffer, int row) {
0171: _buffer = buffer;
0172: _row = row;
0173: }
0174:
0175: public boolean submitPerformed(SubmitEvent e) throws Exception {
0176: if (_buffer == DataStoreBuffer.BUFFER_DELETED) {
0177: int row = _ds.unDeleteRow(_row);
0178: _ds.undoChanges(row);
0179: if (_deleteBucketName != null)
0180: _ds.setAny(row, _deleteBucketName, null);
0181: jumpToPage(row);
0182: } else
0183: _ds.undoChanges(_row);
0184: return true;
0185: }
0186: }
0187:
0188: private DirtyDataUndoAction _ddAction = new DirtyDataUndoAction();
0189:
0190: private class LocalPageListener implements PageListener {
0191: public void pageRequested(PageEvent p) throws Exception {
0192: if (!getPage().isReferredByCurrentPage()) {
0193: HttpServletRequest r = getPage().getCurrentRequest();
0194: String refresh = r.getParameter("refresh");
0195: if (refresh != null && refresh.equalsIgnoreCase("true"))
0196: doSearch();
0197: }
0198: }
0199:
0200: public void pageRequestEnd(PageEvent p) throws Exception {
0201: }
0202:
0203: public void pageSubmitEnd(PageEvent p) {
0204: }
0205:
0206: public void pageSubmitted(PageEvent p) {
0207: }
0208: }
0209:
0210: public JspListFormDisplayBox(String name, int mode, HtmlPage page) {
0211: this (name, mode, null, page);
0212:
0213: }
0214:
0215: public JspListFormDisplayBox(String name, int mode, String theme,
0216: HtmlPage page) {
0217: super (name, theme, page);
0218: _mode = mode;
0219:
0220: if (mode == MODE_EDIT) {
0221: _addButton = new HtmlSubmitButton(name + "addButton",
0222: "Add", theme, page);
0223: _saveButton = new HtmlSubmitButton(name + "saveButton",
0224: "Save", theme, page);
0225: _addButton.addSubmitListener(this );
0226: _saveButton.addSubmitListener(this );
0227: _buttons.add(_saveButton);
0228: _buttons.add(_addButton);
0229: add(_addButton, TYPE_COMP);
0230: add(_saveButton, TYPE_COMP);
0231: } else if (mode == MODE_DISPLAY_MULTI_PAGE) {
0232: _addButton = new HtmlSubmitButton(name + "addButton",
0233: "Add", theme, page);
0234: _addButton.addSubmitListener(this );
0235: _buttons.add(_addButton);
0236: add(_addButton, TYPE_COMP);
0237: getPage().addPageListener(new LocalPageListener());
0238: }
0239:
0240: _undoButton = new MessageButton(getPage(), "dirtyDataUndo",
0241: _undoButtonCap, _ddAction);
0242: _messageButtons.add(_undoButton);
0243: setUpButtons();
0244: }
0245:
0246: /**
0247: *Called by the tag handler to set the name of the validator. The autoBindComponents will lookup the name of the component and attach it to this one or try to discover it if the name is null
0248: */
0249: public void setValidatorName(String name) {
0250: _validatorName = name;
0251: }
0252:
0253: /**
0254: *Called by the tag handler to set the name of the ListForm. The autoBindComponents will lookup the name of the component and attach it to this one or try to discover it if the name is null
0255: */
0256: public void setDetailFormName(String name) {
0257: _detailFormName = name;
0258: }
0259:
0260: /**
0261: *Called by the tag handler to set the name of the ListForm. The autoBindComponents will lookup the name of the component and attach it to this one or try to discover it if the name is null
0262: */
0263: public void setSearchFormName(String name) {
0264: _searchFormName = name;
0265: }
0266:
0267: /**
0268: * Binds various components to the component based on their names passed to the constructor. CriteriaBuilder, CriteriaValidator and ListForm. This method is called by the framework and should not be called directly.
0269: */
0270: public void autoBindComponents() throws Exception {
0271: JspController cont = (JspController) getPage();
0272:
0273: if (getDataSource() != null) {
0274: _ds = cont.getDataSource(getDataSource());
0275: Enumeration enum = getComponents();
0276: while (enum.hasMoreElements()) {
0277: Object o = enum.nextElement();
0278: if (o instanceof JspDataTable) {
0279: _datatable = (JspDataTable) o;
0280: break;
0281: }
0282: }
0283: } else {
0284: Enumeration enum = getComponents();
0285: while (enum.hasMoreElements()) {
0286: Object o = enum.nextElement();
0287: if (o instanceof JspDataTable) {
0288: _datatable = (JspDataTable) o;
0289: _ds = _datatable.getDataStoreBuffer();
0290: break;
0291: }
0292: }
0293: }
0294:
0295: //add an expression to set the style for the selected row
0296: if (_datatable != null) {
0297: for (int i = 0; i < _datatable.getComponentCount(); i++) {
0298: Object o = _datatable.getComponent(i);
0299: if (_datatable.getComponentType(i) == JspContainer.TYPE_ROW && o instanceof JspTableRow) {
0300: _datatable.addPropertyExpression(o, "backgroundColor", new SelectRowExpression());
0301: Enumeration enum = ((JspContainer) o).getComponents();
0302: while (enum.hasMoreElements()) {
0303: o = enum.nextElement();
0304: if (o instanceof JspTableCell)
0305: _datatable.addPropertyExpression(o, "backgroundColor", new SelectRowExpression());
0306:
0307: }
0308: }
0309: }
0310: }
0311:
0312: if (_validatorName != null)
0313: _validator = (HtmlValidatorText) cont.getComponent(_validatorName);
0314: else if (_mode == MODE_EDIT) {
0315: //see if there is a validator for this datastore
0316: Enumeration enum = cont.getComponents();
0317: while (enum.hasMoreElements()) {
0318: Object o = enum.nextElement();
0319: if (o instanceof HtmlValidatorText) {
0320: HtmlValidatorText test = (HtmlValidatorText) o;
0321: if (test.getDataStore() == _ds) {
0322: _validator = test;
0323: break;
0324: }
0325: }
0326: }
0327: }
0328: if (_validator == null && _ds != null && _mode == MODE_EDIT) {
0329: boolean hasRules = false;
0330: for (int i = 0; i < _ds.getColumnCount(); i++) {
0331: if (_ds.getValidationRulesForColumn(i) != null) {
0332: hasRules = true;
0333: break;
0334: }
0335: }
0336: if (hasRules) {
0337: _validator = new HtmlValidatorText(getName() + "validator", cont);
0338: _validator.setBreaksBefore(0);
0339: _validator.setBreaksAfter(2);
0340: _validator.setDataStore(_ds);
0341: _validator.importRules(_ds);
0342: _validator.setUseJavaScript(false);
0343: _validator.setMultipleErrorsOK(false);
0344: _validator.setAddFocusLinksToErrors(false);
0345: _validatorBuiltInternally = true;
0346: add(_validator, TYPE_COMP);
0347: }
0348: }
0349:
0350: if (_validator != null && _saveButton != null)
0351: _validator.addSubmitToListenTo(_saveButton);
0352:
0353: //find or create the delete check box
0354: if (_mode == MODE_EDIT && _deleteBucketName == null) {
0355: if (_datatable != null && _ds != null) {
0356: HtmlCheckBox cbx = findFirstUnboundCheckBox(_datatable);
0357: if (cbx != null) {
0358: String name = getName() + "deleteCbx";
0359: _ds.addBucket(name, DataStore.DATATYPE_INT);
0360: cbx.setColumn(_ds, name);
0361: cbx.setTrueValue("1");
0362: cbx.setFalseValue(null);
0363: _deleteBucketName = name;
0364: _deleteBucketValue = new Integer(1);
0365: if (_validator != null) {
0366: try {
0367: _validator.setSkipRowExpression(new SkipRowExpression());
0368: } catch (DataStoreException e) {
0369: MessageLog.writeErrorMessage("error setting skip row expression for validator", e, this );
0370: }
0371: }
0372: }
0373: }
0374: }
0375:
0376: //find the first text component in the table and change it to a link
0377: if ((_mode == MODE_DISPLAY_MULTI_PAGE || _mode == MODE_DISPLAY_SINGLE_PAGE) && _autoCreateLink && _datatable != null) {
0378: HtmlText t = findFirstTextComponent(_datatable);
0379: if (t != null) {
0380: if (!(t.getParent() instanceof JspLink)) {
0381: String name = t.getName();
0382: HtmlLink l = new HtmlLink(getFullName() + "zoomlink", "none", getPage());
0383: HtmlText t2 = new HtmlText(getFullName() + "zoomtext", t.getText(), t.getStyle(), getPage());
0384: t2.setFont(t.getFont());
0385: t2.setFont(HtmlText.FONT_LINK);
0386: DataStoreEvaluator eval = t.getExpressionEvaluator();
0387: if (eval != null) {
0388: DataStoreExpression exp = eval.getDataStoreExpression();
0389: if (exp != null)
0390: t2.setExpression(eval.getDataStore(), exp);
0391: else
0392: t2.setExpression(eval.getDataStore(), eval.getExpression());
0393:
0394: }
0395: l.addSubmitListener(this );
0396: l.add(t2);
0397: ((JspController) getPage()).replaceComponent(name, l);
0398: _editLink = l;
0399: }
0400: }
0401: }
0402:
0403: //if there is a detail form on the page, find it and use it
0404: if (_detailFormName != null)
0405: _detailForm = (JspDetailFormDisplayBox) cont.getComponent(_detailFormName);
0406: else {
0407: Enumeration enum = cont.getComponents();
0408: while (enum.hasMoreElements()) {
0409: Object o = enum.nextElement();
0410: if (o instanceof JspDetailFormDisplayBox) {
0411: _detailForm = (JspDetailFormDisplayBox) o;
0412: break;
0413: }
0414: }
0415: }
0416:
0417: //if there is a search form on the page, find it and use it
0418: if (_searchFormName != null)
0419: _searchForm = (JspSearchFormDisplayBox) cont.getComponent(_searchFormName);
0420: else {
0421: Enumeration enum = cont.getComponents();
0422: while (enum.hasMoreElements()) {
0423: Object o = enum.nextElement();
0424: if (o instanceof JspSearchFormDisplayBox) {
0425: _searchForm = (JspSearchFormDisplayBox) o;
0426: break;
0427: }
0428: }
0429: }
0430:
0431: //for sorting, add a listener that keeps the row the same after a sort
0432: if (_ds != null && _mode == MODE_DISPLAY_SINGLE_PAGE) {
0433: _ds.addModelChangedListener(new DataStoreSortListener());
0434: }
0435:
0436: //setup the lookup return expression
0437: setupLookupReturnEvaluator();
0438: setupLookupDescReturnEvaluator();
0439:
0440: }
0441:
0442: /**
0443: * Sets the save button visible or not
0444: */
0445: public void setSaveButtonVisible(boolean visible) {
0446: if (_saveButton != null)
0447: _saveButton.setVisible(visible);
0448: }
0449:
0450: /**
0451: * Sets the text to display on the save button
0452: */
0453: public void setSaveButtonCaption(String caption) {
0454: if (_saveButton != null)
0455: _saveButton.setDisplayName(caption);
0456: }
0457:
0458: /**
0459: * Sets the add button visible or not
0460: */
0461: public void setAddButtonVisible(boolean visible) {
0462: if (_addButton != null)
0463: _addButton.setVisible(visible);
0464: }
0465:
0466: /**
0467: * Sets the add button visible or not
0468: */
0469: public void setAddButtonCaption(String caption) {
0470: if (_addButton != null)
0471: _addButton.setDisplayName(caption);
0472: }
0473:
0474: /**
0475: * Returns the save button visible or not
0476: */
0477: public boolean isSaveButtonVisible() {
0478: if (_saveButton == null)
0479: return false;
0480: else
0481: return _saveButton.getVisible();
0482: }
0483:
0484: /**
0485: * Returns the text to display on the save button
0486: */
0487: public String getSaveButtonCaption() {
0488: if (_saveButton == null)
0489: return null;
0490: else
0491: return _saveButton.getDisplayName();
0492: }
0493:
0494: /**
0495: * Return the add button visible or not
0496: */
0497: public boolean isAddButtonVisible() {
0498: if (_addButton == null)
0499: return false;
0500: else
0501: return _addButton.getVisible();
0502: }
0503:
0504: /**
0505: * Returns the add button visible or not
0506: */
0507: public String getAddButtonCaption() {
0508: if (_addButton == null)
0509: return null;
0510: else
0511: return _addButton.getDisplayName();
0512: }
0513:
0514: /**
0515: * Returns the font style for the save and add buttons
0516: */
0517: public String getButtonFontStyle() {
0518: if (_saveButton == null)
0519: return null;
0520: else
0521: return _saveButton.getButtonFontStyle();
0522: }
0523:
0524: /**
0525: * Returns the background color for the save and add buttons
0526: */
0527: public String getButtonBgColor() {
0528: if (_saveButton == null)
0529: return null;
0530: else
0531: return _saveButton.getButtonBgColor();
0532: }
0533:
0534: /**
0535: * Adds a button to the display box
0536: */
0537: public void addButton(HtmlSubmitButton b) {
0538: _buttons.add(b);
0539: add(b, TYPE_COMP);
0540: }
0541:
0542: /**
0543: * Updates the display box button labels for the current language<br>
0544: * The language property file must have the following key structure<br>
0545: * FormDisplayBox.add represents the caption for the add button.<br>
0546: * FormDisplayBox.save represents the caption for the save button.<br>
0547: * FormDisplayBox.undo represents the caption for the ok button.<br>
0548: * ListFormDisplayBox.dirtyDataDeleteError represents the error message that occurs when a dirty data exception occurs on a deleted row<br>
0549: * ListFormDisplayBox.dirtyDataUpdateError represents the error message that occurs when a dirty data exception occurs on an updated row<br>
0550: * ListFormDisplayBox.maxRowsExceededError represents the error message that occurs when trying to load more data then is allowed<br>
0551: */
0552: public void updateLocale() {
0553: _updateLocale = true;
0554: }
0555:
0556: protected void processLocaleInfo() {
0557: if (_updateLocale) {
0558: _updateLocale = false;
0559: LanguagePreferences p = getPage().getLanguagePreferences();
0560: String appName = getPage().getApplicationName();
0561: String descr = null;
0562: String key = "FormDisplayBox.add";
0563: descr = LanguageResourceFinder.getResource(appName, key, p);
0564: if (descr != null)
0565: _addButtonCaption = descr;
0566:
0567: descr = null;
0568: key = "FormDisplayBox.save";
0569: descr = LanguageResourceFinder.getResource(appName, key, p);
0570: if (descr != null)
0571: _saveButtonCaption = descr;
0572:
0573: descr = null;
0574: key = "ListFormDisplayBox.dirtyDataDeleteError";
0575: descr = LanguageResourceFinder.getResource(appName, key, p);
0576: if (descr != null)
0577: _dirtyDataDeleteError = descr;
0578:
0579: descr = null;
0580: key = "ListFormDisplayBox.dirtyDataUpdateError";
0581: descr = LanguageResourceFinder.getResource(appName, key, p);
0582: if (descr != null)
0583: _dirtyDataUpdateError = descr;
0584:
0585: descr = null;
0586: key = "ListFormDisplayBox.maxRowsExceededError";
0587: descr = LanguageResourceFinder.getResource(appName, key, p);
0588: if (descr != null)
0589: _maxRowsErrorMessage = descr;
0590:
0591: super .processLocaleInfo();
0592:
0593: }
0594: }
0595:
0596: /**
0597: * @return the location for displaying the buttons
0598: */
0599: public int getButtonDisplayLocation() {
0600: return _buttonDisplayLocation;
0601: }
0602:
0603: /**
0604: * Sets the display location for a button. Valid values are BUTTON_DISPLAY_IN_HEADER and BUTTON_DISPLAY_BOX_BELOW_TABLE
0605: */
0606: public void setButtonDisplayLocation(int loc) {
0607: _buttonDisplayLocation = loc;
0608: }
0609:
0610: /**
0611: * framework method, do not call directly
0612: */
0613: public boolean submitPerformed(SubmitEvent e) throws Exception {
0614: if (e.getComponent() == _addButton)
0615: doAdd();
0616: else if (e.getComponent() == _saveButton)
0617: doSave();
0618: else if (e.getComponent() == _editLink) {
0619: if (isFromPopupLookup() || isFromLookup()) {
0620: returnValueToLookup(e.getRow());
0621: } else {
0622: _rowToEdit = e.getRow();
0623: doEdit();
0624: }
0625: }
0626: return true;
0627: }
0628:
0629: /*Claudio Pi - 7/1/2004 Encapsulated the return to lookup method so it can be called in other situtations*/
0630: public void returnValueToLookup(int row) throws DataStoreException,
0631: IOException {
0632:
0633: String lookupRet = null;
0634: String lookupDescRet = null;
0635: if (_lookupReturnEval != null)
0636: lookupRet = _lookupReturnEval.evaluateRowFormat(row);
0637: if (_lookupReturnDescEval != null)
0638: lookupDescRet = _lookupReturnDescEval
0639: .evaluateRowFormat(row);
0640:
0641: if (lookupDescRet == null)
0642: lookupDescRet = "";
0643: else
0644: lookupDescRet = escapeSingleQuote(lookupDescRet);
0645: if (isFromPopupLookup()) {
0646: JspController this Cont = getController();
0647: HtmlScriptGenerator gen = new HtmlScriptGenerator(this Cont);
0648: String script = gen.generateReturnValueToLookupScript(
0649: lookupRet, lookupDescRet);
0650: getPage().writeScript(script);
0651: } else {
0652: getPage().getCurrentResponse().sendRedirect(
0653: getLookupReturnToURL(lookupRet, lookupDescRet));
0654: }
0655: }
0656:
0657: /**
0658: * This method gets fired when the user clicks an edit link. Subclasses can override it to customize behavior
0659: */
0660: public void doEdit() throws SQLException, DataStoreException,
0661: Exception {
0662: if (_mode == MODE_DISPLAY_MULTI_PAGE) {
0663: try {
0664: StringBuffer filterParm = new StringBuffer();
0665: if (_ds instanceof DataStore) {
0666: DataStore ds = (DataStore) _ds;
0667: String tableList[] = _ds.getTableList(false);
0668: for (int i = 0; i < tableList.length; i++) {
0669: String where = ds.buildCriteriaStringForRow(
0670: getRowToEdit(), tableList[i]);
0671: if (where != null && where.length() > 0) {
0672: filterParm.append("&id=");
0673: filterParm.append(tableList[i]);
0674: filterParm.append(":");
0675: filterParm.append(Util.urlEncode(where,
0676: true));
0677: }
0678: }
0679: } else if (_ds instanceof BeanDataStore) {
0680: BeanDataStore ds = (BeanDataStore) _ds;
0681: String criteriaString = ds
0682: .buildCriteriaStringForRow(getRowToEdit());
0683: if (criteriaString != null
0684: && criteriaString.length() > 0) {
0685: filterParm.append("&id=");
0686: filterParm.append(Util.urlEncode(
0687: criteriaString, true));
0688: }
0689: }
0690: String returnTo = getURI();
0691: getPage().getCurrentResponse().sendRedirect(
0692: _detailPageURL + "?mode=edit"
0693: + filterParm.toString() + "&listPage="
0694: + returnTo);
0695: } catch (IOException e) {
0696: e.printStackTrace();
0697: }
0698: } else if (_mode == MODE_DISPLAY_SINGLE_PAGE) {
0699: if (_detailForm != null)
0700: _detailForm.tryEdit();
0701: else if (_ds != null)
0702: _ds.gotoRow(getRowToEdit());
0703: }
0704: }
0705:
0706: /**
0707: * This method gets fired when the user clicks the add button. Subclasses can override it to customize behavior
0708: */
0709: public void doAdd() throws SQLException, DataStoreException,
0710: Exception {
0711: if (_mode == MODE_EDIT) {
0712: setVisible(true);
0713: DataStoreBuffer ds = getDataStore();
0714: if (ds != null) {
0715: ds.insertRow();
0716: if (getDataTable() != null) {
0717: JspDataTable tab = getDataTable();
0718: if (!tab.isRowOnPage(ds.getRowCount() - 1))
0719: tab.setPage(tab.getPage(ds.getRowCount() - 1));
0720:
0721: HtmlFormComponent comp = findFirstFormComponent(tab);
0722: if (comp != null)
0723: comp.setFocus(ds.getRowCount() - 1);
0724: }
0725: }
0726: } else if (_mode == MODE_DISPLAY_MULTI_PAGE) {
0727: if (_detailPageURL != null) {
0728: try {
0729: String returnTo = getURI();
0730: getPage().getCurrentResponse().sendRedirect(
0731: _detailPageURL + "?mode=add&listPage="
0732: + returnTo);
0733:
0734: } catch (IOException e) {
0735: MessageLog.writeErrorMessage("doAdd()", e, this );
0736: }
0737: }
0738: } else if (_mode == MODE_DISPLAY_SINGLE_PAGE
0739: && _detailForm != null) {
0740: setVisible(true);
0741: _detailForm.tryAdd();
0742: }
0743: }
0744:
0745: /**
0746: * This method gets fired when the user clicks the save button. Subclasses can override it to customize behavior
0747: */
0748: public void doSave() throws Exception {
0749: if (getDataStore() != null) {
0750: DataStoreBuffer dsb = getDataStore();
0751: for (int i = dsb.getRowCount() - 1; i >= 0; i--) {
0752: if (_deleteBucketName != null
0753: && _deleteBucketValue != null) {
0754: Object o;
0755: try {
0756: o = dsb.getAny(i, _deleteBucketName);
0757: if (_deleteBucketValue.equals(o))
0758: dsb.deleteRow(i);
0759: else if (dsb.getRowStatus(i) == DataStoreBuffer.STATUS_NEW)
0760: dsb.deleteRow(i);
0761: } catch (DataStoreException e) {
0762: }
0763:
0764: } else if (dsb.getRowStatus(i) == DataStoreBuffer.STATUS_NEW)
0765: dsb.deleteRow(i);
0766:
0767: }
0768: try {
0769: doDataStoreUpdate();
0770: _datatable.setPage(0);
0771: } catch (DirtyDataException ex) {
0772: if (_validator != null) {
0773: int row = ex.getRow();
0774: String message = null;
0775: if (ex.getBuffer() == DataStoreBuffer.BUFFER_DELETED) {
0776: dsb.clearSelectedRow();
0777: message = _dirtyDataDeleteError;
0778: } else {
0779: jumpToPage(row);
0780: message = _dirtyDataUpdateError;
0781: }
0782: _ddAction.setRowAndBuffer(ex.getBuffer(), row);
0783: _validator.setErrorMessage(message, null, row,
0784: _undoButton);
0785: }
0786: } catch (DataStoreException ex) {
0787: if (_validator != null)
0788: _validator.addErrorMessage(ex.getMessage(),
0789: ((JspController) getPage())
0790: .getBoundComponent(_ds, ex
0791: .getColumn()), ex.getRow());
0792: } catch (Exception ex) {
0793: if (_validator != null)
0794: _validator.addErrorMessage(ex.getMessage());
0795: }
0796:
0797: }
0798: }
0799:
0800: public void doSearch() throws SQLException, DataStoreException,
0801: Exception {
0802: QBEBuilder search = null;
0803: if (_searchForm != null)
0804: search = _searchForm.getCriteriaBuilder();
0805: DataStoreBuffer ds = getDataStore();
0806: if (search != null && ds != null) {
0807: if (_maxRows != -1) {
0808: try {
0809: if (doDataStoreEstimateRowsRetrieved(search
0810: .generateSQLFilter(ds)) > _maxRows)
0811: throw new SQLException(_maxRowsErrorMessage);
0812: } catch (Exception e) {
0813: throw new DataStoreException(e.getMessage(), e);
0814: }
0815: }
0816: doDataStoreRetrieve(search.generateSQLFilter(ds));
0817: ds.gotoFirst();
0818: }
0819: if (getDataTable() != null)
0820: getDataTable().setPage(0);
0821: setVisible(true);
0822: if (_mode == MODE_DISPLAY_SINGLE_PAGE && _detailForm != null) {
0823: if (_detailForm.getDataStore() != _ds
0824: && _ds.getRowCount() > 0) {
0825: _detailForm.getDataStore().reset();
0826: _rowToEdit = 0;
0827: doEdit();
0828: _detailForm.setVisible(_detailForm.getDataStore()
0829: .getRowCount() == 1);
0830: } else {
0831: if (_ds.getRowCount() > 0)
0832: doEdit();
0833: else {
0834: _detailForm.setVisible(false);
0835: _detailForm.getDataStore().reset();
0836: }
0837: }
0838:
0839: }
0840: }
0841:
0842: /**
0843: * returns the criteria validator the component is using to validate entered criteria
0844: */
0845: public HtmlValidatorText getValidator() {
0846: return _validator;
0847: }
0848:
0849: /**
0850: * @return
0851: */
0852: public JspDataTable getDataTable() {
0853: return _datatable;
0854: }
0855:
0856: /**
0857: * @return
0858: */
0859: public DataStoreBuffer getDataStore() {
0860: return _ds;
0861: }
0862:
0863: /**
0864: * Set the access key for the add button
0865: */
0866: public void setAddButtonAccessKey(String key) {
0867: _addButton.setAccessKey(key);
0868: }
0869:
0870: /**
0871: * Set the access key for the save button
0872: */
0873: public void setSaveButtonAccessKey(String key) {
0874: _saveButton.setAccessKey(key);
0875: }
0876:
0877: /**
0878: * Set to true to automatically create a link to zoom to a detail row (MODE_DISPLAY_MULTIPAGE, MODE_DISPLAY_SINGLE_PAGE only)
0879: */
0880: public void setAutoCreateLink(boolean autoCreate) {
0881: _autoCreateLink = autoCreate;
0882: }
0883:
0884: /**
0885: * Sets the url for the JSP page representing the detail page for this list page (MODE_DISPLAY_MULTIPAGE only)
0886: */
0887: public void setDetailPageURL(String url) {
0888: url = translateSiteMapURL(url);
0889: _detailPageURL = url;
0890: }
0891:
0892: /**
0893: * Sets the url for the JSP page representing the detail page for this list page by looking up the page in the site map(MODE_DISPLAY_MULTIPAGE only)
0894: */
0895: public void setDetailPageFromSiteMap(String logicalName) {
0896: _detailPageURL = ((JspController) getPage())
0897: .getSiteMapURL(logicalName);
0898: }
0899:
0900: /**
0901: * Sets the theme for the component
0902: */
0903: public void setTheme(String theme) {
0904: super .setTheme(theme);
0905: Props props = getPage().getPageProperties();
0906: _saveButtonCaption = props.getThemeProperty(theme,
0907: Props.LIST_FORM_DISPLAY_BOX_SAVE_BUTTON_CAPTION);
0908: _saveButtonAccessKey = props.getThemeProperty(theme,
0909: Props.LIST_FORM_DISPLAY_BOX_SAVE_BUTTON_ACCESS_KEY);
0910: _addButtonCaption = props.getThemeProperty(theme,
0911: Props.LIST_FORM_DISPLAY_BOX_ADD_BUTTON_CAPTION);
0912: _addButtonAccessKey = props.getThemeProperty(theme,
0913: Props.LIST_FORM_DISPLAY_BOX_ADD_BUTTON_ACCESS_KEY);
0914: _rowHighlightColor = props.getThemeProperty(theme,
0915: Props.LIST_FORM_DISPLAY_BOX_ROW_HIGHLIGHT_COLOR);
0916: String st = props.getThemeProperty(theme,
0917: Props.LIST_FORM_DISPLAY_BOX_BUTTON_LOCATION);
0918: if (st != null) {
0919: if (st.equalsIgnoreCase("BELOW_TABLE"))
0920: setButtonDisplayLocation(BUTTON_DISPLAY_BELOW_TABLE);
0921: else if (st.equalsIgnoreCase("IN_HEADER"))
0922: setButtonDisplayLocation(BUTTON_DISPLAY_IN_HEADER);
0923: else if (st.equalsIgnoreCase("IN_HEADER_AND_BELOW_TABLE"))
0924: setButtonDisplayLocation(BUTTON_DISPLAY_IN_HEADER_AND_BELOW_TABLE);
0925: }
0926: setUpButtons();
0927: }
0928:
0929: protected void setUpButtons() {
0930: super .setUpButtons();
0931: if (_saveButton != null) {
0932: if (_saveButtonCaption != null)
0933: _saveButton.setDisplayName(_saveButtonCaption);
0934: if (_saveButtonAccessKey != null)
0935: _saveButton.setAccessKey(_saveButtonAccessKey);
0936: }
0937: if (_addButton != null) {
0938: if (_addButtonCaption != null)
0939: _addButton.setDisplayName(_addButtonCaption);
0940: if (_addButtonAccessKey != null)
0941: _addButton.setAccessKey(_addButtonAccessKey);
0942: }
0943:
0944: }
0945:
0946: /**
0947: * Returns the last row selected when an edit link was clicked
0948: */
0949: public int getRowToEdit() {
0950: return _rowToEdit;
0951: }
0952:
0953: /**
0954: * Sets the the row in the table to edit
0955: */
0956: public void setRowToEdit(int row) {
0957: _rowToEdit = row;
0958: }
0959:
0960: /**
0961: * @return the background color for the selected row
0962: */
0963: public String getRowHighlightColor() {
0964: return _rowHighlightColor;
0965: }
0966:
0967: /**
0968: * Sets the background color for the selected row
0969: */
0970: public void setRowHighlightColor(String string) {
0971: _rowHighlightColor = string;
0972: }
0973:
0974: private void jumpToPage(int row) {
0975: if (_datatable != null) {
0976: if (!_datatable.isRowOnPage(row))
0977: _datatable.setPage(_datatable.getPage(row));
0978: }
0979: if (_ds != null)
0980: _ds.gotoRow(row);
0981: }
0982:
0983: /**
0984: * Sets the error message for a dirty data exception
0985: * @param _deleteErrorMessage The message to display if a dirty data exception occurs on a deleted row
0986: * @param _updateErrorMessage The message to display if a dirty data exception occurs on a updated row
0987: */
0988: public void setDirtyDataErrorMessages(String _deleteErrorMessage,
0989: String _updateErrorMessage) {
0990: _dirtyDataDeleteError = _deleteErrorMessage;
0991: _dirtyDataUpdateError = _updateErrorMessage;
0992: }
0993:
0994: /**
0995: * Returns true if the data in the list has been modified
0996: */
0997: public boolean isDataModified() {
0998: if (_mode == MODE_EDIT) {
0999: for (int i = 0; i < _ds.getRowCount(); i++) {
1000: int stat = _ds.getRowStatus(i);
1001: if (stat == DataStoreBuffer.STATUS_MODIFIED)
1002: return true;
1003: else if (stat == DataStoreBuffer.STATUS_NEW_MODIFIED)
1004: return true;
1005: }
1006: } else if (_mode == MODE_DISPLAY_SINGLE_PAGE) {
1007: if (_detailForm != null)
1008: return _detailForm.isDataModified();
1009: }
1010:
1011: return false;
1012: }
1013:
1014: /**
1015: * returns the maximum number of rows the list is allowed to retrieve (-1 for unlimited)
1016: */
1017: public int getMaxRows() {
1018: return _maxRows;
1019: }
1020:
1021: /**
1022: * sets the maximum number of rows the list is allowed to retrieve (-1 for unlimited)
1023: */
1024: public void setMaxRows(int i) {
1025: _maxRows = i;
1026: }
1027:
1028: /**
1029: * sets the error message that will be displayed when the maximum number of rows would be exceeded
1030: */
1031: public void setMaxRowsErrorMessage(String string) {
1032: _maxRowsErrorMessage = string;
1033: }
1034:
1035: private String getURI() {
1036: return Util.urlEncode(((JspController) getPage())
1037: .getCurrentRequest().getRequestURI(), true);
1038: }
1039:
1040: public void generateHTML(TagWriter t, String boxBody)
1041: throws Exception {
1042: boolean oldVis[] = null;
1043: if (isFromLookup() || isFromPopupLookup()) {
1044: oldVis = getButtonsVisible();
1045: if (_addButton != null)
1046: _addButton.setVisible(false);
1047: if (_saveButton != null)
1048: _saveButton.setVisible(false);
1049: }
1050: super .generateHTML(t, boxBody);
1051: if (oldVis != null)
1052: setButtonVisible(oldVis);
1053:
1054: }
1055:
1056: /**
1057: * If this component is being called from a lookup, the datastore expression to return to compute to return to the calling lookup
1058: */
1059: public void setLookupReturnExpression(String exp)
1060: throws DataStoreException {
1061: _lookupReturnExpString = exp;
1062: _lookupReturnExp = null;
1063: setupLookupReturnEvaluator();
1064:
1065: }
1066:
1067: /**
1068: * If this component is being called from a lookup, the datastore expression to return to compute to return to the calling lookup
1069: */
1070: public void setLookupReturnExpression(DataStoreExpression exp)
1071: throws DataStoreException {
1072: _lookupReturnExpString = null;
1073: _lookupReturnExp = exp;
1074: setupLookupReturnEvaluator();
1075:
1076: }
1077:
1078: /**
1079: * If this component is being called from a lookup, the datastore expression to return to compute a description to return to the calling lookup
1080: */
1081: public void setLookupDescReturnExpression(DataStoreExpression exp)
1082: throws DataStoreException {
1083: _lookupReturnDescExpString = null;
1084: _lookupReturnDescExp = exp;
1085: setupLookupDescReturnEvaluator();
1086:
1087: }
1088:
1089: /**
1090: * If this component is being called from a lookup, the datastore expression to return to compute a description to return to the calling lookup
1091: */
1092: public void setLookupDescReturnExpression(String exp)
1093: throws DataStoreException {
1094: _lookupReturnDescExpString = exp;
1095: _lookupReturnDescExp = null;
1096: setupLookupDescReturnEvaluator();
1097:
1098: }
1099:
1100: private void setupLookupDescReturnEvaluator()
1101: throws DataStoreException {
1102: if (_ds == null)
1103: return;
1104: if (_lookupReturnDescExp != null)
1105: _lookupReturnDescEval = new DataStoreEvaluator(_ds,
1106: _lookupReturnDescExp);
1107: else if (_lookupReturnDescExpString != null)
1108: _lookupReturnDescEval = new DataStoreEvaluator(_ds,
1109: _lookupReturnDescExpString);
1110: }
1111:
1112: private void setupLookupReturnEvaluator() throws DataStoreException {
1113: if (_ds == null)
1114: return;
1115: if (_lookupReturnExp != null)
1116: _lookupReturnEval = new DataStoreEvaluator(_ds,
1117: _lookupReturnExp);
1118: else if (_lookupReturnExpString != null)
1119: _lookupReturnEval = new DataStoreEvaluator(_ds,
1120: _lookupReturnExpString);
1121: }
1122:
1123: /**
1124: * Returns the datastore evaluator used to process a return from a lookup
1125: */
1126: protected DataStoreEvaluator getLookupReturnEval() {
1127: return _lookupReturnEval;
1128: }
1129:
1130: /**
1131: * Returns the datastore evaluator used to process a return description from a lookup
1132: */
1133: protected DataStoreEvaluator getLookupDescReturnEval() {
1134: return _lookupReturnDescEval;
1135: }
1136:
1137: /**
1138: * Returns the url for the detail page this list form will zoom to
1139: */
1140: protected String getDetailPageURL() {
1141: return _detailPageURL;
1142: }
1143:
1144: /**
1145: * Override this method in subclasses to change the way the rows retrieved will be estimated
1146: */
1147: public int doDataStoreEstimateRowsRetrieved(String criteria)
1148: throws Exception {
1149: DataStoreBuffer ds = getDataStore();
1150: if (ds instanceof DataStore)
1151: return ((DataStore) ds).estimateRowsRetrieved(criteria);
1152: else
1153: return 0;
1154: }
1155:
1156: /**
1157: * Override this method in subclasses to change the way the datastore is updated
1158: */
1159: public void doDataStoreUpdate() throws Exception {
1160: DataStoreBuffer ds = getDataStore();
1161: if (ds instanceof DataStore)
1162: ((DataStore) ds).update();
1163: else if (ds instanceof BeanDataStore)
1164: ((BeanDataStore) ds).update();
1165: }
1166:
1167: /**
1168: * Override this method in subclasses to change the way the datastore is retrieved
1169: */
1170: public void doDataStoreRetrieve(String where) throws Exception {
1171: if (where != null && where.length() == 0)
1172: where = null;
1173: DataStoreBuffer ds = getDataStore();
1174: if (ds instanceof DataStore)
1175: ((DataStore) ds).retrieve(where);
1176: else if (ds instanceof BeanDataStore)
1177: ((BeanDataStore) ds).retrieve(where);
1178: }
1179:
1180: /**
1181: * @return the save button used by this component
1182: */
1183: public HtmlSubmitButton getSaveButton() {
1184: return _saveButton;
1185: }
1186:
1187: /**
1188: * @return the add button used by this component
1189: */
1190: public HtmlSubmitButton getAddButton() {
1191: return _addButton;
1192: }
1193:
1194: private String escapeSingleQuote(String messageIn) {
1195: if (messageIn.indexOf('\'') == -1)
1196: return messageIn;
1197: StringBuffer sb = new StringBuffer(messageIn.length() + 10);
1198: for (int i = 0; i < messageIn.length(); i++) {
1199: char c = messageIn.charAt(i);
1200: if (c == '\'') {
1201: sb.append('\\');
1202: sb.append('\'');
1203: } else
1204: sb.append(c);
1205: }
1206: return sb.toString();
1207: }
1208: }
|