I have a mvp structured javafx application. There is a view with a textfield, which has its own textProperty of type StringProperty. There is also a model which contains an Object called Item. Item has an IntegerProperty.
Now I'd like to bind these two Properties within my presenter-class, so that they get updated, when one or another changes. Eventhough they have different types, there is the possibility to bind them the following way:
Bindings.bindBidirectional( textField.textProperty(), item.percentProperty(), new NumberStringConverter() );
This works perfectly fine, unless the value of the textfield gets cleared, which results in a NullPointerException, because an empty value of textProperty results in a Null-Value and setting a null Value in IntegerProperty results in a NullPointerException. Can you think of any way to avoid this? Do I have to write my own NumberStringConverter?
Moreover I'd like to define, that Item can only hold a percent value between 0 and 100. The View should be informed, when the value is invalid, so the user can get feedback. Where should I verify these kind of businessrules?
I came up with a first example, but I am not sure, if that should be the way to go, so I'd be curious, if you might have better ideas how to solve this.
class PercentProperty extends SimpleIntegerProperty
{
private InvalidValueListener invalidValueListener = null;
public PercentProperty ( final Integer defaultValue )
{
set( defaultValue );
}
#Override
public void set( final int newValue )
{
if ( isValid( newValue ) )
{
super.set( newValue );
if ( invalidValueListener != null )
invalidValueListener.validValue();
}
else
{
if ( invalidValueListener != null )
invalidValueListener.invalidValue();
}
}
private boolean isValid( final int value )
{
return (value >= 0 && value <= 100);//FIXME: Better use Predicates to define Rules.
}
public void setListener( final InvalidValueListener listener )
{
invalidValueListener = listener;
}
public void removeListener( #SuppressWarnings( "unused" ) final InvalidValueListener listener )
{
invalidValueListener = null;
}
protected void fireInvalidationValue()
{
invalidValueListener.invalidValue();
}
}
interface InvalidValueListener
{
void validValue();
void invalidValue();
}
JavaFX is a simple graphical toolkit, not a comprehensive framework, and this means that lots of things you have to engineer yourself. Data validation is such a thing, and you have to find your own way among your previous experience and others' suggestions.
I would not bind the two properties: the text field should be initialized (just set, not bound, to avoid glitches while the user is typing without her explicit consensus) with the value from the model, and then the integer property should be updated by a listener (a text field's ChangeListener or a listener to the form submission, if appliable and depending on your likes), which is responsible for validating input and reporting errors to the user.
This way you decouple two things that are indeed unrelated: one is a widget for accepting user input (a text you need to parse to get a number), and the other is a number in your model, which is used to make a computation.
As a side note, I would not use two properties altogether, and I'd revisit your three tiers parition. MVP and all MVC derivatives proved to be good patterns to build GUI toolkits, but I was never convinced they were equally good for structuring GUI applications. I mean, if what you call model is a way to share session data between different parts of the application (kind of an events sink) then it's a perfectly legitimate implementation, otherwise I see no use in having a separate bunch of properties grouped in a class. In the latter case, the widgets themselves are the model:
// This is the controller
public class PesonalDetails {
// Model starts here: it's implicitely defined by the widgets
// You may also use #FXML
private final TextField first = new TextField();
private final TextField last = new TextField();
// Model ends here
}
Note I'm not saying MVC should be thrown away and everything should be collapsed in one single file. Just that MVC, MVP, MVVM are design patterns and it's up to you to decide when, where and how to implement them - depending on how much they buy to you. With JavaFX I like to use these tiers:
A visual layout tier (a layout builder implemented in Java or FXML)
Event handling code
If appliable, a data access layer (and you can apply a pattern here, like ActiveRecord)
(The new version of the answer)
I think the best aproach is to not let a user enter an incorrect value in the first place. You can achive this easily with help of JideFX Fields:
FormattedTextField<Integer> field = new FormattedTextField<>();
field.getPatternVerifiers().put("p", new IntegerRangePatternVerifier(0, 100));
field.setPattern("p");
field.valueProperty().bindBidirectional(item.percentProperty());
Particularly FormattedTextField is very convenient because it do text-to-value conversion and validation for you, so there is no need to implement any utility classes yourself.
Links:
JideFX Fields Developer Guide: http://www.jidesoft.com/jidefx/JideFX_Fields_Developer_Guide.pdf
Source code: https://github.com/jidesoft/jidefx-oss
Binary: http://search.maven.org/#search%7Cga%7C1%7Cjidefx
Related
The thing is that I am using Hibernate on the server side and that I am sending basically "raw" database data to the client - which is fine I guess but that also means that my client gets a List<UpcomingEventDTO> when calling the according service which is just a list from a specified date to another one.
If I now want to split those events into a map where the keys map to lists of events of one day e.g. a Map<Integer, List<UpcomingEventDTO>> then I will have to do this on the client side. This wouldn't bother me if I wouldn't have to do that in my Presenter.
On the one hand I'm having the loading in my presenter:
private void loadUpcomingEvents(final Integer calendarWeekOffset) {
new XsrfRequest<StoreServletAsync, List<UpcomingEventDTO>>(this.storeServlet) {
#Override
protected void onCall(AsyncCallback<List<UpcomingEventDTO>> asyncCallback) {
storeServlet.getUpcomingEventsForCalendarWeek(storeId, calendarWeekOffset, asyncCallback);
}
#Override
protected void onFailure(Throwable caught) {
}
#Override
protected void onSuccess(List<UpcomingEventDTO> result) {
upcomingEvents = result;
presentUpcomingEvents();
}
}.request();
}
and the conversion of the data before I can present it:
private void presentUpcomingEvents() {
Map<Integer, List<UpcomingEventDTO>> dayToUpcomingEvent = new HashMap<>();
for (UpcomingEventDTO upcomingEvent : this.upcomingEvents) {
#SuppressWarnings("deprecation")
Integer day = upcomingEvent.getDate().getDay();
List<UpcomingEventDTO> upcomingEvents = dayToUpcomingEvent.get(day);
if(upcomingEvents == null) {
upcomingEvents = new ArrayList<>();
}
upcomingEvents.add(upcomingEvent);
dayToUpcomingEvent.put(day, upcomingEvents);
}
List<Integer> days = new ArrayList<Integer>(dayToUpcomingEvent.keySet());
Collections.sort(days);
this.calendarWeekView.removeUpcomingEvent();
for(Integer day : days) {
CalendarDayPresenterImpl eventCalendarDayPresenter = null;
eventCalendarDayPresenter = this.dayToEventCalendarDayPresenter.get(day);
if(eventCalendarDayPresenter == null) {
List<UpcomingEventDTO> upcomingEvents = dayToUpcomingEvent.get(day);
eventCalendarDayPresenter = new CalendarDayPresenterImpl(upcomingEvents);
this.dayToEventCalendarDayPresenter.put(day, eventCalendarDayPresenter);
}
this.calendarWeekView.appendEventCalendarDay(eventCalendarDayPresenter.getView());
}
}
So my problem is basically that I am not really happy with having code like this in my presenter but on the other hand I wouldn't know how and where to provide the data in this "upgraded" form for my presenter(s).
One could argue and say that I could also just return the data from the server in a way I would need it on the server but then I would lose generality and I don't want to write for all views and presenters their "own" API to the database.
Another possibility would be e.g. to introduce another layer between the service/servlet layer and have something like a DAO- or database-layer before my presenters model. But this would also raise quite a lot questions for me. E.g. what would be the name of such a layer ^^ and would that layer provide "customize" data for presenters or would the data still be kind of generalized?
I'm having quite a huge issue figuring out what to do here so I hope I can benefit from someones experience.
Thanks a lot for any help here!
The presentation logic should be on server side in controller layer where its meant to prepare the view for the clients. ( MVC pattern )
And if many views want to use this, you can make an abstract controller which can be reused for other views.
Also its good to prepare your controller layer for the future requirements. Ask yourself whether another client will ask to present the data in different granularity ? May be show the upcoming events by month/time ? Hence you have to provide your API a granularity enum UPCOMING_EVENTS_DAY_GRANULARITY( DAY, MONTH, HOUR) as a method parameter so that you will make client to decide what they want.
And to make it more beautiful, you can also say rename/move controller layer into a webservice layer which can be considered as your future API for external systems (not only for your views but for anyone outside your system)..
This is more of a general question. We have a lot of wizard, some of which start a long-running process and display the result after. The question is: what is the correct way to do long calculations?
Formerly most wizards did their calculations in DialogPage#setVisible, something like that:
public void setVisible(final boolean visible) {
if (visible) {
getWizard().getContainer().run(true, true, new MyCalculation());
}
super.setVisible(visible);
}
I don't think that's a good idea, since usually getWizard() gets called a lot in these methods. Moreover, usually the parent wizard gets cast to a specific implementation to get input values from or set the result to other pages. So usually it looks something like this:
public void setVisible(final boolean visible) {
if (visible) {
Input input = ((MyCalculationWizard)getWizard()).getInputPage().getInput();
MyCalculation calculation = new MyCalculation(input);
getWizard().getContainer().run(true, true, calculation);
Output output = calculation.getOutput();
((MyCalculationWizard)getWizard()).getOtherPage().setOutput(output);
}
super.setVisible(visible);
}
Just from looking at the code you know that's very bad style.
So we replaced it with something that calculates in Wizard#getNextPage():
public IWizardPage getNextPage(final IWizardPage page) {
final IWizardPage nextPage = super.getNextPage(page);
if (nextPage == this.myResultPage)
getContainer().run(true, true, new MyCalculation());
return nextPage;
}
That way, the wizard is able to fine-tune a lot better than a page would, and the wizard already knows it's pages and can handle input and output a lot better than a page ever could.
The drawback is: getNextPage() gets called a lot for updating the buttons and every time really the wizard feels like it. So while it works for small processes, it does not cut it for long-running ones.
After some more poking around I found the following to work while overriding Wizard#setContainer:
public void setContainer(final IWizardContainer wizardContainer) {
final IWizardContainer oldContainer = getContainer();
if (oldContainer instanceof WizardDialog)
((WizardDialog) oldContainer).removePageChangingListener(this);
super.setContainer(wizardContainer);
if (wizardContainer instanceof WizardDialog)
((WizardDialog) wizardContainer).addPageChangingListener(this);
}
public void handlePageChanging(final PageChangingEvent event) {
final IWizardPage currentPage = (IWizardPage) event.getCurrentPage();
final IWizardPage nextPage = (IWizardPage) event.getTargetPage();
if (currentPage == this.myInputPage && nextPage == this.myResultPage)
getContainer().run(true, true, new MyCalculation());
}
The big advantage here is that the listener only gets called if the wizard wants to jump between pages, and we are able to really fine-tune the calculation (e.g. to not be called when calling 'Previous'). We are even able to not show the next page after all (event.doit = false).
The drawback is the cast of the container to WizardDialog, because potentially it could be an entirely different implementation.
So the question stands: What is the best way to start long processes in wizards?
This is my zul code:
<combobox id="digitalPublisherCombobox" value="#load(ivm.inventory.digitalPublisherName)"
onOK="#command('setDigitalPublisher', digitalPublisherBox = self)"
onSelect="#command('setDigitalPublisher', digitalPublisherBox = self)"
onChanging="#command('setupQuicksearchByEvent', searchlayout = event, prefix = 'PUB', tags = 'PublisherName, PublisherNameTranslit')"
mold="rounded" hflex="1" buttonVisible="false" autodrop="true">
<comboitem self="#{each=entry}" value="#{entry.key}" label="#{entry.value}"/>
</combobox>
And this is QuickSearch implementations:
#Command
public void setupQuicksearchByEvent(#BindingParam("searchlayout")Event event, #BindingParam("prefix") String prefix, #BindingParam("tags") String tags) throws WrongValueException, SearchException, IOException
{
if(event instanceof InputEvent)
{
InputEvent inputEvent = (InputEvent) event;
String inputText = inputEvent.getValue();
List<String> searchFields = Arrays.asList(tags.split(","));
ListModel model = new ListModelMap(ZKLogic.findDocsStartingWith(prefix, searchFields, "proxy", inputText), true);
ListModel subModel = ListModels.toListSubModel(model, Autocompleter.MAP_VALUE_CONTAINS_COMPARATOR, 10);
Combobox searchBox = (Combobox) event.getTarget();
searchBox.setModel(subModel);
searchBox.setItemRenderer(new ComboitemRenderer()
{
#Override
public void render( Comboitem item, Object data, int pos ) throws Exception
{
String publisherString = data.toString();
UID key = getUidFromPublisherString(publisherString);
int startIndex = publisherString.indexOf('=') + 1;
String publisher = publisherString.substring(startIndex);
item.setLabel(publisher);
item.setValue(key);
}
});
}
}
ZKLogic.findDocsStartingWith return map with UID-key and String-value.
With code above I achieved to get dropdown list when I switch to another window. I need to type something, then select another browser or notepad window - and comboitems will be displayed immediately.
So, my question still need answer, is there are any techniques to reproduce this windows switching in code? Or maybe I should do something with autocomplete, because I've got some ac working with preloaded lists, but this thing should return only 10 records from db, instead of all 70000 entries, every time when user type something in the field.
Edit 20/09/2013: Problem still exist. Rename question a bit, because thing that I need is to call render option by force in code. Is there is any way to do it? Code hasn't changed a lot, but print option in render method said, that method can miss two or more onChange events and suddenly render text for one variant.
Maybe you know another autocomplete options in zk framework where database participating? I'm ready to change implementation, if there is a guide with working implementation of it.
Ok I see two problems, you should solve first.
Setting the Renderer in every call of setupQuicksearchByEvent(...).
that is not logical, cos it is the same every time.
Add to the zul combobox tag something like
itemRenderer="#load(ivm.myRenderer)" ....
If you want just 10 items, do not let the db-request return more then 10.
If you use JPA klick here or for sql here or just google a bit.
After you fixed this two issues, we can exclude these as a reason of the unexpected behavior and fix it, if it is still present.
Edit
Ok, I have two possible ways to fix it.
Call Combobox#invalidate()
This schould force zk to rerender the Combobox, but could
lead to low performance and I would not prefer this.
Use Listbox with the select mold instead of Combobox.
To force the rerender, use Listbox#renderAll()
Try setting the selected item on your combobox or throw its related event
Solution is simple. Really. Nothing is better then brute-force, but I think I tried to avoid it and use it in despair.
#Command
public void setupQuicksearchByEvent(#BindingParam("searchlayout")Event event, #BindingParam("prefix") String prefix, #BindingParam("tags") String tags) throws WrongValueException, SearchException, IOException
{
if(event instanceof InputEvent)
{
InputEvent inputEvent = (InputEvent) event;
String inputText = inputEvent.getValue();
List<String> searchFields = Arrays.asList(tags.split(","));
Map<UID, String> publishers = ZKLogic.findDocsStartingWith(prefix, searchFields, "proxy", inputText);
Combobox searchBox = (Combobox) event.getTarget();
searchBox.getChildren().clear();
for (Map.Entry<UID, String > entry : publishers.entrySet())
{
Comboitem item = new Comboitem();
item.setLabel(entry.getValue());
item.setValue(entry.getKey());
searchBox.appendChild(item);
}
}
}
In my Vaadin UI, I have the following scenario:
In other words, there are two tables:
a "master" table that is editable,
a "slave" table that is non-editable, but must contain the same data as the master table, however with a potentially different sort order.
The final requirement precludes the tables having the same Container (in my understanding, which might be wrong).
What I've done currently is that I attach an ItemSetChangeListener and a ValueChangeListener, and use the events to update the data accordingly.
Here's the current crude implementation (in Scala actually, but I hope it's readable enough, if not, please comment) :
class DataTableSynchronizer(val master: Table, val slave: Table) extends ItemSetChangeListener with ValueChangeListener {
def init():Unit = {
master.addItemSetChangeListener(this)
containerMaster.addListener(this.asInstanceOf[ValueChangeListener])
}
private def containerOf(t: Table) = t.getContainerDataSource().asInstanceOf[IndexedContainer]
private def containerMaster = containerOf(master)
private def containerSlave = containerOf(slave)
override def containerItemSetChange(event: ItemSetChangeEvent) {
//handling
//remove all items that have been deleted
for(toDel <- containerSlave.getItemIds().filterNot(containerMaster.containsId(_))) {
containerSlave.removeItem(toDel)
}
//add new items to the start
for(toAdd <- containerMaster.getItemIds().filterNot(containerSlave.containsId(_))) {
containerSlave.addItem(toAdd)
}
slave.validate();
}
override def valueChange(event: ValueChangeEvent) = {
updateValuesInResults()
}
private def updateValuesInResults(): Unit = {
//update all values in the "slave" table from the "master" table
for((itemData,itemResults) <- containerMaster.getItemIds().map(id => (containerMaster.getItem(id),containerSlave.getItem(id)))) {
for(propId <- itemData.getItemPropertyIds()) {
itemResults.getItemProperty(propId).asInstanceOf[Property[Any]].setValue(itemData.getItemProperty(propId).getValue().asInstanceOf[Any])
}
}
}
}
However, my problem is that I need the data to be synchronized continuously, as the user types, which is not happening due to the relevant events being sent only after some operation completes (a row is added, etc.).
How do I solve this, i.e. how do I enforce events being emitted often enough to enable continuous synchronization? The only idea I had was to use an ActionListener mapping all the keys, but that screams "abuse".
Note: I realize doing this through the server-side is less efficient, but this is not a concern in my case. However, client-side-based answers are OK as well, of course.
You can set the TextChangeEventMode of the editor to EAGER and process single keystrokes in the event listener:
TextField textField = ...;
textField.setTextChangeEventMode(TextChangeEventMode.EAGER);
textField.addTextChangeListener(new TextChangeListener() {
#Override
public void textChange(TextChangeEvent event) {
String text = event.getText();
// sync with other component
}
});
I'm sure there must be a standard way to do this, but my attempts to search Stackoverflow have failed.
I have a method like:
public void processSomeWidgetsForUser(int userItemId) {
Iterator<Widgets> iter = allWidgets.values().iterator();
while(iter.hasNext()) {
Widget thisWidget = iter.next();
if (userItemId == -1 || thisWidget.getUsersItemId() == userItemId) {
widget.process();
}
}
}
As you can see -1 is a "special value" meaning process all. Doing this saves repeating the loop code in another method called processSomeWidgetsForAllUsers.
But I dislike special values like this because they are easy to misuse or misunderstand, which is exactly the situation what I'm having to fix now (where someone thought -1 meant something else).
I can only think of two ways to improve this.
have a constant, containing -1 called something like
Widget.ALLWIDGETS which at least is self-documenting, but doesn't
stop code from using a -1 (if someone integrates old code in, for
example)
change the method to take a list of all user ids to
process, which can be empty, but that doesn't seem great
performance-wise (would need to retrieve all user ids first and then loop through
removing. Also what happens if the number of widgets in the list changes between
retreiving the ids and removing
Is there a better way? I'm sure I'm missing something obvious.
The above code has been changed slightly, so may not compile, but you should get the gist.
Although somewhat redundant, a fairly neat self-documenting approach could be to have 3 methods rather than one;
Make your original method private, and make one small change which would be to add your static final int EXECUTE_ALL = -1 and use that in your original method, then add the two new methods;
public void processWidget(int wID) throws IllegalArgumentException {
if(wID == EXECUTE_ALL) throw new IllegalArgumentException();
originalMethod(wID);
}
public void processAllWidgets() {
originalMethod(EXECUTE_ALL);
}
It makes your class a little more cluttered, but as far as the exposed methods go, it is clearer and hopefully foolproof. You could alter it not to throw an exception and just ignore any invalid ids, that just depends on your situation.
This approach of course has the major downside that it changes how the class appears to other classes, breaking everything that currently uses the, now private, originalMethod().
Number 1 would work very nicely. Be sure to document what the variable is though, so future coders (possibly yourself) know what it means.
/**This is the explanation for the below variable*/
public final static int ALL_WIDGETS = -1;
Have an external method like so:
static boolean idRepresentsAll(int id) {
return id == -1;
}
In this case, if you decide to replace it with a different mechanism, you only replace your magic number one place in your code.
At the very least, you would want to do something like this:
public static final int ID_REPRESENTING_ALL = -1;
You can change the method signature to accept a boolean for when you want to process them all.
public void processSomeWidgets(boolean doAll, int userItemId) {
Iterator<Widgets> iter = allWidgets.values().iterator();
while(iter.hasNext()) {
Widget thisWidget = iter.next();
if (doAll || thisWidget.getUsersItemId() == userItemId) {
widget.process();
}
}
}
This makes it more explicit, and easier to read in my opinion as there are no special values.