SWT - TableViewer - Refreshing Selection - swt

I have a button that runs a method. The method gets the selected Rows in the table and adds them to an arraylist. This works well the first time executed. But if the user selected the wrong row, they will be able to re select a different row and add that selection data to the arraylist.
But with my current the code, it does not matter what row the user selects the second time the first selected data is always added to the arraylist. It is like the selection needs to be reset or refreshed before the user selects the new row.
Button Code
Button pdfButton = new Button(composite, SWT.PUSH);
pdfButton.setText("Get Plotter List");
pdfButton.setEnabled(true);
pdfButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
getPlotterSelection();
}
});
Method Code
public void getPlotterSelection() {
selectedPlotters.clear(); <-- Clearing the ArrayList
int[] row = viewer.getTable().getSelectionIndices(); <-- Getting Current Selections
Arrays.sort(row);
if (row.length > 0) {
for(int i = row.length-1; i >= 0; i--){
PrinterProfile pp = new PrinterProfile(aa.get(i).getPrinterName(), aa.get(i).getProfileName());
selectedPlotters.add(pp);
}
}
viewer.getTable().deselectAll();
}
As I am writing this, I think maybe the problem is in the getSelectionIndices(). It seems to be getting the number of rows selected, but not the actual row number
Edit
The problem was in my logic. I was getting the correct Indices but using i varaible in the for loop to get the value.
for(int i = row.length-1; i >= 0; i--){
PrinterProfile pp = new PrinterProfile(aa.get(i).getPrinterName(), aa.get(i).getProfileName());
changed it to
aa.get(row[i].getPrinterName(), etc...
and it works like I thought it would

Since you are already using a TableViewer, why not get the selection from it?
IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
YourObject[] array = (YourObject[])selection.toArray();
Then you can iterate over the array and add them to your ArrayList.

Related

Change value of widget inside GWT flex table when other widget's value changes?

Ok, so I have a pretty specific and to me quite complicated issue, as I'm a GWT newbie.
I have a GWT flex table, which I use to dynamically add rows, whose cells contain GWT widgets. The row number changes, but the number of columns in static, always 6. Each row contains a cell with a remove button and five cells each with their own textbox.
What I need to do is somehow code a kind of relationship between the textbox in cell 6 of one row and the textbox in cell 5 in the next row (and vice versa).
To illustrate: when something changes in the textbox at [1,6] the content of textbox at [2,5] needs to be overwritten with the same value. If the textbox at [2,5] changes the textbox at [1,6] needs to change as well. I cannot use a button to commit the changes, it needs to happen via onValueChange or Blur or something similar, which doesn't require the user to perform a specific action.
My problem stems mostly from trying to figure out how to address specific cells in the flex table and their content. For the remove button the solution was easy enough with a click event handler, but for this issue I just can't seem to be able to come up with a solution.
Sadly I also cannot provide any of the code which I have up until now, since it's a business secret. I can only give a broad description of the problem like the one above.
EDIT:
Actually, it's probably more a problem of not having much code in terms of this specific problem.
What I have is a flex table, which has initially only the header row. Upon clicking a button below this table the addNewField() method is called, which just contains the creation, setting of default values and adding of the text fields into a new row.
addNewField() {
int rows = flextable.getRowCount();
Button removeBtn = new Button("x");
removeBtn.getElement().setId(Integer.toString(rows));
//then the button's event handler
TextBox name = new TextBox();
name.setText("something");
flextable.setWidget(rows, 0, "name");
//repeat 4 more times with incrementing columns for the other widgets
}
This way I add entire rows of editable TextBoxes. What I need is a way to influence the values of the 6th column TextBox of a chosen row and the 5th column TextBox of chosen row + 1.
EDIT2: I've tried the dirty option just to see how it would go and somehow the compare inside the if breaks the app. The compiler detects a nullpointerexception and I can't even debug it with breakpoints because it fails to compile and won't start. I can't figure out why though. I threw the code directly into the event for testing purposes, so pardon the ugliness.
TextBox bis = new TextBox();
bis.setText(rows + ":10:00");
subs.setWidget(rows, 5, bis);
bis.addValueChangeHandler(new ValueChangeHandler<String>()
{
#Override
public void onValueChange(ValueChangeEvent<String> event)
{
allRows: for (int i = 0; i < subs.getRowCount(); i++)
{
for (int j = 0; j < subs.getCellCount(i); j++)
{
if ( subs.getWidget(i, j) == bis )
{
TextBox widgetAtColumnSix = ((TextBox) subs.getWidget(i, 5));
String text = widgetAtColumnSix.getText();
TextBox widgetAtColumnFiveRowPlusOne = ((TextBox) subs.getWidget(i + 1, 4));
widgetAtColumnFiveRowPlusOne.setText(text);
break allRows;
}
}
}
}
});
EDIT: Since you edited your question and you dont want to use EventBus you could iterate over your FlexTable and set your TextBox value depending on your current rowIndex and cellIndex... Its not nice but it should work:
public class CellWidget extends Composite {
private TextBox nameBox;
public CellWidget() {
FlowPanel flowPanel = new FlowPanel();
Button deleteButton = new Button("x");
nameBox = new TextBox();
nameBox.addValueChangeHandler(new ValueChangeHandler<String>() {
#Override
public void onValueChange(ValueChangeEvent<String> event) {
notifiyTextBox(CellWidget.this, event.getValue());
}
});
flowPanel.add(nameBox);
flowPanel.add(deleteButton);
initWidget(flowPanel);
}
public void setText(String text) {
nameBox.setText(text);
}
}
public void notifiyTextBox(CellWidget source, String string) {
rows: for (int i = 0; i < flextable.getRowCount(); i++) {
columns: for (int j = 0; j < flextable.getCellCount(i); j++) {
if (flextable.getWidget(i, j) == source) {
CellWidget widgetAtColumnSix = ((CellWidget) flextable.getWidget(i, 5));
widgetAtColumnSix.setText(string);
CellWidget widgetAtColumnFiveRowPlusOne = ((CellWidget) flextable.getWidget(i + 1, 4));
widgetAtColumnFiveRowPlusOne.setText(string);
break rows;
}
}
}
}
I still would recommend using an eventbus. To make it even more convenient there is the GWT Event Binder lib, which makes using events a breeze.
So when you change a value in your textbox[2,5] it also fires your CustomEvent. All Widgets, that need to change their textbox value just need to catch...

Eclipse Scout Neon Focus inside rows after import data

I have some dependencies hierarchy on my form, so I implemented hierarchy check on server side of the scout. If one field is changed, it triggered check if other need to be changed as well. This is done with export/import form data.
MyFormData input = new MyFormData();
FormDataUtility.exportFormData(this, input);
input = BEANS.get(IMYService.class).validate(input, field);
FormDataUtility.importFormFieldData(this, input, false, null, null);
validate function change all other fields that need to be changed.
My problem is with editing cells in editable tables.
If I change value in cell, and this chain validation is triggered, after importing form data I lose focus in cell. So instead, tab will move me to another cell, tab trigger import and focus in cells are lost. And this is a really bad user experience.
How to fix this?
How to stay in focus (of next cell) after import has been called?
Marko
I am not sure, if this applies for you, but you can try the following:
I assume, that you do your export/validate/import logic in the execCompleteEdit(ITableRow row, IFormField editingField) of your column class. I suggest, that you calculate your next focusable cell by yourself and request its focus after importing the form data.
As an example, you can do this like that:
#Override
protected void execCompleteEdit(ITableRow row, IFormField editingField) {
super.execCompleteEdit(row, editingField);
// create form data object
// export form data
// call service and validate
// import form data
// request focus for next cell
focusNextAvailableCell(this, row);
}
with focusNextAvailableCell(this, row) as following:
private void focusNextAvailableCell(IColumn<?> col, ITableRow row) {
if (col == null || row == null) {
return;
}
IColumn<?> nextColumn = getColumnSet().getColumn(col.getColumnIndex()+1);
ITableRow nextRow = getTable().getRow(row.getRowIndex());
if (nextColumn == null) {
// no next column (last column lost focus)
// check if next row is available
nextRow = getTable().getRow(row.getRowIndex()+1);
// maybe select first cell again?
if (nextRow == null) {
nextColumn = getColumnSet().getColumn(0);
nextRow = getTable().getRow(0);
}
}
if (nextColumn != null && nextRow != null) {
getTable().requestFocusInCell(nextColumn, nextRow);
}
}
You should be aware, that you have to call this after every form data import in your execCompleteEdit method of your column. Also this is triggered not only when switching cells through pressing the tab key, but also when clicking with the mouse button.
Best regards!

How do I prevent a CellTable RowElement from being redrawn after a SelectionChangehander fires?

I'm probably doing something else wrong but I've followed examples given here:
How to remove a row from the Cell Table
and
GWT get CellTable contents for printing or export
to accomplish my goal and the result is close but not quite right.
I have a page with two widgets. The first wiget contains a CellTable that uses an aSync ListDataProvider to pull results and populate a table. The table has a selection change event handler associated with it that loads further details about the selected item into the second widget below it.
public OrderAdminTable() {
selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
#Override
public void onSelectionChange(SelectionChangeEvent event) {
OrderAdminListProxy selected = selectionModel.getSelectedObject();
if (selected != null && orderSnapShot != null) {
orderSnapShot.loadSnapShot(selected);
}
}
});
initTable();
this.addStyleName("order-list fixed_headers BOM");
this.setSelectionModel(selectionModel);
}
Once the second widget has loaded the details about the selected item, the user can remove the item from the table/list by clicking a button in the RootPanel that is the parent of both widgets.
searchView.getCmdReview().addClickHandler(new ClickHandler() {
#Override public void onClick(ClickEvent event) {
searchView.getOrderAdminSnapshot().reviewOrder();//this line calls a web service that deletes the item from the server data
dataProvider.getList().remove(searchView.getOrderAdminSnapshot().getSelectedOrder());
for(int i=0;i<table.getRowCount();i++){
TableRowElement row = table.getRowElement(i);
for(int j=0;j<row.getCells().getLength();j++){
if(row.getCells().getItem(j).getInnerText().contains(searchView.getOrderAdminSnapshot().getSelectedOrder().getSalesOrderNumber())){
row.setAttribute("removed", "true");
row.addClassName("hidden");
}
}
}
}
});
This all works fine until you select another item in the table. When that happens, the selection change event seems to redraw the table and remove my custom attribute and class from the previously selected item. This makes it appear in the list again.
The ultimate goal here is to avoid a round trip to the server to pull new results when you remove an item from the list. The line "searchView.getOrderAdminSnapshot().reviewOrder();" makes a web service call that removes the item from the data on the server side so it does not appear in subsequent reloads.
Is there some way to force the selection change event to maintain the state of the table row that was previously selected? Is there a better way to remove the selected item from the list? Any advice would be appreciated.
Once you remove the object from the list dataProvider.getList().remove, it should disappear from the table. There is no need to hide the row - this row should be gone. So your loop should never find it.

