How to drag and drop multiple rows in jface table in java RCP? - swt

Here , setIdList is list of student ids. I want to add these ids into table.
The ids are set in dragSetData() method.
I am able to access the list of ids by dropping into table. But it is adding at last of table.
I want it to add this list in between any row selected by mouse pointer.
Drag code...
private void addDragSupport()
{
int operations = DND.DROP_COPY | DND.DROP_MOVE;
Transfer[] transferTypes = new Transfer[] { TextTransfer.getInstance() };
viewer.addDragSupport(operations, transferTypes, new DragSourceListener()
{
#Override
public void dragStart(DragSourceEvent event) {
event.doit = false;
if (null != myVariable) {
if (myVariable instanceof StudentDetails) {
event.doit = true;
}
}
}
#Override
public void dragSetData(DragSourceEvent event) {
event.data = setIdList;
}
#Override
public void dragFinished(DragSourceEvent event) {
}
});
}
I tried below in drop code
IStructuredSelection structuredSelection = this.getStructuredSelection();
List<StudentDetails> studentDetailList = structuredSelection.toList();
But it is giving me the selected row. I want the pointer selected by mouse.

Considering you are using table viewer.
In drop handler :
1) Get the model object from TableViewer : tableViewer.getInput()
2) From dropTarget object find the object location where you want to add dropped object.
Then insert new object in the model at that location and refresh the tableviewer

Related

Select Children when selecting Parent checkbox

I am using a Grid where the first column is checkbox. Every row is a folder which can have many other elements to be selected. There could be another folder inside a folder.
Now, when I have to select a element I have to select it one by one. I am not able to understand that how could I make it possible that if I check a folder checkbox, It checks the all selectable elements inside this folder.
Please let me know if more info required.
RemoteSortTreeLoader<BasicModel> loader =
new BaseRemoteSortTreeLoader<BasicModel>(proxy, reader) {
public boolean hasChildren(BasicModel parent) {
//code;
}
};
TreeStore store = new TreeStore(loader);
List<ColumnConfig> columnList = new ArrayList<ColumnConfig>();
CheckBoxSelectionModel checkBoxSelectionModel =
new CheckBoxSelectionModel();
columnList.add(checkBoxSelectionModel.getColumn());
ColumnModel columns = new ColumnModel(columnList);
EditorTreeGrid grid = new EditorTreeGrid<BasicModel>(store,columns);
grid.getSelectionModel().setSelectionMode(SelectionMode.SIMPLE);
grid.getSelectionModel().addListener(Events.BeforeSelect,
new Listener<SelectionEvent<BasicModel>>() {
#Override
public void handleEvent(SelectionEvent<BasicModel> event) {
if (event.getModel() instanceof SDPTimelineCatalogModel) {
event.setCancelled(false);
}
} // handleEvent
}
);
grid.getSelectionModel().addSelectionChangedListener(
new SelectionChangedListener<BasicModel>() {
#Override
public void selectionChanged(SelectionChangedEvent<BasicModel> event) {
logger.info(" Inside addSelectionChangedListener ");
if (event.getSelection().size() == 0) {
disableNext();
} else {
enableNext();
}
} // selectionChanged
}
);
thanks

Delete Multiple rows from Nattable

