• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Dirty Forms

 
Ranch Hand
Posts: 15304
6
Mac OS X IntelliJ IDE Chrome
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'm investigating the best way to go about determining when a form is "dirty" meaning changes have been made and the user should be visually notified that a save is required and/or if the form is closed the user is notified that a save should be performed before closing the form.

I'd like to avoid attaching a listener to every single form component manually. Especially since they would require different types of listeners. To simply prompt the user to save on close I could keep a copy of the form's model object and compare it to a new model object that holds all changed values. I just don't know how elegant that solution is.

So just looking for suggestions here.
 
Bartender
Posts: 4121
IntelliJ IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The way I've done it before is to add "dirty" state to the model object that backs the form, or add a sort of proxy layer that keeps track of changes between the real model object and the form.
 
Gregg Bolinger
Ranch Hand
Posts: 15304
6
Mac OS X IntelliJ IDE Chrome
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Nathan Pruett:
The way I've done it before is to add "dirty" state to the model object that backs the form, or add a sort of proxy layer that keeps track of changes between the real model object and the form.



Ok, yea, but how? Do you attach listeners to all the forms components to update the "dirty" state of the model? Are you using some binding framework that aids in this? How did you implement the proxy?
 
Marshal
Posts: 28193
95
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Seems to me (putting words in Nathan's mouth here) that if you want to track changes to the model, you don't do anything with the GUI at all. You just add code to the model which reacts to changes being made.
 
Gregg Bolinger
Ranch Hand
Posts: 15304
6
Mac OS X IntelliJ IDE Chrome
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Paul Clapham:
Seems to me (putting words in Nathan's mouth here) that if you want to track changes to the model, you don't do anything with the GUI at all. You just add code to the model which reacts to changes being made.



Maybe, but there is a missing piece here. If you type text in a JTextField that data doesn't automatically go into the model. So again, is there a binding framework/mechanism being used? I've looked into a couple of them but am looking for something people are actually using. Is there something else?
 
Ranch Hand
Posts: 62
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
In the case of a dialog (for instance) that contains say a few buttons, text input fields, etc..., you would need to implement your own model for that dialog to have one. The only way to know that something was entered in a text field, and if that data is now different than before (i.e. "dirty"), would be to have the appropriate listeners as needed. You could do this by implementing an Observable interface whereby you have an observer (maybe your model?) that registers as an "observer" for the controls/components you are concerning yourself with. The "observer" (model) would know the original state of each of the fields, and could determine at "go time" if the form is dirty or not...
 
Gregg Bolinger
Ranch Hand
Posts: 15304
6
Mac OS X IntelliJ IDE Chrome
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Gil Estes:
In the case of a dialog (for instance) that contains say a few buttons, text input fields, etc..., you would need to implement your own model for that dialog to have one. The only way to know that something was entered in a text field, and if that data is now different than before (i.e. "dirty"), would be to have the appropriate listeners as needed. You could do this by implementing an Observable interface whereby you have an observer (maybe your model?) that registers as an "observer" for the controls/components you are concerning yourself with. The "observer" (model) would know the original state of each of the fields, and could determine at "go time" if the form is dirty or not...



The Observer pattern works okay if your domain model is fairly simple. Since Observable is a class and we are using quite a bit of inheritance it just adds a layer of complexity that isn't worth the reward, IMHO.

But this brings up a good point. Again, Swing is disappointing because this problem is not solved in an industry standard way. Why is that Swing's fault? Because the engineers didn't consider this very simple situation that has been around since GUI inception when they designed Swing. But I digress, I'm stuck with Swing so I have to cope.

Again, I'd like to avoid attaching listeners to every component if possible. So still looking for more ideas. Thanks for the input though.
 
Ranch Hand
Posts: 4632
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
> Again, I'd like to avoid attaching listeners to every component if possible.

if the changes are just to text components, perhaps an AWTEventListener might be enough



but it won't pick up rightClick/paste changes
 
Ranch Hand
Posts: 142
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Greg,

How about creating sort of a listener adapter, which implements all the required listener interfaces (should be no more than 5 or 6), wraps incoming events, and forwards them to a single souce. Any listener can listen to more than one input field if if does not matter from which actual field of a group of fields (e.g. a form) a given event comes, right. So you might use envisioned adapter for all the fields of a given form.

If you want to track reversion of changes as well, you might also make the adapter get the state of any fields it is registered to, by the time it is registered. A isAnyOfThFieldsDirty() method might then check the values field by field, and compare each value to the respective field's initial value. This way, you have a universal observer for any given form, just need to register it with all the fields.

Instead of registering the listener with all the fields oneby ne, you might finally add the root JPanel (or other container) of the form with the listener, which then can walk through the container's component hierarchy and register with all the input fields it find. The only prerequise for this to work is that no fields are added to or removed from the forms on the fly. And the listener should inspect the form after it's been fully created.

Hope that helps.
 
Bartender
Posts: 11497
19
Android Google Web Toolkit Mac Eclipse IDE Ubuntu Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I would approach it from the View point of view (!) rather than the Model.
1) Extend DefaultKeyboardFocusManager
2) The dispatchKeyEvent is invoked whenever any keyboard key is pressed/released/typed. That would mean (in most cases) that the user has "done" something. Your model is dirty.
3)Add your KeyboardFocusManager to the current keyboard focus manager's dispatcher chain.

This would work presuming there are no copy pastes using the mouse.
Also if the user types and deletes something, it would not be dirty any longer. However, the way I look at things, the user has still changed the model.
 
Guido Sautter
Ranch Hand
Posts: 142
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Maneesh,

your idea is going to work pretty well on text fields, but what about checkboxes, combobxes, etc? These are things you usually change with the mouse, so there won't be any keyboard events involved.

In addition, your solution would not catch cases where a field is modified and then re-modified back to the original value. In this case, the form was dirty some time, but actually is not dirty at the time of the check.

Furthermore, the KeyboardFocusManger approach would have to make sure that the fields in the form in question are the only ones on the UI. Or how would you exclude changes to fields that do not belong to the form whose dirty status is to be watched?
reply
    Bookmark Topic Watch Topic
  • New Topic