I am working on eclipse JFace GUI stuff.
I am reading some input from the user and able to validate using the validator as below.
// creating input prompt
InputDialog inputDialog = new InputDialog(parentShell, dialogTitle, dialogMessage, initialValue, validator);
// Validator
IInputValidator validator = new IInputValidator()
{
#Override
public String isValid(String newName)
{
if (newName.isBlank())
{
return "Warning: Input is empty";
}
return null;
}
};
What I want to implement is to add a note to the user which is not related to validation.
Basically the note is about describing what happens if the button OK is pressed (As shown in image).
Any help/idea will be much appreciated.
You would have to create a new dialog class extending InputDialog to do this overriding createDialog to add extra controls. Something like:
public class InputDialogWithNote extends InputDialog
{
private Label noteLabel;
public InputDialogWithNote(final Shell parentShell, final String dialogTitle, final String dialogMessage, final String initialValue, final IInputValidator validator)
{
super(parentShell, dialogTitle, dialogMessage, initialValue, validator);
}
#Override
protected Control createDialogArea(final Composite parent)
{
Composite body = (Composite)super.createDialogArea(parent);
noteLabel = new Label(body, SWT.LEAD);
noteLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
return body;
}
}
You will have to arrange some way to set the noteLabel field.
Related
I have a UI bug in a legacy code in our Java project. We display a table, with three columns (HumanReadable, name and value) in a window. In that window, users can click on each cell and update the values. Before that, user clicks the "add" button to add a new row (three new cells). Each cell has a default value, until the user decides to update the value. Now, when the users decides to update the value of the cell, he clicks on the cell and types in the value. The bug is that, once done editing, it keeps the default value in the UI. In the backend, the value has changed (if you click the cell again, it will go into editing mode and show you the value).
I uploaded a short GIF that shows the issue and can be found here.
In that GIF you can see that I updated the default value of the first column to be test. Then I click some other place (to exit the edit mode) and it showed the default value instead of test in the first column.
The method that creates the table:
private void createTable(final Composite parent) {
final Table varTable = new Table(parent, SWT.MULTI);
varTable.setHeaderVisible(true);
varTable.setLinesVisible(true);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(varTable);
varTableViewer = new TableViewer(varTable);
final DataBindingContext bindingContext = new DataBindingContext();
final TableViewerColumn col1 = GuiUtils.createTableColumn(varTableViewer, "Human Readable");
col1.setEditingSupport(new StringEditingSupport(varTableViewer, bindingContext, dataProperty));
col1.getColumn().setWidth(120);
final TableViewerColumn col2 = GuiUtils.createTableColumn(varTableViewer, "Name");
col2.getColumn().setWidth(120);
col2.setEditingSupport(new StringEditingSupport(varTableViewer, bindingContext, nameProperty));
final TableViewerColumn col3 = GuiUtils.createTableColumn(varTableViewer, "Value");
col3.setEditingSupport(new StringEditingSupport(varTableViewer, bindingContext, valueProperty));
KeyBoardNavigationSupport.createSupport(varTableViewer);
input = new WritableList(globalVars, FlowVar.class);
ViewerSupport.bind(varTableViewer, input, BeanProperties.values(new String[] { dataProperty, nameProperty, valueProperty }));
}
The StringEditingSupport class:
public class StringEditingSupport extends ObservableValueEditingSupport {
private class CellEditorPrintValidatorErrors extends TextCellEditor {
public CellEditorPrintValidatorErrors(Composite control) {
super(control);
}
#Override
protected void focusLost(){
if(this.getErrorMessage() != null) {
MessageDialog.openError(this.getControl().getShell(), "Invalid input", this.getErrorMessage());
}
}
}
private final CellEditor cellEditor;
String propertyName;
public StringEditingSupport(final ColumnViewer viewer, final DataBindingContext dbc, final String propertyName) {
super(viewer, dbc);
cellEditor = new TextCellEditor((Composite) viewer.getControl());
this.propertyName = propertyName;
}
public StringEditingSupport(final ColumnViewer viewer, final DataBindingContext dbc, final String propertyName, final ICellEditorValidator validator) {
super(viewer, dbc);
cellEditor = new CellEditorPrintValidatorErrors((Composite) viewer.getControl());
cellEditor.setValidator(validator);
this.propertyName = propertyName;
}
#Override
protected IObservableValue doCreateCellEditorObservable(final CellEditor cellEditor) {
return SWTObservables.observeText(cellEditor.getControl(), SWT.Modify);
}
#Override
protected IObservableValue doCreateElementObservable(final Object element, final ViewerCell cell) {
return BeansObservables.observeValue(element, propertyName);
}
#Override
protected CellEditor getCellEditor(final Object element) {
return cellEditor;
}
public String getErrorMessage(){
return cellEditor.getErrorMessage();
}
}
I believe it has something to do with the StringEditingSupport class. This class allows to edit the value in each cell of table. But I couldn't figure out a way to "update" the value shown in the GUI. As I understand input (of type WritableList) contains all the information. Here is the add button listener method:
private class AddButtonSelectionListener extends SelectionAdapter {
#Override
public void widgetSelected(final SelectionEvent e) {
String name = nameProperty;
String meaning = dataProperty;
final List<String> names = new ArrayList<String>();
final List<String> meanings = new ArrayList<String>();
for (final Object var : input) {
names.add(((FlowVar) var).getName());
meanings.add(((FlowVar) var).getData());
}
int index = 0;
while (names.contains(name)) {
name = nameProperty + ++index;
}
index = 0;
while (meanings.contains(meaning)) {
meaning = dataProperty + ++index;
}
input.add(new FlowVar(name, valueProperty, meaning));
}
}
So, as I understand, I need to somehow bind the input to the UI (the content of each cell). I did try many attempts like trying to set a listener to the whole table (varTableViewer.addSelectionChangedListener) but none of them worked. Is it possible to suggest a way to solve this kind of issue?
If anything is missing, please let me know and I'll add it.
How is it possible to display non-printable characters in an SWT StyledText widget in a way it's done by Swing with an empty square?
To replace all occurrences with a symbol via regex in the source string can't be the solution because copy & paste with the original codepoint won't be possible anymore.
The best way might be to intercept the text rendering and replace them there, but that seems to open Pandora's box...
Edit 1:
The control characters, it's all about, are characters that are normally just skipped and not shown by the editor like HOP (U+0081)
For an E4 RCP application I have attached some code to start with.
Basically is uses the IEventBroker to add/remove the painter of the TextViewer by means of a button.
The StyledText can be obtained from
styledText = tv.getTextWidget();
as commented above
import org.eclipse.jface.text.WhitespaceCharacterPainter;
public class TheEditor{
#Inject MPart thePart;
private WhitespaceCharacterPainter whitespaceCharacterPainter;
#PostConstruct
public void postConstruct(Composite parent) {
TextViewer tv = new TextViewer(parent, SWT.MULTI | SWT.V_SCROLL |SWT.H_SCROLL);
whitespaceCharacterPainter = new WhitespaceCharacterPainter(tv);
tv.addPainter(whitespaceCharacterPainter);
whitespaceCharacterPainter.deactivate(true);
}
#Inject
#Optional
public void updatePartByWSButton(#UIEventTopic(EventConstants.WHITE_CHARACTERS_STATUS) boolean newButtonStatus) {
final MElementContainer<MUIElement>container = thePart.getParent();
if (thePart.equals((MPart)container.getSelectedElement())){
wsToolBarButtonStatus = newButtonStatus;
if(wsToolBarButtonStatus){
this.whitespaceCharacterPainter.paint(IPainter.CONFIGURATION);
}
else{
whitespaceCharacterPainter.deactivate(true);
tv.removePainter(whitespaceCharacterPainter);
}
}
}
}
Handler Class
public class WhitespaceCharactersHandler {
boolean status;
#Execute
public void execute(final MToolItem item, IEventBroker broker) {
if (item.isSelected()){
status = true;
}
else{
status = false;
}
broker.post(EventConstants.WHITE_CHARACTERS_STATUS, status);
}
}
Contants interface:
public interface EventConstants {
String WHITE_CHARACTERS_STATUS = "WHITE-CHARACTERS-STATUS";
}
My Setup
I have some code in an Eclipse RCP application that looks like this (it is in the #PostConstruct method of a Part):
scroll = new ScrolledComposite(parent, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER);
taskingInputsGroup = new Composite(scroll, SWT.NONE);
textSendTime = new Text(taskingInputsGroup, SWT.BORDER);
textSubject = new Text(taskingInputsGroup, SWT.BORDER);
textTaskStartTime = new Text(taskingInputsGroup, SWT.BORDER);
I'm trying to set a private Control field for an Enum's constants to each of these Text objects:
textSendTime = new Text(taskingInputsGroup, SWT.BORDER);
MsgField.SEND_TIME.setControl(textSendTime);
In the Enum, I just have a simple getter/setter for the Control field.
I have a method that is called when a user presses a Button. This method loops through the Enum constants and sets the text of some TreeItems to whatever is in the Control objects:
MsgField[] msgFields= MsgField.values();
for (int i = 0; i < msgFields.length; i++) {
Control control = msgFields[i].getControl();
if (control != null) {
if (control instanceof Text) {
root.getItem(i).getItem(0).setText(((Text)control).getText());
}
}
}
My Question
I am getting empty text from ((Text)control).getText() even if there is text in the Text field. Why could this be? I know I'm overlooking something simple (it's been a long day). I've read a bunch of SO posts on Java passing by value, but I can't seem to apply the answers to this issue. This works fine if I call getText() directly on the object in my view class:
root.getItem(1).getItem(0).setText(textSendTime.getText());
EDIT - Some MsgField enum code:
public enum MsgField {
private boolean isRequiredField;
private String treeName;
public abstract void setValue(Msg msg, String value);
public abstract Object getValue(Msg msg);
private MsgField(boolean req, String name) {
isRequiredField = req;
treeName = name;
}
SEND_TIME("Send Time", true) {
#Override
public void setValue(Msg msg, String value) {
msg.setSendTime(value);
}
#Override
public Object getValue(Msg msg) {
return msg.getSendTime();
}
},
// ....
// other fields
// ....
START_TIME("Start Time", false) {
#Override
public void setValue(Msg msg, String value) {
msg.setStartTime(value);
}
#Override
public Object getValue(Msg msg) {
return msg.getStartTime();
}
};
}
So the idea here is to represent the fields for the Msg class and have these get/set methods for each one so that I can easily iterate over them and get/set the fields for my Msg object. This worked fine (although maybe you can suggest a better alternative), but the trouble came with the addition of that Control field as I mentioned.
My problem is that I have just created a cellTable but it doesn't work because I see this on my broswer
The red border is of the FlowPanel that contains the table that has a black border, on side there is the GWT.log
Now I've tried everything but I don't know why, maybe it doesn't load the table for something reason. However I'm sure that dataProvider works beacause, as tou can see, the log show that data 'Carrello' are load on the column of my table 'carrello'. Here the code of table:
public class ShopTable extends CellTable {
private CellTable<Carrello> carrello;
private Column<Carrello, String> columnTitolo;
private Column<Carrello, String> columnTipoSupporto;
private AsyncDataProviderCarrello dataProvider;
private String COLUMN_NAME_TITOLO="Titolo film";
private String COLUMN_NAME_SUPPORTO="Tipo";
public ShopTable(){
carrello=new CellTable<>();
createTable();
createWithAsyncDataProvider();
GWT.log("Column example: "+carrello.getColumn(0).toString());
}
private void createTable(){
columnTitolo=buildColumnTitolo();
columnTipoSupporto=buildColumnTipoSupporto();
// NEED TO ADD HEADER (and FOOTER MAYBE)
carrello.addColumn(columnTitolo, "Titolo Film");
carrello.addColumn(columnTipoSupporto, "Tipo");
}
private Column<Carrello, String> buildColumnTitolo(){
columnTitolo=new Column<Carrello, String>(new EditTextCell()) {
#Override
public String getValue(Carrello object) {
GWT.log("aggiungo a carrelloTable: "+object);
return object.getTitolo();
}
};
columnTitolo.setDataStoreName(COLUMN_NAME_TITOLO);
return columnTitolo;
}
private Column<Carrello, String> buildColumnTipoSupporto(){
columnTipoSupporto=new Column<Carrello, String>(new EditTextCell()) {
#Override
public String getValue(Carrello object) {
GWT.log("aggiungo a carrelloTable: "+object);
return object.getTipoSupporto().toString();
}
};
columnTipoSupporto.setDataStoreName(COLUMN_NAME_TITOLO);
return columnTipoSupporto;
}
private void createWithAsyncDataProvider(){
dataProvider=new AsyncDataProviderCarrello();
dataProvider.addDataDisplay(carrello);
dataProvider.updateRowCount(10, false);
//.. SORTING METHOD NEED TO ADD
}
}
Here the code of Widget UIBinder that use the ShopTable
public class CarrelloPage extends Composite {
private static CarrelloPageUiBinder uiBinder = GWT.create(CarrelloPageUiBinder.class);
interface CarrelloPageUiBinder extends UiBinder<Widget, CarrelloPage> {
}
interface MyStyle extends CssResource{
String carrelloTable();
}
#UiField MyStyle style;
#UiField FlowPanel spazio_carrello;
/**
* necessario per dimensionare ad hoc per
* il pannello
*/
private ShopTable carrello;
private void resizeWidget(){
setWidth("100%");
setHeight(Window.getClientHeight() + "px");
}
public CarrelloPage() {
carrello=new ShopTable();
initWidget(uiBinder.createAndBindUi(this));
carrello.setStyleName(style.carrelloTable());
spazio_carrello.add(carrello);
resizeWidget();
Window.addResizeHandler(resizeHandler);
}
private ResizeHandler resizeHandler = new ResizeHandler()
{
public void onResize (ResizeEvent event)
{
setWidgetToMaxWidthAndHeight();
}
};
private void setWidgetToMaxWidthAndHeight ()
{
setWidth("100%");
setHeight(Window.getClientHeight() + "px");
}
}
Thanks for attention!
Your CellTable has a height of zero. This is why you don't see it.
You either have to set height of your CellTable in code, or you should add it to a widget that implements ProvidesResize interface, like a LayoutPanel.
I'm working on developing an Vaadin application. When developing a Java desktop application I use AbstractAction to create the buttons of my GUI. How to do that using Vaadin
Here is how I do in Java Desktop application:
// In my view
JButton button = new JButton(new Action(BUTTON_NAME, presenter, "methodToInvoke", Object... arguments));
class Action extends AbstractAction {
public Action(ButtonName name, Presenter presenter, String method, Object... arguments) {
this.name = name;
this.presenter = presenter;
this.method = method;
this.arguments = arguments;
readButtonProperties();
}
public void actionPerformed(ActionEvent e) {
//Call method from presenter with arguments using reflection
}
}
Edit:
I already read this. It's not the way I'm asking for.
From your example it isn't really clear what your requirements are.
Sounds like you insist on using reflection, but I'm not sure why. You could just do this, which is basically the same thing the Button documentation already says.
Presenter presenter = getPresenter();
String with = "with";
int my = 42;
List<Data> = new List<>();
Button vaadinButton = new Button("I'm a button.", clickEvent -> presenter.doStuff(with, my, arguments));
If you need more than a simple method call, you could just as well create a more elaborate ClickListener implementation that has more than the buttonClick() method.
Button vaadinButton = new Button("Button Caption", new Action(...))
class Action extends AbstractAction implements Button.ClickListener {
public Action(ButtonName name, Presenter presenter, String method, Object... arguments) {
this.name = name;
this.presenter = presenter;
this.method = method;
this.arguments = arguments;
readButtonProperties();
}
public void actionPerformed(ActionEvent e) {
//Call method from presenter with arguments using reflection
}
#Override
public void buttonClick(ClickEvent event) {
actionPerformed(null);
}
}