/*==========================================================================*\ | $Id: WCTable.java,v 1.6 2011/10/25 12:58:38 stedwar2 Exp $ |*-------------------------------------------------------------------------*| | Copyright (C) 2009 Virginia Tech | | This file is part of Web-CAT. | | Web-CAT is free software; you can redistribute it and/or modify | it under the terms of the GNU Affero General Public License as published | by the Free Software Foundation; either version 3 of the License, or | (at your option) any later version. | | Web-CAT is distributed in the hope that it will be useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General Public License for more details. | | You should have received a copy of the GNU Affero General Public License | along with Web-CAT; if not, see <http://www.gnu.org/licenses/>. \*==========================================================================*/ package org.webcat.ui; import org.webcat.core.WCComponent; import org.webcat.ui.generators.JavascriptFunction; import org.webcat.ui.generators.JavascriptGenerator; import org.webcat.ui.util.ComponentIDGenerator; import com.webobjects.appserver.WOActionResults; import com.webobjects.appserver.WOContext; import com.webobjects.appserver.WOMessage; import com.webobjects.appserver.WORequest; import com.webobjects.appserver.WOResponse; import com.webobjects.eocontrol.EOOrQualifier; import com.webobjects.eocontrol.EOQualifier; import com.webobjects.eocontrol.EOSortOrdering; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSMutableArray; import com.webobjects.foundation.NSMutableDictionary; import com.webobjects.foundation.NSSelector; import er.extensions.appserver.ERXDisplayGroup; import er.extensions.appserver.ERXWOContext; import er.extensions.eof.ERXQ; import er.extensions.eof.ERXS; import er.extensions.eof.ERXSortOrdering.ERXSortOrderings; //------------------------------------------------------------------------- /** * <p> * A reusable table component that is bound to a display group, and provides * options to select rows, sort on table headings, and paging. * </p> * <dl> * <dt>id (<code>String</code>)</dt> * <dd>The widget id for the content pane that will surround the table. This * can be used to refresh the table contents in response to events that occur * outside the table.</dd> * <dt>displayGroup (<code>ERXDisplayGroup<?></code>)</dt> * <dd>The display group that contains the objects that this table will * display.</dd> * <dt>fixedPageSize (<code>boolean</code>)</dt> * <dd>If true, the user will not be able to change the page size. This can be * desirable if the table is inside a dialog box and should remain small on the * screen.</dd> * <dt>settingsKey (<code>String</code>)</dt> * <dd>A key prefix that will be used to persist the table's settings in the * current user's preferences.</dd> * <dt>canSelectRows (<code>boolean</code>)</dt> * <dd>Indicates whether checkbox or radio button controls will be inserted at * the front of each table row to allow the user to select them.</dd> * <dt>multipleSelection (<code>boolean</code>)</dt> * <dd>Indicates whether multiple rows can be selected at once (using * checkboxes) or if only one row can be selected at a time (using radio * buttons).</dd> * </dl> * * @author Tony Allevato * @author Last changed by $Author: stedwar2 $ * @version $Revision: 1.6 $, $Date: 2011/10/25 12:58:38 $ */ public class WCTable extends WCComponent { //~ Constructors .......................................................... // ---------------------------------------------------------- public WCTable(WOContext context) { super(context); idFor = new ComponentIDGenerator(this); } //~ KVC attributes (must be public) ....................................... public String id; public ERXDisplayGroup<?> displayGroup; public String settingsKey; public boolean canSelectRows = false; public boolean fixedPageSize = false; public boolean multipleSelection = false; public String searchOnKeyPaths; public ComponentIDGenerator idFor; //~ Methods ............................................................... // ---------------------------------------------------------- @Override public void appendToResponse(WOResponse response, WOContext context) { if (id == null) { id = idFor.get(); } setInitialSortOrdering(); WCTable oldTable = setCurrentTable(this); super.appendToResponse(response, context); setCurrentTable(oldTable); } // ---------------------------------------------------------- @Override public void takeValuesFromRequest(WORequest request, WOContext context) { WCTable oldTable = setCurrentTable(this); super.takeValuesFromRequest(request, context); setCurrentTable(oldTable); } // ---------------------------------------------------------- @Override public WOActionResults invokeAction(WORequest request, WOContext context) { WCTable oldTable = setCurrentTable(this); WOActionResults result = super.invokeAction(request, context); setCurrentTable(oldTable); return result; } // ---------------------------------------------------------- public void setSearchOnKeyPaths(String keyPaths) { searchOnKeyPaths = keyPaths; if (keyPaths == null) { searchOnKeyPathArray = null; } else { searchOnKeyPathArray = new NSMutableArray<String>(); String[] keyPathArray = searchOnKeyPaths.split(","); for (String keyPath : keyPathArray) { searchOnKeyPathArray.addObject(keyPath); } } } // ---------------------------------------------------------- private EOQualifier qualifierFromSearchString(String searchString) { if (searchOnKeyPathArray == null || searchString == null) { return null; } else { NSMutableArray<EOQualifier> quals = new NSMutableArray<EOQualifier>(searchOnKeyPathArray.count()); for (String keyPath : searchOnKeyPathArray) { quals.addObject(ERXQ.contains(keyPath, searchString)); } return new EOOrQualifier(quals); } } // ---------------------------------------------------------- private void setInitialSortOrdering() { String keyPaths = persistentSortOrdering(); Boolean ascending = persistentSortIsAscending(); if (keyPaths != null) { sortDisplayGroup(keyPaths, ascending); needsInitialSort = false; } else { NSArray<EOSortOrdering> orderings = displayGroup.sortOrderings(); needsInitialSort = (orderings == null || orderings.count() == 0); } } // ---------------------------------------------------------- private String persistentSortOrdering() { if (settingsKey == null) { return null; } else { return (String) user().preferences().valueForKeyPath( settingsKey + "_sortOrdering"); } } // ---------------------------------------------------------- private void setPersistentSortOrdering(String ordering, boolean ascending) { if (settingsKey != null) { user().preferences().takeValueForKey( ordering, settingsKey + "_sortOrdering"); user().preferences().takeValueForKey( ascending, settingsKey + "_sortIsAscending"); user().savePreferences(); } } // ---------------------------------------------------------- private Boolean persistentSortIsAscending() { if (settingsKey == null) { return null; } else { return (Boolean) user().preferences().valueForKeyPath( settingsKey + "_sortIsAscending"); } } // ---------------------------------------------------------- public String sortOrderingKeyPathsFromDisplayGroup() { NSArray<EOSortOrdering> orderings = displayGroup.sortOrderings(); StringBuffer keyPaths = new StringBuffer(); if (orderings != null && orderings.count() > 0) { keyPaths.append(orderings.objectAtIndex(0).key()); for (int i = 1; i < orderings.count(); i++) { keyPaths.append(","); keyPaths.append(orderings.objectAtIndex(1).key()); } } return keyPaths.toString(); } // ---------------------------------------------------------- public boolean isDisplayGroupSortOrderingAscending() { NSArray<EOSortOrdering> orderings = displayGroup.sortOrderings(); if (orderings != null && orderings.count() > 0) { NSSelector<?> selector = orderings.objectAtIndex(0).selector(); return ERXS.INS_ASC.equals(selector) || ERXS.ASC.equals(selector); } else { return true; } } // ---------------------------------------------------------- protected void sortDisplayGroup(String keyPaths, boolean ascending) { ERXSortOrderings orderings = new ERXSortOrderings(); String[] keyPathArray = keyPaths.split(","); for (String keyPath : keyPathArray) { orderings.addObject(ERXS.sortOrder(keyPath.trim(), ascending ? ERXS.INS_ASC : ERXS.INS_DESC)); } displayGroup.clearSelection(); displayGroup.setSortOrderings(orderings); displayGroup.updateDisplayedObjects(); } // ---------------------------------------------------------- public JavascriptGenerator sortUsingKeyPaths(String keyPaths, boolean ascending) { setPersistentSortOrdering(keyPaths, ascending); sortDisplayGroup(keyPaths, ascending); return refreshTable(); } // ---------------------------------------------------------- public String searchText() { return searchText; } // ---------------------------------------------------------- public JavascriptGenerator filterUsingSearchString(String searchString) { searchText = searchString; displayGroup.clearSelection(); displayGroup.setCurrentBatchIndex(1); displayGroup.setQualifier(qualifierFromSearchString(searchString)); displayGroup.updateDisplayedObjects(); JavascriptGenerator js = refreshTable(new JavascriptFunction() { @Override public void generate(JavascriptGenerator g) { g.dijit(idFor.get("searchField")).call("focus"); } }); return js; } // ---------------------------------------------------------- public static void refresh(JavascriptGenerator js, String id) { refresh(js, id, null); } // ---------------------------------------------------------- public static void refresh(JavascriptGenerator js, String id, JavascriptFunction onAfterRefresh) { js.append(renderTableBusyScript(id)); js.refresh(onAfterRefresh, id); } // ---------------------------------------------------------- public JavascriptGenerator refreshTable() { return refreshTable(null); } // ---------------------------------------------------------- public JavascriptGenerator refreshTable(JavascriptFunction onAfterRefresh) { if (onAfterRefresh == null) { return new JavascriptGenerator().refresh(id); } else { return new JavascriptGenerator().refresh(onAfterRefresh, id); } } // ---------------------------------------------------------- public String tableBodyId() { return id + "__tbody"; } // ---------------------------------------------------------- public static String renderTableBusyScript(String gridId) { NSMutableDictionary<String, Object> props = new NSMutableDictionary<String, Object>(); props.setObjectForKey(0.25, "opacity"); JavascriptGenerator js = new JavascriptGenerator(); // TODO change this id to be more general js.animateProperty(gridId + "__tbody", props, 250, null).play(); return js.toString(true); } // ---------------------------------------------------------- // TODO rewrite this function to use the one above public String renderTableBusyScript() { NSMutableDictionary<String, Object> props = new NSMutableDictionary<String, Object>(); props.setObjectForKey(0.25, "opacity"); JavascriptGenerator js = new JavascriptGenerator(); js.animateProperty(tableBodyId(), props, 250, null).play(); return js.toString(true); } // ---------------------------------------------------------- public static WCTable currentTable() { return (WCTable) ERXWOContext.contextDictionary().objectForKey( CURRENT_TABLE_KEY); } // ---------------------------------------------------------- public static WCTable setCurrentTable(WCTable table) { WCTable oldTable = (WCTable) ERXWOContext.contextDictionary().objectForKey( CURRENT_TABLE_KEY); if (table == null) { ERXWOContext.contextDictionary().removeObjectForKey( CURRENT_TABLE_KEY); } else { ERXWOContext.contextDictionary().setObjectForKey(table, CURRENT_TABLE_KEY); } return oldTable; } // ---------------------------------------------------------- public int numberOfColumns() { return numberOfColumns; } // ---------------------------------------------------------- public String passthroughAttributes() { return passthroughAttributes; } // ---------------------------------------------------------- public void handleTakeValueForUnboundKey(Object value, String key) { if (passthroughAttributes == null) { passthroughAttributes = ""; } if (value != null) { passthroughAttributes += " " + key + "=\"" + WOMessage.stringByEscapingHTMLAttributeValue( value.toString()) + "\""; } } //~ Static/instance variables ............................................. private static final String CURRENT_TABLE_KEY = "org.webcat.ui.WCTable.currentTable"; private String passthroughAttributes; protected boolean needsInitialSort = false; protected int numberOfColumns = 0; private String searchText; private NSMutableArray<String> searchOnKeyPathArray; }