Fill Visible Area of Eclipse RCP Editor Without Scrolling - swt

This is a question about which general approach to take, so I haven't included any code.
Requirement:
I need to create a page within a multi-page editor that has two vertical sections in it. The top section has a tree and the bottom section has a text field. The tree and text field should fill their respective sections. Each section should scroll independently and there should be a splitter in between. When the editor is opened I want the visible area of the editor to be divided among the two sections based on some ratio I provide. Then when the editor is resized, the two sections will adjust proportionally to maintain the ratio and fit the page. This way there won't be scroll bars on the editor page itself, just the two sections.
Proposed Solution:
My idea was to add a SashForm to the editor page and set the size of the SashForm to be the same as the editor's visible area. Then I'd add a resize listener to the editor page and adjust the size of the SashForm so that it stays in sync with the page. However, I can't find a way to get the editor's visible area. So when I add the SashForm it just makes each section big enough to fit its data and adds a scroll on the editor page itself.
Is it possible to meet my requirement?

Success! The key was to listen for resize events on the ScrolledForm. I've only tested on Fedora but I'll take a look on Windows soon. The only thing that bothers me is that the use of the buffer constants seems a little hacky.
/**
* Form page that contains a sash form and a button. The sash form is dynamically sized to ensure
* that it always fills the available space on the page.
*/
public class SashFormDemoPage extends FormPage
{
/** Horizontal buffer needed to ensure that content fits inside the page */
private static final int HORIZONTAL_BUFFER = 8;
/** Vertical buffer needed to ensure that content fits inside the page */
private static final int VERTICAL_BUFFER = 12;
/** Percentages of the sash form occupied by the tree and text box respectively */
private static final int[] SASH_FORM_WEIGHTS = new int[] {30, 70};
/**
* Constructor
*
* #param editor parent editor
*/
public SashFormDemoPage(ComponentEditor editor)
{
super(editor, "sashFormDemoPage", "Demo");
}
/**
* {#inheritDoc}
*/
#Override
protected void createFormContent(IManagedForm managedForm)
{
// Set page title
ScrolledForm scrolledForm = managedForm.getForm();
scrolledForm.setText("SashForm Demo");
// Set page layout and add a sash form
final Composite parent = scrolledForm.getBody();
parent.setLayout(new GridLayout());
final SashForm sashForm = new SashForm(parent, SWT.VERTICAL);
// Add a tree as the top row of the sash form and fill it with content
FormToolkit toolkit = managedForm.getToolkit();
int style = SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER;
Tree tree = toolkit.createTree(sashForm, style);
for (int i = 0; i < 40; i++) {
TreeItem parentNode = new TreeItem(tree, SWT.NONE);
parentNode.setText("parent-" + i);
for (int j = 0; j < 3; j++) {
TreeItem childNode = new TreeItem(parentNode, SWT.NONE);
childNode.setText("child-" + i + "-" + j);
}
}
// Add a text box as the bottom row of the sash form and fill it with content
style = SWT.MULTI | SWT.V_SCROLL | SWT.WRAP | SWT.BORDER;
Text text = toolkit.createText(sashForm, null, style);
String message = "";
for (int i = 0; i < 100; i++) {
message += "This is a test of the layout demo system. This is only a test. ";
}
text.setText(message);
// Add button below sash form
final Button button = toolkit.createButton(parent, "Test", SWT.NONE);
// Add resize listener to sash form's parent so that sash form always fills the page
parent.addControlListener(new ControlListener() {
#Override
public void controlMoved(ControlEvent e)
{
// Stub needed to implement ControlListener
}
#Override
public void controlResized(ControlEvent e)
{
GridData data = new GridData();
Point size = parent.getSize();
data.widthHint = size.x - HORIZONTAL_BUFFER;
data.heightHint = size.y - button.getSize().y - VERTICAL_BUFFER;
sashForm.setLayoutData(data);
}
});
// Set sash form's weights and pack its parent so that the initial layout is correct
sashForm.setWeights(SASH_FORM_WEIGHTS);
parent.pack();
}
}

Why set the size of the SashForm explicitly? Why not just add it to the parent Composite of the editor? The parent Compositehas a FillLayout and thus the SashForm with fill the editor area automatically.

Related

Is there way to auto resize percentage columns when column group is collapsed/expaned in NatTable

I found ResizeColumnHideShowLayer class at nattable version 1.6.
(about https://bugs.eclipse.org/bugs/show_bug.cgi?id=521486)
That is work fine for normal column headers only.
But, if I collapse a column group, no adjust size to fit window. (no increasing column size)
How can I solve the problem?
Is there way to resize other columns to fit window automatically increase?
Thank you.
Currently not because the ColumnGroupExpandCollapseLayer is taking care of hiding collapsed columns.
I found solution by myself!
It works fine very well. :-)
I was run based on NatTable v1.6 version.(downloaded yesterday)
I think this is a basic feature, so I hope this feature will be included in the next NatTable version.
In narrow tables, behavior that collapsing column group means that may be someone want to view other column data more widely.
Overview (Problem screen and solved screen)
I explain using two application(before, after) screen shot.
Refer to bottom image if you want understand my issue easily at once.
Problem screen
enter image description here
Improved screen
enter image description here
Solution summary :
Add event listener to ColumnGroupExpandCollapseLayer.
      (HideColumnPositionsEvent, ShowColumnPositionsEvent)