GWT CellTable rebuilding rows unnecessarily

I have found an interesting issue, and I am wondering if I am misusing or overlooking something. I have a large CellTable that is vertically scrollable. I want to show all the rows at once instead of traditional pagination. So at the bottom of my table I have a row that the user can click to load 50 more rows. I have provided the table with a custom table builder (setTableBuilder(new Builder());). When the user clicks "load more" I query the data, add to the ListDataProvider and call table.setVisibleRange(0, dataProvider.getList().size());.
I put a log statement in the
#Override
public void buildRowImpl(Object rowValue, int absRowIndex) {
}
method to see when it was building rows. I notice that it would build 0-dataProvider.getList().size() (all the rows), then it would build oldLength-dataProvider.getList().size() (the new rows). For instance, if I have 100 rows and then load 50 more it would build 0-150, and then rebuild 100-50. What I want is for it to only build the new rows, obviously.
So I start debugging to see why it is rebuilding the whole table each time. What I found was in com.google.gwt.user.cellview.client.HasDataPresenter it would set the "redrawRequired" flag to true at line 1325:
else if (range1 == null && range0 != null && range0.getStart() == pageStart
&& (replaceDiff >= oldRowDataCount || replaceDiff > oldPageSize)) {
// Redraw if the new data completely overlaps the old data.
redrawRequired = true;
}
So my question is why does it think that the new data completely overlaps the old data?
Am I using something incorrectly, is there a better way? This gets to be quite a slow down when it has to redraw thousands of rows that don't need to be redrawn.
Thanks,
Will
I think that, in this situation, the only way a CellTable can react to the call of the setVisibleRange() method is to redraw all rows.
You have just informed a CellTable that now it has to display new range (0-150 rows) instead of last (0-100 rows). There is no information that rows 0-100 remain unchanged and there is no need to redraw them.
The interesting thing is that you found the new rows are updated (rebuild) twice:
For instance, if I have 100 rows and then load 50 more it would build 0-150, and then rebuild 100-50
I've tried to reproduce this behavior in the smallest example:
public class ListDataProviderTest implements EntryPoint {
private static final int ADD_COUNT = 10;
private int nextVal = 0;
public void onModuleLoad() {
final CellTable<Integer> cellTable = new CellTable<Integer>();
cellTable.addColumn(new TextColumn<Integer>() {
#Override
public String getValue(Integer object) {
return object.toString();
}});
final ListDataProvider<Integer> listDataProvider = new ListDataProvider<Integer>();
listDataProvider.addDataDisplay(cellTable);
RootPanel.get().add(cellTable);
RootPanel.get().add(new Button("Add more...", new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
List<Integer> list = listDataProvider.getList();
for(int i = 0; i < ADD_COUNT; i++)
list.add(nextVal++);
cellTable.setVisibleRange(0, list.size());
}
}));
}
}
But I get all the rows updated once.
Can you confirm that this example reproduces the issue or provide one that is more accurate?
AFAIK a CellTable always redraws all cells.
This is how the renderer from the CellTable works. Although it always redraws all cells, it is in most times still faster than using a FlexTable and only updating a few cells.

