package com.eas.grid;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.eas.core.HasPublished;
import com.eas.core.Utils;
import com.eas.core.XElement;
import com.eas.core.Utils.JsObject;
import com.eas.grid.builders.RenderedTableCellBuilder;
import com.eas.grid.builders.ThemedHeaderOrFooterBuilder;
import com.eas.grid.cells.TreeExpandableCell;
import com.eas.grid.columns.CheckServiceColumn;
import com.eas.grid.columns.ModelColumn;
import com.eas.grid.columns.RadioServiceColumn;
import com.eas.grid.columns.UsualServiceColumn;
import com.eas.grid.columns.header.HeaderAnalyzer;
import com.eas.grid.columns.header.HeaderNode;
import com.eas.grid.columns.header.HeaderSplitter;
import com.eas.grid.processing.IndexOfProvider;
import com.eas.grid.processing.ListMultiSortHandler;
import com.eas.grid.processing.TreeDataProvider;
import com.eas.grid.processing.TreeMultiSortHandler;
import com.eas.grid.rows.JsArrayListDataProvider;
import com.eas.grid.rows.JsArrayTreeDataProvider;
import com.eas.grid.rows.JsDataContainer;
import com.eas.grid.selection.CheckBoxesEventTranslator;
import com.eas.grid.selection.HasSelectionLead;
import com.eas.grid.selection.MultiJavaScriptObjectSelectionModel;
import com.eas.menu.HasComponentPopupMenu;
import com.eas.menu.PlatypusPopupMenu;
import com.eas.ui.HasBinding;
import com.eas.ui.HasEventsExecutor;
import com.eas.ui.HasJsFacade;
import com.eas.ui.HasJsName;
import com.eas.ui.HasOnRender;
import com.eas.ui.JavaScriptObjectKeyProvider;
import com.eas.ui.PublishedCell;
import com.eas.ui.PublishedComponent;
import com.eas.ui.EventsPublisher;
import com.eas.ui.events.CollapsedHandler;
import com.eas.ui.events.EventsExecutor;
import com.eas.ui.events.ExpandedHandler;
import com.eas.ui.events.HasHideHandlers;
import com.eas.ui.events.HasShowHandlers;
import com.eas.ui.events.HideEvent;
import com.eas.ui.events.HideHandler;
import com.eas.ui.events.ShowEvent;
import com.eas.ui.events.ShowHandler;
import com.eas.widgets.WidgetsUtils;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ContextMenuEvent;
import com.google.gwt.event.dom.client.ContextMenuHandler;
import com.google.gwt.event.dom.client.DragStartEvent;
import com.google.gwt.event.dom.client.DragStartHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.HasBlurHandlers;
import com.google.gwt.event.dom.client.HasFocusHandlers;
import com.google.gwt.event.dom.client.HasKeyDownHandlers;
import com.google.gwt.event.dom.client.HasKeyPressHandlers;
import com.google.gwt.event.dom.client.HasKeyUpHandlers;
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.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.logical.shared.HasResizeHandlers;
import com.google.gwt.event.logical.shared.HasSelectionHandlers;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortEvent;
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
import com.google.gwt.user.cellview.client.Header;
import com.google.gwt.user.client.ui.Focusable;
import com.google.gwt.user.client.ui.HasEnabled;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.CellPreviewEvent;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SelectionModel;
import com.google.gwt.view.client.SetSelectionModel;
/**
* Class intended to wrap a grid or tree grid. It also contains grid API.
*
* @author mg
*
*/
public class ModelGrid extends Grid<JavaScriptObject>
implements HasJsFacade, HasOnRender, HasComponentPopupMenu, HasEventsExecutor, HasEnabled, HasShowHandlers,
HasHideHandlers, HasResizeHandlers, HasBinding, HasSelectionHandlers<JavaScriptObject>, HasFocusHandlers,
HasBlurHandlers, Focusable, HasKeyDownHandlers, HasKeyPressHandlers, HasKeyUpHandlers, JsDataContainer {
protected boolean enabled = true;
protected EventsExecutor eventsExecutor;
protected PlatypusPopupMenu menu;
protected String name;
//
protected String parentField;
protected String childrenField;
//
protected JavaScriptObject data;
protected String field;
protected HandlerRegistration boundToData;
protected HandlerRegistration boundToCursor;
protected String cursorProperty = "cursor";
protected JavaScriptObject onRender;
protected JavaScriptObject onAfterRender;
protected JavaScriptObject onExpand;
protected JavaScriptObject onCollapse;
protected PublishedComponent published;
protected FindWindow finder;
protected String groupName = "group-name-" + Document.get().createUniqueId();
protected List<HeaderNode<JavaScriptObject>> header = new ArrayList<>();
// runtime
protected Widget activeEditor;
protected ListHandler<JavaScriptObject> sortHandler;
protected HandlerRegistration sortHandlerReg;
protected HandlerRegistration positionSelectionHandler;
protected HandlerRegistration onSelectEventSelectionHandler;
protected boolean editable = true;
protected boolean deletable = true;
protected boolean insertable = true;
protected boolean draggableRows;
public ModelGrid() {
super(new JavaScriptObjectKeyProvider());
addDomHandler(new DragStartHandler() {
@Override
public void onDragStart(DragStartEvent event) {
if (draggableRows) {
EventTarget et = event.getNativeEvent().getEventTarget();
Element targetElement = Element.as(et);
if ("tr".equalsIgnoreCase(targetElement.getTagName())) {
event.stopPropagation();
int viewIndex = Integer.valueOf(targetElement.getAttribute("__gwt_row"));
if (sortHandler != null && sortHandler.getList() != null) {
List<JavaScriptObject> sorted = sortHandler.getList();
if (viewIndex >= 0 && viewIndex < sorted.size()) {
JavaScriptObject dragged = sorted.get(viewIndex);
if (ModelGrid.this.data != null) {
Utils.JsObject dataArray = ModelGrid.this.data.cast();
int dataIndex = dataArray.indexOf(dragged);
event.getDataTransfer().setData("text/modelgrid-row",
"{\"gridName\":\"" + name + "\", \"dataIndex\": " + dataIndex + "}");
}
}
}
}
}
}
}, DragStartEvent.getType());
addDomHandler(new KeyUpHandler() {
@Override
public void onKeyUp(KeyUpEvent event) {
Object oData = data != null && field != null && !field.isEmpty() ? Utils.getPathData(data, field)
: data;
JsObject jsData = oData instanceof JavaScriptObject ? ((JavaScriptObject) oData).<JsObject> cast()
: null;
if (jsData != null) {
if (activeEditor == null && getSelectionModel() instanceof SetSelectionModel<?>) {
final SetSelectionModel<JavaScriptObject> rowsSelection = (SetSelectionModel<JavaScriptObject>) getSelectionModel();
if (event.getNativeKeyCode() == KeyCodes.KEY_DELETE && deletable) {
final List<JavaScriptObject> viewElements = dataProvider.getList();
if (!viewElements.isEmpty() && rowsSelection.getSelectedSet() != null
&& !rowsSelection.getSelectedSet().isEmpty()) {
// calculate some view sugar
int lastSelectedViewIndex = -1;
for (int i = viewElements.size() - 1; i >= 0; i--) {
JavaScriptObject element = viewElements.get(i);
if (rowsSelection.isSelected(element)) {
lastSelectedViewIndex = i;
break;
}
}
// actually delete selected elements
int deletedAt = -1;
for (int i = jsData.length() - 1; i >= 0; i--) {
JavaScriptObject element = jsData.getSlot(i);
if (rowsSelection.isSelected(element)) {
jsData.splice(i, 1);
deletedAt = i;
}
}
final int viewIndexToSelect = lastSelectedViewIndex;
if(deletedAt > -1){
afterRender(new Runnable(){
@Override
public void run() {
int vIndex = viewIndexToSelect;
if (vIndex >= 0 && !viewElements.isEmpty()) {
if (vIndex >= viewElements.size())
vIndex = viewElements.size() - 1;
JavaScriptObject toSelect = viewElements.get(vIndex);
makeVisible(toSelect, true);
} else {
ModelGrid.this.setFocus(true);
}
}
});
}
}
} else if (event.getNativeKeyCode() == KeyCodes.KEY_INSERT && insertable) {
int insertAt = -1;
if (rowsSelection instanceof HasSelectionLead<?>
&& dataProvider instanceof IndexOfProvider<?>) {
JavaScriptObject lead = ((HasSelectionLead<JavaScriptObject>) rowsSelection).getLead();
insertAt = ((IndexOfProvider<JavaScriptObject>) dataProvider).indexOf(lead);
insertAt++;
JavaScriptObject oElementClass = jsData.getJs("elementClass");
JsObject elementClass = oElementClass != null ? oElementClass.<JsObject> cast() : null;
final JavaScriptObject inserted = elementClass != null ? elementClass.newObject()
: JavaScriptObject.createObject();
jsData.splice(insertAt, 0, inserted);
afterRender(new Runnable(){
@Override
public void run() {
makeVisible(inserted, true);
}
});
}
}
}
}
}
}, KeyUpEvent.getType());
addDomHandler(new KeyDownHandler() {
@Override
public void onKeyDown(KeyDownEvent event) {
if ((event.isMetaKeyDown() || event.isControlKeyDown()) && event.getNativeKeyCode() == KeyCodes.KEY_F) {
event.stopPropagation();
event.preventDefault();
ModelGrid.this.find();
} else if (event.getNativeKeyCode() == KeyCodes.KEY_F3) {
event.stopPropagation();
event.preventDefault();
if (finder != null) {
finder.findNext();
}
}
}
}, KeyDownEvent.getType());
applyRows();
}
public boolean isDraggableRows() {
return draggableRows;
}
public void setDraggableRows(boolean aValue) {
if (draggableRows != aValue) {
draggableRows = aValue;
for (GridSection<?> section : new GridSection<?>[] { frozenLeft, frozenRight, scrollableLeft,
scrollableRight }) {
GridSection<JavaScriptObject> gSection = (GridSection<JavaScriptObject>) section;
gSection.setDraggableRows(aValue);
}
}
}
public Widget getActiveEditor() {
return activeEditor;
}
public void setActiveEditor(Widget aWidget) {
activeEditor = aWidget;
}
public String getGroupName() {
return groupName;
}
protected void installCellBuilders() {
for (GridSection<?> section : new GridSection<?>[] { frozenLeft, frozenRight, scrollableLeft,
scrollableRight }) {
GridSection<JavaScriptObject> gSection = (GridSection<JavaScriptObject>) section;
gSection.setTableBuilder(new RenderedTableCellBuilder<>(gSection, dynamicTDClassName, dynamicCellClassName,
dynamicOddRowsClassName, dynamicEvenRowsClassName));
}
}
protected boolean serviceColumnsRedrawQueued;
protected void enqueueServiceColumnsRedraw() {
serviceColumnsRedrawQueued = true;
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
if (serviceColumnsRedrawQueued) {
serviceColumnsRedrawQueued = false;
if (getDataColumnCount() > 0) {
for (int i = 0; i < getDataColumnCount(); i++) {
ModelColumn col = (ModelColumn) getDataColumn(i);
if (col instanceof UsualServiceColumn) {
if (i < frozenColumns) {
frozenLeft.redrawAllRowsInColumn(i, dataProvider);
scrollableLeft.redrawAllRowsInColumn(i, dataProvider);
} else {
frozenRight.redrawAllRowsInColumn(i - frozenColumns, dataProvider);
scrollableRight.redrawAllRowsInColumn(i - frozenColumns, dataProvider);
}
}
}
}
}
}
});
}
protected ScheduledCommand redrawQueued;
private void enqueueRedraw() {
redrawQueued = new ScheduledCommand() {
@Override
public void execute() {
if (redrawQueued == this) {
redrawQueued = null;
redraw();
}
}
};
Scheduler.get().scheduleDeferred(redrawQueued);
}
protected void applyRows() {
unbindCursor();
if (sortHandlerReg != null)
sortHandlerReg.removeHandler();
Runnable onResize = new Runnable() {
@Override
public void run() {
setupVisibleRanges();
if (dataProvider instanceof IndexOfProvider<?>)
((IndexOfProvider<?>) dataProvider).rescan();
sortHandler.setList(dataProvider != null ? dataProvider.getList() : new ArrayList<JavaScriptObject>());
if (sortList.size() > 0) {
sortList.clear();
redrawHeaders();
}
if(dataProvider == null || dataProvider.getList() == null || dataProvider.getList().isEmpty()){
clearSelection();
}
}
};
Runnable onChange = new Runnable() {
@Override
public void run() {
ModelGrid.this.redraw();
}
};
Runnable onSort = new Runnable() {
@Override
public void run() {
if (dataProvider instanceof IndexOfProvider<?>)
((IndexOfProvider<?>) dataProvider).rescan();
}
};
Object oData = data != null && field != null && !field.isEmpty() ? Utils.getPathData(data, field) : data;
JavaScriptObject jsData = oData instanceof JavaScriptObject ? (JavaScriptObject) oData : null;
if (jsData != null) {
if (isTreeConfigured()) {
JsArrayTreeDataProvider treeDataProvider = new JsArrayTreeDataProvider(parentField, childrenField,
onResize);
setDataProvider(treeDataProvider);
sortHandler = new TreeMultiSortHandler<>(treeDataProvider, onSort);
treeDataProvider.addExpandedHandler(new ExpandedHandler<JavaScriptObject>() {
@Override
public void expanded(JavaScriptObject anElement) {
ColumnSortEvent.fire(ModelGrid.this, sortList);
if (onExpand != null) {
JavaScriptObject jsEvent = EventsPublisher.publishItemEvent(ModelGrid.this.published,
anElement);
try {
Utils.executeScriptEventVoid(ModelGrid.this.published, onExpand, jsEvent);
} catch (Exception e) {
Logger.getLogger(EventsExecutor.class.getName()).log(Level.SEVERE, null, e);
}
}
}
});
treeDataProvider.addCollapsedHandler(new CollapsedHandler<JavaScriptObject>() {
@Override
public void collapsed(JavaScriptObject anElement) {
ColumnSortEvent.fire(ModelGrid.this, sortList);
if (onCollapse != null) {
JavaScriptObject jsEvent = EventsPublisher.publishItemEvent(ModelGrid.this.published,
anElement);
try {
Utils.executeScriptEventVoid(ModelGrid.this.published, onCollapse, jsEvent);
} catch (Exception e) {
Logger.getLogger(EventsExecutor.class.getName()).log(Level.SEVERE, null, e);
}
}
}
});
} else {
setDataProvider(new JsArrayListDataProvider(onResize, onChange, null));
sortHandler = new ListMultiSortHandler<>(dataProvider.getList(), onSort);
}
for (int colIndex = 0; colIndex < getDataColumnCount(); colIndex++) {
ModelColumn modelCol = (ModelColumn) getDataColumn(colIndex);
sortHandler.setComparator(modelCol, modelCol.getComparator());
}
sortHandlerReg = addColumnSortHandler(sortHandler);
((JsDataContainer) getDataProvider()).setData(jsData);
boundToCursor = Utils.listenPath(jsData, cursorProperty, new Utils.OnChangeHandler() {
@Override
public void onChange(JavaScriptObject anEvent) {
enqueueServiceColumnsRedraw();
}
});
} else {
setDataProvider(null);
}
}
@Override
public void setDataProvider(ListDataProvider<JavaScriptObject> aDataProvider) {
if(getDataProvider() != null){
((JsDataContainer) getDataProvider()).setData(null);
}
super.setDataProvider(aDataProvider);
checkTreeIndicatorColumnDataProvider();
}
@Override
public void changedItems(JavaScriptObject anItems){
((JsDataContainer) getDataProvider()).changedItems(anItems);
}
@Override
public void addedItems(JavaScriptObject anItems){
((JsDataContainer) getDataProvider()).addedItems(anItems);
}
@Override
public void removedItems(JavaScriptObject anItems){
((JsDataContainer) getDataProvider()).removedItems(anItems);
}
public void redraw() {
super.redraw();
pingGWTFinallyCommands();
}
public void rebind() {
unbind();
bind();
pingGWTFinallyCommands();
}
private void pingGWTFinallyCommands() {
// Dirty hack of GWT Scgeduler.get().scheduleFinally();
// Finally commands occasionally not been executed without user
// interaction for a while.
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
Logger.getLogger(ModelGrid.class.getName()).log(Level.FINE, "ping GWT Finally commands");
}
});
}
protected void bind() {
if (data != null) {
applyRows();
setSelectionModel(new MultiJavaScriptObjectSelectionModel(this));
if (field != null && !field.isEmpty()) {
boundToData = Utils.listenPath(data, field, new Utils.OnChangeHandler() {
@Override
public void onChange(JavaScriptObject anEvent) {
applyRows();
setSelectionModel(new MultiJavaScriptObjectSelectionModel(ModelGrid.this));
}
});
}
} else {
applyRows();
setSelectionModel(null);
}
}
protected void unbind() {
if (boundToData != null) {
boundToData.removeHandler();
boundToData = null;
}
unbindCursor();
}
protected void unbindCursor() {
if (boundToCursor != null) {
boundToCursor.removeHandler();
boundToCursor = null;
}
}
@Override
public JavaScriptObject getData() {
return data;
}
@Override
public void setData(JavaScriptObject aValue) {
if (data != aValue) {
unbind();
data = aValue;
bind();
}
}
@Override
public String getField() {
return field;
}
@Override
public void setField(String aValue) {
if (field == null ? aValue != null : !field.equals(aValue)) {
unbind();
field = aValue;
bind();
}
}
public String getParentField() {
return parentField;
}
public void setParentField(String aValue) {
if (parentField == null ? aValue != null : !parentField.equals(aValue)) {
boolean wasTree = isTreeConfigured();
parentField = aValue;
boolean isTree = isTreeConfigured();
if (wasTree != isTree) {
applyRows();
}
}
}
public String getChildrenField() {
return childrenField;
}
public void setChildrenField(String aValue) {
if (childrenField == null ? aValue != null : !childrenField.equals(aValue)) {
boolean wasTree = isTreeConfigured();
childrenField = aValue;
boolean isTree = isTreeConfigured();
if (wasTree != isTree) {
applyRows();
}
}
}
public final boolean isTreeConfigured() {
return parentField != null && !parentField.isEmpty() && childrenField != null && !childrenField.isEmpty();
}
private List<Runnable> onAfterRenderTasks = new ArrayList<>();
protected void afterRender(Runnable aTask){
onAfterRenderTasks.add(aTask);
}
@Override
protected void renderingCompleted() {
super.renderingCompleted();
for(final Runnable task : onAfterRenderTasks){
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
task.run();
}
});
}
onAfterRenderTasks.clear();
if (onAfterRender != null) {
final Utils.JsObject event = JavaScriptObject.createObject().cast();
event.setJs("source", published);
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
if (onAfterRender != null) {
onAfterRender.<Utils.JsObject> cast().call(published, event);
}
}
});
}
}
public ListHandler<JavaScriptObject> getSortHandler() {
return sortHandler;
}
@Override
public HandlerRegistration addResizeHandler(ResizeHandler handler) {
return addHandler(handler, ResizeEvent.getType());
}
@Override
public HandlerRegistration addHideHandler(HideHandler handler) {
return addHandler(handler, HideEvent.getType());
}
@Override
public HandlerRegistration addShowHandler(ShowHandler handler) {
return addHandler(handler, ShowEvent.getType());
}
public HandlerRegistration addSelectionHandler(SelectionHandler<JavaScriptObject> handler) {
return addHandler(handler, SelectionEvent.getType());
}
@Override
public HandlerRegistration addFocusHandler(FocusHandler handler) {
return addDomHandler(handler, FocusEvent.getType());
}
@Override
public HandlerRegistration addBlurHandler(BlurHandler handler) {
return addDomHandler(handler, BlurEvent.getType());
}
@Override
public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
return addDomHandler(handler, KeyDownEvent.getType());
}
@Override
public HandlerRegistration addKeyPressHandler(KeyPressHandler handler) {
return addDomHandler(handler, KeyPressEvent.getType());
}
public HandlerRegistration addKeyUpHandler(KeyUpHandler handler) {
return addDomHandler(handler, KeyUpEvent.getType());
};
@Override
public void setVisible(boolean visible) {
boolean oldValue = isVisible();
super.setVisible(visible);
if (oldValue != visible) {
if (visible) {
ShowEvent.fire(this, this);
} else {
HideEvent.fire(this, this);
}
}
}
@Override
public EventsExecutor getEventsExecutor() {
return eventsExecutor;
}
@Override
public void setEventsExecutor(EventsExecutor aExecutor) {
eventsExecutor = aExecutor;
}
@Override
public boolean isEnabled() {
return enabled;
}
@Override
public void setEnabled(boolean aValue) {
boolean oldValue = enabled;
enabled = aValue;
if (!oldValue && enabled) {
getElement().<XElement> cast().unmask();
} else if (oldValue && !enabled) {
getElement().<XElement> cast().disabledMask();
}
}
@Override
public PlatypusPopupMenu getPlatypusPopupMenu() {
return menu;
}
protected HandlerRegistration menuTriggerReg;
@Override
public void setPlatypusPopupMenu(PlatypusPopupMenu aMenu) {
if (menu != aMenu) {
if (menuTriggerReg != null)
menuTriggerReg.removeHandler();
menu = aMenu;
if (menu != null) {
menuTriggerReg = super.addDomHandler(new ContextMenuHandler() {
@Override
public void onContextMenu(ContextMenuEvent event) {
event.preventDefault();
event.stopPropagation();
menu.setPopupPosition(event.getNativeEvent().getClientX(), event.getNativeEvent().getClientY());
menu.show();
}
}, ContextMenuEvent.getType());
}
}
}
@Override
public String getJsName() {
return name;
}
@Override
public void setJsName(String aValue) {
name = aValue;
}
public List<HeaderNode<JavaScriptObject>> getHeader() {
return header;
}
public void setHeader(List<HeaderNode<JavaScriptObject>> aHeader) {
if (header != aHeader) {
unpublishColumnNodes(header);
header = aHeader;
if (autoRefreshHeader) {
applyColumns();
}
publishColumnNodes(header);
}
}
public boolean removeColumnNode(HeaderNode<JavaScriptObject> aNode) {
boolean res = header.remove(aNode);
if (autoRefreshHeader) {
applyColumns();
}
return res;
}
public void addColumnNode(HeaderNode<JavaScriptObject> aNode) {
header.add(aNode);
if (autoRefreshHeader) {
applyColumns();
}
}
public void insertColumnNode(int aIndex, HeaderNode<JavaScriptObject> aNode) {
header.add(aIndex, aNode);
if (autoRefreshHeader) {
applyColumns();
}
}
@Override
public void moveColumnNode(HeaderNode<JavaScriptObject> aSubject, HeaderNode<JavaScriptObject> aInsertBefore) {
if (aSubject != null && aInsertBefore != null && aSubject.getParent() == aInsertBefore.getParent()) {
List<HeaderNode<JavaScriptObject>> neighbours = aSubject.getParent() != null
? aSubject.getParent().getChildren() : header;
boolean removed = neighbours.remove(aSubject);
assert removed;
int insertAt = neighbours.indexOf(aInsertBefore);
neighbours.add(insertAt, aSubject);
applyColumns();
onResize();
}
}
/*
* Indicates that subsequent changes will take no effect in general columns
* collection and header. They will affect only underlying grid sections
*/
protected boolean columnsAjusting;
public boolean isColumnsAjusting() {
return columnsAjusting;
}
public void setColumnsAjusting(boolean aValue) {
columnsAjusting = aValue;
}
@Override
protected void refreshColumns() {
// no op since hierarchical header processing
}
@Override
public void moveColumn(int aFromIndex, int aToIndex) {
if (aFromIndex < frozenColumns && aToIndex < frozenColumns
|| aFromIndex >= frozenColumns && aToIndex >= frozenColumns) {
Column<JavaScriptObject, ?> movedColumn = getColumn(aFromIndex);
}
}
protected ModelColumn treeIndicatorColumn;
@Override
public void addColumn(int aIndex, Column<JavaScriptObject, ?> aColumn, String aWidth, Header<?> aHeader,
Header<?> aFooter, boolean hidden) {
((ModelColumn) aColumn).setGrid(this);
super.addColumn(aIndex, aColumn, aWidth, aHeader, aFooter, hidden);
}
private void checkTreeIndicatorColumnDataProvider() {
if (dataProvider instanceof TreeDataProvider<?>) {
if (treeIndicatorColumn == null) {
int treeIndicatorIndex = 0;
while (treeIndicatorIndex < getDataColumnCount()) {
Column<JavaScriptObject, ?> indicatorColumn = getDataColumn(treeIndicatorIndex);
if (indicatorColumn instanceof UsualServiceColumn || indicatorColumn instanceof RadioServiceColumn
|| indicatorColumn instanceof CheckServiceColumn) {
treeIndicatorIndex++;
} else if (indicatorColumn instanceof ModelColumn) {
treeIndicatorColumn = (ModelColumn) indicatorColumn;
break;
}
}
}
if (treeIndicatorColumn != null && treeIndicatorColumn.getCell() instanceof TreeExpandableCell<?, ?>) {
TreeExpandableCell<JavaScriptObject, ?> treeCell = (TreeExpandableCell<JavaScriptObject, ?>) treeIndicatorColumn
.getCell();
treeCell.setDataProvider((TreeDataProvider<JavaScriptObject>) dataProvider);
}
} else {
if (treeIndicatorColumn != null && treeIndicatorColumn.getCell() instanceof TreeExpandableCell<?, ?>) {
TreeExpandableCell<JavaScriptObject, ?> treeCell = (TreeExpandableCell<JavaScriptObject, ?>) treeIndicatorColumn
.getCell();
treeCell.setDataProvider(null);
}
treeIndicatorColumn = null;
}
}
@Override
public void removeColumn(int aIndex) {
Column<JavaScriptObject, ?> toDel = getDataColumn(aIndex);
ModelColumn mCol = (ModelColumn) toDel;
if (mCol == treeIndicatorColumn) {
TreeExpandableCell<JavaScriptObject, ?> treeCell = (TreeExpandableCell<JavaScriptObject, ?>) mCol.getCell();
treeCell.setDataProvider(null);
treeIndicatorColumn = null;
}
super.removeColumn(aIndex);
mCol.setGrid(null);
}
@Override
public void setColumnWidthFromHeaderDrag(Column<JavaScriptObject, ?> aColumn, double aWidth, Unit aUnit) {
ModelColumn modelCol = (ModelColumn) aColumn;
if (aWidth <= modelCol.getMinWidth())
aWidth = modelCol.getMinWidth();
if (aWidth >= modelCol.getMaxWidth())
aWidth = modelCol.getMaxWidth();
super.setColumnWidth(aColumn, aWidth, aUnit);
modelCol.setWidth(aWidth);
propagateHeightButScrollable();
}
@Override
public void setColumnWidth(Column<JavaScriptObject, ?> aColumn, double aWidth, Unit aUnit) {
ModelColumn modelCol = (ModelColumn) aColumn;
if (aWidth <= modelCol.getMinWidth())
aWidth = modelCol.getMinWidth();
if (aWidth >= modelCol.getMaxWidth())
aWidth = modelCol.getMaxWidth();
super.setColumnWidth(aColumn, aWidth, aUnit);
modelCol.updateWidth(aWidth);
}
@Override
public void showColumn(Column<JavaScriptObject, ?> aColumn) {
super.showColumn(aColumn);
ModelColumn colFacade = (ModelColumn) aColumn;
colFacade.updateVisible(true);
enqueueRedraw(); // because of AbstractCellTable.isInteractive crazy
// updating while rendering instead of updating it
// while show/hide columns
}
public void hideColumn(Column<JavaScriptObject, ?> aColumn) {
super.hideColumn(aColumn);
ModelColumn colFacade = (ModelColumn) aColumn;
colFacade.updateVisible(false);
}
@Override
public void setFrozenColumns(int aValue) {
if (aValue >= 0 && frozenColumns != aValue) {
frozenColumns = aValue;
if (autoRefreshHeader && getDataColumnCount() > 0 && aValue <= getDataColumnCount()) {
applyColumns();
}
}
}
protected boolean autoRefreshHeader = true;
public boolean isAutoRefreshHeader() {
return autoRefreshHeader;
}
public void setAutoRefreshHeader(boolean aValue) {
autoRefreshHeader = aValue;
}
protected void clearColumns() {
for (int i = getDataColumnCount() - 1; i >= 0; i--) {
Column<JavaScriptObject, ?> toDel = getDataColumn(i);
ModelColumn mCol = (ModelColumn) toDel;
if (mCol == treeIndicatorColumn) {
TreeExpandableCell<JavaScriptObject, ?> treeCell = (TreeExpandableCell<JavaScriptObject, ?>) mCol
.getCell();
treeCell.setDataProvider(null);
treeIndicatorColumn = null;
}
mCol.setGrid(null);
}
for (int i = headerRight.getColumnCount() - 1; i >= 0; i--) {
headerRight.removeColumn(i);
}
for (int i = headerLeft.getColumnCount() - 1; i >= 0; i--) {
headerLeft.removeColumn(i);
}
}
public void applyColumns() {
clearColumns();
List<HeaderNode<JavaScriptObject>> leaves = new ArrayList<>();
HeaderAnalyzer.achieveLeaves(header, leaves);
for (HeaderNode<JavaScriptObject> leaf : leaves) {
Header<String> header = leaf.getHeader();
ModelColumn column = (ModelColumn) leaf.getColumn();
column.setGrid(this);
addColumn(column, column.getWidth() + "px", header, null, !column.isVisible());
}
ThemedHeaderOrFooterBuilder<JavaScriptObject> leftBuilder = (ThemedHeaderOrFooterBuilder<JavaScriptObject>) headerLeft
.getHeaderBuilder();
ThemedHeaderOrFooterBuilder<JavaScriptObject> rightBuilder = (ThemedHeaderOrFooterBuilder<JavaScriptObject>) headerRight
.getHeaderBuilder();
List<HeaderNode<JavaScriptObject>> leftHeader = HeaderSplitter.split(header, 0, frozenColumns - 1);
leftBuilder.setHeaderNodes(leftHeader);
List<HeaderNode<JavaScriptObject>> rightHeader = HeaderSplitter.split(header, frozenColumns,
getDataColumnCount());
rightBuilder.setHeaderNodes(rightHeader);
checkTreeIndicatorColumnDataProvider();
redrawHeaders();
}
@Override
public void setSelectionModel(final SelectionModel<JavaScriptObject> aValue) {
SelectionModel<? super JavaScriptObject> oldValue = getSelectionModel();
if (aValue != oldValue) {
if (positionSelectionHandler != null)
positionSelectionHandler.removeHandler();
if (onSelectEventSelectionHandler != null)
onSelectEventSelectionHandler.removeHandler();
CellPreviewEvent.Handler<JavaScriptObject> eventsManager = GridSelectionEventManager
.<JavaScriptObject> create(new CheckBoxesEventTranslator<JavaScriptObject>());
headerLeft.setSelectionModel(aValue, eventsManager);
headerRight.setSelectionModel(aValue, eventsManager);
frozenLeft.setSelectionModel(aValue, eventsManager);
frozenRight.setSelectionModel(aValue, eventsManager);
scrollableLeft.setSelectionModel(aValue, eventsManager);
scrollableRight.setSelectionModel(aValue, eventsManager);
if (aValue != null) {
Object oData = field != null && !field.isEmpty() ? Utils.getPathData(data, field) : data;
if (oData instanceof JavaScriptObject) {
positionSelectionHandler = aValue.addSelectionChangeHandler(
new CursorPropertySelectionReflector((JavaScriptObject) oData, aValue));
onSelectEventSelectionHandler = aValue
.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
if (aValue instanceof HasSelectionLead<?>) {
try {
JavaScriptObject lead = ((HasSelectionLead<JavaScriptObject>) aValue)
.getLead();
SelectionEvent.fire(ModelGrid.this, lead);
} catch (Exception e) {
Logger.getLogger(CursorPropertySelectionReflector.class.getName())
.log(Level.SEVERE, e.getMessage());
}
}
}
});
}
}
}
}
protected void applyColorsFontCursor() {
if (published.isBackgroundSet() && published.isOpaque())
WidgetsUtils.applyBackground(this, published.getBackground());
if (published.isForegroundSet())
WidgetsUtils.applyForeground(this, published.getForeground());
if (published.isFontSet())
WidgetsUtils.applyFont(this, published.getFont());
if (published.isCursorSet())
WidgetsUtils.applyCursor(this, published.getCursor());
}
public JavaScriptObject getPublished() {
return published;
}
public void setPublished(JavaScriptObject aValue) {
published = aValue != null ? aValue.<PublishedComponent> cast() : null;
if (published != null) {
publish(this, published);
publishColumnNodes(header);
}
}
protected void unpublishColumnNodes(List<HeaderNode<JavaScriptObject>> aNodes) {
for (HeaderNode<JavaScriptObject> node : aNodes) {
String jsName = ((HasJsName) node).getJsName();
if (jsName != null && !jsName.isEmpty()) {
published.<JsObject> cast().deleteProperty(jsName);
}
unpublishColumnNodes(node.getChildren());
}
}
protected void publishColumnNodes(List<HeaderNode<JavaScriptObject>> aNodes) {
for (HeaderNode<JavaScriptObject> node : aNodes) {
String jsName = ((HasJsName) node).getJsName();
if (jsName != null && !jsName.isEmpty()) {
HasPublished pCol = (HasPublished) node;
published.<JsObject> cast().inject(jsName, pCol.getPublished(), true);
}
publishColumnNodes(node.getChildren());
}
}
private native static void publish(ModelGrid aWidget, JavaScriptObject aPublished)/*-{
aPublished.select = function(aRow) {
if (aRow != null && aRow != undefined)
aWidget.@com.eas.grid.ModelGrid::selectElement(Lcom/google/gwt/core/client/JavaScriptObject;)(aRow);
};
aPublished.unselect = function(aRow) {
if (aRow != null && aRow != undefined)
aWidget.@com.eas.grid.ModelGrid::unselectElement(Lcom/google/gwt/core/client/JavaScriptObject;)(aRow);
};
aPublished.clearSelection = function() {
aWidget.@com.eas.grid.ModelGrid::clearSelection()();
};
aPublished.find = function() {
aWidget.@com.eas.grid.ModelGrid::find()();
};
aPublished.findSomething = function() {
aPublished.find();
};
aPublished.makeVisible = function(aInstance, needToSelect) {
var need2Select = arguments.length > 1 ? !!needToSelect : false;
if (aInstance != null){
// We have to use willBeVisible() instead of makeVisible(), because of
// asynchronous nature of grid's cells rendering.
// Imagine, that someone requested cells re-rendering already.
// In such situation, results of makeVisible call is a zombie.
aWidget.@com.eas.grid.ModelGrid::willBeVisible(Lcom/google/gwt/core/client/JavaScriptObject;Z)(aInstance, need2Select);
}
};
aPublished.expanded = function(aInstance) {
return aWidget.@com.eas.grid.ModelGrid::expanded(Lcom/google/gwt/core/client/JavaScriptObject;)(aInstance);
};
aPublished.expand = function(aInstance) {
aWidget.@com.eas.grid.ModelGrid::expand(Lcom/google/gwt/core/client/JavaScriptObject;)(aInstance);
};
aPublished.collapse = function(aInstance) {
aWidget.@com.eas.grid.ModelGrid::collapse(Lcom/google/gwt/core/client/JavaScriptObject;)(aInstance);
};
aPublished.toggle = function(aInstance) {
aWidget.@com.eas.grid.ModelGrid::toggle(Lcom/google/gwt/core/client/JavaScriptObject;)(aInstance);
};
aPublished.unsort = function() {
aWidget.@com.eas.grid.ModelGrid::unsort()();
};
aPublished.redraw = function() {
// ModelGrid.redraw() is used as a rebinder in applications.
// Because applications don't care about grid's dataProviders' internal
// data structures, such as JsArrayDataProvider and its internal list of elements.
// So, redraw grid through rebinding of its data.
aWidget.@com.eas.grid.ModelGrid::rebind()();
};
aPublished.changed = function(aItems){
if(!$wnd.Array.isArray(aItems))
aItems = [aItems];
aWidget.@com.eas.grid.ModelGrid::changedItems(Lcom/google/gwt/core/client/JavaScriptObject;)(aItems);
};
aPublished.added = function(aItems){
if(!$wnd.Array.isArray(aItems))
aItems = [aItems];
aWidget.@com.eas.grid.ModelGrid::addedItems(Lcom/google/gwt/core/client/JavaScriptObject;)(aItems);
};
aPublished.removed = function(aItems){
if(!$wnd.Array.isArray(aItems))
aItems = [aItems];
aWidget.@com.eas.grid.ModelGrid::removedItems(Lcom/google/gwt/core/client/JavaScriptObject;)(aItems);
};
aPublished.removeColumnNode = function(aColumnFacade){
if(aColumnFacade && aColumnFacade.unwrap)
return aWidget.@com.eas.grid.ModelGrid::removeColumnNode(Lcom/eas/grid/columns/header/HeaderNode;)(aColumnFacade.unwrap());
else
return false;
};
aPublished.addColumnNode = function(aColumnFacade){
if(aColumnFacade && aColumnFacade.unwrap)
aWidget.@com.eas.grid.ModelGrid::addColumnNode(Lcom/eas/grid/columns/header/HeaderNode;)(aColumnFacade.unwrap());
};
aPublished.insertColumnNode = function(aIndex, aColumnFacade){
if(aColumnFacade && aColumnFacade.unwrap)
aWidget.@com.eas.grid.ModelGrid::insertColumnNode(ILcom/eas/grid/columns/header/HeaderNode;)(aIndex, aColumnFacade.unwrap());
};
aPublished.columnNodes = function(){
var headerRoots = aWidget.@com.eas.grid.ModelGrid::getHeader()();
var rootsCount = headerRoots.@java.util.List::size()();
var res = [];
for(var r = 0; r < rootsCount; r++){
var nNode = headerRoots.@java.util.List::get(I)(r);
var jsNode = nNode.@com.eas.core.HasPublished::getPublished()();
res.push(jsNode);
}
return res;
};
Object.defineProperty(aPublished, "headerVisible", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::isHeaderVisible()();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setHeaderVisible(Z)(!!aValue);
}
});
Object.defineProperty(aPublished, "draggableRows", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::isDraggableRows()();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setDraggableRows(Z)(!!aValue);
}
});
Object.defineProperty(aPublished, "frozenRows", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::getFrozenRows()();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setFrozenRows(I)(+aValue);
}
});
Object.defineProperty(aPublished, "frozenColumns", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::getFrozenColumns()();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setFrozenColumns(I)(+aValue);
}
});
Object.defineProperty(aPublished, "rowsHeight", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::getRowsHeight()();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setRowsHeight(I)(aValue * 1);
}
});
Object.defineProperty(aPublished, "showHorizontalLines", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::isShowHorizontalLines()();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setShowHorizontalLines(Z)(!!aValue);
}
});
Object.defineProperty(aPublished, "showVerticalLines", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::isShowVerticalLines()();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setShowVerticalLines(Z)(!!aValue);
}
});
Object.defineProperty(aPublished, "showOddRowsInOtherColor", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::isShowOddRowsInOtherColor()();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setShowOddRowsInOtherColor(Z)(!!aValue);
}
});
Object.defineProperty(aPublished, "gridColor", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::getGridColor()();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setGridColor(Lcom/eas/ui/PublishedColor;)(aValue);
}
});
Object.defineProperty(aPublished, "oddRowsColor", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::getOddRowsColor()();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setOddRowsColor(Lcom/eas/ui/PublishedColor;)(aValue);
}
});
Object.defineProperty(aPublished, "cursorProperty", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::getCursorProperty()();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setCursorProperty(Ljava/lang/String;)(aValue ? '' + aValue : null);
}
});
Object.defineProperty(aPublished, "onRender", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::getOnRender()();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setOnRender(Lcom/google/gwt/core/client/JavaScriptObject;)(aValue);
}
});
Object.defineProperty(aPublished, "onAfterRender", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::getOnAfterRender()();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setOnAfterRender(Lcom/google/gwt/core/client/JavaScriptObject;)(aValue);
}
});
Object.defineProperty(aPublished, "onExpand", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::getOnExpand()();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setOnExpand(Lcom/google/gwt/core/client/JavaScriptObject;)(aValue);
}
});
Object.defineProperty(aPublished, "onCollapse", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::getOnCollapse()();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setOnCollapse(Lcom/google/gwt/core/client/JavaScriptObject;)(aValue);
}
});
Object.defineProperty(aPublished, "selected", {
get : function() {
var selectionList = aWidget.@com.eas.grid.ModelGrid::getJsSelected()();
var selectionArray = [];
for ( var i = 0; i < selectionList.@java.util.List::size()(); i++) {
selectionArray[selectionArray.length] = selectionList.@java.util.List::get(I)(i);
}
return selectionArray;
}
});
Object.defineProperty(aPublished, "editable", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::isEditable()();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setEditable(Z)(aValue);
}
});
Object.defineProperty(aPublished, "deletable", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::isDeletable()();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setDeletable(Z)(aValue);
}
});
Object.defineProperty(aPublished, "insertable", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::isInsertable()();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setInsertable(Z)(aValue);
}
});
Object.defineProperty(aPublished, "data", {
get : function() {
return aWidget.@com.eas.ui.HasBinding::getData()();
},
set : function(aValue) {
aWidget.@com.eas.ui.HasBinding::setData(Lcom/google/gwt/core/client/JavaScriptObject;)(aValue);
}
});
Object.defineProperty(aPublished, "field", {
get : function() {
return aWidget.@com.eas.ui.HasBinding::getField()();
},
set : function(aValue) {
aWidget.@com.eas.ui.HasBinding::setField(Ljava/lang/String;)(aValue != null ? '' + aValue : null);
}
});
Object.defineProperty(aPublished, "parentField", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::getParentField();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setParentField(Ljava/lang/String;)(aValue != null ? '' + aValue : null);
}
});
Object.defineProperty(aPublished, "childrenField", {
get : function() {
return aWidget.@com.eas.grid.ModelGrid::getChildrenField();
},
set : function(aValue) {
aWidget.@com.eas.grid.ModelGrid::setChildrenField(Ljava/lang/String;)(aValue != null ? '' + aValue : null);
}
});
}-*/;
public JavaScriptObject getOnRender() {
return onRender;
}
public void setOnRender(JavaScriptObject aValue) {
onRender = aValue;
}
public JavaScriptObject getOnAfterRender() {
return onAfterRender;
}
public void setOnAfterRender(JavaScriptObject aValue) {
onAfterRender = aValue;
}
public JavaScriptObject getOnExpand() {
return onExpand;
}
public void setOnExpand(JavaScriptObject aValue) {
onExpand = aValue;
}
public JavaScriptObject getOnCollapse() {
return onCollapse;
}
public void setOnCollapse(JavaScriptObject aValue) {
onCollapse = aValue;
}
public String getCursorProperty() {
return cursorProperty;
}
public void setCursorProperty(String aValue) {
if (aValue != null && !cursorProperty.equals(aValue)) {
unbind();
cursorProperty = aValue;
bind();
}
}
public void selectElement(JavaScriptObject aElement) {
getSelectionModel().setSelected(aElement, true);
pingGWTFinallyCommands();
}
public void unselectElement(JavaScriptObject anElement) {
getSelectionModel().setSelected(anElement, false);
pingGWTFinallyCommands();
}
public List<JavaScriptObject> getJsSelected() throws Exception {
SetSelectionModel<? super JavaScriptObject> sm = getSelectionModel();
return new ArrayList<JavaScriptObject>((Collection<JavaScriptObject>)sm.getSelectedSet());
}
public void clearSelection() {
SetSelectionModel<? super JavaScriptObject> sm = getSelectionModel();
sm.clear();
pingGWTFinallyCommands();
}
public boolean isEditable() {
return editable;
}
public void setEditable(boolean aValue) {
editable = aValue;
}
public boolean isDeletable() {
return deletable;
}
public void setDeletable(boolean aValue) {
deletable = aValue;
}
public boolean isInsertable() {
return insertable;
}
public void setInsertable(boolean aValue) {
insertable = aValue;
}
public boolean expanded(JavaScriptObject anElement) {
if (getDataProvider() instanceof JsArrayTreeDataProvider) {
JsArrayTreeDataProvider treeDataProvider = (JsArrayTreeDataProvider) getDataProvider();
return treeDataProvider.isExpanded(anElement);
} else {
return false;
}
}
public void expand(JavaScriptObject anElement) {
if (getDataProvider() instanceof JsArrayTreeDataProvider) {
JsArrayTreeDataProvider treeDataProvider = (JsArrayTreeDataProvider) getDataProvider();
treeDataProvider.expand(anElement);
}
}
public void collapse(JavaScriptObject anElement) {
if (getDataProvider() instanceof JsArrayTreeDataProvider) {
JsArrayTreeDataProvider treeDataProvider = (JsArrayTreeDataProvider) getDataProvider();
treeDataProvider.collapse(anElement);
}
}
public void toggle(JavaScriptObject anElement) {
if (getDataProvider() instanceof JsArrayTreeDataProvider) {
JsArrayTreeDataProvider treeDataProvider = (JsArrayTreeDataProvider) getDataProvider();
if (treeDataProvider.isExpanded(anElement)) {
treeDataProvider.collapse(anElement);
} else {
treeDataProvider.expand(anElement);
}
}
}
public void willBeVisible(final JavaScriptObject anElement, final boolean aNeedToSelect){
redraw(); // force rendering request to avoid makeVisible() deferring on an undefined moment in the future.
afterRender(new Runnable(){
@Override
public void run() {
makeVisible(anElement, aNeedToSelect);
}
});
}
public boolean makeVisible(JavaScriptObject anElement, boolean aNeedToSelect) {
IndexOfProvider<JavaScriptObject> indexOfProvider = (IndexOfProvider<JavaScriptObject>) dataProvider;
int index = indexOfProvider.indexOf(anElement);
if (index > -1) {
if (index >= 0 && index < frozenRows) {
TableCellElement leftCell = frozenLeft.getCell(index, 0);
if (leftCell != null) {
leftCell.scrollIntoView();
} else {
TableCellElement rightCell = frozenRight.getCell(index, 0);
if (rightCell != null)
rightCell.scrollIntoView();
}
} else {
TableCellElement leftCell = scrollableLeft.getCell(index, 0);
if (leftCell != null) {
leftCell.scrollIntoView();
} else {
TableCellElement rightCell = scrollableRight.getCell(index, 0);
if (rightCell != null)
rightCell.scrollIntoView();
}
}
if (aNeedToSelect) {
clearSelection();
selectElement(anElement);
if (index >= 0 && index < frozenRows) {
frozenLeft.setKeyboardSelectedRow(index, true);
frozenRight.setKeyboardSelectedRow(index, true);
} else {
scrollableLeft.setKeyboardSelectedRow(index - frozenRows, true);
scrollableRight.setKeyboardSelectedRow(index - frozenRows, true);
}
}
pingGWTFinallyCommands();
return true;
} else
return false;
}
public void find() {
if (finder == null) {
finder = new FindWindow(ModelGrid.this);
}
finder.show();
}
@Override
protected void onDetach() {
super.onDetach();
if (finder != null) {
finder.close();
}
}
@Override
protected void onColumnsResize() {
if (isAttached()) {
double prevError = 0;
double error = distributeColumnsWidths();
while (Math.abs(error) > 0.8 && Math.abs(error - prevError) > 2) {
prevError = error;
error = distributeColumnsWidths();
}
}
}
protected double distributeColumnsWidths() {
List<ModelColumn> availableColumns = new ArrayList<>();
double commonWidth = 0;
for (int i = 0; i < getDataColumnCount(); i++) {
Column<JavaScriptObject, ?> column = getDataColumn(i);
ModelColumn mCol = (ModelColumn) column;
if (mCol.isVisible()) {
commonWidth += mCol.getWidth();
availableColumns.add(mCol);
}
}
double widthError = 0;
double delta = (scrollableLeftContainer.getElement().getClientWidth()
+ scrollableRightContainer.getElement().getClientWidth()) - 1 - commonWidth;
for (ModelColumn mCol : availableColumns) {
double coef = mCol.getWidth() / commonWidth;
double newWidth = mCol.getWidth() + delta * coef;
setColumnWidth(mCol, newWidth, Style.Unit.PX);
widthError += Math.abs(mCol.getWidth() - newWidth);
}
return widthError;
}
@Override
public void onResize() {
super.onResize();
if (isAttached()) {
ResizeEvent.fire(this, getElement().getOffsetWidth(), getElement().getOffsetHeight());
}
}
public void complementPublishedStyle(PublishedCell aComplemented) {
if (published.isBackgroundSet()) {
aComplemented.setBackground(published.getBackground());
}
if (published.isForegroundSet()) {
aComplemented.setForeground(published.getForeground());
}
if (published.isFontSet()) {
aComplemented.setFont(published.getFont());
}
}
}