Java tutorial
/* * License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt */ package edu.caltech.ipac.firefly.ui.table; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; import com.google.gwt.dom.client.Style; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.DoubleClickHandler; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyDownEvent; import com.google.gwt.event.dom.client.KeyDownHandler; import com.google.gwt.event.dom.client.MouseOutEvent; import com.google.gwt.event.dom.client.MouseOutHandler; import com.google.gwt.event.dom.client.MouseOverEvent; import com.google.gwt.event.dom.client.MouseOverHandler; import com.google.gwt.gen2.table.client.ColumnDefinition; import com.google.gwt.gen2.table.client.FixedWidthGrid; import com.google.gwt.gen2.table.client.ScrollTable; import com.google.gwt.gen2.table.client.SortableGrid; import com.google.gwt.gen2.table.client.TableModel; import com.google.gwt.gen2.table.client.TableModelHelper; import com.google.gwt.gen2.table.event.client.PageChangeEvent; import com.google.gwt.gen2.table.event.client.PageChangeHandler; import com.google.gwt.gen2.table.event.client.PageCountChangeEvent; import com.google.gwt.gen2.table.event.client.PageCountChangeHandler; import com.google.gwt.gen2.table.event.client.PageLoadEvent; import com.google.gwt.gen2.table.event.client.PageLoadHandler; import com.google.gwt.gen2.table.event.client.PagingFailureEvent; import com.google.gwt.gen2.table.event.client.PagingFailureHandler; import com.google.gwt.gen2.table.event.client.RowSelectionEvent; import com.google.gwt.gen2.table.event.client.RowSelectionHandler; import com.google.gwt.gen2.table.event.client.TableEvent; import com.google.gwt.gen2.table.override.client.HTMLTable; import com.google.gwt.i18n.client.NumberFormat; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.DeferredCommand; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.rpc.StatusCodeException; import com.google.gwt.user.client.ui.AbsolutePanel; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.DeckPanel; import com.google.gwt.user.client.ui.DockLayoutPanel; import com.google.gwt.user.client.ui.FocusPanel; import com.google.gwt.user.client.ui.FocusWidget; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HasText; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.ProvidesResize; import com.google.gwt.user.client.ui.RequiresResize; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import edu.caltech.ipac.firefly.core.Application; import edu.caltech.ipac.firefly.core.GeneralCommand; import edu.caltech.ipac.firefly.core.HelpManager; import edu.caltech.ipac.firefly.core.RPCException; import edu.caltech.ipac.firefly.core.layout.LayoutManager; import edu.caltech.ipac.firefly.data.DownloadRequest; import edu.caltech.ipac.firefly.data.Request; import edu.caltech.ipac.firefly.data.SortInfo; import edu.caltech.ipac.firefly.data.TableServerRequest; import edu.caltech.ipac.firefly.data.table.DataSet; import edu.caltech.ipac.firefly.data.table.MetaConst; import edu.caltech.ipac.firefly.data.table.TableData; import edu.caltech.ipac.firefly.data.table.TableDataView; import edu.caltech.ipac.firefly.data.table.TableMeta; import edu.caltech.ipac.firefly.fftools.FFToolEnv; import edu.caltech.ipac.firefly.resbundle.images.TableImages; import edu.caltech.ipac.firefly.resbundle.images.VisIconCreator; import edu.caltech.ipac.firefly.ui.BadgeButton; import edu.caltech.ipac.firefly.ui.Component; import edu.caltech.ipac.firefly.ui.GwtUtil; import edu.caltech.ipac.firefly.ui.PopoutToolbar; import edu.caltech.ipac.firefly.ui.PopupPane; import edu.caltech.ipac.firefly.ui.PopupUtil; import edu.caltech.ipac.firefly.ui.StatefulWidget; import edu.caltech.ipac.firefly.ui.VisibleListener; import edu.caltech.ipac.firefly.ui.creator.XYPlotViewCreator; import edu.caltech.ipac.firefly.ui.panels.BackButton; import edu.caltech.ipac.firefly.util.BrowserUtil; import edu.caltech.ipac.firefly.util.Constants; import edu.caltech.ipac.firefly.util.PropertyChangeEvent; import edu.caltech.ipac.firefly.util.PropertyChangeListener; import edu.caltech.ipac.firefly.util.event.Name; import edu.caltech.ipac.firefly.util.event.WebEvent; import edu.caltech.ipac.firefly.util.event.WebEventListener; import edu.caltech.ipac.firefly.util.event.WebEventManager; import edu.caltech.ipac.firefly.visualize.graph.XYPlotWidget; import edu.caltech.ipac.util.CollectionUtil; import edu.caltech.ipac.util.StringUtils; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Set; /** * Date: Feb 10, 2009 * * @author lo * @version $Id: TablePanel.java,v 1.149 2012/12/14 22:15:15 loi Exp $ */ public class TablePanel extends Component implements StatefulWidget, FilterToggle.FilterToggleSupport, RequiresResize, ProvidesResize { private static final String HIGHLIGHTED_ROW_IDX = "TP_HLIdx"; private static int maxRowLimit = Application.getInstance().getProperties() .getIntProperty("SelectableTablePanel.max.row.Limit", 100000); // private static int maxRowLimit = Constants.MAX_ROWS_SUPPORTED; private static final String TOO_LARGE_MSG = "Sorting is disabled on table with more than " + NumberFormat.getFormat("#,##0").format(maxRowLimit) + " rows."; private static final HTML FEATURE_ONLY_TABLE = new HTML( "<i><font color='red'>This feature is only available in Table View</font></i>"); private static final HTML TOO_LARGE = new HTML("<i><font color='red'>" + TOO_LARGE_MSG + "</font></i>"); private static final HTML NOT_LOADED = new HTML("<i><font color='red'>This function is not available <br> " + "until the table is fully loaded.</font></i>"); public static final Name ON_DATA_LOAD = new Name("onDataLoad", "After new data is loaded."); public static final Name ON_PAGE_LOAD = new Name("onPageLoad", "After a page is loaded."); public static final Name ON_PAGE_CHANGE = new Name("onPageChange", "Page change; before a new page is loaded."); public static final Name ON_PAGE_ERROR = new Name("onPageError", "Page load error."); public static final Name ON_PAGECOUNT_CHANGE = new Name("onPageCountChange", "The number of pages changed."); public static final Name ON_ROWSELECT_CHANGE = new Name("onRowSelectChange", "After a row is selected. Checkbox checked."); public static final Name ON_ROWHIGHLIGHT_CHANGE = new Name("onRowHighlightChange", "After a row is highlighted with a click. Row changes color."); public static final Name ON_VIEW_CHANGE = new Name("onViewChange", "After a view switch"); public static final Name ON_STATUS_UPDATE = new Name("onStatusUpdate", "Called when table's status is updated"); private static final int TOOLBAR_SIZE = 30; private List<View> views = new ArrayList<View>(); private List<View> activeViews = new ArrayList<View>(); private int maskDelayMillSec = 200; private boolean onlyMaskWhenUncovered = true; private String stateId = "TPL"; private String name; private String shortDesc; private HTML titleHolder; private DeckPanel viewDeck = new DeckPanel(); private DockLayoutPanel mainPanel = new DockLayoutPanel(Style.Unit.PX); private BasicPagingTable table; private PagingToolbar pagingBar; private HorizontalPanel centerToolbar; private HorizontalPanel rightToolbar; private HorizontalPanel leftToolbar; private HorizontalPanel toolbarWrapper; // private Loader<TableDataView> loader; private DataSetTableModel dataModel; // private TableDataView dataset; private boolean headerWidthSet = false; private boolean tableTooLarge = false; private boolean tableNotLoaded = true; private PopupPanel notAllowWarning; private int cMouseX; private int cMouseY; // private CheckBox filters; private FilterToggle filters; private TableOptions options; private BadgeButton optionsButton; private SimplePanel mainWrapper; private PopoutToolbar popoutButton; private boolean expanded = false; private Image textView = new Image(TableImages.Creator.getInstance().getTextViewImage()); private Image tableView = new Image(TableImages.Creator.getInstance().getTableViewImage()); private BadgeButton viewSelector = new BadgeButton(textView); private BadgeButton saveButton; private SimplePanel helpButton = new SimplePanel(); private boolean handleEvent = true; private DSModelHandler modelEventHandler = new DSModelHandler(); private XYPlotViewCreator.XYPlotView xyPlotView = null; private DownloadRequest downloadRequest = null; public TablePanel(Loader<TableDataView> loader) { this("untitled", loader); } public TablePanel(String name, Loader<TableDataView> loader) { setInit(false); this.name = name; dataModel = new DataSetTableModel(loader); dataModel.addHandler(modelEventHandler); mainWrapper = new SimplePanel(); mainWrapper.addStyleName("mainWrapper"); mainWrapper.setSize("100%", "100%"); mainPanel.setSize("100%", "100%"); mainPanel.addStyleName("mainPanel"); DOM.setStyleAttribute(mainPanel.getElement(), "borderSpacing", "0px"); toolbarWrapper = new HorizontalPanel(); toolbarWrapper.setStyleName("firefly-toolbar"); stateId = name; mainWrapper.add(mainPanel); initWidget(mainWrapper); sinkEvents(Event.ONMOUSEOVER); WebEventManager.getAppEvManager().addListener(Name.DOWNLOAD_REQUEST_READY, new WebEventListener() { public void eventNotify(WebEvent ev) { if (ev.getName().equals(Name.DOWNLOAD_REQUEST_READY)) { if (ev.getSource() instanceof DownloadRequest) { downloadRequest = (DownloadRequest) ev.getSource(); } } } }); helpButton.setVisible(false); } public DataSetTableModel getDataModel() { return dataModel; } @Override public void onBrowserEvent(Event event) { super.onBrowserEvent(event); if (event.getTypeInt() == Event.ONMOUSEOVER) { cMouseX = event.getClientX(); cMouseY = event.getClientY(); } } public void setMaskDelayMillSec(int maskDelayMillSec) { this.maskDelayMillSec = maskDelayMillSec; } public void setHelpId(String id) { if (!StringUtils.isEmpty(id)) { Widget helpIcon = HelpManager.makeHelpIcon(id); helpIcon.setSize("24px", "24px"); helpButton.setWidget(helpIcon); helpButton.setVisible(true); } else { helpButton.setVisible(false); } } public void showOptionsButton(boolean show) { if (optionsButton != null) { optionsButton.getWidget().setVisible(show); } } public void showOptions(boolean show) { if (show) { GwtUtil.DockLayout.showWidget(mainPanel, options); } else { GwtUtil.DockLayout.hideWidget(mainPanel, options); } } public void showFiltersButton(boolean show) { if (filters != null) { filters.setVisible(show); } } public void showSaveButton(boolean show) { if (saveButton != null) { saveButton.getWidget().setVisible(show); } } public void showTableView(boolean show) { int idx = getViewIdx(TableView.NAME); if (idx >= 0) { getViews().get(idx).setHidden(!show); } } public void showPopOutButton(boolean show) { if (popoutButton != null) { popoutButton.setVisible(show); } } public void showColumnHeader(boolean show) { if (getTable() != null && getTable().getHeaderTable() != null) { getTable().getHeaderTable().setVisible(show); } } public void showTitle(boolean show) { if (titleHolder == null) { titleHolder = new HTML("<b>" + name + "</b>"); } titleHolder.setVisible(show); } public void addView(View view) { views.add(view); activeViews.add(view); view.bind(this); } public void init() { init(null); } public void switchView(Name name) { if (name != null) { if (name.equals(TableView.NAME)) { viewSelector.setIcon(textView); viewSelector.getWidget().setVisible(true); } else if (name.equals(TextView.NAME)) { viewSelector.setIcon(tableView); viewSelector.getWidget().setVisible(true); } else { viewSelector.getWidget().setVisible(false); } } int vidx = getViewIdx(name); if (viewDeck.getVisibleWidget() != vidx) { viewDeck.showWidget(vidx); for (View v : views) { v.onViewChange(views.get(vidx)); } if (!isExpanded()) { getEventManager() .fireEvent(new WebEvent(this, ON_VIEW_CHANGE, views.get(vidx).getName().getName())); } } } private int getViewIdx(Name name) { if (!StringUtils.isEmpty(name)) { for (int i = 0; i < views.size(); i++) { View v = views.get(i); if (v.getName().equals(name)) { return i; } } } return 0; } private String getServerError(final Throwable caught) { String eMsg = caught != null ? caught.getMessage() : "unknown"; String msgExtra = "<span class=\"faded-text\">" + "<br><br>If you still continue to receive this message, contact IRSA for <a href='https://irsa.ipac.caltech.edu/applications/Helpdesk' target='_blank'>help</a>. " + "<span>"; String msg = "<b> Unable to load table.</b><br>"; if (caught instanceof StatusCodeException) { StatusCodeException scx = (StatusCodeException) caught; if (scx.getStatusCode() == 503) { msg = "The site is down for scheduled maintenance."; msgExtra = ""; } else if (scx.getStatusCode() == 0) { msg = "If you are not connected to the internet, check your internet connection and try again"; } else { msg = "The server encountered an unexpected condition which prevented it from fulfilling the request.<br>" + "Refreshing the page may resolve the problem."; } } else if (caught instanceof RPCException) { RPCException ex = (RPCException) caught; if (ex.getEndUserMsg() != null) { eMsg = ex.getEndUserMsg(); } } return msg + eMsg + msgExtra; } public void init(final AsyncCallback<Integer> callback) { AsyncCallback<TableDataView> cb = new AsyncCallback<TableDataView>() { public void onFailure(Throwable caught) { // not sure what to do with this. // need to set init to true so other code can continue.. // but, has no way of passing the error. try { handleEvent = false; if (callback != null) { callback.onSuccess(0); } PopupUtil.showError("Request Fail", getServerError(caught)); } finally { TablePanel.this.setInit(true); } } public void onSuccess(TableDataView result) { try { table = makeTable(dataModel); layout(); addListeners(); if (GwtUtil.isOnDisplay(TablePanel.this)) { onShow(); } table.gotoFirstPage(); TablePanel.this.setInit(true); } finally { if (callback != null) { callback.onSuccess(dataModel.getTotalRows()); } } } }; // load up the first page of data.. upon success, creates and initializes the tablepanel. dataModel.getData(cb, 0); } public boolean isTableLoaded() { return !tableNotLoaded; } public int getRowCount() { if (table == null || table.getRowValues() == null) { GWT.log("TablePanel not ready", null); return -1; } else { return table.getRowValues().size(); } } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getShortDesc() { return shortDesc; } public void setShortDesc(String shortDesc) { this.shortDesc = shortDesc; } public BasicPagingTable getTable() { return table; } public TableDataView getDataset() { if (table == null || table.getDataModel() == null) return null; return table.getDataModel().getCurrentData(); } public List<View> getViews() { return views; } public List<View> getVisibleViews() { List<View> options = new ArrayList<View>(); for (View v : activeViews) { if (!v.isHidden()) { options.add(v); } } return options; } public void showToolBar(final boolean show) { if (toolbarWrapper.isAttached()) { toolbarWrapper.setVisible(show); leftToolbar.setVisible(show); rightToolbar.setVisible(show); centerToolbar.setVisible(show); if (show) { GwtUtil.DockLayout.showWidget(mainPanel, toolbarWrapper); } else { GwtUtil.DockLayout.hideWidget(mainPanel, toolbarWrapper); } } else { this.getEventManager().addListener(ON_SHOW, new WebEventListener() { public void eventNotify(WebEvent ev) { showToolBar(show); TablePanel.this.getEventManager().removeListener(ON_SHOW, this); } }); } } public PagingToolbar getPagingBar() { return pagingBar; } public void showPagingBar(final boolean show) { if (pagingBar != null && pagingBar.isAttached()) { if (show) { toolbarWrapper.setVisible(true); centerToolbar.setVisible(true); pagingBar.setVisible(true); GwtUtil.DockLayout.showWidget(mainPanel, toolbarWrapper); } else { pagingBar.setVisible(false); } } else { this.getEventManager().addListener(ON_SHOW, new WebEventListener() { public void eventNotify(WebEvent ev) { showPagingBar(show); TablePanel.this.getEventManager().removeListener(ON_SHOW, this); } }); } } public Widget addToolButton(final GeneralCommand cmd) { return addToolButton(cmd, true); } public void clearToolButtons() { clearToolButtons(true, true, true); } public void clearToolButtons(boolean left, boolean center, boolean right) { if (rightToolbar != null && right) { rightToolbar.clear(); } if (centerToolbar != null && center) { centerToolbar.clear(); } if (leftToolbar != null && left) { leftToolbar.clear(); } } public void removePanels() { if (toolbarWrapper != null) { mainPanel.remove(toolbarWrapper); } } public void addToolWidget(Widget w, boolean alignRight) { if (alignRight && rightToolbar != null) { rightToolbar.add(w); rightToolbar.setCellVerticalAlignment(w, VerticalPanel.ALIGN_BOTTOM); GwtUtil.setStyle(w, "marginLeft", "5px"); } else if (leftToolbar != null) { leftToolbar.add(w); leftToolbar.setCellVerticalAlignment(w, VerticalPanel.ALIGN_BOTTOM); GwtUtil.setStyle(w, "marginRight", "5px"); } } public void addToolButton(FocusWidget btn, boolean alignRight) { btn.addStyleName("button"); addToolWidget(btn, alignRight); } public Widget addToolButton(final GeneralCommand cmd, boolean alignRight) { final FocusWidget btn = new Button(cmd.getLabel()); updateHighlighted(btn, cmd); btn.addClickHandler(new ClickHandler() { public void onClick(ClickEvent ev) { cmd.execute(); } }); cmd.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent pce) { if (pce.getPropertyName().equals(GeneralCommand.PROP_TITLE)) { if (btn instanceof HasText) { ((HasText) btn).setText(String.valueOf(pce.getNewValue())); } } else if (pce.getPropertyName().equals(GeneralCommand.PROP_HIGHLIGHT)) { updateHighlighted(btn, cmd); } } }); if (!StringUtils.isEmpty(cmd.getShortDesc())) { btn.setTitle(cmd.getShortDesc()); } addToolButton(btn, alignRight); return btn; } public boolean isActiveView(Name vname) { int idx = viewDeck.getVisibleWidget(); return idx >= 0 && vname != null && views.get(idx).getName().equals(vname); } public Name getActiveView() { int idx = viewDeck.getVisibleWidget(); return idx >= 0 && idx < views.size() ? views.get(idx).getName() : null; } public boolean hasView(Name view) { if (view == null) return false; for (View v : views) { if (v.getName().equals(view)) { return true; } } return false; } public DownloadRequest getDownloadRequest() { return downloadRequest; } public static void updateHighlighted(FocusWidget b, GeneralCommand cmd) { if (cmd.isHighlighted()) { b.removeStyleName("button"); b.removeStyleName("normal-text"); b.addStyleName("button-highlight"); b.addStyleName("highlight-text"); } else { b.removeStyleName("button-highlight"); b.removeStyleName("highlight-text"); b.addStyleName("button"); b.addStyleName("normal-text"); } } void updateHasAccessRows() { HTMLTable.RowFormatter formatter = table.getDataTable().getRowFormatter(); List<TableData.Row> rows = table.getRowValues(); if (rows != null) { for (int i = 0; i < rows.size(); i++) { if (!rows.get(i).hasAccess()) { formatter.addStyleName(i, "caution"); } } } } void showTooLargeWarning() { showNotAllowWarning(TOO_LARGE); } void showNotLoadedWarning() { showNotAllowWarning(NOT_LOADED); } public void showNotAllowWarning(HTML msg) { showNotAllowWarning(msg, 4000); } /** * * @param msg * @param delay how long should the message stay up in msec. */ public void showNotAllowWarning(HTML msg, int delay) { if (notAllowWarning == null) { notAllowWarning = new PopupPanel(true); notAllowWarning.setAnimationEnabled(true); notAllowWarning.addStyleName("onTopDialog"); } notAllowWarning.setWidget(msg); notAllowWarning.setPopupPosition(cMouseX - 75, cMouseY - 25); notAllowWarning.show(); new Timer() { public void run() { notAllowWarning.hide(); } }.schedule(delay); } public void addDoubleClickListner(DoubleClickHandler dch) { table.addDoubleClickListener(dch); } //==================================================================== // override methods //==================================================================== @Override public void onShow() { if (!handleEvent) return; setAppStatus(true); Name vn = getActiveView(); if (vn != null) { View v = views.get(getViewIdx(vn)); if (v != null && v instanceof VisibleListener) { ((VisibleListener) v).onShow(); } } super.onShow(); } @Override public void onHide() { if (!handleEvent) return; setAppStatus(false); Name vn = getActiveView(); if (vn != null) { View v = views.get(getViewIdx(vn)); if (v != null && v instanceof VisibleListener) { ((VisibleListener) v).onHide(); } } super.onHide(); } private void setAppStatus(boolean onshow) { if (onshow && getDataModel().isMaxRowsExceeded()) { Application.getInstance() .setStatus("Dataset too large: some functions are disabled. Filter the data down to " + Constants.MAX_ROWS_SUPPORTED + " rows."); if (xyPlotView != null && activeViews.contains(xyPlotView)) { activeViews.remove(xyPlotView); if (isActiveView(xyPlotView.getName())) { switchView(TableView.NAME); } Application.getInstance().getLayoutManager().getLayoutSelector().layout(); } } else { Application.getInstance().setStatus(""); if (xyPlotView != null && !activeViews.contains(xyPlotView)) { activeViews.add(xyPlotView); Application.getInstance().getLayoutManager().getLayoutSelector().layout(); } } } @Override public void onInit() { super.onInit(); applySortIndicator(); } private void applySortIndicator() { SortInfo si = dataModel.getSortInfo(); if (si != null) { TableDataView.Column c = getDataset().findColumn(si.getPrimarySortColumn()); if (c != null) { getTable().setSortIndicator(c.getTitle(), si.getDirection()); } } } //==================================================================== // private/protected methods //==================================================================== protected void layout() { if (table == null) return; // final FlexTable.FlexCellFormatter formatter = mainPanel.getFlexCellFormatter(); // Initialize the tables // Create the tables table.addStyleName("expand-fully"); table.setFilterChangeHandler(new ChangeHandler() { public void onChange(ChangeEvent event) { doFilters(); } }); // Override the column sorter table.getDataTable().setColumnSorter(new CustomColumnSorter()); FocusPanel fp = new FocusPanel(table); fp.addKeyDownHandler(new HighlightedKeyMove(table.getDataTable())); DOM.setStyleAttribute(fp.getElement(), "outline", "yellow dotted thin"); fp.addStyleName("expand-fully"); addView(new TableView()); addView(new TextView()); TableServerRequest r = dataModel.getRequest(); if (XYPlotWidget.ENABLE_XY_CHARTS && isCatalogData()) { xyPlotView = new XYPlotViewCreator.XYPlotView(new HashMap<String, String>()); addView(xyPlotView); } viewDeck.setAnimationEnabled(true); viewDeck.addStyleName("expand-fully"); // sort the views based on its index Collections.sort(views, new Comparator<View>() { public int compare(View v1, View v2) { return v1.getViewIdx() == v2.getViewIdx() ? 0 : v1.getViewIdx() < v2.getViewIdx() ? -1 : 1; } }); for (View view : views) { viewDeck.add(view.getDisplay()); } options = new TableOptions(this); // Create top rightToolbar centerToolbar = new HorizontalPanel(); // Create top rightToolbar rightToolbar = new HorizontalPanel(); // Create top leftToolbar leftToolbar = new HorizontalPanel(); Widget cbar = GwtUtil.centerAlign(centerToolbar); Widget rbar = GwtUtil.rightAlign(rightToolbar); toolbarWrapper.add(leftToolbar); toolbarWrapper.add(cbar); toolbarWrapper.add(rbar); toolbarWrapper.setCellVerticalAlignment(leftToolbar, VerticalPanel.ALIGN_MIDDLE); toolbarWrapper.setCellVerticalAlignment(cbar, VerticalPanel.ALIGN_MIDDLE); toolbarWrapper.setCellVerticalAlignment(rbar, VerticalPanel.ALIGN_MIDDLE); mainPanel.addNorth(toolbarWrapper, TOOLBAR_SIZE); mainPanel.addEast(options, 200); // Create the paging bar pagingBar = new PagingToolbar(TablePanel.this); // mainPanel.addSouth(pagingBar, 32); centerToolbar.add(pagingBar); // Add the scroll table to the mainPanel mainPanel.add(viewDeck); // mainPanel.setCellWidth(tableHolder, "100%"); // mainPanel.setCellHeight(tableHolder, "100%"); addToolBar(); if (table != null && table.getDataModel() != null && table.getDataModel().getTotalRows() == 0) { showToolBar(false); } switchView(views.get(0).getName()); showOptions(false); if (FFToolEnv.isAPIMode()) { showPopOutButton(false); } } private boolean isCatalogData() { DataSet ds = dataModel == null ? null : dataModel.getCurrentData(); TableMeta meta = ds == null ? null : ds.getMeta(); return meta != null && meta.contains(MetaConst.CATALOG_OVERLAY_TYPE); } void updateTableStatus() { if (table == null || pagingBar == null) return; tableTooLarge = table.getTableModel().getRowCount() > maxRowLimit; tableNotLoaded = !getDataset().getMeta().isLoaded(); pagingBar.setIsLoading(tableNotLoaded); pagingBar.updateStatusMsg(); if (!expanded) { getEventManager().fireEvent(new WebEvent<Boolean>(this, ON_STATUS_UPDATE, isTableLoaded())); } if (GwtUtil.isOnDisplay(this)) { setAppStatus(true); } } protected void addListeners() { WebEventListener handler = new WebEventListener() { public void eventNotify(WebEvent ev) { if (ev.getName().equals(ON_PAGE_LOAD)) { if (isActiveView(TableView.NAME)) { if (GwtUtil.isOnDisplay(table) && getTable().getDataTable().getRowCount() > 0) { if (getTable().getDataTable().isSelectionEnabled()) { getTable().getDataTable().selectRow(0, true); filters.reinit(); } } } } else if (ev.getName().equals(ON_SHOW)) { if (isActiveView(TableView.NAME)) { table.onShow(); filters.reinit(); if (table.getRowCount() > 0 && table.getDataTable().getSelectedRows().size() == 0) { Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { public void execute() { table.getDataTable().selectRow(0, true); table.scrollHighlightedIntoView(); } }); } else { table.scrollHighlightedIntoView(); } } } } }; getEventManager().addListener(ON_PAGE_LOAD, handler); getEventManager().addListener(ON_SHOW, handler); getEventManager().addListener(ON_HIDE, handler); bindDataViewToTable(getDataset()); // listen to table's events table.addPageChangeHandler(new PageChangeHandler() { public void onPageChange(PageChangeEvent event) { mask("Loading...", maskDelayMillSec); if (!expanded) { getEventManager().fireEvent(new WebEvent(TablePanel.this, ON_PAGE_CHANGE)); } } }); table.addPageCountChangeHandler(new PageCountChangeHandler() { public void onPageCountChange(PageCountChangeEvent event) { updateTableStatus(); if (!expanded) { getEventManager().fireEvent(new WebEvent(TablePanel.this, ON_PAGECOUNT_CHANGE)); } } }); table.addPageLoadHandler(new PageLoadHandler() { public void onPageLoad(PageLoadEvent event) { unmask(); updateHasAccessRows(); if (!expanded && handleEvent) { getEventManager().fireEvent(new WebEvent(TablePanel.this, ON_PAGE_LOAD)); } } }); table.addPagingFailureHandler(new PagingFailureHandler() { public void onPagingFailure(PagingFailureEvent event) { unmask(); if (!expanded) { getEventManager().fireEvent(new WebEvent(TablePanel.this, ON_PAGE_ERROR)); } } }); table.getDataTable().addRowSelectionHandler(new RowSelectionHandler() { public void onRowSelection(RowSelectionEvent event) { if (!expanded && (GwtUtil.isOnDisplay(TablePanel.this) && handleEvent)) { Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { public void execute() { getEventManager().fireEvent(new WebEvent(TablePanel.this, ON_ROWHIGHLIGHT_CHANGE)); } }); } } }); } protected void bindDataViewToTable(TableDataView dataset) { new TableDataViewToTableAdapter(this, dataset); } protected BasicPagingTable newTable(DataSetTableModel model, TableDataView dataset) { return new BasicPagingTable(name, model, new BasicPagingTable.DataTable(), new DatasetTableDef(dataset)); } protected BasicPagingTable makeTable(DataSetTableModel cachedModel) { // Create the scroll table final BasicPagingTable table = newTable(cachedModel, cachedModel.getCurrentData()); table.setPageSize(dataModel.getPageSize()); table.setEmptyTableWidget(new HTML("There are no data to display")); // Setup the formatting table.setCellPadding(0); table.setCellSpacing(0); table.setResizePolicy(ScrollTable.ResizePolicy.UNCONSTRAINED); return table; } protected void addToolBar() { final Image saveImg = new Image(TableImages.Creator.getInstance().getSaveImage()); saveButton = new BadgeButton(saveImg); saveButton.setTitle("Save the content as an IPAC table"); saveButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent clickEvent) { // for browsers not supporting pointer-event if (!saveButton.isEnabled()) return; if (tableNotLoaded) { showNotLoadedWarning(); } else { // determine visible columns boolean hasCollapseCols = false; List<String> cols = new ArrayList<String>(); for (int i = 0; i < getDataset().getColumns().size(); i++) { if (getDataset().getColumn(i).isVisible()) { cols.add(getDataset().getColumn(i).getName()); } else { hasCollapseCols = true; } } // if there are hidden columns, set request to only include visible columns if (hasCollapseCols && cols.size() > 0) { dataModel.getRequest().setParam(TableServerRequest.INCL_COLUMNS, StringUtils.toString(cols, ",")); if (dataModel.getTotalRows() > maxRowLimit) { showNotAllowWarning(new HTML( "<i><font color='brown'>Due to the size of this table, it may take a few minutes to process your request." + " <br>Please be patient. Your file will start downloading after this process has completed.</font></i>"), 8000); } } saveButton.setEnabled(false); Image loadingImage = new Image(GwtUtil.LOADING_ICON_URL); saveButton.setIcon(loadingImage); // check every 5 seconds.. up to 120 times. ==> 10 mins. button will be re-enable after this. GwtUtil.submitDownloadUrl(dataModel.getLoader().getSourceUrl(), 5000, 60, new Command() { public void execute() { saveButton.setEnabled(true); saveButton.setIcon(saveImg); } }); dataModel.getRequest().removeParam(TableServerRequest.INCL_COLUMNS); } } }); filters = new FilterToggle(this); BackButton close = new BackButton("Close"); final AbsolutePanel popoutWrapper = new AbsolutePanel(); popoutWrapper.setSize("100%", "100%"); popoutWrapper.add(close, 0, 0); close.addClickHandler(new ClickHandler() { public void onClick(ClickEvent clickEvent) { Application.getInstance().getLayoutManager().getRegion(LayoutManager.POPOUT_REGION).hide(); if (mainWrapper.getWidget() == null) { mainWrapper.add(mainPanel); mainPanel.setSize("100%", "100%"); } expanded = false; if (BrowserUtil.isTouchInput()) popoutButton.showToolbar(true); onShow(); } }); ClickHandler popoutHandler = new ClickHandler() { public void onClick(ClickEvent event) { popoutButton.hideToolbar(); popoutWrapper.add(mainPanel, 0, 32); Application.getInstance().getLayoutManager().getRegion(LayoutManager.POPOUT_REGION) .setDisplay(popoutWrapper); expanded = true; mainPanel.forceLayout(); } }; popoutButton = new PopoutToolbar(popoutHandler, true); textView.addClickHandler(new ClickHandler() { public void onClick(ClickEvent clickEvent) { switchView(TextView.NAME); } }); tableView.addClickHandler(new ClickHandler() { public void onClick(ClickEvent clickEvent) { switchView(TableView.NAME); } }); textView.setTitle("Text View"); tableView.setTitle("Table View"); optionsButton = new BadgeButton(new Image(VisIconCreator.Creator.getInstance().getSettings())); optionsButton.setTitle("Edit Table Options"); optionsButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent ev) { if (GwtUtil.DockLayout.isHidden(options)) { options.syncOptions(); showOptions(true); } else { showOptions(false); } } }); addToolWidget(filters, true); addToolWidget(viewSelector.getWidget(), true); addToolWidget(saveButton.getWidget(), true); addToolWidget(optionsButton.getWidget(), true); addToolWidget(helpButton, true); addToolWidget(popoutButton, true); if (!BrowserUtil.isTouchInput()) { this.addDomHandler(new MouseOverHandler() { public void onMouseOver(MouseOverEvent event) { if (!expanded) popoutButton.showToolbar(true); } }, MouseOverEvent.getType()); this.addDomHandler(new MouseOutHandler() { public void onMouseOut(MouseOutEvent event) { if (!expanded) popoutButton.showToolbar(false); } }, MouseOutEvent.getType()); } } public void highlightRow(boolean forceEventTrigger, int idx) { boolean oldVal = handleEvent; this.handleEvent = handleEvent || forceEventTrigger; table.highlightRow(idx); this.handleEvent = oldVal; } /** * This method clear out cache, then reload the table plus its data. * * @param page after loaded, goto the given page if possible. if page is out of range, goto first page or last * page. */ public void reloadTable(int page) { reloadTable(page, dataModel.getPageSize(), -1); } /** * This method clear out cache, then reload the table plus its data. * * @param page after loaded, goto the given page if possible. if page is out of range, goto first page or last * page. * @param pageSize use the given pageSize * @param hlRowIdx highlight the given row index. index is the index of the whole table, not relative to a page. */ public void reloadTable(int page, int pageSize, final int hlRowIdx) { if (table.getDataModel() == null) return; table.getDataModel().clearCache(); SortInfo sortInfo = dataModel.getSortInfo(); if (sortInfo != null) { int cidx = 0; List<ColumnDefinition<TableData.Row, ?>> vcol = table.getTableDefinition() .getVisibleColumnDefinitions(); for (cidx = 0; cidx < vcol.size(); cidx++) { ColDef col = (ColDef) vcol.get(cidx); if (col.getName() != null && col.getName().equals(sortInfo.getPrimarySortColumn())) { break; } } if (cidx >= 0) { TableModelHelper.ColumnSortList sl = new TableModelHelper.ColumnSortList(); sl.add(new TableModelHelper.ColumnSortInfo(cidx, sortInfo.getDirection() == SortInfo.Direction.ASC)); getTable().getDataTable().setColumnSortList(sl); } } else { table.getDataTable().getColumnSortList().clear(); table.clearSortIndicator(); } if (dataModel.getPageSize() != pageSize) { dataModel.setPageSize(pageSize); table.setPageSize(pageSize); } page = Math.min(page, getDataset().getTotalRows() / pageSize); table.getTableModel().setRowCount(TableModel.UNKNOWN_ROW_COUNT); // this line is needed to force loader to load when previous results in zero rows. table.gotoPage(page, true); WebEventListener doHL = new WebEventListener() { public void eventNotify(WebEvent ev) { int hlidx = hlRowIdx < 0 ? getTable().getAbsoluteFirstRowIndex() : hlRowIdx; getTable().highlightRow(hlidx); syncTableUI(); TablePanel.this.getEventManager().removeListener(ON_PAGE_LOAD, this); } }; getEventManager().addListener(ON_PAGE_LOAD, doHL); } /** * update the table's UI. Will not reload the data. */ public void redrawTable() { handleEvent = false; Set<Integer> selRows = getTable().getDataTable().getSelectedRows(); int sRow = selRows == null || selRows.size() == 0 ? 0 : selRows.iterator().next(); table.refresh(); getTable().getDataTable().selectRow(sRow, true); syncTableUI(); handleEvent = true; } private void syncTableUI() { applySortIndicator(); table.setFilters(dataModel.getFilters()); filters.reinit(); if (isActiveView(TextView.NAME)) { TextView tview = (TextView) getViews().get(getViewIdx(TextView.NAME)); tview.loadTextView(); } } public boolean isExpanded() { return expanded; } public void doFilters() { List<String> filterList = table.getFilters(true); String newFilters = StringUtils.toString(filterList); String oldFilters = StringUtils.toString(dataModel.getFilters()); if (!newFilters.equals(oldFilters)) { dataModel.setFilters(filterList); reloadTable(0); fireStaleEvent(); } } private void fireStaleEvent() { handleEvent = false; dataModel.fireDataStaleEvent(); handleEvent = true; } protected void onSorted() { if (getDataset().getMeta().isLoaded()) { fireStaleEvent(); } else { modelEventHandler.fireStaleEventOnload(); } } //==================================================================== // Implementing StatefulWidget //==================================================================== public String getStateId() { return stateId; } public void setStateId(String id) { stateId = id; } public void recordCurrentState(Request req) { if (getTable() == null) return; int ps = getTable().getPageSize(); int startIdx = getTable().getCurrentPage() * getTable().getPageSize(); int hlIdx = getTable().getHighlightedRowIdx(); if (ps > 0) { req.setParam(getStateId() + "_" + Request.PAGE_SIZE, String.valueOf(ps)); } if (startIdx > 0) { req.setParam(getStateId() + "_" + Request.START_IDX, String.valueOf(startIdx)); } if (!CollectionUtil.isEmpty(dataModel.getFilters())) { req.setParam(getStateId() + "_" + Request.FILTERS, Request.toFilterStr(dataModel.getFilters())); } if (req.getSortInfo() != null) { req.setParam(getStateId() + "_" + Request.SORT_INFO, String.valueOf(req.getSortInfo())); } if (hlIdx >= 0) { req.setParam(getStateId() + "_" + HIGHLIGHTED_ROW_IDX, String.valueOf(hlIdx)); } } public void moveToRequestState(final Request req, final AsyncCallback callback) { if (getTable() == null) return; int rps = Math.max(0, req.getIntParam(getStateId() + "_" + Request.PAGE_SIZE)); int lps = Math.max(0, dataModel.getPageSize()); int rsIdx = Math.max(0, req.getIntParam(getStateId() + "_" + Request.START_IDX)); int lsIdx = Math.max(0, getTable().getCurrentPage() * getTable().getPageSize()); List<String> filters = Request.parseFilters(req.getParam(getStateId() + "_" + Request.FILTERS)); final SortInfo sortInfo = SortInfo.parse(req.getParam(getStateId() + "_" + Request.SORT_INFO)); int selIdx = req.getIntParam(getStateId() + "_" + HIGHLIGHTED_ROW_IDX); boolean doRefresh = (rps != 0 && rps != lps) || (rsIdx != lsIdx); doRefresh = doRefresh || !Request.toFilterStr(filters).equals(Request.toFilterStr(dataModel.getFilters())); doRefresh = doRefresh || !String.valueOf(sortInfo).equals(String.valueOf(dataModel.getSortInfo())); if (doRefresh) { rps = rps == 0 ? dataModel.getPageSize() : rps; int page = rsIdx / rps; dataModel.setFilters(filters); dataModel.setSortInfo(sortInfo); reloadTable(page, rps, selIdx); getEventManager().addListener(ON_PAGE_LOAD, new WebEventListener() { public void eventNotify(WebEvent ev) { TablePanel.this.getEventManager().removeListener(ON_PAGE_LOAD, this); DeferredCommand.addCommand(new Command() { public void execute() { onMoveToReqStateCompleted(req); callback.onSuccess(null); } }); } }); } else { selIdx = selIdx < 0 ? 0 : selIdx; getTable().highlightRow(true, selIdx); onMoveToReqStateCompleted(req); callback.onSuccess(null); } } protected void onMoveToReqStateCompleted(Request req) { } public boolean isActive() { return true; } // FilterToggleSupport public void toggleFilters() { if (getTable() == null || getTable().getDataModel() == null) return; if (!isActiveView(TableView.NAME)) { getTable().togglePopoutFilters(filters, PopupPane.Align.BOTTOM_LEFT); } else { if (getTable().isShowFilters()) { getTable().showFilters(false); } else { if (!isTableLoaded()) { showNotLoadedWarning(); } else { getTable().setFilters(table.getDataModel().getFilters()); getTable().showFilters(true); } } //reinit(); } } public List<String> getFilters() { return getTable().getFilters(); } public void clearFilters() { getTable().setFilters(null); doFilters(); } public void onResize() { for (View view : getViews()) { if (view != null && view.getDisplay() instanceof RequiresResize) { ((RequiresResize) view.getDisplay()).onResize(); } } } //==================================================================== // Inner classes //==================================================================== private class DSModelHandler implements ModelEventHandler { private boolean fireStaleEventOnload = false; public void onFailure(Throwable caught) { updateTableStatus(); } public void onLoad(TableDataView result) { updateTableStatus(); if (fireStaleEventOnload) { fireStaleEventOnload = false; fireStaleEvent(); } if (!expanded && handleEvent) { getEventManager().fireEvent(new WebEvent(TablePanel.this, ON_DATA_LOAD)); } } public void onStatusUpdated(TableDataView result) { updateTableStatus(); } public void onDataStale(DataSetTableModel model) { if (handleEvent) { reloadTable(0); } } public void fireStaleEventOnload() { this.fireStaleEventOnload = true; } } private class CustomColumnSorter extends SortableGrid.ColumnSorter { public void onSortColumn(SortableGrid grid, TableModelHelper.ColumnSortList sortList, SortableGrid.ColumnSorterCallback callback) { if (tableTooLarge) { showTooLargeWarning(); } else if (tableNotLoaded) { showNotLoadedWarning(); } else { // Get the primary column and sort order int column = sortList.getPrimaryColumn(); SortInfo prevSortInfo = dataModel.getSortInfo(); if (prevSortInfo != null) { String prevCol = prevSortInfo.getPrimarySortColumn(); ColDef col = (ColDef) table.getTableDefinition().getVisibleColumnDefinitions().get(column); if (col != null && col.getName().equals(String.valueOf(prevCol))) { if (prevSortInfo.getDirection().equals(SortInfo.Direction.DESC)) { sortList.clear(); dataModel.setSortInfo(null); table.clearSortIndicator(); } } } table.gotoPage(0, true); if (sortList.size() > 0) { callback.onSortingComplete(); } onSorted(); } } } public static class HighlightedKeyMove implements KeyDownHandler { private FixedWidthGrid table; public HighlightedKeyMove(FixedWidthGrid table) { this.table = table; } private void adjustHighligtedIdx(int offset) { Set<Integer> hlighted = table.getSelectedRows(); int hlrow = hlighted == null || hlighted.size() == 0 ? 0 : hlighted.toArray(new Integer[hlighted.size()])[0]; if (hlrow > -1) { int idx = hlrow + offset; if (idx >= 0 && idx < table.getRowCount()) { table.selectRow(idx, true); } } } public void onKeyDown(KeyDownEvent event) { if (event.getNativeKeyCode() == KeyCodes.KEY_DOWN) { adjustHighligtedIdx(1); event.stopPropagation(); } else if (event.getNativeKeyCode() == KeyCodes.KEY_UP) { adjustHighligtedIdx(-1); event.stopPropagation(); } } } public static class TableDataViewToTableAdapter { private TablePanel table; private TableDataView dataset; boolean sinkEvent = true; public TableDataViewToTableAdapter(TablePanel table, TableDataView dataset) { this.table = table; this.dataset = dataset; bind(); } private boolean isEqual(TableData.Row r1, TableData.Row r2, String col) { if (r1 == null || r2 == null) return false; String cv = String.valueOf(r1.getValue(col)); String tv = String.valueOf(r2.getValue(col)); return cv.equals(tv); } protected void bind() { final List<String> relatedCols = table.getDataset().getMeta().getRelatedCols(); final HTMLTable.RowFormatter rowFormatter = table.getTable().getDataTable().getRowFormatter(); if (relatedCols.size() > 0) { table.getTable().getDataTable().addRowSelectionHandler(new RowSelectionHandler() { public void onRowSelection(RowSelectionEvent event) { if (sinkEvent) { sinkEvent = false; Set<TableEvent.Row> rows = event.getSelectedRows(); if (rows != null && rows.size() > 0) { TableData.Row row = table.getTable() .getRowValue(rows.iterator().next().getRowIndex()); for (int r = 0; r < table.getRowCount(); r++) { boolean isRelated = true; for (String c : relatedCols) { TableData.Row cRow = table.getTable().getRowValue(r); if (cRow == row || !isEqual(row, cRow, c)) { isRelated = false; break; } } if (isRelated) { rowFormatter.addStyleName(r, "related"); } else { rowFormatter.removeStyleName(r, "related"); } } } sinkEvent = true; } } }); } table.getTable().getDataTable().addRowSelectionHandler(new RowSelectionHandler() { public void onRowSelection(RowSelectionEvent event) { if (sinkEvent) { sinkEvent = false; Set<TableEvent.Row> rowIdxs = event.getSelectedRows(); if (rowIdxs.size() > 0) { int idx = rowIdxs.iterator().next().getRowIndex() + table.getTable().getAbsoluteFirstRowIndex(); dataset.highlight(idx); if (table.getTable().getHighlightedRowIdx() >= 0) { table.getTable().scrollHighlightedIntoView(); } } sinkEvent = true; } } }); dataset.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent pce) { try { if (sinkEvent) { sinkEvent = false; if (table.getTable().getDataTable().getRowCount() > 0) { if (pce.getPropertyName().equals(DataSet.ROW_HIGHLIGHTED)) { Integer idx = (Integer) pce.getNewValue(); table.getTable().highlightRow(true, idx); } else if (pce.getPropertyName().equals(DataSet.ROW_CLEARHIGHLIGHTED)) { table.getTable().clearHighlighted(); } } sinkEvent = true; } } catch (Exception e) { GWT.log(e.getMessage(), e); } } }); } } //==================================================================== // //==================================================================== public interface View { int getViewIdx(); //-1 for default order, use other number to override. Name getName(); String getShortDesc(); Widget getDisplay(); void onViewChange(View newView); TablePanel getTablePanel(); void onMaximize(); void onMinimize(); ImageResource getIcon(); void bind(TablePanel table); void bind(EventHub hub); boolean isHidden(); void setHidden(boolean flg); } }