I am trying to delete more than one row from NatTable. Following the solution described in Delete rows from Nattable. I have created a the following classes:
the Command class looks like this :
public class DeleteMultiRowCommand extends AbstractMultiRowCommand {
public DeleteMultiRowCommand(AbstractMultiRowCommand command) {
super(command);
}
protected DeleteMultiRowCommand(ILayer layer, int[] rowPositions) {
super(layer, rowPositions);
}
#Override
public ILayerCommand cloneCommand() {
return new DeleteMultiRowCommand(this);
}
}
Command Handler class:
public class DeleteMultiRowCommandHandler<T> implements ILayerCommandHandler<DeleteMultiRowCommand> {
private List<T> bodyData;
private SelectionLayer layer;
public DeleteMultiRowCommandHandler(List<T> bodyData, SelectionLayer selectionLayer) {
this.bodyData = bodyData;
this.layer = selectionLayer;
}
public DeleteMultiRowCommandHandler(List<T> bodyData){
this.bodyData = bodyData;
}
#Override
public Class<DeleteMultiRowCommand> getCommandClass() {
return DeleteMultiRowCommand.class;
}
#Override
public boolean doCommand(ILayer targetLayer, DeleteMultiRowCommand command) {
//convert the transported position to the target layer
if (command.convertToTargetLayer(targetLayer)) {
Collection<Integer>rowpos = command.getRowPositions();
//remove the element
for(Integer val : rowpos){
this.bodyData.remove(val.intValue());
targetLayer.fireLayerEvent(new RowDeleteEvent(targetLayer, val.intValue()));
}
return true;
}
return false;
}
}
and the Command will be triggered on clicking a MenuItem
this.contextMenu = new PopupMenuBuilder(natTable)
.withInspectLabelsMenuItem()
.withClearAllFilters()
.withColumnRenameDialog()
.withMenuItemProvider(new IMenuItemProvider() {
#Override
public void addMenuItem(final NatTable natTable, Menu popupMenu) {
MenuItem deleteRow = new MenuItem(popupMenu, SWT.PUSH);
deleteRow.setText("Delete Row(s)");
deleteRow.setEnabled(true);
deleteRow.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent event) {
//int rowPosition = MenuItemProviders.getNatEventData(event).getRowPosition();
ILayer bl = ((GridLayer)natTable.getLayer()).getBodyLayer();
BodyLayerStack bl1 = (BodyLayerStack) bl;
SelectionLayer sl = bl1.getSelectionLayer();
int []poss = new int[sl.getFullySelectedRowPositions().length];
int i=0;
for(int pos1 : sl.getFullySelectedRowPositions()){
poss[i]=sl.getRowIndexByPosition(pos1);
i++;
}
//System.out.println("Menu item selected "+rowPosition);
//natTable.doCommand(new DeleteRowCommand(natTable, rowPosition));
natTable.doCommand(new DeleteMultiRowCommand(natTable, poss));
}
});
}
})
.build();
when I try to delete the rows, rows which not selected are deleted. Seems like an issue with the row postion to row index conversion. is the row postion to row index conversion correct within my IMenuItemProvider right ?
It seems like you do the conversion from position to index twice: once in the menu item selection listener and once in the command handler (by calling convertToTargetLayer). The first is not necessary.
That is not an issue of NatTable, but an issue on how to work with collections. You need to remove the items backwards if you remove the elements one by one. Otherwise the items for the indexes are changing while processing.
Let's assume you want to delete the elements at index 1 and 2. After removing the element at index 1, the elements below will move up. So the element that was before on index 2 will be on index 1 now, and the element at index 3 will be on index 2. Therefore the removal of the element at index 2 in the next iteration will remove the item that was before on index 3.
I'd suggest to sort and reverse the collection of indexes before iterating to remove items from the collection. Than it should work.

Delete rows from Nattable

I want to implement a row deletion logic in a Nebula Nattable.
This is what I plan to do:
Add context menu to the Nattable which is described in http://blog.vogella.com/2015/02/03/nattable-context-menus-with-eclipse-menus/
Add an SWT Action to the menu which will implement the delete
my question is, which is the best way to accomplish this:
Should I delete the corresponding value from my data model and the table view is refreshed when I execute this.natview.refresh();?
OR
Should I get the rows from SelectionLayer and delete them (if so how do I do ?)?
OR
is there any default support for this function through IConfiguration?
In NatTable you would typically do the following:
Create a command for deleting a row
public class DeleteRowCommand extends AbstractRowCommand {
public DeleteRowCommand(ILayer layer, int rowPosition) {
super(layer, rowPosition);
}
protected DeleteRowCommand(DeleteRowCommand command) {
super(command);
}
#Override
public ILayerCommand cloneCommand() {
return new DeleteRowCommand(this);
}
}
Create a command handler for that command
public class DeleteRowCommandHandler<T> implements ILayerCommandHandler<DeleteRowCommand> {
private List<T> bodyData;
public DeleteRowCommandHandler(List<T> bodyData) {
this.bodyData = bodyData;
}
#Override
public Class<DeleteRowCommand> getCommandClass() {
return DeleteRowCommand.class;
}
#Override
public boolean doCommand(ILayer targetLayer, DeleteRowCommand command) {
//convert the transported position to the target layer
if (command.convertToTargetLayer(targetLayer)) {
//remove the element
this.bodyData.remove(command.getRowPosition());
//fire the event to refresh
targetLayer.fireLayerEvent(new RowDeleteEvent(targetLayer, command.getRowPosition()));
return true;
}
return false;
}
}
Register the command handler to the body DataLayer
bodyDataLayer.registerCommandHandler(
new DeleteRowCommandHandler<your type>(bodyDataProvider.getList()));
Add a menu item to your menu configuration that fires the command
new PopupMenuBuilder(natTable)
.withMenuItemProvider(new IMenuItemProvider() {
#Override
public void addMenuItem(NatTable natTable, Menu popupMenu) {
MenuItem deleteRow = new MenuItem(popupMenu, SWT.PUSH);
deleteRow.setText("Delete");
deleteRow.setEnabled(true);
deleteRow.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent event) {
int rowPosition = MenuItemProviders.getNatEventData(event).getRowPosition();
natTable.doCommand(new DeleteRowCommand(natTable, rowPosition));
}
});
}
})
.build();
Using this you don't need to call NatTable#refresh() because the command handler fires a RowDeleteEvent. I also don't suggest to call NatTable#refresh() in such a case, as it might change and refresh more than it should and would not update other states correctly, which is done correctly by firing the RowDeleteEvent.
Note that the shown example deletes the row for which the context menu is opened. If all selected rows should be deleted, you should create a command handler that knows the SelectionLayer and retrieve the selected rows as shown in the other answer.
In our application we do the following:
Get selected row objects:
SelectionLayer selectionLayer = body.getSelectionLayer();
int[] selectedRowPositions = selectionLayer.getFullySelectedRowPositions();
Vector<Your Model Objects> rowObjectsToRemove = new Vector<Your Model Objects>();
for (int rowPosition : selectedRowPositions) {
int rowIndex = selectionLayer.getRowIndexByPosition(rowPosition);
rowObjectsToRemove .add(listDataProvider.getRowObject(rowIndex));
}
Remove them from the data provider
call natTable.refresh()