Handle above events.
      Get column indices which is hidden by collapsed
      Execute MultiColumnHideCommand with the indices
Layer structure of my test code
↑ ViewportLayer (top layer)
| SelectionLayer
| ColumnGroupExpandCollapseLayer
| ResizeColumnHideShowLayer
| ColumnGroupReorderLayer
| ColumnReorderLayer
| DataLayer (base layer)
Implementation code is below:
void method() {
...
columnGroupExpandCollapseLayer.addLayerListener(new ILayerListener() {
#Override
public void handleLayerEvent(ILayerEvent event) {
boolean doRedraw = false;
//It works for HideColumnPositionsEvent and ShowColumnPositionsEvent
// triggered by ColumnGroupExpandCollapseCommandHandler
if (event instanceof HideColumnPositionsEvent) {
HideColumnPositionsEvent hideEvent = (HideColumnPositionsEvent)event;
Collection<Range> columnPositionRanges = hideEvent.getColumnPositionRanges();
Collection<Integer> convertIntegerCollection = convertIntegerCollection(columnPositionRanges);
int[] positions = convertIntPrimitiveArray(convertIntegerCollection);
//Execute command to hide columns that was hidden by collapsed column group.
MultiColumnHideCommand multiColumnHideCommand = new MultiColumnHideCommand(resizeColumnHideShowLayer, positions);
resizeColumnHideShowLayer.doCommand(multiColumnHideCommand);
doRedraw = true;
}else if (event instanceof ShowColumnPositionsEvent) {//called by ColumnGroupCollapsedCollapseCommandHandler
ShowColumnPositionsEvent showEvent = (ShowColumnPositionsEvent)event;
Collection<Range> columnPositionRanges = showEvent.getColumnPositionRanges();
Collection<Integer> positions = convertIntegerCollection(columnPositionRanges);
//Execute command to show columns that was hidden by expanded column group.
MultiColumnShowCommand multiColumnShowCommand = new MultiColumnShowCommand(positions);
resizeColumnHideShowLayer.doCommand(multiColumnShowCommand);
//Set whether or not to redraw table
doRedraw = true;
}
if (doRedraw) {
natTable.redraw();
}
}
/**
* Merge position values within several Ranges to Integer collection
*/
private Collection<Integer> convertIntegerCollection(Collection<Range> rangeCollection) {
Iterator<Range> rangeIterator = rangeCollection.iterator();
Set<Integer> mergedPositionSet = new HashSet<Integer>();
while (rangeIterator.hasNext()) {
Range range = rangeIterator.next();
mergedPositionSet.addAll(range.getMembers());
}
return mergedPositionSet;
}
/**
* Convert Integer wrapper object to primitive value
*/
private int [] convertIntPrimitiveArray(Collection<Integer> integerCollection) {
Integer [] integers = (Integer [])integerCollection.toArray(new Integer[integerCollection.size()]);
int [] positionPrimitives = new int[integers.length];
for (int i = 0 ; i < integers.length ; i++) {
positionPrimitives[i] = integers[i].intValue();
}
return positionPrimitives;
}
});
}

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...

GWT ScrollPanel get max size of children without scrolling

