Last active
December 16, 2015 07:19
-
-
Save mtho11/5398159 to your computer and use it in GitHub Desktop.
SmartGWT 3.0p SortSpecifier Bug
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Wed Apr 10 09:14:01 GMT-700 2013 | |
SEVERE: At [Wed Apr 10 09:14:01 GMT-700 2013] MessageCenter received: Failed to draw Table [HLayout{ID: "isc_RecentAlertsPortlet_0", | |
width: 726, | |
height: 221, | |
members: Array[2], | |
position: "absolute", | |
className: "normal", | |
top: -9999, | |
vertical: false, | |
children: Array[2], | |
locatorParent: [Window ID:isc_PortletWindow_1], | |
parentElement: [Layout ID:isc_PortletWindow_1_body], | |
topElement: [VLayout ID:isc_CoreGUI_RootCanvas_0], | |
tabIndex: 1450, | |
cacheOffsetCoords: true, | |
zIndex: 201404, | |
memberSizes: Array[1], | |
}]. 4076844B783EE5AA1E5455D5C6154183.cache.html:10434 | |
Wed Apr 10 09:14:01 GMT-700 2013 | |
WARNING: Failed to draw Table [HLayout{ID: "isc_RecentAlertsPortlet_0", | |
width: 726, | |
height: 221, | |
members: Array[2], | |
position: "absolute", | |
className: "normal", | |
top: -9999, | |
vertical: false, | |
children: Array[2], | |
locatorParent: [Window ID:isc_PortletWindow_1], | |
parentElement: [Layout ID:isc_PortletWindow_1_body], | |
topElement: [VLayout ID:isc_CoreGUI_RootCanvas_0], | |
tabIndex: 1450, | |
cacheOffsetCoords: true, | |
zIndex: 201404, | |
memberSizes: Array[1], | |
}]. | |
com.google.gwt.core.client.JavaScriptException: (TypeError) : Cannot call method 'find' of undefined | |
at Unknown.isc_ListGrid_setSort(http://192.168.1.7:7080/coregui/org.rhq.enterprise.gui.coregui.CoreGUI/sc/modules/ISC_Grids.js@176) | |
at Unknown.isc_ListGrid_setData(http://192.168.1.7:7080/coregui/org.rhq.enterprise.gui.coregui.CoreGUI/sc/modules/ISC_Grids.js@34) | |
at Unknown.isc_ListGrid_initWidget(http://192.168.1.7:7080/coregui/org.rhq.enterprise.gui.coregui.CoreGUI/sc/modules/ISC_Grids.js@118) | |
at Unknown.isc_Canvas_init(http://192.168.1.7:7080/coregui/org.rhq.enterprise.gui.coregui.CoreGUI/sc/modules/ISC_Core.js@6) | |
at Unknown.isc_Class_completeCreation(http://192.168.1.7:7080/coregui/org.rhq.enterprise.gui.coregui.CoreGUI/sc/modules/ISC_Core.js@6) | |
at Unknown.isc_c_Class_create(http://192.168.1.7:7080/coregui/org.rhq.enterprise.gui.coregui.CoreGUI/sc/modules/ISC_Core.js@1790) | |
at Unknown.create_53(http://192.168.1.7:7080/coregui/org.rhq.enterprise.gui.coregui.CoreGUI/4076844B783EE5AA1E5455D5C6154183.cache.html@38) | |
at Unknown.$getOrCreateJsObj_0(http://192.168.1.7:7080/coregui/org.rhq.enterprise.gui.coregui.CoreGUI/4076844B783EE5AA1E5455D5C6154183.cache.html@25) | |
at Unknown.addMember(http://192.168.1.7:7080/coregui/org.rhq.enterprise.gui.coregui.CoreGUI/4076844B783EE5AA1E5455D5C6154183.cache.html@17) | |
at Unknown.$doOnDraw(http://192.168.1.7:7080/coregui/org.rhq.enterprise.gui.coregui.CoreGUI/4076844B783EE5AA1E5455D5C6154183.cache.html@28) 4076844B783EE5AA1E5455D5C6154183.cache.html:10434 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* RHQ Management Platform | |
* Copyright (C) 2005-2011 Red Hat, Inc. | |
* All rights reserved. | |
* | |
* This program is free software; you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation version 2 of the License. | |
* | |
* This program 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 General Public License | |
* along with this program; if not, write to the Free Software | |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
*/ | |
package org.rhq.enterprise.gui.coregui.client.components.table; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.LinkedHashMap; | |
import java.util.LinkedHashSet; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Set; | |
import com.google.gwt.user.client.Timer; | |
import com.smartgwt.client.data.Criteria; | |
import com.smartgwt.client.data.DSCallback; | |
import com.smartgwt.client.data.DSRequest; | |
import com.smartgwt.client.data.DSResponse; | |
import com.smartgwt.client.data.DataSourceField; | |
import com.smartgwt.client.data.Record; | |
import com.smartgwt.client.data.ResultSet; | |
import com.smartgwt.client.data.SortSpecifier; | |
import com.smartgwt.client.types.ListGridFieldType; | |
import com.smartgwt.client.types.Overflow; | |
import com.smartgwt.client.types.SelectionStyle; | |
import com.smartgwt.client.types.VerticalAlignment; | |
import com.smartgwt.client.util.BooleanCallback; | |
import com.smartgwt.client.util.SC; | |
import com.smartgwt.client.widgets.Canvas; | |
import com.smartgwt.client.widgets.HTMLFlow; | |
import com.smartgwt.client.widgets.IButton; | |
import com.smartgwt.client.widgets.Label; | |
import com.smartgwt.client.widgets.events.ClickEvent; | |
import com.smartgwt.client.widgets.events.ClickHandler; | |
import com.smartgwt.client.widgets.events.DoubleClickEvent; | |
import com.smartgwt.client.widgets.events.DoubleClickHandler; | |
import com.smartgwt.client.widgets.form.DynamicForm; | |
import com.smartgwt.client.widgets.form.fields.FormItem; | |
import com.smartgwt.client.widgets.form.fields.HiddenItem; | |
import com.smartgwt.client.widgets.form.fields.SelectItem; | |
import com.smartgwt.client.widgets.form.fields.TextItem; | |
import com.smartgwt.client.widgets.form.fields.events.ChangedEvent; | |
import com.smartgwt.client.widgets.form.fields.events.ChangedHandler; | |
import com.smartgwt.client.widgets.form.fields.events.KeyPressEvent; | |
import com.smartgwt.client.widgets.form.fields.events.KeyPressHandler; | |
import com.smartgwt.client.widgets.grid.ListGrid; | |
import com.smartgwt.client.widgets.grid.ListGridField; | |
import com.smartgwt.client.widgets.grid.events.DataArrivedEvent; | |
import com.smartgwt.client.widgets.grid.events.DataArrivedHandler; | |
import com.smartgwt.client.widgets.grid.events.SelectionChangedHandler; | |
import com.smartgwt.client.widgets.grid.events.SelectionEvent; | |
import com.smartgwt.client.widgets.layout.Layout; | |
import com.smartgwt.client.widgets.layout.LayoutSpacer; | |
import com.smartgwt.client.widgets.menu.IMenuButton; | |
import com.smartgwt.client.widgets.menu.Menu; | |
import com.smartgwt.client.widgets.menu.MenuItem; | |
import com.smartgwt.client.widgets.menu.events.MenuItemClickEvent; | |
import org.rhq.core.domain.search.SearchSubsystem; | |
import org.rhq.enterprise.gui.coregui.client.CoreGUI; | |
import org.rhq.enterprise.gui.coregui.client.InitializableView; | |
import org.rhq.enterprise.gui.coregui.client.RefreshableView; | |
import org.rhq.enterprise.gui.coregui.client.components.TitleBar; | |
import org.rhq.enterprise.gui.coregui.client.components.form.DateFilterItem; | |
import org.rhq.enterprise.gui.coregui.client.components.form.EnhancedSearchBarItem; | |
import org.rhq.enterprise.gui.coregui.client.util.CriteriaUtility; | |
import org.rhq.enterprise.gui.coregui.client.util.Log; | |
import org.rhq.enterprise.gui.coregui.client.util.RPCDataSource; | |
import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedHLayout; | |
import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedIButton; | |
import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedToolStrip; | |
import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedUtility; | |
import org.rhq.enterprise.gui.coregui.client.util.enhanced.EnhancedVLayout; | |
import org.rhq.enterprise.gui.coregui.client.util.message.Message; | |
/** | |
* A tabular view of set of data records from an {@link RPCDataSource}. | |
* | |
* WARNING! If you make _any_ changes to this class, no matter how seemingly | |
* trivial, you must get it peer reviewed. Send out your proposed changes | |
* to the dev mailing list and ask for comments. Any problems introduced to | |
* this class are magnified because it is used in so many UI views and problems | |
* are hard to detect due to the various ways it is used. | |
* | |
* @author Greg Hinkle | |
* @author Ian Springer | |
*/ | |
@SuppressWarnings("rawtypes") | |
public class Table<DS extends RPCDataSource> extends EnhancedHLayout implements RefreshableView, InitializableView { | |
private static final int DATA_PAGE_SIZE = 50; | |
protected static final String FIELD_ID = "id"; | |
protected static final String FIELD_NAME = "name"; | |
private EnhancedVLayout contents; | |
private HTMLFlow titleCanvas; | |
private EnhancedVLayout titleLayout; | |
private TitleBar titleBar; | |
private String titleIcon; | |
private TableFilter filterForm; | |
private ListGrid listGrid; | |
private Label tableInfo; | |
private List<String> headerIcons = new ArrayList<String>(); | |
private boolean showHeader = true; | |
private boolean showFooter = true; | |
private boolean showFooterRefresh = true; | |
private boolean showFilterForm = true; | |
private String titleString; | |
private Criteria initialCriteria; | |
private boolean initialCriteriaFixed = true; | |
private SortSpecifier[] sortSpecifiers; | |
private String[] excludedFieldNames; | |
private boolean autoFetchData; | |
private boolean flexRowDisplay = true; | |
private boolean hideSearchBar = false; | |
private String initialSearchBarSearchText = null; | |
private DS dataSource; | |
private DoubleClickHandler doubleClickHandler; | |
private List<TableActionInfo> tableActions = new ArrayList<TableActionInfo>(); | |
private boolean tableActionDisableOverride = false; | |
protected List<Canvas> extraWidgetsAboveFooter = new ArrayList<Canvas>(); | |
protected List<Canvas> extraWidgetsInMainFooter = new ArrayList<Canvas>(); | |
private EnhancedToolStrip footer; | |
private EnhancedToolStrip footerExtraWidgets; | |
private EnhancedIButton refreshButton; | |
private boolean initialized; | |
public Table() { | |
this(null, null, null, null, true); | |
} | |
public Table(String tableTitle) { | |
this(tableTitle, null, null, null, true); | |
} | |
public Table(String tableTitle, String icon) { | |
this(tableTitle, null, null, null, true); | |
setTitleIcon(icon); | |
} | |
public Table(String tableTitle, Criteria criteria, String icon) { | |
this(tableTitle, criteria, null, null, (criteria == null)); | |
setTitleIcon(icon); | |
} | |
public Table(String tableTitle, Criteria criteria) { | |
this(tableTitle, criteria, null, null, (criteria == null)); | |
} | |
public Table(String tableTitle, SortSpecifier[] sortSpecifiers) { | |
this(tableTitle, null, sortSpecifiers, null, true); | |
} | |
protected Table(String tableTitle, SortSpecifier[] sortSpecifiers, Criteria criteria) { | |
this(tableTitle, criteria, sortSpecifiers, null, (criteria == null)); | |
} | |
public Table(String tableTitle, boolean autoFetchData) { | |
this(tableTitle, null, null, null, autoFetchData); | |
} | |
public Table(String tableTitle, SortSpecifier[] sortSpecifiers, String[] excludedFieldNames) { | |
this(tableTitle, null, sortSpecifiers, excludedFieldNames, true); | |
} | |
public Table(String tableTitle, Criteria criteria, SortSpecifier[] sortSpecifiers, String[] excludedFieldNames) { | |
this(tableTitle, criteria, sortSpecifiers, excludedFieldNames, (criteria == null)); | |
} | |
public Table(String tableTitle, Criteria criteria, SortSpecifier[] sortSpecifiers, String[] excludedFieldNames, | |
boolean autoFetchData) { | |
super(); | |
if (criteria != null && autoFetchData) { | |
throw new IllegalArgumentException( | |
"Non-null initialCriteria and autoFetchData=true cannot be specified together, due to a bug in SmartGWT."); | |
} | |
setWidth100(); | |
setHeight100(); | |
//setOverflow(Overflow.HIDDEN); | |
this.titleString = tableTitle; | |
this.initialCriteria = criteria; | |
this.sortSpecifiers = sortSpecifiers; | |
this.excludedFieldNames = excludedFieldNames; | |
this.autoFetchData = autoFetchData; | |
} | |
/** | |
* If this returns true, then even if a {@link #getSearchSubsystem() search subsystem} | |
* is defined by the table class, the search bar will not be shown. | |
* | |
* @return true if the search bar is to be hidden (default is false) | |
*/ | |
public boolean getHideSearchBar() { | |
return this.hideSearchBar; | |
} | |
public void setHideSearchBar(boolean flag) { | |
this.hideSearchBar = flag; | |
} | |
public String getInitialSearchBarSearchText() { | |
return this.initialSearchBarSearchText; | |
} | |
public void setInitialSearchBarSearchText(String text) { | |
this.initialSearchBarSearchText = text; | |
} | |
public void setFlexRowDisplay(boolean flexRowDisplay) { | |
this.flexRowDisplay = flexRowDisplay; | |
} | |
/** | |
* Override Point: | |
* Override this method to use a customized layout. | |
* | |
* @return the Layout for all of the Table contents | |
* @see #configureTableContents(Layout) | |
*/ | |
protected EnhancedVLayout createTableContents() { | |
if (null == contents) { | |
contents = new EnhancedVLayout(); | |
} | |
return contents; | |
} | |
/** | |
* Override Point: | |
* Override this method to set Layout attributes that can be set at initialization time. By default | |
* the contents layout is: | |
* <pre> | |
* - set to 100% width and height | |
* - set to Overflow.AUTO | |
* </pre> | |
* | |
* @param contents | |
*/ | |
protected void configureTableContents(Layout contents) { | |
contents.setWidth100(); | |
contents.setHeight100(); | |
contents.setOverflow(Overflow.AUTO); | |
} | |
public EnhancedVLayout getTableContents() { | |
return contents; | |
} | |
/** | |
* Override Point: | |
* Override this method to set grid properties outside of those required by Table or set via Table's constructors. | |
* The default implementation: | |
* <pre> | |
* - sets to 100% width and height | |
* </pre> | |
* This is called from onInit() and guarantees grid not null. | |
* | |
* @param grid | |
*/ | |
protected void configureListGrid(ListGrid grid) { | |
listGrid.setWidth100(); | |
listGrid.setHeight100(); | |
listGrid.setLoadingDataMessage("${loadingImage} " + MSG.common_msg_loading()); | |
listGrid.setEmptyMessage(MSG.common_msg_noItemsToShow()); | |
} | |
@Override | |
protected void onInit() { | |
super.onInit(); | |
contents = createTableContents(); | |
configureTableContents(contents); | |
addMember(contents); | |
filterForm = new TableFilter(this); | |
// Table filters and search bar are currently mutually exclusive. | |
if (getSearchSubsystem() == null) { | |
configureTableFilters(); | |
} else { | |
if (!this.hideSearchBar) { | |
final EnhancedSearchBarItem searchFilter = new EnhancedSearchBarItem("search", getSearchSubsystem(), | |
getInitialSearchBarSearchText()); | |
setFilterFormItems(searchFilter); | |
} | |
} | |
listGrid = createListGrid(); | |
configureListGrid(listGrid); | |
listGrid.setAutoFetchData(autoFetchData); | |
if (initialCriteria != null) { | |
listGrid.setInitialCriteria(initialCriteria); | |
} | |
if (sortSpecifiers != null) { | |
listGrid.setInitialSort(sortSpecifiers); | |
} | |
listGrid.setAlternateRecordStyles(true); | |
listGrid.setResizeFieldsInRealTime(false); | |
listGrid.setSelectionType(getDefaultSelectionStyle()); | |
listGrid.setDataPageSize(DATA_PAGE_SIZE); // the default is 75 - lower it to speed up data loading | |
// Don't fetch more than 200 records for the sake of an attempt to group-by. | |
listGrid.setGroupByMaxRecords(200); // the default is 1000 | |
// Disable the group-by option in the column header context menu, since group-by requires the entire data set to | |
// by loaded on the client-side, which isn't practical for most of our list views, since they can contain | |
// thousands of records. | |
listGrid.setCanGroupBy(false); | |
if (flexRowDisplay) { | |
//listGrid.setAutoFitData(Autofit.HORIZONTAL); // do NOT set this - smartgwt appears to have a problem that causes it to eat CPU | |
listGrid.setWrapCells(true); | |
listGrid.setFixedRecordHeights(false); | |
} | |
// By default, SmartGWT will disable any rows that have a record named "enabled" with a value of false - setting | |
// these fields to a bogus field name will disable this behavior. Note, setting them to null does *not* disable | |
// the behavior. | |
listGrid.setRecordEnabledProperty("foobar"); | |
listGrid.setRecordEditProperty("foobar"); | |
// TODO: Uncomment the below line once we've upgraded to SmartGWT 2.3. | |
//listGrid.setRecordCanSelectProperty("foobar"); | |
DS dataSource = getDataSource(); | |
if (dataSource != null) { | |
dataSource.setDataPageSize(DATA_PAGE_SIZE); | |
listGrid.setDataSource(dataSource); | |
} | |
this.initialized = true; | |
} | |
@Override | |
public boolean isInitialized() { | |
return this.initialized; | |
} | |
protected SelectionStyle getDefaultSelectionStyle() { | |
return SelectionStyle.MULTIPLE; | |
} | |
// Table is an InitializableView. This onDraw() waits until we're sure we're initialized and then | |
// lays down the canvas. This gives subclasses a chance to perform initialization (including async calls) | |
// required to support the overrides (like configureTable()) they may have provided and that are called in | |
// doOnDraw(). | |
@Override | |
protected void onDraw() { | |
super.onDraw(); | |
if (isInitialized()) { | |
doOnDraw(); | |
} else { | |
new Timer() { | |
final long startTime = System.currentTimeMillis(); | |
public void run() { | |
if (isInitialized()) { | |
doOnDraw(); | |
cancel(); | |
} else { | |
// if after 10s we still aren't initialized just keep going, else try again | |
long elapsedMillis = System.currentTimeMillis() - startTime; | |
if (elapsedMillis < 10000L) { | |
schedule(100); // Reschedule the timer. | |
} else { | |
doOnDraw(); | |
cancel(); | |
} | |
} | |
} | |
}.run(); // fire the timer immediately | |
} | |
} | |
protected void doOnDraw() { | |
try { | |
// I'm not sure this is necessary as I'm not sure it's the case that draw()/onDraw() will get called | |
// multiple times. But if it did/does, this protects us by removing the current members before they | |
// get set below. Note that by having this here we *can not* add members in onInit, because they will | |
// immediately get removed. -jshaughn | |
for (Canvas child : contents.getMembers()) { | |
contents.removeChild(child); | |
} | |
// Title | |
this.titleCanvas = new HTMLFlow(); | |
updateTitleCanvas(this.titleString); | |
if (showHeader) { | |
// titleLayout not really needed now as TitleBar has a VLayout | |
titleLayout = new EnhancedVLayout(); | |
titleLayout.setAutoHeight(); | |
titleLayout.setAlign(VerticalAlignment.BOTTOM); | |
contents.addMember(titleLayout, 0); | |
} | |
if (filterForm.hasContent()) { | |
contents.addMember(filterForm); | |
} | |
// add the listGrid defined in onInit | |
contents.addMember(listGrid); | |
// Footer | |
// A second toolstrip that optionally appears before the main footer - it will contain extra widgets. | |
// This is hidden from view unless extra widgets are actually added to the table above the main footer. | |
this.footerExtraWidgets = new EnhancedToolStrip(); | |
footerExtraWidgets.setPadding(5); | |
footerExtraWidgets.setWidth100(); | |
footerExtraWidgets.setMembersMargin(15); | |
footerExtraWidgets.hide(); | |
contents.addMember(footerExtraWidgets); | |
this.footer = new EnhancedToolStrip(); | |
footer.setPadding(5); | |
footer.setWidth100(); | |
footer.setMembersMargin(15); | |
if (!showFooter) { | |
footer.hide(); | |
} | |
contents.addMember(footer); | |
// The ListGrid has been created and configured - now give subclasses a chance to configure the table. | |
configureTable(); | |
listGrid.addDoubleClickHandler(new DoubleClickHandler() { | |
@Override | |
public void onDoubleClick(DoubleClickEvent event) { | |
if (doubleClickHandler != null && !getTableActionDisableOverride()) { | |
doubleClickHandler.onDoubleClick(event); | |
} | |
} | |
}); | |
Label tableInfo = new Label(); | |
tableInfo.setWrap(false); | |
setTableInfo(tableInfo); | |
refreshRowCount(); | |
// NOTE: It is essential that we wait to hide any excluded fields until after super.onDraw() is called, since | |
// super.onDraw() is what actually adds the fields to the ListGrid (based on what fields are defined in | |
// the underlying datasource). | |
if (this.excludedFieldNames != null) { | |
for (String excludedFieldName : excludedFieldNames) { | |
this.listGrid.hideField(excludedFieldName); | |
} | |
} | |
if (showHeader) { | |
drawHeader(); | |
} | |
if (showFooter) { | |
drawFooter(); | |
} | |
if (!autoFetchData && (initialCriteria != null)) { | |
refresh(); | |
} | |
} catch (Exception e) { | |
CoreGUI.getErrorHandler().handleError(MSG.view_table_drawFail(this.toString()), e); | |
} | |
markForRedraw(); | |
} | |
private void refreshRowCount() { | |
Label tableInfo = getTableInfo(); | |
if (tableInfo != null) { | |
boolean lengthIsKnown = false; | |
if (listGrid != null) { | |
ResultSet results = listGrid.getResultSet(); | |
if (results != null) { | |
Boolean flag = results.lengthIsKnown(); | |
if (flag != null) { | |
lengthIsKnown = flag.booleanValue(); | |
} | |
} else { | |
lengthIsKnown = (listGrid.getDataSource() == null); // not bound by a datasource, assume we know | |
} | |
} | |
String contents; | |
if (lengthIsKnown) { | |
int totalRows = this.listGrid.getTotalRows(); | |
int selectedRows = this.listGrid.getSelectedRecords().length; | |
contents = MSG.view_table_totalRows(String.valueOf(totalRows), String.valueOf(selectedRows)); | |
} else { | |
contents = MSG.view_table_totalRowsUnknown(); | |
} | |
tableInfo.setContents(contents); | |
} | |
} | |
@Override | |
public void destroy() { | |
this.initialized = false; | |
// immediately null out the listGrid to stop async refresh requests from executing during the destroy | |
// logic. This happens in selenium testing or when a user navs away prior to the refresh. | |
this.listGrid = null; | |
EnhancedUtility.destroyMembers(createTableContents()); | |
super.destroy(); | |
} | |
private void drawHeader() { | |
// just use the first icon (not sure use case for multiple icons in title) | |
titleBar = new TitleBar(titleString); | |
if (titleIcon != null) { | |
titleBar.setIcon(titleIcon); | |
} | |
titleLayout.addMember(titleBar); | |
titleLayout.addMember(titleCanvas); | |
} | |
private void drawFooter() { | |
// populate the extraWidgets toolstrip | |
footerExtraWidgets.removeMembers(footerExtraWidgets.getMembers()); | |
if (!extraWidgetsAboveFooter.isEmpty()) { | |
for (Canvas extraWidgetCanvas : extraWidgetsAboveFooter) { | |
footerExtraWidgets.addMember(extraWidgetCanvas); | |
} | |
footerExtraWidgets.show(); | |
} | |
footer.removeMembers(footer.getMembers()); | |
for (final TableActionInfo tableAction : tableActions) { | |
if (null == tableAction.getValueMap()) { | |
// button action | |
IButton button = new EnhancedIButton(tableAction.getTitle()); | |
button.setDisabled(true); | |
button.setOverflow(Overflow.VISIBLE); | |
button.addClickHandler(new ClickHandler() { | |
public void onClick(ClickEvent clickEvent) { | |
disableAllFooterControls(); | |
if (tableAction.confirmMessage != null) { | |
String message = tableAction.confirmMessage.replaceAll("\\#", | |
String.valueOf(listGrid.getSelectedRecords().length)); | |
SC.ask(message, new BooleanCallback() { | |
public void execute(Boolean confirmed) { | |
if (confirmed) { | |
tableAction.action.executeAction(listGrid.getSelectedRecords(), null); | |
} else { | |
refreshTableInfo(); | |
} | |
} | |
}); | |
} else { | |
tableAction.action.executeAction(listGrid.getSelectedRecords(), null); | |
} | |
} | |
}); | |
tableAction.actionCanvas = button; | |
footer.addMember(button); | |
} else { | |
// menu action | |
Menu menu = new Menu(); | |
final Map<String, Object> menuEntries = tableAction.getValueMap(); | |
for (final String key : menuEntries.keySet()) { | |
MenuItem item = new MenuItem(key); | |
item.addClickHandler(new com.smartgwt.client.widgets.menu.events.ClickHandler() { | |
public void onClick(MenuItemClickEvent event) { | |
disableAllFooterControls(); | |
tableAction.getAction().executeAction(listGrid.getSelectedRecords(), menuEntries.get(key)); | |
} | |
}); | |
menu.addItem(item); | |
} | |
IMenuButton menuButton = new IMenuButton(tableAction.getTitle()); | |
menuButton.setMenu(menu); | |
menuButton.setDisabled(true); | |
menuButton.setAutoFit(true); // this makes it pretty tight, but maybe better than the default, which is pretty wide | |
menuButton.setOverflow(Overflow.VISIBLE); | |
menuButton.setShowMenuBelow(false); | |
tableAction.actionCanvas = menuButton; | |
footer.addMember(menuButton); | |
} | |
} | |
for (Canvas extraWidgetCanvas : extraWidgetsInMainFooter) { | |
footer.addMember(extraWidgetCanvas); | |
} | |
footer.addMember(new LayoutSpacer()); | |
if (isShowFooterRefresh()) { | |
this.refreshButton = new EnhancedIButton(MSG.common_button_refresh()); | |
refreshButton.addClickHandler(new ClickHandler() { | |
public void onClick(ClickEvent clickEvent) { | |
disableAllFooterControls(); | |
refresh(); | |
} | |
}); | |
footer.addMember(refreshButton); | |
} | |
footer.addMember(tableInfo); | |
// Manages enable/disable buttons for the grid | |
listGrid.addSelectionChangedHandler(new SelectionChangedHandler() { | |
public void onSelectionChanged(SelectionEvent selectionEvent) { | |
refreshTableInfo(); | |
} | |
}); | |
listGrid.addDataArrivedHandler(new DataArrivedHandler() { | |
public void onDataArrived(DataArrivedEvent dataArrivedEvent) { | |
if (null != listGrid) { | |
refreshTableInfo(); | |
} | |
} | |
}); | |
// Ensure buttons are initially set correctly. | |
refreshTableInfo(); | |
} | |
public void disableAllFooterControls() { | |
for (TableActionInfo tableAction : tableActions) { | |
tableAction.actionCanvas.disable(); | |
} | |
for (Canvas extraWidget : extraWidgetsAboveFooter) { | |
extraWidget.disable(); | |
} | |
for (Canvas extraWidget : extraWidgetsInMainFooter) { | |
extraWidget.disable(); | |
} | |
if (isShowFooterRefresh() && this.refreshButton != null) { | |
this.refreshButton.disable(); | |
} | |
} | |
/** | |
* Subclasses can use this as a chance to configure the list grid after it has been | |
* created but before it has been drawn to the DOM. This is also the proper place to add table | |
* actions so that they're rendered in the footer. | |
*/ | |
protected void configureTable() { | |
return; | |
} | |
public void setFilterFormItems(FormItem... formItems) { | |
setShowHeader(false); | |
this.filterForm.setItems(formItems); | |
this.filterForm.setNumCols(4); | |
} | |
/** | |
* Overriding components can use this as a chance to add {@link FormItem}s which will filter | |
* the table that displays their data. | |
*/ | |
protected void configureTableFilters() { | |
} | |
public String getTitleString() { | |
return this.titleString; | |
} | |
/** | |
* Set the Table's title string. This will subsequently call {@link #updateTitleCanvas(String)}. | |
* @param titleString | |
*/ | |
public void setTitleString(String titleString) { | |
this.titleString = titleString; | |
if (this.titleCanvas != null) { | |
updateTitleCanvas(titleString); | |
} | |
} | |
public void setTitleIcon(String titleIcon) { | |
this.titleIcon = titleIcon; | |
} | |
public Canvas getTitleCanvas() { | |
return this.titleCanvas; | |
} | |
/** | |
* To set the Table's title, call {@link #setTitleString(String)}. This is primarily declared for purposes of | |
* override. | |
* @param titleString | |
*/ | |
public void updateTitleCanvas(String titleString) { | |
if (titleString == null) { | |
titleString = ""; | |
} | |
titleCanvas.markForRedraw(); | |
} | |
public boolean isShowHeader() { | |
return showHeader; | |
} | |
public void setShowHeader(boolean showHeader) { | |
this.showHeader = showHeader; | |
} | |
public boolean isShowFooter() { | |
return showFooter; | |
} | |
public void setShowFooter(boolean showFooter) { | |
this.showFooter = showFooter; | |
} | |
/** | |
* Refreshes the list grid's data, filtered by any fixed criteria, as well as any user-specified filters. | |
*/ | |
public void refresh() { | |
refresh(false); | |
} | |
/** | |
* Refreshes the list grid's data, filtered by any fixed criteria, as well as any user-specified filters. | |
* <p/> | |
* If resetPaging is true, resets paging on the grid prior to refreshing the data. resetPaging=true should be | |
* specified when refreshing right after records have been deleted, since the current paging settings may have | |
* become invalid due to the decrease in the total data set size. | |
*/ | |
public void refresh(boolean resetPaging) { | |
if (!isInitialized()) { | |
return; | |
} | |
final ListGrid listGrid = getListGrid(); | |
Criteria criteria = getCurrentCriteria(); | |
Log.debug(getClass().getName() + ".refresh() using criteria [" + CriteriaUtility.toString(criteria) + "]..."); | |
listGrid.setCriteria(criteria); | |
if (resetPaging) { | |
listGrid.scrollToRow(0); | |
} | |
// Only call invalidateCache() and fetchData() if the ListGrid is backed by a DataSource. | |
if (listGrid.getDataSource() != null) { | |
// Invalidate the cached records - if listGrid.getAutoFetchData() is true, this will cause the ListGrid to | |
// automatically call fetchData(). | |
listGrid.invalidateCache(); | |
if (!this.autoFetchData && (initialCriteria != null)) { | |
listGrid.fetchData(criteria); | |
} | |
} | |
listGrid.markForRedraw(); | |
} | |
protected Criteria getInitialCriteria() { | |
return initialCriteria; | |
} | |
/** | |
* Can be called in constructor to reset initialCriteria. | |
* @param initialCriteria | |
*/ | |
protected void setInitialCriteria(Criteria initialCriteria) { | |
this.initialCriteria = initialCriteria; | |
} | |
protected boolean isInitialCriteriaFixed() { | |
return initialCriteriaFixed; | |
} | |
/** | |
* @param initialCriteriaFixed If true initialCriteria is applied to all subsequent fetch criteria. If false | |
* initialCriteria is used only for the initial autoFetch. Irrelevant if autoFetch is false. Default is true. | |
*/ | |
protected void setInitialCriteriaFixed(boolean initialCriteriaFixed) { | |
this.initialCriteriaFixed = initialCriteriaFixed; | |
} | |
/** | |
* | |
* @return the current criteria, which includes any fixed criteria, as well as any user-specified filters; may be | |
* null if there are no fixed criteria or user-specified filters | |
*/ | |
protected Criteria getCurrentCriteria() { | |
Criteria criteria = null; | |
// If this table has a filter form (table filters OR search bar), | |
// we need to refresh it as per the filtering, combined with any fixed criteria. | |
if (this.filterForm != null && this.filterForm.hasContent()) { | |
criteria = this.filterForm.getValuesAsCriteria(); | |
if (this.initialCriteriaFixed) { | |
if (criteria != null) { | |
if (this.initialCriteria != null) { | |
// There is fixed criteria - add it to the filter form criteria. | |
CriteriaUtility.addCriteria(criteria, this.initialCriteria); | |
} | |
} else { | |
criteria = this.initialCriteria; | |
} | |
} | |
} else if (this.initialCriteriaFixed) { | |
criteria = this.initialCriteria; | |
} | |
return criteria; | |
} | |
public DS getDataSource() { | |
return dataSource; | |
} | |
public void setDataSource(DS dataSource) { | |
this.dataSource = dataSource; | |
} | |
/** | |
* Creates this Table's list grid (called by onInit()). Subclasses can override this if they require a custom | |
* subclass of ListGrid. | |
* | |
* @return this Table's list grid (must be an instance of ListGrid) | |
*/ | |
protected ListGrid createListGrid() { | |
return new ListGrid(); | |
} | |
/** | |
* Returns this Table's list grid - may be null if the Table has not yet been {@link #isInitialized() initialized}. | |
* Subclasses should *not* override this method. | |
* | |
* @return this Table's list grid - may be null if the Table has not yet been {@link #isInitialized() initialized} | |
*/ | |
public ListGrid getListGrid() { | |
return listGrid; | |
} | |
/** | |
* Wraps ListGrid.setFields(...) but takes care of "id" field display handling. Equivalent to calling: | |
* <pre> | |
* setFields( false, fields ); | |
* </pre> | |
* | |
* @param fields the fields | |
*/ | |
public void setListGridFields(ListGridField... fields) { | |
setListGridFields(false, fields); | |
} | |
/** | |
* Wraps ListGrid.setFields(...) but takes care of "id" field display handling. | |
* | |
* @param forceIdField if true, and "id" is a defined field, then display it. If false, it is displayed | |
* only in debug mode. | |
* @param fields the fields | |
*/ | |
public void setListGridFields(boolean forceIdField, ListGridField... fields) { | |
if (getDataSource() == null) { | |
throw new IllegalStateException("setListGridFields() called on " + getClass().getName() | |
+ ", which is not a DataSource-backed Table."); | |
} | |
String[] dataSourceFieldNames = getDataSource().getFieldNames(); | |
Set<String> dataSourceFieldNamesSet = new LinkedHashSet<String>(); | |
dataSourceFieldNamesSet.addAll(Arrays.asList(dataSourceFieldNames)); | |
Map<String, ListGridField> listGridFieldsMap = new LinkedHashMap<String, ListGridField>(); | |
for (ListGridField listGridField : fields) { | |
listGridFieldsMap.put(listGridField.getName(), listGridField); | |
} | |
dataSourceFieldNamesSet.removeAll(listGridFieldsMap.keySet()); | |
DataSourceField dataSourceIdField = getDataSource().getField(FIELD_ID); | |
boolean hideIdField = (!CoreGUI.isDebugMode() && !forceIdField); | |
if (dataSourceIdField != null && hideIdField) { | |
// setHidden() will not work on the DataSource field - use the listGrid.hideField() instead. | |
this.listGrid.hideField(FIELD_ID); | |
} | |
ListGridField listGridIdField = listGridFieldsMap.get(FIELD_ID); | |
if (listGridIdField != null) { | |
listGridIdField.setHidden(hideIdField); | |
} | |
if (!dataSourceFieldNamesSet.isEmpty()) { | |
ListGridField[] newFields = new ListGridField[fields.length + dataSourceFieldNamesSet.size()]; | |
int destIndex = 0; | |
if (dataSourceFieldNamesSet.contains(FIELD_ID)) { | |
String datasourceFieldTitle = getDataSource().getField(FIELD_ID).getTitle(); | |
String listGridFieldTitle = (datasourceFieldTitle != null) ? datasourceFieldTitle : MSG | |
.common_title_id(); | |
listGridIdField = new ListGridField(FIELD_ID, listGridFieldTitle, 55); | |
// Override the DataSource id field metadata for consistent display across all Tables. | |
listGridIdField.setType(ListGridFieldType.INTEGER); | |
listGridIdField.setCanEdit(false); | |
listGridIdField.setHidden(hideIdField); | |
newFields[destIndex++] = listGridIdField; | |
dataSourceFieldNamesSet.remove(FIELD_ID); | |
} | |
System.arraycopy(fields, 0, newFields, destIndex, fields.length); | |
destIndex += fields.length; | |
for (String dataSourceFieldName : dataSourceFieldNamesSet) { | |
DataSourceField dataSourceField = getDataSource().getField(dataSourceFieldName); | |
ListGridField listGridField = new ListGridField(dataSourceField.getName()); | |
this.listGrid.hideField(dataSourceFieldName); | |
listGridField.setHidden(true); | |
newFields[destIndex++] = listGridField; | |
} | |
this.listGrid.setFields(newFields); | |
} else { | |
this.listGrid.setFields(fields); | |
} | |
} | |
public void setTitleBar(TitleBar titleBar1) { | |
this.titleBar = titleBar1; | |
} | |
/** | |
* Note: To prevent user action while a current action completes, all widgets on the footer are disabled | |
* when footer actions take place, typically a button click. It is up to the action to ensure the page | |
* (via refresh() or CoreGUI.refresh()) or footer (via refreshTableActions) are refreshed as needed at action | |
* completion. Failure to do so may leave the widgets disabled. | |
*/ | |
public void addTableAction(String title, TableAction tableAction) { | |
this.addTableAction(title, null, null, tableAction); | |
} | |
/** | |
* Note: To prevent user action while a current action completes, all widgets on the footer are disabled | |
* when footer actions take place, typically a button click. It is up to the action to ensure the page | |
* (via refresh() or CoreGUI.refresh()) or footer (via refreshTableActions) are refreshed as needed at action | |
* completion. Failure to do so may leave the widgets disabled. | |
*/ | |
public void addTableAction(String title, String confirmation, TableAction tableAction) { | |
this.addTableAction(title, confirmation, null, tableAction); | |
} | |
/** | |
* Note: To prevent user action while a current action completes, all widgets on the footer are disabled | |
* when footer actions take place, typically a button click. It is up to the action to ensure the page | |
* (via refresh() or CoreGUI.refresh()) or footer (via refreshTableActions) are refreshed as needed at action | |
* completion. Failure to do so may leave the widgets disabled. | |
*/ | |
public void addTableAction(String title, String confirmation, Map<String, Object> valueMap, TableAction tableAction) { | |
TableActionInfo info = new TableActionInfo(title, confirmation, valueMap, tableAction); | |
tableActions.add(info); | |
} | |
/** | |
* Updates the list of table's associated actions <code>tableActions</code>. | |
* It automatically updates the gui by calling <code>drawFooter()</code> provided the table has been initialized. | |
* | |
* Note: To prevent user action while a current action completes, all widgets on the footer are disabled | |
* when footer actions take place, typically a button click. It is up to the action to ensure the page | |
* (via refresh() or CoreGUI.refresh()) or footer (via refreshTableActions) are refreshed as needed at action | |
* completion. Failure to do so may leave the widgets disabled. | |
* | |
* @param title the title of a modified action | |
* @param valueMap the map containing the tuples with name of a select item and <code>actionValue</code> which is | |
* then passed to <code>tableAction.executeAction()</code>; use the <code>LinkedHashMap</code> if you want to | |
* preserve the order of map items | |
* @param tableAction the tableAction object (on this object the <code>executeAction()</code> is actually invoked) | |
*/ | |
public void updateTableAction(String title, Map<String, Object> valueMap, TableAction tableAction) { | |
if (title == null) { | |
return; | |
} | |
for (TableActionInfo info : tableActions) { | |
if (title.equals(info.getTitle())) { | |
if (valueMap != null) | |
info.setValueMap(valueMap); | |
if (tableAction != null) | |
info.setAction(tableAction); | |
// the action listeners have to be re-added | |
if (isInitialized()) | |
drawFooter(); | |
break; | |
} | |
} | |
} | |
public void setListGridDoubleClickHandler(DoubleClickHandler handler) { | |
doubleClickHandler = handler; | |
} | |
/** | |
* Adds extra widgets to the bottom of the table view. | |
* <br/><br/> | |
* Note: To prevent user action while a current action completes, all widgets on the footer are disabled | |
* when footer actions take place, typically a button click. It is up to the action to ensure the page | |
* (via refresh() or CoreGUI.refresh()) or footer (via refreshTableActions) are refreshed as needed at action | |
* completion. Failure to do so may leave the widgets disabled. | |
* | |
* @param widget the new widget to add to the table view | |
* @param aboveFooter if true, the widget will be placed in a second toolstrip just above the main footer. | |
* if false, the widget will be placed in the main footer toolstrip itself. This is | |
* useful if the widget is really big and won't fit in the main footer along with the | |
* rest of the main footer members. | |
*/ | |
public void addExtraWidget(Canvas widget, boolean aboveFooter) { | |
if (aboveFooter) { | |
this.extraWidgetsAboveFooter.add(widget); | |
} else { | |
this.extraWidgetsInMainFooter.add(widget); | |
} | |
} | |
public void setHeaderIcon(String headerIcon) { | |
if (this.headerIcons.size() > 0) { | |
this.headerIcons.clear(); | |
} | |
addHeaderIcon(headerIcon); | |
} | |
public void addHeaderIcon(String headerIcon) { | |
this.headerIcons.add(headerIcon); | |
} | |
/** | |
* By default, all table actions have buttons that are enabled or | |
* disabled based on if and how many rows are selected. There are | |
* times when you don't want the user to be able to press table action | |
* buttons regardless of which rows are selected. This method let's | |
* you set this override-disable flag. | |
* | |
* Note: this also effects the double-click handler - if this disable override | |
* is on, the double-click handler is not called. | |
* | |
* @param disabled if true, all table action buttons will be disabled | |
* if false, table action buttons will be enabled based on their predefined | |
* selection enablement rule. | |
*/ | |
public void setTableActionDisableOverride(boolean disabled) { | |
this.tableActionDisableOverride = disabled; | |
refreshTableInfo(); | |
} | |
public boolean getTableActionDisableOverride() { | |
return this.tableActionDisableOverride; | |
} | |
public void refreshTableInfo() { | |
if (this.showFooter && (this.listGrid != null)) { | |
if (this.tableActionDisableOverride) { | |
this.listGrid.setSelectionType(SelectionStyle.NONE); | |
} else { | |
this.listGrid.setSelectionType(getDefaultSelectionStyle()); | |
} | |
//int selectionCount = this.listGrid.getSelectedRecords().length; | |
for (TableActionInfo tableAction : this.tableActions) { | |
if (tableAction.actionCanvas != null) { // if null, we haven't initialized our buttons yet, so skip this | |
boolean enabled = (!this.tableActionDisableOverride && tableAction.action.isEnabled(this.listGrid | |
.getSelectedRecords())); | |
tableAction.actionCanvas.setDisabled(!enabled); | |
} | |
} | |
for (Canvas extraWidget : this.extraWidgetsAboveFooter) { | |
extraWidget.enable(); | |
if (extraWidget instanceof TableWidget) { | |
((TableWidget) extraWidget).refresh(this.listGrid); | |
} | |
} | |
for (Canvas extraWidget : this.extraWidgetsInMainFooter) { | |
extraWidget.enable(); | |
if (extraWidget instanceof TableWidget) { | |
((TableWidget) extraWidget).refresh(this.listGrid); | |
} | |
} | |
refreshRowCount(); | |
if (isShowFooterRefresh() && this.refreshButton != null) { | |
this.refreshButton.enable(); | |
} | |
} | |
} | |
protected void deleteSelectedRecords() { | |
deleteSelectedRecords(null); | |
} | |
protected void deleteSelectedRecords(DSRequest requestProperties) { | |
ListGrid listGrid = getListGrid(); | |
final int selectedRecordCount = listGrid.getSelectedRecords().length; | |
final List<String> deletedRecordNames = new ArrayList<String>(selectedRecordCount); | |
listGrid.removeSelectedData(new DSCallback() { | |
public void execute(DSResponse response, Object rawData, DSRequest request) { | |
if (response.getStatus() == DSResponse.STATUS_SUCCESS) { | |
Record[] deletedRecords = response.getData(); | |
for (Record deletedRecord : deletedRecords) { | |
String name = deletedRecord.getAttribute(getTitleFieldName()); | |
deletedRecordNames.add(name); | |
} | |
if (deletedRecordNames.size() == selectedRecordCount) { | |
// all selected schedules were successfully deleted. | |
String deletedMessage = getDeletedMessage(deletedRecordNames.size()); | |
String deletedMessageDetail = deletedMessage + ": [" + deletedRecordNames.toString() + "]"; | |
Message message = new Message(deletedMessage, deletedMessageDetail); | |
CoreGUI.getMessageCenter().notify(message); | |
refresh(); | |
} | |
} | |
// TODO: Print error messages for failures or partial failures. | |
} | |
}, requestProperties); | |
} | |
protected String getTitleFieldName() { | |
return FIELD_NAME; | |
} | |
protected String getDeletedMessage(int numDeleted) { | |
String num = String.valueOf(numDeleted); | |
String thing = (1 == numDeleted) ? MSG.common_label_item() : MSG.common_label_items(); | |
return MSG.common_msg_deleted(num, thing); | |
} | |
protected String getDeleteConfirmMessage() { | |
return MSG.common_msg_deleteConfirm(MSG.common_label_items()); | |
} | |
protected void hideField(ListGridField field) { | |
getListGrid().hideField(field.getName()); | |
field.setHidden(true); | |
} | |
// -------------- Inner utility classes ------------- // | |
/** | |
* A subclass of SmartGWT's DynamicForm widget that provides a more convenient interface for filtering a | |
* {@link Table} of results. | |
* | |
* @author Joseph Marques | |
*/ | |
private static class TableFilter extends DynamicForm implements KeyPressHandler, ChangedHandler { | |
private Table<?> table; | |
private EnhancedSearchBarItem searchBarItem; | |
private HiddenItem hiddenItem; | |
public TableFilter(Table<?> table) { | |
super(); | |
setWidth100(); | |
setPadding(5); | |
this.table = table; | |
} | |
@Override | |
public void setItems(FormItem... items) { | |
for (FormItem nextFormItem : items) { | |
nextFormItem.setWrapTitle(false); | |
nextFormItem.setWidth(300); // wider than default | |
if (nextFormItem instanceof TextItem) { | |
nextFormItem.addKeyPressHandler(this); | |
} else if (nextFormItem instanceof SelectItem) { | |
nextFormItem.addChangedHandler(this); | |
} else if (nextFormItem instanceof DateFilterItem) { | |
nextFormItem.addChangedHandler(this); | |
} else if (nextFormItem instanceof EnhancedSearchBarItem) { | |
searchBarItem = (EnhancedSearchBarItem) nextFormItem; | |
searchBarItem.getSearchBar().getSearchTextItem().addKeyPressHandler(this); | |
String name = searchBarItem.getName(); | |
// postfix the name of the item so it is not processed by the filters and that the | |
// hidden item is used instead. | |
searchBarItem.setName(name + "_hidden"); | |
hiddenItem = new HiddenItem(name); | |
hiddenItem.setValue(searchBarItem.getSearchBar().getSearchTextItem().getValueAsString()); | |
} | |
} | |
if (hiddenItem != null) { | |
Log.debug("Found hidden items"); | |
// Add the hidden item if it exists | |
FormItem[] tmpItems = new FormItem[items.length + 1]; | |
System.arraycopy(items, 0, tmpItems, 0, items.length); | |
tmpItems[items.length] = hiddenItem; | |
items = tmpItems; | |
} | |
for (FormItem item : items) { | |
Log.debug(" ******** Form Items sent: " + item.getName() + ": " + item.getValue()); | |
} | |
super.setItems(items); | |
} | |
private void fetchFilteredTableData() { | |
table.refresh(); | |
} | |
@Override | |
public void onKeyPress(KeyPressEvent event) { | |
if (event.getKeyName().equals("Enter")) { | |
Log.debug("Table.TableFilter Pressed Enter key"); | |
if (null != searchBarItem) { | |
if (searchBarItem.getSearchBar().isFilterEnabled()) { | |
TextItem searchTextItem = searchBarItem.getSearchBar().getSearchTextItem(); | |
String searchBarValue = searchTextItem.getValueAsString(); | |
String hiddenValue = (String) hiddenItem.getValue(); | |
Log.debug("Table.TableFilter searchBarValue :" + searchBarValue + ", hiddenValue" + hiddenValue); | |
// Only send a fetch request if the user actually changed the search expression. | |
if (!equals(searchBarValue, hiddenValue)) { | |
hiddenItem.setValue(searchBarValue); | |
Log.debug("Table.TableFilter fetchFilteredTableData"); | |
fetchFilteredTableData(); | |
} | |
} | |
} else { | |
fetchFilteredTableData(); | |
} | |
} | |
} | |
@Override | |
public void onChanged(ChangedEvent event) { | |
fetchFilteredTableData(); | |
} | |
public boolean hasContent() { | |
return super.getFields().length != 0; | |
} | |
private static boolean equals(String string1, String string2) { | |
if (string1 == null) { | |
return (string2 == null); | |
} else { | |
return (string1.equals(string2)); | |
} | |
} | |
} | |
public static class TableActionInfo { | |
private String title; | |
private String confirmMessage; | |
private Map<String, Object> valueMap; | |
private TableAction action; | |
private Canvas actionCanvas; | |
protected TableActionInfo(String title, String confirmMessage, Map<String, Object> valueMap, TableAction action) { | |
this.title = title; | |
this.confirmMessage = confirmMessage; | |
this.valueMap = valueMap; | |
this.action = action; | |
} | |
public String getTitle() { | |
return title; | |
} | |
public String getConfirmMessage() { | |
return confirmMessage; | |
} | |
public Map<String, Object> getValueMap() { | |
return valueMap; | |
} | |
public void setValueMap(Map<String, Object> valueMap) { | |
this.valueMap = valueMap; | |
} | |
public Canvas getActionCanvas() { | |
return actionCanvas; | |
} | |
public void setActionCanvas(Canvas actionCanvas) { | |
this.actionCanvas = actionCanvas; | |
} | |
public TableAction getAction() { | |
return action; | |
} | |
public void setAction(TableAction action) { | |
this.action = action; | |
} | |
} | |
public boolean isShowFooterRefresh() { | |
return showFooterRefresh; | |
} | |
public void setShowFooterRefresh(boolean showFooterRefresh) { | |
this.showFooterRefresh = showFooterRefresh; | |
} | |
public Label getTableInfo() { | |
return tableInfo; | |
} | |
public void setTableInfo(Label tableInfo) { | |
this.tableInfo = tableInfo; | |
} | |
public boolean isShowFilterForm() { | |
return showFilterForm; | |
} | |
public void setShowFilterForm(boolean showFilterForm) { | |
this.showFilterForm = showFilterForm; | |
} | |
/* | |
* By default, no search bar is shown above this table. if this table represents a subsystem that is capable | |
* of search, return the specific object here. | |
*/ | |
protected SearchSubsystem getSearchSubsystem() { | |
return null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment