I have a list of objects in a Swing GUI. The user can select one and edit the object before having to confirm the change by pressing a button. The state of the object is done with binding.
My problem is; the user should be able to cancel the editing, reverting the changes. The original data is already changed.
I guess I need to have a copy of the object, but I don't know what the correct way is to obtain one. Clone method, copy constructor, serialization,... They all seem to have drawbacks.
This must be a common requirement and I wonder which approach I should use? What is the most elegant way?
One can maintain a history of undoable actions so a list of Undos is possible. Doing an actionPerformed registers the reverse undo action restoring the state.
That would fit nicely.
A bit dated, und/redo essay with patterns.
UndoManager.
Related
I'm building an application which contains a GUI and a Model. I'm using the Observer pattern (using java's built in interfaces) to update the GUI when fields in the model are changed.
This is generally working fine, but I have a situation in which a particular String variable in the model (specifically the url of a file) can be changed by two separate JTextFields (swing) the contents of which actually reflects the value of the model variable in question.
The issue I am having comes from the fact that an change in one of these JTextFields needs to cause an update to the state of the model, and the contents of the other JTextField. My Model ensures that notifications are sent to observers only in the case that the state of the model has changed. However, the process by which JTextFields are modified involves blanking it's text content then reseting it.
Without going into too much detail, the upshot of this is that the update / notification process gets stuck in an infinte loop. I have temporarily hacked around this by setting aside the observer pattern for this particular problem, but I was wondering if anyone could suggest a neat way of ensuring that a particular component is not "updated" by a change which originated from the same component.
Any help appreciated.
As discussed in Java SE Application Design With MVC, this is one of several Issues With Application Design. The suggested approach relies on a PropertyChangeListener, illustrated here. The PropertyChangeEvent includes both old & new values for reference.
This link which talks about a Bidirectional Observer may offer some help on this.
It does seem in your case that the Model and View are trying to update each other. The solution would lie in enforcing the direction of an update. For example Inner layer -> Model -> View and View -> Model -> Inner layer. So it wouldn't really be a true Observer Pattern.
The update(Observable o, Object arg) method of java.util.Observer does accept an Observable(Subject) object. This object can be used to provide a hint to the Model asking it to propagate the update inward rather than toward the View.
I gave it a quick try and found that setting up Bidirectional observer (using Java apis) is not as simple as I thought. But you could venture a try.
We are trying to build a GUI framework using GWT. We are finding it hard to implement the cancel functionality in the framework.
Required feature is this:
We have CRUD screens which have pop-ups, grids and so on. When the user changes anything in the GUI and then clicks on cancel() he should be given a notification message saying that something has changed.
Approach that we have tried:
Currently we are trying to keep a hashmap of key vs value of the entire pojo object and trying to compare it against the model which gets updated as and when user changes something. But this is adding lot of unwanted code in every pojo and not working as expected when user adds data directly from the backend.
Is there any elegant way in achieving this functionality? Kindly note that *we are not using Editor framework of GWT *(https://developers.google.com/web-toolkit/doc/latest/DevGuideUiEditors) in our application.
Example:
Suppose I have a pojo like this:
public class Person {
List<Address> address;
PhoneNumber phoneData;
// and so on along with getters and setters
}
How will I write a generic clone method for this? And even if I manage to do that somehow that will lead to lot of code in every pojo (our application has hundreds of them) which doesn't seem right.
Please note that, our pojo gets updated as soon as something is changed in GUI to achieve live binding.
So you have "Save" and "Cancel" buttons in your form?
I would recommend you to change the concept. Update your object properties immediately as user edit them (as in GMail, JIRA and many other modern applications) in an OnChange event handler.
Save all updates to the session stack as UpdateAction objects and let the user undo every single property modification calling UpdateAction.undo() method.
The benefits are:
this design is much more user friendly than "Click "Edit" - update - click "Save"" scenario.
You don't need separate view/edit forms/popup dialogs - just a single form for both viewing and editing.
When I edit the quantity of an object in a list and the toString changes, how do I get the list to update with the new toString?
Example, when I change nodes in my JTree, I use nodeChanged(node) what do I do when I change a list item?
AbstractListModel#fireContentsChanged if you extend from AbstractListModel.
It is the same principle as for the JTree of your previous question. The AbstractListModel does not know when some internal property of your objects is changed. So when you make a change, you must call that particular method indicating the object is changed. The list model will fire the correct event which is received by the JList, which will update/repaint (whatever you want to call it).
Personally I prefer to create ListModels which are self-contained, e.g. if the objects you use fire events when they change the ListModel can listen for those changes and fire the appropriate events itself instead of having to call this method externally.
Edit
Just noticed that that particular method is protected, so you need to create the model as I suggested and you cannot call that method externally (which is a good thing)
List.updateUI() will do it, although I'm told this has some overhead.
I am in charge of maintenance of an old application written in Swing, combined with a CAD-like tool written in Java3D. We are having problems with memory usage. After profiling, this is related to the undo functionality in the application.
All undo functionality is state-based, with a basic concept like this:
public class UndoAction {
private UndoTarget target;
private Object old_data;
private Object new_data;
}
Code to create these UndoActions is basically littered throughout the application. Because there is no distinction between modifications of new objects, modifications of existing objects and modifications of subtrees, the following happens:
What happens is a single action is the following:
Create a new object A.
Modify field foo of the object. A new UndoAction is placed on the stack, which contains foo_old and foo_new.
Modify field bar of the object. A new UndoAction is placed on the stack, which contains bar_old and bar_new.
Execute B.setField(A). A new UndoAction is placed on the stack, which contains field_old and field_new (== A).
There is no granularity or any control over this at all. This does not help maintainability at all.
I want to refactor this system so it becomes maintainable and memory-friendly. Unfortunately, implementing the Undo system using the Command pattern is not possible; the actions are too impacting to revert. I want to implement the following:
Use annotations to provide "Undo demarcation". #Undoable() would mark a method as generating an UndoAction which is put on the stack. This can be parametrised just like transactions: REQUIRE, NEST, JOIN... The full object graph is cloned upon entering the Undoable method.
When a Transaction (=method) finishes, an algorithm should compare the new state with the old state and save a diff.
To implement this, we can use AOP. This allows us to keep the core code very clean.
An now, my question:
Do any of the above 3 functionalities already exist in Java? I can imagine I am not the first to wrestle with state-based undo and the problems linked to it (Undo demarcation, state compare, ...)
After this question has been open for quite some time, it seems the question is: "No, no such framework already exists."
As a guide for other people, I am looking into Eclipse Modeling Framework and the EMF.Edit framework. In this framework, you define the model in a descriptor language, and the framework handles the model and any manipulations for you. This automatically results in Actions and Undo/Redo being created.
For reference, one other framework that may serve as a model (if not a solution) is UndoManager, which supports a limited number of edits. It's part of the javax.swing.undo package, one of several core Text Component Features.
If I get a bean and a dialog, and they are coupled with bidirectional data-binding, what is the best way to roll back to the original bean when user canceled the editing.
EDIT 1
If user opened up the dialog in edit mode, he then did some modification and pressed "OK", then this dialog closed and the underlying bean got updated. When I said "canceled the editing", I mean the user opened up the dialog and did some modification but pressed "cancel" button. In this case, the underlying bean should keep untouched, but due to data-binding, it become dirty, I want the original bean back.
I can just clone a bean when the dialog opens, if user presses "OK" the cloned bean will be copied back to original bean; if user presses "cancel" the cloned bean will be abandoned.
I don't know if this is a good approach.
I have always used the clone approach quite successfully. The clone approach comes in two varieties: bind to clone and bind to original.
Bind to clone will make it so any other binding to the same field on the screen will not update while your dialog box is up. When OK is pressed you copy the clone to the original object, on cancel you simply throw the clone away.
Bind to original allows screen updates to others components bound to the same field. When OK is pressed you throw the clone away. When cancel is pressed you copy the clone to the original.
I favor the bind to clone approach since I think it is confusing to see other on screen components updating while a dialog box is up. I think it creates confusion as to whether cancel will rollback changes that are appearing outside the dialog box.
The alternative is to use a flushable binding strategy where a binding can be set up in such a way that it will not update the object until some kind of flush() method has been called. If your databinding framework does not support this then it can be a lot of work to tack this on later.
What do you mean by "canceled the editing?" Without some example code, it's hard to help. The most generic solution is to store the previous value as a variable somewhere.
Perhaps implement a PropertyChangeListener? You can grab the old value via PropertyChangeEvent.getOldValue()? Maybe a VetoableChangeListener may work for you too.