How to make jtable transferhandler highlight a row when implementing DnD? - java

How to highlight the row under the cursor when dragging and dropping?
I need to identify the row in the jtable I'm dragging onto, not the insert position which the default transfer handler supplies out of the box.
Having identified the row itself, I expect that importData(TransferSupport support) can handle the fine details.

This is a known issue in the themes for RadGridView. Currently, the ControlTemplate for GridViewRow did not have Template bindings for BorderBrush and BorderThickness. This means that the change you are making did not get propagated to the Border element that is in the GridViewRow's template. We will fix this for our official release.
However, there is a way you can do this in the current situation. You should just find the border in the template. Here is an example of how to achieve this:
var border = rowItem.ChildrenOfType<Border>().FirstOrDefault();
if(border != null) {
border.BorderBrush = new SolidColorBrush(Colors.Red);
border.BorderThickness = new Thickness(1);
}

myTable.setDropMode(DropMode....); is what I was after.
Options are:
DropMode.USE_SELECTION
DropMode.ON
DropMode.INSERT
DropMode.ON_OR_INSERT
The final one ( DropMode.ON_OR_INSERT) provided me with more than what I needed, (which is good) - the ability to distinguish between inserting a row between other rows, AND an indication of dropping data ONTO a row.
I should have done more research initially before posing the question.

Related

Dynamic columns for JTreeTable

I am building a JTreeTable. I found some starter code and have come pretty far. In the end my goal is to be able to have different data at different levels like a hierarchical list.
Currently, I have it working with data at different levels. However, I am running up against a wall when it comes to changing the columns as a next goal. From where I currently stand I have 3 more milestones:
Show different set of columns for different levels
Ability to adjust column widths for different levels
Ensure the JTree part of the table always stays to left
I am getting close to closing out this task but again stuck at the first of these 3.
Since creating a JTreeTable is complex, the minimum example leverages several class listed below in the image:
I am happy to post the code to any of those classes but I also did not want clog the question with useless code. First let me show the functionality I want.
The first image is when the top level is selected and the second image is when the second level is selected. Notice how the columns are different. That is what I want to happen in my application.
Top level selected:
Second level selected:
So one way I tried to solve this problem, is when the list selection is changed inside this section of code:
ListSelectionListener listener = (ListSelectionEvent e) -> {
TreeTableModelAdapter adapter = (TreeTableModelAdapter) JTreeTable.this.getModel();
//Need to see why this breaks.
JTreeTable.this.getTableHeader().setColumnModel(adapter.getColumnModel());
};
this.getSelectionModel().addListSelectionListener(listener);
This code is in the initialization of the JTreeTable. I have tried setting the column model on both the TableHeader and the table as well. Below is what happens then when I select a row:
The columns just disappear on me. The creation of the column model is happening in the TreeTableModelAdapter class with the following method:
public TableColumnModel getColumnModel(){
DefaultTableColumnModel model = new DefaultTableColumnModel();
for(int i=0;i<getColumnCount();i++){
TableColumn column = new TableColumn();
column.setIdentifier(getColumnName(i));
model.addColumn(column);
}
return model;
}
Any direction would be very helpful. Again happy to post any code you think could be helpful to answer the question. Just put a comment in and I will add it right away.
I will add the milestones as I find them in case this helps others, but for now this question is answered.
Milestone 1
I was actually able to solve the first milestone. The key is to trigger the creation of the columns of the column model, not to create a new column model. Below is the code for when the row selection is changed:
//Change columns depending on row
ListSelectionListener listener = (ListSelectionEvent e) -> {
createDefaultColumnsFromModel();
};
this.getSelectionModel().addListSelectionListener(listener);
This code creates the columns based on the row selected in the JTree part of the JTreeTable. The TreeTableModelAdapter implements the getColumnCount() and getColumnName() methods by also passing the selected row in the JTree to the JTreeTableModel so that the columns and their names are dynamically retrieved based on a particular node in the JTree. The key for this for me was trigger those to be called again to update the JTreeTable.
Milestone 2
Adjusting column widths based on the data level proved to be much more difficult than I had originally anticipated. In order to retain the cells state when the column model changed I had to disconnect the painting of the cells from it. This is a hairy process because this is done inside BasicTableUI and the method that gets the rectangle of the cell is private. So I had to subclass it, overload the paint() method and create my own methods that get called inside the paint method. There was a lot of copy pasting so that I could call normally private methods. I just renamed them and referenced these methods instead. The way the ui class was designed did not make it very flexible. Below is 2 images where I am selecting different levels and the columns are obviously different widths at different levels.
Milestone 3
I was able to make this work by keeping track of the view in the model. This seems very dirty to me as the model should separated from the view. Since the tree column's class is unique, I just returned the right class if that column was the first in the view.
The one problem I have with this technique is that I get unexpected behavior where the value returned is not consistent. I attempted to resolve this by overriding JTree.covertValueToText(). Since a JTree only expects 1 value and depending on the sequence of columns in the view this value could change. So in overriding this method I check the stored index for the JTree column's value. Again this causes the unexpected behavior. I will update the post if I find the fix.