GWT CellTable SelectionModel can not deselect item after editing

Hello I have a Contact class with informations which i show in a CellTable.
The CellTable has a DataListProvider, MultiSelectionModel and KeyProvider
which checks the id of the Contact.
DataListProvider and CellTable have the same KeyProvider.
if i only select/deselect the items in the CellTable and show them in a TextBox ists working fine. But the when i change the value of the Contact item in the TextBox(Contact instance) and try to deselect the item the selectionmodel says its still selected?
I tried with clear() but its still selected!
GWT 2.5 / FireFox
ProvidesKey<Contact> keyProvider = new ProvidesKey<Contact>(){
#Override
public Object getKey(Contact item) {
return item.getIdContact();
}
};
public MyCellTable(boolean canLoad, Integer pagesize, ProvidesKey<T> keyProvider) {
super(-1, resource, keyProvider);
selectionModel = new MultiSelectionModel<T>();
selectionModel .addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
#Override
public void onSelectionChange(SelectionChangeEvent event) {
selectionChange();
}
});
dataProvider = new ListDataProvider<T>(keyProvider);
dataProvider.addDataDisplay(this);
}
in the selection event i call
protected void selectionChange(){
Contact c = grid.getGrid().getSelectedItem();
if(c != null){
cpForm.enable();
cpForm.clear();
form.bind(c); // Formular which updates the selected instance
cpForm.add(form);
}else{
cpForm.disable(noseletionText);
}
}
i have no ValueUpdater
when i select an item i generate a formular and if i change something i call:
#Override
public void save() {
super.save();
ContactServiceStore.get().updateContact(manager.getBean(),
new MyAsyncCallback<Void>() {
#Override
public void onSuccess(Void result) {
onchange();
}
});
}
i if call the method without changes on the contact its still working and i can deselect but when i change the name or something else i cant select other items or deselect the current item!
You're not actually using your ProvidesKeys in your MultiSelectionModel. You need to create your MultiSelectionModel like so:
MultiSelectionModel<T> selectionModel = new MultiSelectionModel<T>(keyProvider);
If you don't supply the MultiSelectionModel with a ProvidesKey it will use the actual object as a key.
Make sure you also add the MultiSelectionModel to the table:
cellTable.setSelectionModel(selectionModel);
The reason selectionModel.clear() wasn't working was because selectionModel was not set to the table.

Creating custom ActionCell in CellTable Column

I want one of my table columns to have a deleteButton.
ActionCell<Entrata> deleteCell = new ActionCell<Entrata>("x",new Delegate<Entrata>() {
#Override
public void execute(Entrata object) {
// rpc stuff....
}
});
Ok but this line generates an error:
Column<Entrata,Entrata> deleteColumn = new Column<Entrata, Entrata>(deleteCell);
"Cannot instantiate the type Column"
What do you think?
Here you go with working code:
Assumptions:
TYPE - Is the class of the data you show in rows of Cell Table it the same because I assume you want reference to the instance of data when you going to delete it
public class DeleteColumn extends Column<TYPE, TYPE>
{
public DeleteColumn()
{
super(new ActionCell<TYPE>("Delete", new ActionCell.Delegate<TYPE>() {
#Override
public void execute(TYPE record)
{
/**
*Here you go. You got a reference to an object in a row that delete was clicked. Put your "delete" code here
*/
}
}));
}
#Override
public TYPE getValue(TYPE object)
{
return object;
}
};
From the doku:
A representation of a column in a table. The column may maintain view data for each cell on demand. New view data, if needed, is created by the cell's onBrowserEvent method, stored in the Column, and passed to future calls to Cell's
So you have to declar it something like this:
Column<String, String> colum = new Column<String, String>(null) {
#Override
public String getValue(String object) {
// TODO Auto-generated method stub
return null;
}
};
Still I don't exactly know how you implement the delete button, so it would be nice if you can give us the rest of your code.
This works
//table = initialized CellTable with content already loaded
ActionCell editCell = new ActionCell<EmployeeObject>("remove", new ActionCell.Delegate<EmployeeObject>() {
public void execute(EmployeeObject object){
List<EmployeeObject> list = new ArrayList<EmployeeObject>(table.getVisibleItems());
for(int i = 0; i < list.size(); i ++){
if(object.getFirstname().equals(list.get(i).getFirstname())){
list.remove(i);
break;
}
}
table.setRowData(list);
}
});
Column<EmployeeObject, ActionCell> editColumn = (new IdentityColumn(editCell));