Add new labels on button listener GWT

I'm trying to add new labels to a panel and this is when a button is clicked, in fact the number of labels is unknowing because my application consists in extracting some informations from a file and then display each information in a label so i have to upload the file and then extract the informations, i created an uploadfile and i'm able to extract the informations but i face a problem to display each information in its label, i can't create many labels and then with label.settext() make each information in its label beacuase the number of labels/informations is variable.
So can you advice/help me so i can make this working.
Best regards.
If you get the result from an Array for example you can do like this:
String[] data; //You can add you data here
addButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
for (String s : data) {
RootPanel.get().add(new Label(s));
}
}
});
That way you can add as much Labels as you want
You can create a variable number of Labels with a LinkedList.
int count = x ; //Quantity of labels you need;
LinkedList<Label> labelList = new LinkedList<Label>();
for (int i = 0; i < count ;i++)
{
Label tmpLabel = new Label();
tmpLabel.setText(STUFF) //Here you have to set your content
labelList.add(tmpLabel);
}
// Now we add the Labels to the Panel
for (int ind = 0; ind < labelList.size() ;ind++)
{
panel.add(labelList.get(ind)); //panel is the panel you show
}
If you don't have to access the labels later, you don't need the LinkedList and could add them direct to your panel.
You didnt say how you exactly attach the Labels, but if you use a Grid you have to set the size of it depending on your information.