With Pro 3.1d (June 12 build):
I had a nice standalone example of a simple ListGrid with a dynamic structure that made use of the new canSelectCells(true) behaviors. The table can be redrawn based on different query results with different column structures. When called in standalone mode (making use of the EntryPoint's onModuleLoad()), the single cell selection and range selection works fine upon rebuilds.
I moved the code into my larger app, where the "canvas" containing the table and other elements is placed into a TabSet. A number of problems came up, starting with the inability to actually call the canSelectCells method
By taking that out, I was able to get the code to render, but not with the correct visualization of the selected range. Then on the second and subsequent renderings, the ListGrid reverts to a rendering mode where all the cells in the row beneath the mouse are highlighted (the typical ListGrid behavior?)
Here's an example which can be run standalone.
Here's some additional code which would add a CellSelectionTester to a TabSet:
I took the time to demonstrate one other bug I came across recently. In a DynamicForm, an IntegerItem will throw an Exception on a call to getValueAsInteger. Run the code to see.
Lastly, as I need to be able to treat this code like a "panel class" that I can put into a Tab, when running it that way, I ran into a variety of exceptions when configuring the ListGrid in the constructor, just before the "Tester" would be added to the Tab. Here are snippets of two other exceptions besides the canSelectCells exception mentioned above:
I had to remove those method calls to get the code to run. I'm not sure yet if I can leave them out for my final purposes.
One last item: I was experimenting with the various ListGrid Handlers with the goal being to track and retrieve the selected region. Ultimately, a call to getSelectedCells() does the work...
When tracking a selection range with canSelectCells(true), the CellMouseUpHandler is not called when the range stops being tracked. The CellMouseDownHandler is always called -- you can see that if you simply click single cells one at a time it different places in the grid. If you click one and then extend a selection rectangle down, upon stopping and releasing the mouse, the UpHandler is not called.
In summary, four different issues (the isolation of which ate up a good part of my day):
1. Differences in canSelectCells behavior and rendering between EntryPoint use cases and non-EntryPoint use cases
2. Inability to call certain ListGrid configuration methods in the non-EntryPoint use case. Ideally with this family of error messages, I'd like more help in knowing what 'component' has been 'created' to determine where the problem is coming from.
3. Problem with DynamicForm's IntegerItem
4. Wanting a CellMouseUpEvent when the cell selection range stops changing due to a mouse up.
Back to my other application logging/configuration issue... http://forums.smartclient.com/showthread.php?t=22601
I had a nice standalone example of a simple ListGrid with a dynamic structure that made use of the new canSelectCells(true) behaviors. The table can be redrawn based on different query results with different column structures. When called in standalone mode (making use of the EntryPoint's onModuleLoad()), the single cell selection and range selection works fine upon rebuilds.
I moved the code into my larger app, where the "canvas" containing the table and other elements is placed into a TabSet. A number of problems came up, starting with the inability to actually call the canSelectCells method
Code:
(BaseWidget.java:600) 2012-06-25 19:22:19,435 [ERROR] Uncaught exception com.google.gwt.event.shared.UmbrellaException: One or more exceptions caught, see full set in UmbrellaException#getCauses at com.google.gwt.event.shared.HandlerManager.fireEvent(HandlerManager.java:129) at com.smartgwt.client.widgets.BaseWidget.fireEvent(BaseWidget.java:71) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) .... Caused by: java.lang.IllegalStateException: Cannot change configuration property 'canSelectCells' to false after the component has been created.
Here's an example which can be run standalone.
Code:
import com.allen_sauer.gwt.log.client.Log; import com.google.gwt.core.client.GWT; import com.smartgwt.client.data.RecordList; import com.smartgwt.client.types.Alignment; import com.smartgwt.client.types.ListGridFieldType; import com.smartgwt.client.types.SelectionStyle; import com.smartgwt.client.util.SC; import com.smartgwt.client.widgets.Canvas; import com.smartgwt.client.widgets.IButton; import com.smartgwt.client.widgets.events.ClickEvent; import com.smartgwt.client.widgets.events.ClickHandler; import com.smartgwt.client.widgets.form.DynamicForm; import com.smartgwt.client.widgets.form.fields.IntegerItem; import com.smartgwt.client.widgets.form.fields.TextItem; import com.smartgwt.client.widgets.grid.*; import com.smartgwt.client.widgets.grid.events.*; import com.smartgwt.client.widgets.layout.HLayout; import com.smartgwt.client.widgets.layout.VLayout; public class CellSelectionTester implements EntryPoint { private ListGrid d_simpleGrid; private Canvas d_canvas; private VLayout d_vertLayout; private HLayout d_placeholderForTable; private DynamicForm d_simpleForm; private IntegerItem d_numColsIntItem; private TextItem d_numColsTextItem; private boolean d_didRebuild = false; public void onModuleLoad() { Log.warn("onModuleLoad was called"); } public CellSelectionTester() { Log.warn("CellSelectionTester()"); GWT.setUncaughtExceptionHandler(new GWT.UncaughtExceptionHandler() { public void onUncaughtException(Throwable e) { Log.error("Uncaught exception", e); } }); d_canvas = new Canvas(); d_vertLayout = new VLayout(); IButton testButton = new IButton("Test Cell Selection"); testButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent clickEvent) { testCellSelection(); } }); d_simpleForm = new DynamicForm(); d_simpleForm.setWidth(225); d_simpleForm.setWrapItemTitles(false); d_simpleForm.setTitleWidth(150); d_numColsIntItem = new IntegerItem("numColsInt","Num Cols As Int"); d_numColsIntItem.setValue(5); d_numColsTextItem = new TextItem("numColsText","Num Cols As Text"); d_numColsTextItem.setValue("5"); d_simpleForm.setFields(d_numColsIntItem,d_numColsTextItem); IButton rebuildGrid = new IButton("Rebuild Grid"); rebuildGrid.addClickHandler(new ClickHandler() { public void onClick(ClickEvent clickEvent) { rebuildGridInteractive(); if (!d_didRebuild){ SC.warn("*** IF NOT CALLED VIA onModuleLoad() ****\nMove the mouse over the grid to notice that the selection mode is now row-like, not single-cell.\nClick Rebuild Grid again with different form values to see Form error."); d_didRebuild = true; } } }); d_placeholderForTable = new HLayout(); d_simpleGrid = new ListGrid(); d_placeholderForTable.addMember(d_simpleGrid); d_vertLayout.addMember(d_placeholderForTable); d_vertLayout.addMember(d_simpleForm); d_vertLayout.addMember(rebuildGrid); d_vertLayout.addMember(testButton); d_canvas.addChild(d_vertLayout); rebuildGrid(10); d_canvas.draw(); SC.warn("Move the mouse over the grid to notice single-cell selection"); } private void rebuildGridInteractive() { int numCols = 0; try{ Integer valueAsInteger = d_numColsIntItem.getValueAsInteger(); numCols = valueAsInteger; } catch (Throwable t){ // The code above seems to generate this error on the second and subsequent call; // com.google.gwt.dev.shell.HostedModeException: invoke arguments: JS value of type string, expected int // at com.google.gwt.dev.shell.JsValueGlue.getIntRange(JsValueGlue.java:266) // [ If it only happens in HostedMode... it still makes the development cycle very tedious] // This Exception seems to only be thrown if you change the original integer value to something else. SC.warn("Got error message trying to getValueAsInteger"); Log.error("Error with getValueAsInteger",t); String numColsText = d_numColsTextItem.getValueAsString(); if (numColsText != null){ try{ numCols = Integer.parseInt(numColsText); } catch (Throwable t2){ SC.warn("Couldn't parse an integer..."); } } } if (numCols > 0){ rebuildGrid(numCols); } } private void rebuildGrid(int numCols) { /* Exceptions: 1. With rebuildGrid() being called at the end of the constructor a. Caused by: java.lang.IllegalStateException: Cannot change configuration property 'canSelectCells' to false after the component has been created. b. Caused by: java.lang.IllegalStateException: Cannot change configuration property 'canRemoveRecords' to false after the component has been created. b. Caused by: java.lang.IllegalStateException: Cannot change configuration property 'autoFetchData' to false after the component has been created. */ if ((d_simpleGrid != null) && (d_placeholderForTable != null)){ Log.warn("Grid and layout existed already... destroying..."); d_placeholderForTable.removeMember(d_simpleGrid); d_simpleGrid.destroy(); } d_simpleGrid = new ListGrid(); d_simpleGrid.setID("masterGrid"); d_simpleGrid.setWidth(400); d_simpleGrid.setHeight(300); // This only works if the code is called via the EntryPoint d_simpleGrid.setCanSelectCells(true); d_simpleGrid.setCanDragSelect(true); d_simpleGrid.setCanSort(false); d_simpleGrid.setHeaderHeight(40); d_simpleGrid.setCanEdit(false); d_simpleGrid.setShowAllRecords(true); d_simpleGrid.setKeepInParentRect(true); // d_simpleGrid.setCanRemoveRecords(false); d_simpleGrid.setLeaveScrollbarGap(false); d_simpleGrid.setUseAllDataSourceFields(true); // d_simpleGrid.setAutoFetchData(false); d_simpleGrid.addCellClickHandler(new CellClickHandler() { public void onCellClick(CellClickEvent cellClickEvent) { Log.warn("Clicked: " + cellClickEvent.getRowNum() + "," + cellClickEvent.getColNum()); } }); d_simpleGrid.addSelectionChangedHandler(new SelectionChangedHandler() { public void onSelectionChanged(SelectionEvent selectionEvent) { Log.warn("selection changed: " + d_simpleGrid.getEventRow() + "," + d_simpleGrid.getEventRow()); } }); d_simpleGrid.addCellMouseDownHandler(new CellMouseDownHandler() { public void onCellMouseDown(CellMouseDownEvent event) { Log.warn("Mouse down at: " + d_simpleGrid.getEventRow() + "," + d_simpleGrid.getEventColumn()); } }); d_simpleGrid.addCellMouseUpHandler(new CellMouseUpHandler() { public void onCellMouseUp(CellMouseUpEvent event) { Log.warn("Mouse up at: " + d_simpleGrid.getEventRow() + "," + d_simpleGrid.getEventColumn()); } }); /* This is quite noisy... d_simpleGrid.addCellSelectionChangedHandler(new CellSelectionChangedHandler() { public void onCellSelectionChanged(CellSelectionChangedEvent event) { dumpSelectedCells(event.getCellList(), "From cell selection changed handler"); } }); */ // Dynamically generate the structures... int numRows = 10; ListGridRecord[] records = new ListGridRecord[numRows]; ListGridField[] fields = new ListGridField[numCols]; int col = 0; while (col < numCols){ String key = "col-" + col; ListGridField field = new ListGridField(key,"Col " + col); field.setType(ListGridFieldType.TEXT); field.setWidth(50); field.setAlign(Alignment.RIGHT); fields[col] = field; int row = 0; while (row < numRows){ ListGridRecord record = null; if (col == 0){ record = new ListGridRecord(); records[row] = record; } record = records[row]; record.setAttribute(key,"r" + row + ", c" + col); row++; } col++; } d_simpleGrid.setFields(fields); d_simpleGrid.setData(records); d_placeholderForTable.addMember(d_simpleGrid); d_canvas.draw(); } private void dumpSelectedCells(int[][] cellList, String fromWhere) { if (cellList != null){ int length = cellList.length; Log.warn("cellList len = " + length + " " + fromWhere); int i = 0; while (i < length){ int[] cols = cellList[i]; int c = 0; int numCols = cols.length; if (numCols == 2){ Log.warn("r=" + cols[0] + ",c=" + cols[1]); } else{ Log.warn("NumCols = " + numCols); // Always in pairs of two, first one is row, second one is column. while (c < numCols){ Log.warn(" (" + cellList[i][c] + ")"); c++; } } i++; } } } private void testCellSelection() { Log.warn("test selection..."); SelectionStyle selectionType = d_simpleGrid.getSelectionType(); RecordList selectedCellData = d_simpleGrid.getSelectedCellData(); ListGridRecord[] selectedRecords = d_simpleGrid.getSelectedRecords(); if (selectedCellData != null){ Log.warn("selectedCellData.length = " + selectedCellData.getLength()); } if (selectedRecords != null){ Log.warn("Num selected records = " + selectedRecords.length); } CellSelection cellSelection = d_simpleGrid.getCellSelection(); int[][] selectedCells = cellSelection.getSelectedCells(); dumpSelectedCells(selectedCells,"Upon Button Click"); } public Canvas getMainCanvas() { return d_canvas; } }
Code:
CellSelectionTester cellSelectionTester = new CellSelectionTester(); Tab reportTab = new Tab("Cell Selection Tester"); reportTab.setCanClose(true); reportTab.setPane(cellSelectionTester.getMainCanvas()); d_mainTabs.addTab(reportTab); d_mainTabs.selectTab(reportTab);
I took the time to demonstrate one other bug I came across recently. In a DynamicForm, an IntegerItem will throw an Exception on a call to getValueAsInteger. Run the code to see.
Lastly, as I need to be able to treat this code like a "panel class" that I can put into a Tab, when running it that way, I ran into a variety of exceptions when configuring the ListGrid in the constructor, just before the "Tester" would be added to the Tab. Here are snippets of two other exceptions besides the canSelectCells exception mentioned above:
Code:
(1) Caused by: java.lang.IllegalStateException: Cannot change configuration property 'canRemoveRecords' to false after the component has been created. (2) Caused by: java.lang.IllegalStateException: Cannot change configuration property 'autoFetchData' to false after the component has been created.
One last item: I was experimenting with the various ListGrid Handlers with the goal being to track and retrieve the selected region. Ultimately, a call to getSelectedCells() does the work...
When tracking a selection range with canSelectCells(true), the CellMouseUpHandler is not called when the range stops being tracked. The CellMouseDownHandler is always called -- you can see that if you simply click single cells one at a time it different places in the grid. If you click one and then extend a selection rectangle down, upon stopping and releasing the mouse, the UpHandler is not called.
In summary, four different issues (the isolation of which ate up a good part of my day):
1. Differences in canSelectCells behavior and rendering between EntryPoint use cases and non-EntryPoint use cases
2. Inability to call certain ListGrid configuration methods in the non-EntryPoint use case. Ideally with this family of error messages, I'd like more help in knowing what 'component' has been 'created' to determine where the problem is coming from.
3. Problem with DynamicForm's IntegerItem
4. Wanting a CellMouseUpEvent when the cell selection range stops changing due to a mouse up.
Back to my other application logging/configuration issue... http://forums.smartclient.com/showthread.php?t=22601
Comment