Changing the NatTable cell selection color

When I click on a row, the entire row color changes as expected. However the cell that the mouse is over changes to a different color than the rest of the row. I am trying to prevent the cell from changing to a color that is different from the rest of the row.
I am trying to figure out where the cell selection color is getting set and how to remove that (let the cell selection use the cells current background color).
I have unsuccessfully tried things like modifying the CellConfigAttribute or unregistering it via:
getNatTable().getConfigRegistry().
unregisterConfigAttribute(CellConfigAttributes.CELL_STYLE);
but no luck. I have no clue how to iterate over all the styles in order and see where this is generated from. I would have liked to see an existing method similar to:
List<ConfigAttribute<IStyle>> list = getNatTable().getConfigRegistry().
getConfigAttributesInOrder();
Unfortunately all I see is something like this, which I don't find useful for my situation:
List<String> strings = getNatTable().getConfigRegistry().
getDisplayModeOrdering().getDisplayModeOrdering("SELECT");
I have read the documentation which has some general advice but seen no explicit code samples showing how to do this. So, show do I determine where the cell is getting modified and how do I prevent it?
The code I am using for complete row selection is:
public void foo() {
final SelectionLayer selectionLayer = glazedListsGridLayer.
getBodyLayerStack().getSelectionLayer();
final RowOnlySelectionConfiguration<T> selectionConfig =
new RowOnlySelectionConfiguration<>();
selectionLayer.addConfiguration(selectionConfig);
getNatTable().addConfiguration(new RowOnlySelectionBindings());
}
You are talking about the selection anchor. And the only thing you have to do is to register the same style for DisplayMode.SELECT and label SelectionStyleLabels.SELECTION_ANCHOR_STYLE that you register for only DisplayMode.SELECT. The different style is registered in DefaultSelectionStyleConfiguration

JUnit-testing of NatTable

