Right now I'm working in a big smartgwt project. I need to implement a nice feature but I have no idea how to do it.
Our application has a lots of forms located in different tabs and grids and so on. Each form has his own save button and when it gets pressed it performs some few actions before the save action. For the application, it is really important to only save the form when the user presses the button. What I need is some kind of handler to prevent a user leaving unsaved forms. My intention is to show some kind of warning popup but I have no idea how to bind the action.
I don't know even if it's possible to do something like that with smartgwt but it seems to me a very typical feature to have in a big web application.
Some ideas? Someone had this problem before?
You can intercept almost every user action in GWT. If you want for example to prevent user from leaving page you can use something like this:
Window.addWindowClosingHandler(new Window.ClosingHandler() {
#Override
public void onWindowClosing(ClosingEvent event) {
if (unsavedData) {
event.setMessage("There is unsaved data. Do you really want to leave?");
}
}
});
If you want to stop user on different action like closing tab you can also do that by adding proper event listener.
Determining whether there is some unsaved data is also fairly simple but depends on UI component.
For example in listGrid you can use listGrid.getAllEditRows().lenght
In form you can compare form.getOldValues() with form.getValues() (Guava library will be perfect for this task: Maps.difference(form.getOldValues(), form.getValues()).areEqual()) Maybe there is better way to check unsaved data in form but I don't know it.
And last problem - linking it all together. I created custom save controller with multiple save participants. With this approach you can ask controller.isThereAnyUnsavedData() and controller should ask each participant.
Related
I'm dealing with a WebApp (Vaadin19) and stuck now in the question, how to share an object-state change from one component to another. There is one object instance in two or more components. After changing an attribute of the object in one component and going back to another component, I want to see the changed attribute.
Let me explain, what I mean:
There is a grid with some lines of data. The grid shows only a subset of the data to respect the clarity.
A click on the grid opens a detailed view in "read mode". The data is structured (contains sub-objects itself).
A click on the "read mode"-view opens then a dialog with tabs. The activated tab depends on the sub-object, that was clicked before.
After changing an element in the sub-object and closing the dialog, I want that the UI will reload/revalidate it's content. I think it's clear, that I use there the same object-instance.
Is there an event I have to submit to the UI?
Or:
What is the best approach for this?
The actual refresh is easy: theGrid.getDataProvider().refreshAll(), or refreshItem instead if you have access to the item that has been changed and it has a good implementation of equals and hashCode.
How to hook things up so that the dialog notifies the grid is then really depending on your architecture.
If they are already close to each other in the code, then you could e.g. store a reference to the Grid in an instance field and just reference that in the dialog handler.
If you want to decouple, then you need some kind of event bus. You can use the regular Spring event mechanisms as long as you ensure that the event stays within the UI scope. Alternatively, you can use ComponentUtil::addListener and ComponentUtil::fireEvent to use e.g. UI.getCurrent as a simple event bus.
I have a main Layout that contains another UI with grid and a button. This grid shows the data of a table of my database. With the button a wizard gets open, where i can create a new entry to this database. When i close the wizard with a button click, i want the grid to refresh in order to show also the newly added entry. Everythin works fine, including the storage to my database, except the refresh of my grid.
So i have the UI
public class MainLayout{
...
public void refreshGrid()
{
this.grid.getDataProvider().refreshAll();
}
}
where my grid is defined. I already implemented the refresh method.In there is also the button to create a new entry. When i click this button the next UI gets called.
This UI contains the general layout of the wizard, with a tab bar.
public class WizardLayout{
}
In one of those tabs there is finally the UI with the input fields to create the entry. There is also the button to save it to the database.
public class CreateEntry{
...
private void button_onClick(ClickEvent<Button> event)
{
...
}
}
In this button click method the logic is implemented to save it. And after that i would like to call the refresh method from the first UI in order to refresh it. How do i do that, so that it works?
Please remember, everything else works. So my only problem is to refresh the grid because it does not automatically. I have to click the refresh button in my browser to make it work.
First note that while not incorrect, your use of the term UI might be confusing in a Vaadin context, as it's usually used to refer to Vaadin UI objects, of which there is generally one per tab. Communication between Vaadin UIs is more complex than your use case.
There are plenty of solutions for this, the easiest is probably to pass an instance of your MainLayout to your wizard.
In that case, the classes will be tightly coupled, i.e. both depend on each other.
A better way is with some kind of listener or callback. This can be made quite complex, but in the easiest case you just pass a callback that will be run on save.
WizardLayout.java
private final Runnable saveCallback;
public WizardLayout(Runnable saveCallback) {
this.saveCallback = saveCallback;
}
private void button_onClick(ClickEvent<Button> event) {
...
saveCallback.run();
}
MainLayout.java
new WizardLayout(this::refreshGrid);
Is your dataprovider using in-memory items, or do you use a callback dataprovider with lazy loading?
You are probably using an in-memory dataprovider. This is the case, when you load your items from the database and put them in the grid with
grid.setItems(fooService.findAll());
Calling grid.getDataProvider().refresh() will only refresh the items that are already set. Since you have a new item to display, you have to fetch all items again from the DB with your service.
grid.setItems(fooService.findAll());
grid.getDataProvider().refreshAll();
If you're using a callback dataprovider with lazy loading, then I think just refreshing the dataprovider should be enough. I don't know enough about lazy loaded dataproviders to provide a solution to this issue but I do believe this issue should not arise in the first place if using a callback dataprovider
I am working on an eclipse Plugin, and I would like to use an Editor, set some listeners on the current page(good terminology?), and remove these listeners when the user switches on another page (basically, the user is editing several files, as you could do with the default JAVA editor).
For the moment I have written a class extending StructuredTextEditor. The behavior of the plugin was the one expected, but when I try to work on several files, many problems occur. The main problem, according to me, is that I am not able to get notified when the user opens another page.
I read (and tested) a few things about MultiPageEditor, but it seems like it doesn't integrate an XML editor as default editor. How should I proceed in order to get a MultiPageEditor, with XML syntax coloring, and get notified when the user changes the current page to adjust my listeners ?
Thanks for reading.
the code is not perfect but at least you will have an example of a MultiPageEditor integrating an XMLEditor: https://github.com/fusesource/fuseide/blob/8.0.0.Beta2/editor/plugins/org.fusesource.ide.camel.editor/src/org/fusesource/ide/camel/editor/CamelEditor.java
The idea is to call addPage(new StructuredTextEditor()) inside createPages() method.
regards,
In your editor you can listen to selection changes in the editor text using:
getSelectionProvider().addSelectionChangedListener(listener);
where listener implements ISelectionChangedListener.
This applies to any editor derived from AbstractTextEditor (which includes StructuredTextEditor.
You need to do this fairly late in the editor creation. In the createPartControl method works:
#Override
public void createPartControl(final Composite parent)
{
super.createPartControl(parent);
getSelectionProvider().addSelectionChangedListener(listener);
}
I am making some application for myself, just to practice on my designs and GUI.
My application is divided into two sides, first side is the model / logic however you call this, second side is the visual side, where you handle the gui, buttons and view.
So now my application has a feature that pops up and asks the user if he wants to use some feature, and then if he clicks yes, it will open a new JFrame window with many configurations.
these configurations will "probably" be in the Config class.
My question is, what is the best way to transfer data from the GUI to the model? Since you have to create a button listener in order to detect button clicks or text, what is the best proper way to update the configuration after the button was clicked?
For example, you have an application, and in order to start it you need to click on the button, I have two ideas in my head:
Transfer the Config object to the area where you handle the button & listen to it
Make Config static, and set up a Set() method, so you can set configurations without any objects, like Application.setConfiguration(config, type)
But I heard that statics are NOT always good, so I wondered, using static in this case is OK and good or are there better ways to do this? Or passing the config object to the GUI area is OK aswell?
This is how my structure looks like:
(source: gyazo.com)
I'm writing a wizard for an Eclipse RCP application. After doing some processing on a file and taking some user input, I don't want to let the user go back to make changes. At this point they must either accept or reject the changes they are about to make to the system.
What I can't seem to find is a method call that lets me override the buttons that display or the user's ability to hit the back button. I'd prefer that it not be there or at least be disabled.
Has anyone found a way to do this using the JFace Wizard and WizardPage?
Usability-wise, am I breaking wizard conventions? Should I consider a different approach to the problem?
You can return null from the getPreviousPage() method in your wizard page implementation.
Expanding on jodonell's answer:
Disabling the back button is harder than it should be, due to non-intuitive behavior in the default implementation of WizardPage.getPreviousPage(). You can call setPreviousPage( null ), and getPreviousPage() still returns the previous page. You need to override the implementation of getPreviousPage() in order to disable the back button:
public abstract class MyWizardPage extends WizardPage {
private boolean backButtonEnabled = true;
public void setBackButtonEnabled(boolean enabled) {
backButtonEnabled = enabled;
getContainer().updateButtons();
}
#Override
public IWizardPage getPreviousPage() {
if (!backButtonEnabled) {
return null;
}
return super.getPreviousPage();
}
}
See my blog post for a few more JFace wizard tips and tricks:
http://nsawadsky.blogspot.com/2011/07/jface-wizard-tips-and-tricks.html
From a UI perspective this seems rather bad. Your users are going to get frustrated if they make a mistake and want to go back and correct it and you don't let them. I think it would be much better to change the application to allow going back rather than looking for ways to prevent it.
There is no way to do this using standard JFace wizard APIs. My team accomplished this by writing a custom WizardDialog. We did this on an Eclipse RCP application and not on an eclipse plugin. Disabling the back button is breaking convention, but our business analysts really wanted the functionality.