/** * Copyright 2015 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.arcbees.gaestudio.client.application.visualizer.widget; import java.util.List; import com.arcbees.analytics.shared.Analytics; import com.arcbees.gaestudio.client.application.visualizer.ParsedEntity; import com.arcbees.gaestudio.client.application.visualizer.columnfilter.ColumnVisibilityConfigHelper; import com.arcbees.gaestudio.client.application.visualizer.columnfilter.ColumnVisibilityTooltip; import com.arcbees.gaestudio.client.resources.AppResources; import com.arcbees.gaestudio.client.resources.CellTableResource; import com.arcbees.gaestudio.client.resources.PagerResources; import com.arcbees.gaestudio.client.resources.VisualizerResources; import com.arcbees.gaestudio.shared.dto.entity.EntityDto; import com.arcbees.gaestudio.shared.dto.entity.KeyDto; import com.google.common.collect.Lists; import com.google.gwt.core.client.Scheduler; import com.google.gwt.dom.client.BrowserEvents; import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.Element; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.logical.shared.AttachEvent; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.query.client.Function; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.cellview.client.CellTable; import com.google.gwt.user.cellview.client.SimplePager; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.IsWidget; import com.google.gwt.user.client.ui.TextArea; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.view.client.AsyncDataProvider; import com.google.gwt.view.client.CellPreviewEvent; import com.google.gwt.view.client.MultiSelectionModel; import com.google.gwt.view.client.Range; import com.google.gwt.view.client.RowCountChangeEvent; import com.google.inject.Inject; import com.gwtplatform.mvp.client.ViewWithUiHandlers; import static com.arcbees.gaestudio.client.application.analytics.EventCategories.UI_ELEMENTS; import static com.google.gwt.query.client.GQuery.$; public class EntityListView extends ViewWithUiHandlers<EntityListUiHandlers> implements EntityListPresenter.MyView, CellPreviewEvent.Handler<ParsedEntity> { interface Binder extends UiBinder<Widget, EntityListView> { } private static final int PAGE_SIZE = 25; private static final Range DEFAULT_RANGE = new Range(0, PAGE_SIZE); @UiField HTMLPanel panel; @UiField(provided = true) SimplePager pager; @UiField(provided = true) EntityCellTable<ParsedEntity> entityTable; @UiField DivElement refresh; @UiField DivElement byGql; @UiField TextArea formQuery; @UiField DivElement formQueryHolder; @UiField Button runQueryButton; @UiField Element column; private final VisualizerResources visualizerResources; private final String pagerButtons; private final ParsedEntityColumnCreator columnCreator; private final MultiSelectionModel<ParsedEntity> selectionModel; private final ColumnVisibilityTooltip columnVisibilityTooltip; private final Analytics analytics; private HandlerRegistration firstLoadHandlerRegistration; private boolean gwtBound; @Inject EntityListView( Binder uiBinder, CellTableResource cellTableResource, PagerResources pagerResources, AppResources appResources, VisualizerResources visualizerResources, ParsedEntityColumnCreator columnCreator, Analytics analytics, ColumnVisibilityConfigHelper columnVisibilityConfigHelper, ColumnVisibilityTooltip columnVisibilityTooltip) { this.columnCreator = columnCreator; this.visualizerResources = visualizerResources; this.analytics = analytics; this.columnVisibilityTooltip = columnVisibilityTooltip; pager = new SimplePager(SimplePager.TextLocation.CENTER, pagerResources, false, 1000, true); pagerButtons = "." + appResources.styles().pager() + " tbody tr td img"; entityTable = new EntityCellTable<>(PAGE_SIZE, cellTableResource, appResources, columnVisibilityConfigHelper); entityTable.addAttachHandler(new AttachEvent.Handler() { @Override public void onAttachOrDetach(AttachEvent event) { onEditTableAttachedOrDetached(event.isAttached()); } }); selectionModel = new MultiSelectionModel<>(); entityTable.setSelectionModel(selectionModel, this); entityTable.setLoadingIndicator(null); initWidget(uiBinder.createAndBindUi(this)); pager.setPageSize(PAGE_SIZE); pager.setDisplay(entityTable); columnCreator.initializeTable(entityTable); formQuery.getElement().setPropertyString("placeholder", "(e.g. SELECT * FROM Car WHERE model = 'Honda')"); } @Override public void setInSlot(Object slot, IsWidget content) { if (slot == EntityListPresenter.SLOT_COLUMN_CONFIG_TOOLTIP) { columnVisibilityTooltip.bind($("thead", entityTable), "contextmenu", content); columnVisibilityTooltip.bind($(column), "click", content); } } @Override public void setTableDataProvider(AsyncDataProvider<ParsedEntity> dataProvider) { dataProvider.addDataDisplay(entityTable); } @Override public void setRowCount(Integer count) { entityTable.setRowCount(count); } @Override public void setNewKind(String currentKind) { panel.setVisible(true); entityTable.setVisibleRangeAndClearData(DEFAULT_RANGE, true); } @Override public void hideList() { panel.setVisible(false); } @Override public void setData(Range range, List<ParsedEntity> parsedEntities) { entityTable.setRowData(range.getStart(), parsedEntities); } @Override public void blockSendingNewRequests() { runQueryButton.setEnabled(false); } @Override public void allowSendingNewRequests() { runQueryButton.setEnabled(true); } @Override public void addOrReplaceEntities(List<EntityDto> entities) { final List<ParsedEntity> selectedEntities = Lists.newArrayList(); List<ParsedEntity> newParsedEntities = Lists.newArrayList(entityTable.getVisibleItems()); for (EntityDto entity : entities) { int rowIndex = getRowIndex(entity); ParsedEntity parsedEntity = new ParsedEntity(entity); if (rowIndex == -1) { newParsedEntities.add(0, parsedEntity); } else { newParsedEntities.set(rowIndex, parsedEntity); } selectedEntities.add(parsedEntity); } Range range = entityTable.getVisibleRange(); entityTable.setRowData(range.getStart(), newParsedEntities); Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { @Override public void execute() { selectRows(selectedEntities); } }); } @Override public void setKind(String appId, String namespace, String kind) { entityTable.setKind(appId, namespace, kind); } @Override public void updateColumnVisibility() { entityTable.updateCellVisibility(); } @Override public void removeEntity(EntityDto entityDTO) { int rowIndex = getRowIndex(entityDTO); if (rowIndex >= 0) { Range range = entityTable.getVisibleRange(); entityTable.setVisibleRangeAndClearData(range, true); } } @Override public void addProperty(String propertyName) { columnCreator.addPropertyColumn(entityTable, propertyName); } @Override public void redraw() { entityTable.redraw(); } @Override public void removeKindSpecificColumns() { while (entityTable.getColumnCount() > ParsedEntityColumnCreator.getDefaultColumnCount()) { removeLastColumn(entityTable); } } @Override public void unselectRows() { selectionModel.clear(); getUiHandlers().onRowUnlock(); } @Override public void setRowSelected(final String encodedKey) { if (!$(entityTable.getTableLoadingSection()).isVisible()) { $(entityTable).delay(1, new Function() { @Override public void f() { doSetRowSelected(encodedKey); } }); } else { final RowCountChangeEvent.Handler handler = new RowCountChangeEvent.Handler() { @Override public void onRowCountChange(RowCountChangeEvent event) { doSetRowSelected(encodedKey); firstLoadHandlerRegistration.removeHandler(); } }; firstLoadHandlerRegistration = entityTable.addRowCountChangeHandler(handler); } } @UiHandler("runQueryButton") public void runGqlQuery(ClickEvent event) { getUiHandlers().runGqlQuery(formQuery.getText()); analytics.sendEvent(UI_ELEMENTS, "click") .eventLabel("Visualizer -> List View -> Run GQL Query") .go(); } @Override public void onCellPreview(CellPreviewEvent<ParsedEntity> event) { if (BrowserEvents.CLICK.equals(event.getNativeEvent().getType())) { ParsedEntity parsedEntity = event.getValue(); if (event.getNativeEvent().getCtrlKey() || event.getNativeEvent().getShiftKey()) { if (selectionModel.isSelected(parsedEntity)) { unselectRow(parsedEntity); } else { selectRow(parsedEntity); } } else { if (selectionModel.isSelected(parsedEntity)) { unselectRows(); } else { unselectRows(); selectRow(parsedEntity); } } } } private void doSetRowSelected(String encodedKey) { for (int i = 0; i < entityTable.getVisibleItems().size(); i++) { ParsedEntity parsedEntity = entityTable.getVisibleItem(i); KeyDto key = parsedEntity.getKey(); if (key.getEncodedKey().equals(encodedKey)) { selectRow(parsedEntity); return; } } } private void removeLastColumn(CellTable<ParsedEntity> entityTable) { int lastColumnIndex = entityTable.getColumnCount() - 1; entityTable.removeColumn(lastColumnIndex); } private int getRowIndex(EntityDto entityDTO) { List<ParsedEntity> visibleParsedEntities = entityTable.getVisibleItems(); int rowIndex = -1; boolean isReplace = false; int i = 0; while (!isReplace && i < visibleParsedEntities.size()) { ParsedEntity parsedEntity = visibleParsedEntities.get(i); if (parsedEntity.getKey().getEncodedKey().equals(entityDTO.getKey().getEncodedKey())) { isReplace = true; rowIndex = i; parsedEntity.setEntityDto(entityDTO); } i++; } return rowIndex; } private void onEditTableAttachedOrDetached(boolean attached) { if (attached && !gwtBound) { bindGwtQuery(); gwtBound = true; } } private void bindGwtQuery() { $(pagerButtons).click(new Function() { @Override public void f() { unselectRows(); } }); $(refresh).click(new Function() { @Override public void f() { refresh(); } }); $(byGql).click(new Function() { @Override public void f() { toggleGQL(); } }); $(formQueryHolder).slideUp(0); } private void refresh() { getUiHandlers().refresh(); unselectRows(); entityTable.setVisibleRangeAndClearData(DEFAULT_RANGE, true); analytics.sendEvent(UI_ELEMENTS, "click") .eventLabel("Visualizer -> List View -> Refresh") .go(); } private void selectRows(List<ParsedEntity> parsedEntities) { selectionModel.clear(); for (ParsedEntity parsedEntity : parsedEntities) { selectionModel.setSelected(parsedEntity, true); } getUiHandlers().onEntitySelected(selectionModel.getSelectedSet()); } private void selectRow(ParsedEntity parsedEntity) { selectionModel.setSelected(parsedEntity, true); getUiHandlers().onEntitySelected(selectionModel.getSelectedSet()); analytics.sendEvent(UI_ELEMENTS, "select") .eventLabel("Visualizer -> List View -> Entity Row") .go(); } private void unselectRow(ParsedEntity parsedEntity) { selectionModel.setSelected(parsedEntity, false); if (selectionModel.getSelectedSet().isEmpty()) { unselectRows(); } else { getUiHandlers().onEntitySelected(selectionModel.getSelectedSet()); } } private void toggleGQL() { VisualizerResources.EntityList styles = visualizerResources.entityList(); $(byGql).toggleClass(styles.open()); boolean isByGql = $(byGql).hasClass(styles.open()); if (isByGql) { $(formQueryHolder).slideDown(100); analytics.sendEvent(UI_ELEMENTS, "open") .eventLabel("Visualizer -> List View -> GQL Query Textarea") .go(); } else { $(formQueryHolder).slideUp(100); analytics.sendEvent(UI_ELEMENTS, "close") .eventLabel("Visualizer -> List View -> GQL Query Textarea") .go(); } getUiHandlers().setUseGql(isByGql); } }