I want to do plain UI testing (i.e., not using SWTBot or other UI test frameworks) of NatTable contents.
My approach is to create a shell, add my custom NatTable and then access the cell and check its contents (data value, config label etc.):
// Note: this is Xtend code
#Before
def void setup()
{
shell = new Shell(Display.getCurrent)
shell.layout = new FillLayout
parent = new Composite(shell, SWT.NONE)
parent.layout = new GridLayout
fixture = new MyNatTableViewer(parent) // this is my custom nattable impl under test
shell.pack
shell.visible = true
}
#Test
def void testLabel()
{
assertCellLabel(2, 2, "test-label");
}
def assertCellLabel(int row, int col, String expected)
{
val labels = parameterTable.getCellByPosition(col, row)?.configLabels
assertThat(labels).describedAs("Labels for row " + row + " col " + col).isNotNull
assertThat(labels.labels).describedAs("Labels for row " + row + " col " + col).contains(expected)
}
To test my other components it was enough to just create the shell and the parent composite; packing and setting visible was not required for my tests to work.
Yet, with NatTable, getCellByPosition() returns null if the cell is not visible - so I added the code to pack and set the shell visible. This works for small tables (with 2 rows and a few columns).
Sadly, it does not work for large tables. I suspect this is because the viewport layer does not create cells which are not in the visible area (which is, I know, the strength of NatTable - that it only creates the required structures on demand). This is, of course, desired for normal runtime behavior.
But is there a(nother) way to get the cell in a guaranteed way (in other words, can I make the NatTable/ViewportLayer believe that the cell is visible so I don't get null as long as the cell exists content-wise?)
I could, of course, test my label accumulators, data providers etc. directly, but I wanted to approach this more from a black-box point of view here.
That question is contradictory in itself. You are asking for a black box approach for testing NatTable, but you want to change the behavior of NatTable on testing. That is not a black box approach!
If you really want to test with a black box approach, you need to ensure that the cell is rendered. This can be done by triggering scrolling, e.g. by executing the ShowCellInViewportCommand. That is the real black box approach, because returning null for a non-visible cell is the correct result.
If you need something in between a real black box approach and an approach that makes use of internal knowledge (which you are asking for) you have to ways to get there.
Operate on a layer below the ViewportLayer. Typically the SelectionLayer can be used. But of course this doesn't need to mean anything, because the layer stack can differ from setup to setup. The ViewportLayer is the one that introduces the virtual nature to a NatTable and the scrolling ability. It avoids the access to the underlying layers. So asking one of these will return the value you expect.
Disable the ViewportLayer by executing the TurnViewportOffCommand. This is basically a hack and could trigger additional things in the back that you might not want. But I have seen that suggestion in other contexts and therefore want to name it here. I don't suggest to use it anyway!
Note that both approaches are more like hacks when we are talking about black box testing, because you are making assumptions to the composition. They can not be applied in general because of the various configuration abilities.
Regarding the hidden question about why you need to set the Shell visible. Well basically because the SWT events for painting and resizing need to be triggered in order to start the size calculations and printing of NatTable correctly according to the Shell state. In our examples (which are also plain SWT) we call Shell#open().
And as a last comment on your implementation, I don't understand why you are sub-classing NatTable. Our API was never intended to do that. I suppose you do this to do some static pre-configuration e.g. the layer stack. But personally I don't like that approach. Everytime someone extends our classes to override some internal methods it ends up in questions or bug reports because the behavior changes. But I think that is generally an issue of an open API to give developers the most possible flexibility on customization.
I am also trying to read data from invisible cells of nattable. I am trying to use ShowCellInViewportCommand as follows:
widget.doCommand(new ShowCellInViewportCommand(gridlayer.getBodyLayer(), column, row));
//where row is say 50 and column is 20 and the cell is invisible.
I also tried,
widget.doCommand(new ShowRowInViewportCommand(widget.getLayer(), row));
//here the default value given by nattable.getLayer is passed
widget corrosponds to nattable instance.
After the call, nothing happens in UI. The cell does not get displayed.
Do I need to do anything else?
How should I go to read invisible cells of nattable.

Wizard components positioning with hidden values

I have a Wizard that contains multiple components. On the wizard I have drop-downs that can filter the results, which then hides various rows that are not required. However when these rows are hidden the components remain in the same location and do not re-size/move up. My problem I believe is similar to this issue (SWT components relayout after visibility set to false) however it uses RowLayout instead. I have also tried copying what was done but it did not change anything. How would I get the components to be placed togeather instead of leaving gaps?
I'v also read that .pack() and .revalidate() might be options, but I cannot seem how to make them work with the wizard classes. As best I can tell, it is using org.eclipse.jface.wizard for the base components. Any advice is highly appreciated for this, and I will update my question as requires if it needs to be clarified.
Edit
Attempting to recreate the style outlined in the link above, I came up with this (please note the project abstracts a few things away, so I have to make some extra calls). However after implementing I see no notable difference in the program (e.g. everything is still in the exact same spots, no spacing differences).
RowData data = new RowData();
RowData data2 = new RowData();
guiPiece.getGUILayout().getPiece("label").setLayoutData(data);
guiPiece.getGUILayout().getPiece("field").setLayoutData(data2);
guiPiece.getGUILayout().getPiece("label").setVisible(newVisibility);
data = (RowData)guiPiece.getGUILayout().getPiece("label").getLayoutData();
data.exclude = !newVisibility;
guiPiece.getGUILayout().getPiece("field").setVisible(newVisibility);
data2 = (RowData)guiPiece.getGUILayout().getPiece("field").getLayoutData();
data2.exclude = !newVisibility;
guiPiece.getFieldParentingControl().layout(true);
You can use a similar method to the GridLayout link you provide but using RowLayout.
You need to set RowData layout data on each of your controls.
RowData data = new RowData();
control.setLayoutData(data);
RowData also has an exclude flag which you can set the include / exclude a control from the layout.
So to hide a control you would do:
control.setVisible(false);
RowData data = (RowData)control.getLayoutData();
data.exclude = true;
You then call layout(true) on the main Composite of the wizard page.

Libx GDX scrollable with rounded overlay

I am quite new to libGDX and trying to Implement the layout shown in the picture below using the table layout
The container a Table [Green] is composed of a Table header [Blue] and of a ScrollPane body [black items]. the body is also a table with various rows.
I am trying to have the body part to scroll "under" header. At the beginning all the items from body should be visible with a proper padding.
The code so far:
ScrollPane body = new ScrollPane(bodyTable);
header.add(headerBar).expandX().fillX();
container.add(header).top().expandX().fillX().row();
container.add(body).fill().expand();
[note that the required texture are not included in the snipped].
It can scroll properly but there is is like an horizontal cut header and body, while I would like to have like a rounder effect. Wonder is this is possible using tables ? Is there any example / suggestion that can point me in the right direction ?
:
I would like to help but my groin difficult to understand me well, you want it in a table for example the header remains in place, while others move buttons, for example.
http://i.stack.imgur.com/C9cwR.png
1- add window to table and table.row();
2- add other window to table and add scroller.
will not if that's what you meant.
After a bit I managed to have a working version.
In Scene2d there is the Stack widget that is design to stack one item over the other.
The overview of the hierarchy is:
Stack container = new Stack;
// the container is using all the available space
container.setFillParent(true);
container.add(body);
container.add(head);
stage.addActor(container);
The tricky part is to define the correct position of the elements inside both head and body.
So for the head in my implementation I have something like:
Table header = new Table();
Table header_container = new Table(skin);
// assign a background behind the header contents
Drawable tableBackground = skin.getDrawable("top_bg");
//some position tweaks to resize the background to the wanted height
tableBackground.setMinHeight(10);
tableBackground.setBottomHeight(30);
tableBackground.setTopHeight(10);
header_container.setBackground(tableBackground);
// headerBar is another table that contains the buttons that are in the header
header.add(headerBar).expandX().fillX();
header_container.add(header).expandX().fillX();
head.addActor(header_container);
body is a ScollPane that contains a Table. The internal table has a Top Padding defined so it is totally visible at start. When scrolling it goes under the header part and hiding a bit.
It is working but feel that there is a too much of nesting involved, if I found a cleaner solution will update the code above.

Categories