I was wondering is there any possibility to get the inner size of a
com.google.gwt.user.client.ui.ScrollPanel
object in GWT? I would like to create a children of the ScrollPanel that fits exactly into the empty space, without activating the scroll bars.
The ScrollPanel is initialized as follows:
[begin update after answer of #Abhijith Nagaraja]
public void onModuleLoad() {
Window.setMargin("0px");
TabLayoutPanel tabs = new TabLayoutPanel(30, Unit.PX);
//attach the tab panel to the body element
RootPanel.get(null).add(tabs);
//set the TabLayoutPanel to full size of the window.
String width = (Window.getClientWidth()) + "px";
String height = (Window.getClientHeight()) + "px";
tabs.setSize(width, height);
//create the scroll panel and activate the scroll bars
ScrollPanel scrollPanel = new ScrollPanel(new Button("a second button"));
scrollPanel.getElement().getStyle().setOverflowX(Overflow.SCROLL);
scrollPanel.getElement().getStyle().setOverflowY(Overflow.SCROLL);
//attach the scroll panel to the DOM
tabs.add(scrollPanel, "tab1");
System.out.println(scrollPanel.getOffsetWidth()); // --> 0
System.out.println(scrollPanel.getOffsetHeight()); // --> 0
}
[end update]
Reason: I want to initialize a dynamic visualization (which requires scrollbars at a later point in time) in such a way that, it looks nice and avoiding to add the ScrollPanel later.
ScrollPanel sp = new ScrollPanel();
...
int innerWidth = sp.getOffsetWidth()- sp.getElement().getScrollWidth();
...
NOTE: You can use the above code only if your scrollPanell is attached to the screen. In other words it should be rendered.
DOM.setStyleAttribute(scrollpanel.getElement(), "maxHeight", mMainHeight + "px");;

GWT composite dynamic height resize

I Have a GWT Composite to which some other Composites are added dynamically.
I want to make may Parent composite Resize to fit the height of all its child widgets automatically.
i tried setting setHeight("100%") for Composite but this doesn’t work.
any Idea how to accomplish this functionality?
thanks.
EDIT:
final DockLayoutPanel dockLayoutPanel = new DockLayoutPanel(Unit.EM);
dockLayoutPanel.setStyleName("EntryPanel");
dockLayoutPanel.setSize("142px", "72px");
initWidget(dockLayoutPanel);
final VerticalPanel panel = new VerticalPanel();
panel.setSize("140px", "72px");
chckbxExport = new CheckBox("Export");
putField(CommonPresenter.CONSTANTS.EXPORT, chckbxExport);
dateBox = new DateBox();
dateBox.addValueChangeHandler(new ValueChangeHandler<Date>() {
#Override
public void onValueChange(final ValueChangeEvent<Date> event) {
dateChanged = true;
}
});
panel.add(dateBox);
final ListBox visibility = new ListBox();
final Label lblVisibility = new Label("Visibility:");
LabeledWidget vis = new LabeledWidget(lblVisibility, visibility);
for (int i = 0; i < CommonPresenter.CONSTANTS.VISIBILITIES.length; i++) {
visibility.addItem(CommonPresenter.CONSTANTS.VISIBILITIES[i]);
}
putField(CommonPresenter.CONSTANTS.VISIBILITY, visibility);
panel.add(vis);
panel.add(chckbxExport);
dockLayoutPanel.add(panel);
UPDATE:
Setting Composite width to fill all available Window horizontal space:
final int scrollBarWidth = 25;
// editPanel.setHeight("180px");
setWidth(Window.getClientWidth() - scrollBarWidth + "px");
// editPanel.setStyleName("EditorPanel");
Window.addResizeHandler(new ResizeHandler()
{
public void onResize(ResizeEvent event)
{
int width = event.getWidth();
setWidth(width - scrollBarWidth + "px");
}
});
Here's how to do it generally with HTML+CSS:
Create the parent, and do not set its height (or set it to auto).
Then add the children (just make sure, that you don't use absolute/fixed positioning for the children).
Set the height of the children, if required.
The height of the parent will then be adjusted automatically. This is the same for GWT Composites - just make sure, which CSS (including style attributes) applies to your elements! If unsure, use Firebug.
If you need more specifics, then you'd have to post some code which shows how you construct the parent composite (UiBinder, ...?)
Instead of using "100%" you can get the actual height by Window#getClientHeight(). To handle scenarios where the user resizes the browser, you can use a ResizeHandler.
Try Overriding the Resize()(Your class must extend to ResizeComposite).
In this re-size method set the size you want.
This works you dynamically because every time the window is re-sized this method is called and the values are set accordingly.

Editable SWT table

How to edit SWT table Values without Using Mouse Listeners?
Do the TableEditor snippets in the below link help?
SWT Snippets
The first example in the TableEditor section uses a SelectionListener on the table (unlike the second example which uses a MouseDown event you mentioned you don't want)
You could perhaps make use of the TraverseListener or KeyListener too to help you achieve what you want.
final int EDITABLECOLUMN = 1;
tblProvisionInfo.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
// Clean up any previous editor control
final TableEditor editor = new TableEditor(tblProvisionInfo);
// The editor must have the same size as the cell and must
// not be any smaller than 50 pixels.
editor.horizontalAlignment = SWT.LEFT;
editor.grabHorizontal = true;
editor.minimumWidth = 50;
Control oldEditor = editor.getEditor();
if (oldEditor != null)
oldEditor.dispose();
// Identify the selected row
TableItem item = (TableItem) e.item;
if (item == null)
return;
// The control that will be the editor must be a child of the
// Table
Text newEditor = new Text(tblProvisionInfo, SWT.NONE);
newEditor.setText(item.getText(EDITABLECOLUMN));
newEditor.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent me) {
Text text = (Text) editor.getEditor();
editor.getItem()
.setText(EDITABLECOLUMN, text.getText());
}
});
newEditor.selectAll();
newEditor.setFocus();
editor.setEditor(newEditor, item, EDITABLECOLUMN);
}
});
Here tblProvision is the name of your table. you can just now edit Your table by clicking on it. I have Declare EDITABLECOLUMN. this is the column that u want to edit.
If you can use JFace as well and not just pain SWT, have a look at the JFace Snippets, especially
Snippet036FocusBorderCellHighlighter - Demonstrates keyboard navigation by highlighting the currently selected cell with a focus border showing once more the flexibility of the new cell navigation support
Snippet034CellEditorPerRowNewAPI - Demonstrates different CellEditor-Types in one COLUMN with 3.3-API of JFace-Viewers
You can get or set the value of a item, for example:
Table table = new Table(parent, SWT.NONE);
TableItem item = new TableItem(table, SWT.NONE);
item.setText("My new Text");
I suggest you to us TableViewer, it is very powerful table which it you can use databinding very easy too.