When can I use getString() in a Wicket Ajax TabbedPanel? - java

I have the following problem with Wicket 7.3 and JQuery 2.1.4:
In a dynamic tabbed panel (tabs are added and removed), I want to localize the tab titles and add tooltips. My code
JQueryGenericPanel() {
....
populateItem( ListItem<ITab> item) {
getString();
results in a warning in the log file:
Tried to retrieve a localized string for a component that has not yet been added to the page. This can sometimes lead to an invalid or no localized resource returned. Make sure you are not calling Component#getString() inside your Component's constructor
Using getString() in the panel (which is on the tab) within its method
onInitialize()
does not work, because its too late. The label is already set to "lazy".
Is there any other method similar to "populateItem()" which I can use?
** Addendum **
The code for the tabbed panel is:
public class MyTabbedPanel extends JQueryGenericPanel<List<ITab>> implements ITabsListener {
...
#Override
protected void onInitialize() {
super.onInitialize();
this.add( new ListView<ITab>( "tabs", this.getModel() ) {
...
#Override
protected void populateItem( ListItem<ITab> item ) {
Label link = new Label( "widgetId", new PropertyModel<String>( somePanel, "getTitle()" ) );
The code in the panel is:
private String title = "default";
public String getTitle() { return title; }
#Override
public void onInitialize() {
title = getString( "someKey" );
}
So the PropertyModel fetches the title with 'getTitle()'. Unfortunately this happens before 'onInitialize()' gets called. So the tab title shows "default" instead of the localized text for "someKey".

Instead of
new Label(itemId, getString("key"))
... use:
new Label(itemId, new ResourceModel("key"));
... or if you doing something fancy with the string:
new Label(itemId, new AbstractReadOnlyModel<String>() {
public String getObject() {
return ... + getString("key") + ...;
}
});

Related

How to fill in ComboBox from an API call?

I need to call an API, get a response, add items to ComboBox and update the view in the plugin.
Attached is the image of the combobox
I need to update the thread Ids as they load from an API. My custom Combobox for this is as shown below. I am not sure how to update the custom component from outside the class. Any help?
public class MyComboBox extends AnAction implements CustomComponentAction {
#Override
public void actionPerformed(#NotNull AnActionEvent e) {
}
#Override
public #NotNull JComponent createCustomComponent(#NotNull Presentation presentation, #NotNull String place) {
ComboBox<String> jComboBox = new ComboBox<>();
jComboBox.setMinLength(100);
jComboBox.addItem("Thread Id: " + UUID.randomUUID().toString());
jComboBox.addItem("Thread Id: " + UUID.randomUUID().toString());
jComboBox.setEnabled(true);
return jComboBox;
}
}
I needed a reference to the already instantiated combobox.
I got it with
MyComboBox myComboBox = (MyComboBox) ActionManager.getInstance().getAction("searchThread")
I added another method in MyComboBox:
public void updateUI(List<String> ids) {
this.ids = ids;
String[] array = this.ids.toArray(new String[0]);
jComboBox.setModel(new DefaultComboBoxModel<>(array));
jComboBox.setSelectedIndex(0);
jComboBox.updateUI();
}
and used:
myComboBox.updateUI(newList);
That solved my problem.

Wicket CheckBox change visibility of other component

I have a Wicket 7 CheckBox and a hidden DateTextField.
When I click on a CheckBox I want the DateTextField to be appeared and vice versa.
For this reason I have added the DateTextField in a WebMarkUpContainer.
If possible I dont want to use Ajax.
The problem is that the WebMarkUpContainer is always hidden.
In general my code is as follows:
class ResultsPanel extends Panel{
private static final class ResultsPage {
final DateTextField startDate = new DateTextField("startDate", new DateTextFieldConfig().withLanguage("el");
final CheckBox checkBox = new CheckBox("checkBox");
final WebMarkupContainer wmc = new WebMarkupContainer("wmc");
// bla bla bla
public Results(String id, CompoundPropertyModel propertyModel) {
super(id, propertyModel);
add(checkBox);
wmc.setOutputMarkupPlaceholderTag(true);
wmc.add(startDate);
add(wmc.setVisible(false));
}
public ResultsPanel(String id){
super(id);
add(new ResultsPage("resultsPage", new CompoundPropertyModel()));
}
}
if you don't need to trigger any server side code when you click on the checkbox, you can consider to use some simple JavaScript code to hide/show the DateTextField. This code can be attached to the checkbox using a JavaScriptHeaderItem. You can find more details in the user guide.
update
In Wicket 7.x You can try
new CheckBox("id", model) {
protected boolean wantOnSelectionChangedNotifications() {
return true;
}
protected void onSelectionChanged(Boolean newSelection) {
// do something, page will be rerendered;
} };

Ensure Vaadin load latest data in when clicking added components (such as TabSheet or Tree ...)

When I add components to Vaadin's component (such as TabSheet or Tree) , the added components are cached. When user clicks the tab (or tree nodes) , if it contains db data , it shows stale data , not reflecting the latest db state.
I wonder if there is any way to ensure loading latest data ?
I solve the problem by defining my custom interface :
public interface Reloadable {
void reload();
}
And each component implements this Reloadable interface , such as :
#SpringComponent
public class TeachersView extends VerticalLayout implements Reloadable, Serializable {
#Inject
private TeacherDao teacherDao;
private final static int PAGESIZE = 10;
private MTable<Teacher> mTable = new MTable<>(Teacher.class);
#PostConstruct
public void init() {
// mTable settings skip here
reload();
addComponent(mTable);
}
#Override
public void reload() {
mTable.setBeans(new SortableLazyList<>(
sortablePagingProvider ,
() -> (int) teacherDao.count() ,
PAGESIZE
));
}
private SortableLazyList.SortablePagingProvider<Teacher> sortablePagingProvider =
(firstRow, asc, sortProperty) -> {
return teacherDao.findAll(
new PageRequest(
firstRow / PAGESIZE, PAGESIZE,
asc ? Sort.Direction.ASC : Sort.Direction.DESC,
sortProperty == null ? "id" : sortProperty
)
).getContent();
};
}
And this view is injected to UI class :
#SpringUI(path = "/ui")
#Theme("valo")
public class VaadinUI extends UI {
#Inject
private TeacherDao teacherDao;
#Inject
private TeachersView teachersView;
#Override
protected void init(VaadinRequest vaadinRequest) {
Panel panel = new Panel("Admin Panel");
HorizontalSplitPanel splitPanel = new HorizontalSplitPanel();
splitPanel.setSplitPosition(15, Unit.PERCENTAGE);
panel.setContent(splitPanel);
Tree tree = new Tree("Menu");
splitPanel.setFirstComponent(tree);
Label home = new Label("Home");
Map<String, Component> map = new HashMap<>();
map.put("Teachers", teachersView);
map.put("Home", home);
map.forEach((k, v) -> tree.addItem(k));
tree.addItemClickListener(event -> {
Component view = map.get(event.getItemId());
if (view instanceof Reloadable) {
((Reloadable) view).reload();
}
splitPanel.setSecondComponent(view);
});
splitPanel.setSecondComponent(home);
setContent(panel);
} // init()
}
Notice the tree.addItemClickListener , I have to check each component if it implements Reloadable , if true , invoke it.
It works . But I don't know if it the standard way achieving this ? I think it should be a common scenario , there should be something like built-in interface for Components to implement , such as onRender like that (but I cannot find one) . Did I miss anything ?
Thanks.
First of all I'm going to suggest this tutorial on Spring & Vaadin that you may have already seen, but I'll be referencing it in a few places and I think it's a good starting point for Vaadin & Spring integration.
Second, out of curiosity, why are you using a tree to build the menu?
In the example provided you seem to be modelling a navigation between some views feature, which is already available in Vaadin, and since you're using Spring, the Vaadin spring & spring-boot extensions makes it really easy to define and navigate between your views. Then you can define some specific behaviour for each view in their own enter() method. I've used the Vaadin dashboard demo as inspiration for the changes below:
#SpringView(name = TeachersView.NAME)
public class TeachersView extends VerticalLayout implements View {
public static final String NAME = "Teachers";
private Label title = new Label("Teachers view");
#PostConstruct
void init() {
addComponent(title);
}
#Override
public void enter(ViewChangeListener.ViewChangeEvent event) {
// recreate or reload stuff here
title.setValue("Teachers view reloaded # " + new Date());
}
}
#SpringView(name = HomeView.NAME)
public class HomeView extends VerticalLayout implements View {
public static final String NAME = "";
#PostConstruct
void init() {
addComponent(new Label("Home"));
}
#Override
public void enter(ViewChangeListener.ViewChangeEvent event) {
// meh, nothing special to do here
}
}
public class SpringVaadinUI extends UI {
#Autowired
private SpringViewProvider viewProvider;
#Override
protected void init(VaadinRequest vaadinRequest) {
addStyleName(ValoTheme.UI_WITH_MENU);
Panel panel = new Panel("Admin Panel");
HorizontalSplitPanel splitPanel = new HorizontalSplitPanel();
splitPanel.setSplitPosition(15, Unit.PERCENTAGE);
panel.setContent(splitPanel);
VerticalLayout navigationBar = new VerticalLayout();
navigationBar.setPrimaryStyleName(ValoTheme.MENU_ROOT);
navigationBar.addComponent(createNavigationButton("Home", FontAwesome.HOME, HomeView.NAME));
navigationBar.addComponent(createNavigationButton("Teachers", FontAwesome.GROUP, TeachersView.NAME));
splitPanel.setFirstComponent(navigationBar);
CssLayout navigationDisplay = new CssLayout();
splitPanel.setSecondComponent(navigationDisplay);
Navigator navigator = new Navigator(this, navigationDisplay);
navigator.addProvider(viewProvider);
setContent(panel);
}
private Button createNavigationButton(String caption, FontAwesome icon, final String viewName) {
Button button = new Button(caption, icon);
button.setPrimaryStyleName(ValoTheme.MENU_ITEM);
button.addStyleName(ValoTheme.BUTTON_SMALL);
button.addStyleName(ValoTheme.BUTTON_BORDERLESS);
button.addClickListener(event -> getUI().getNavigator().navigateTo(viewName));
return button;
}
}
The result is similar to:
If for some reason you can't or don't want to use the navigator, then your solution looks fine. Nonetheless, whichever solution you chose to use, you should know that by default Spring creates singletons. Except a few such as the UI, you should probably change your components to prototypes so you'll get a new instance each time. Otherwise all your users will get the same instances when accessing the application, which I don't think you want to happen.

TextField onEdit listener

I am trying to use TextField in javafx.
The scenario: I have list view populated with specific objects and edit button to edit the object associated with list cell of list view.
When I click on edit button it redirects me to a pane with editing feature where I can edit the name of that object and save it using a save button.
So I have to put validation on save button to make it enable and disable.
If I edit the name in text field then it should enable the save button otherwise it should remains disabled.
I have tried using different methods on text fields as below.
textField.textPorperty.addListener(listener -> {
//Logic to enable disable save button
});
As I am using list view, this listener gives me old value as previously edited object which does not satisfy my condition.
I can not use
textField.focusedProperty().addListener((observableValue, oldValue, newValue) -> {});
as It does not give me expected behavior.
Can anyone help me to solve this issue?
You need to implement additional logic that decides whether or not a change to the textProperty should change the enablement state of the button. This requires:
a reference to the initial value (on setting the text to the input, f.i. on changes to selection in the list)
a boolean property that keeps the enablement state (below it's called buffering)
a listener to the textField that updates the enablement state as needed
Below is a very simplified example - just to get you started - that extracts those basics into a dedicated class named BufferedTextInput. Buffering is changed internally on:
set to false if the "subject" value is set or a change is committed/discarded
set to true once on being notified on the first change of the textField
More complex logic (like not buffering on detecting a change back to the original value) can be implemented as needed.
/**
* Bind disable property of commit/cancel button to actual change.
* http://stackoverflow.com/q/29935643/203657
*/
public class ManualBufferingDemo extends Application {
private Parent getContent() {
ObservableList<Person> persons = FXCollections.observableList(Person.persons(),
person -> new Observable[] {person.lastNameProperty()});
ListView<Person> listView = new ListView<>(persons);
TextField lastName = new TextField();
Consumer<String> committer = text -> System.out.println("committing: " + text);
BufferedTextInput buffer = new BufferedTextInput(lastName, committer);
Button save = new Button("Save");
save.setOnAction(e -> {
buffer.commit();
});
save.disableProperty().bind(Bindings.not(buffer.bufferingProperty()));
Button cancel = new Button("Cancel");
cancel.setOnAction(e -> {
buffer.flush();
});
listView.getSelectionModel().selectedItemProperty().addListener((source, old, current) -> {
buffer.setSubject(current.lastNameProperty());
});
cancel.disableProperty().bind(Bindings.not(buffer.bufferingProperty()));
VBox content = new VBox(listView, lastName, save, cancel);
return content;
}
public static class BufferedTextInput {
private ReadOnlyBooleanWrapper buffering;
private StringProperty value;
private TextField input;
private Consumer<String> committer;
public BufferedTextInput(TextField input, Consumer<String> committer) {
buffering = new ReadOnlyBooleanWrapper(this, "buffering", false);
value = new SimpleStringProperty(this, "");
this.input = input;
this.committer = committer;
input.textProperty().addListener((source, old, current) -> {
updateState(old, current);
});
input.setOnAction(e -> commit());
}
private void updateState(String old, String current) {
if (isBuffering()) return;
if (value.get().equals(current)) return;
setBuffering(true);
}
public void setSubject(StringProperty value) {
this.value = value;
input.setText(value.get());
setBuffering(false);
}
public void commit() {
committer.accept(input.getText());
this.value.set(input.getText());
setBuffering(false);
}
public void flush() {
input.setText(value.get());
setBuffering(false);
}
public boolean isBuffering() {
return buffering.get();
}
public ReadOnlyBooleanProperty bufferingProperty() {
return buffering.getReadOnlyProperty();
}
private void setBuffering(boolean buffer) {
buffering.set(buffer);
}
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene(new Scene(getContent()));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
For production use, such direct coupling between view and model (f.i. when needing the buffering for a complete form) isn't good enough, further separation might be needed. See BufferedObjectProperty and its usage in a FX adaption of the infamous AlbumManager example (very crude)

Passing parameters while showing a view in Eclipse RCP

I am creating eclipse RCP application and I am stuck with passing parameter while showing a view.
As the first approach, I tried setting a static variable in View2 from View1 and opened that view (as below). It works.
IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
String viewIdToClose = studentListView.ID;
IViewPart viewToClose = activePage.findView(viewIdToClose);
TableItem item = studentTable.getItem(studentTable.getSelectionIndex());
String text = item.getText(ListViewConstants.TABLE_COLUMN_ONE);
activePage.hideView(viewToClose);
try {
String viewIdToOpen = StudentReview.ID;
StudentReview.userId = text;
activePage.showView(viewIdToOpen);
} catch (PartInitException e) {...}
As this doesn't seem to be a good approach, I tried as per the suggestion mentioned in the below link(accepted answer).
Passing parameters to the view
. In this approach, we can pass parameters only after showing the view.
But the issue I have is, the view to be opened should have the value from selected row while calling showView() i.e, I want to populate the parameters in View 2 based on View 1's selection.
Is there any way to achieve this? Is it good to use PULL instead of PUSH approach?
Any suggestion is appreciated.
Thanks!!!
UPDATE 1:
Approach mentioned in Passing parameters to the view
Interface:
public interface ICommunicationView extends IViewPart{
public void accept(Object parameter);
}
Calling accept():
IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
String viewIdToClose = StudentListView.ID;
IViewPart viewToClose = activePage.findView(viewIdToClose);
TableItem item = studentTable.getItem(studentTable.getSelectionIndex());
String text = item.getText(ListViewConstants.TABLE_COLUMN_ONE);
activePage.hideView(viewToClose);
try {
String viewIdToOpen = StudentReview.ID;
ICommunicationView viewToOpen = (ICommunicationView) activePage.showView(viewIdToOpen);
viewToOpen.accept(text);//Sending userId to Review view
} catch (PartInitException e) { ... }
StudentReviewView:
private String studentId;
//getters and setters
#Override
public void accept(Object parameter) {
setStudentId(parameter.toString());
}
public void createPartControl(final Composite parent) {
...
System.out.println("Student Id" + this.getStudentId());
}
It prints Student Id as null.
Am I missing something obvious?
Thanks!
Here is the good links try this..
http://tomsondev.bestsolution.at/2011/02/07/enhanced-rcp-how-views-can-communicate-the-e4-way/
Platform calls createPartControl when the view is opened by activePage.showView(viewIdToOpen). So don't populate your fields on createPartControl. Do it when setStudentId is called.
I also encountered this problem. Found a way around it by repacking the specific view component that needs to be updated.
Here is a proof of concept that sets a string:
Setter interface:
public interface ViewSetter {
void setMessage(String message);
}
View that gets initialized:
//view that implements ViewSetter
#Override
public void createPartControl(Composite parent) {
label = new Label(parent, SWT.NONE); //label is a field
}
#Override
public void setMessage(final String message) {
Display.getDefault().syncExec(new Runnable() {
#Override
public void run() {
label.setText(message);
label.pack(true);
}
});
}
Code that creates and initializes the view:
IViewPart view = page.showView(viewID);
ViewSetter viewSetter = (ViewSetter)view;
viewSetter.setMessage("Hello World");

Categories

Resources