Wednesday, May 18, 2016

Uberfire - The Unanswered Questions: Part 2

And now presenting...

As I mentioned in Part 1, my proposed model changes will necessarily cause some changes in the Presenter and View classes. Most of these are as a consequence of removing the Model bits from Presenter and View.

I have made the design decision to make ProjectsPresenter the "owner" of the model root, listening for model change events from the TasksPresenter and making the model changes. This will also be a good place to handle model persistence. More about this later on, but first let's take a look at the new Presenter and View classes. I don't want to bore you by filling this blog with pages of java code, so I'll just present some of the highlights. The complete tutorial can be found on github here.

ProjectsPresenter.java

The big changes here are the additions of model change handlers: the @Observes annotations identify the change events which are injected into this class by TaskPresenter. This concept was introduced in the original tutorial, and should already be familiar.

The model root object, a TasksRoot instance, is made available with the @Produces annotation. This is consumed by the DashboardPresenter class with @Inject. Consequently, the DashboardPresenter code is greatly simplified because it doesn't have to deal with handling events to update its "total tasks" and "tasks done" counters - it can simply ask the model for this information.

    private TasksRoot tasksRoot = new TasksRoot();

    @Produces
    @Named("tasksRoot")
    public TasksRoot tasksRoot() {
        return tasksRoot;
    }

The other obvious change is that Project, Folder and Task name strings (which are actually attributes of these model objects) have been replaced by their actual model objects, and the object tree hierarchy is strictly modeled.

TasksPresenter.java

Again, the main changes here are replacement of name strings with actual model objects; similar changes were made in the TaskCreated and TaskDone events. These are identical to those in the original tutorial, except for (again) the use of actual model objects instead of strings. I've also added FolderCreated and FolderRemoved events so we can notify the ProjectsPresenter when these are triggered. Recall that the "Create Folder" button is on the TaskView.
    @Inject
    private Event< TaskCreated > taskCreatedEvent;

    @Inject
    private Event< TaskDone > taskDoneEvent;
    
    @Inject
    private Event< FolderCreated > folderCreatedEvent;

    @Inject
    private Event< FolderRemoved > folderRemovedEvent;

    public void newFolder(String folderName) {
        folderCreatedEvent.fire(new FolderCreated(new Folder(folderName)));
        updateView();
    }

    public void removeFolder(Folder folder) {
        folderRemovedEvent.fire(new FolderRemoved(folder));
        updateView();
    }
    
    public void doneTask(Task task) {
        taskDoneEvent.fire(new TaskDone(task.getParent(), task));
        updateView();
    }

    public void createTask(Folder folder, Task task) {
        taskCreatedEvent.fire(new TaskCreated(folder, task));
        updateView();
    }
}

Another thing worth mentioning is that the ProjectsPresenter class notifies TasksPresenter when a different project has been selected. This allows TasksPresenter to redraw its view with content of the new Project.

    private Project currentSelectedProject;

    public void projectSelected(@Observes ProjectSelectedEvent projectSelectedEvent) {
        currentSelectedProject = projectSelectedEvent.getProject();
        selectFolder();
    }

DashboardPresenter.java

As mentioned previously, the code for this class has been reduced to just a few lines because it no longer listens for task events to update its totals. Instead we use an @Inject to get the instance of the model root object (TasksRoot) and ask it for these totals. The Dashboard view remains the same as before.
    @Inject
    @Named("tasksRoot")
    private TasksRoot tasksRoot;

    private void updateView() {
        view.clear();
        for (Project project : tasksRoot.getProjects()) {
            int done = project.countDoneTasks();
            int notDone = project.countTotalTasks() - done;
            view.addProject(project, notDone+"", done+"");
        }
    }



Event Classes

These should be self-explanatory. The TasksPresenter class creates one of these event objects and then fires the event off to any beans that are @Observe'ing these events. Note that the FolderRemoved event is not used yet, but we may want to implement that later.

What's next?

So far I haven't introduced any new Uberfire concepts, just rearranged some bits to make persistence of the model possible. I'll go into this in Part 3 of this blog.

No comments:

Post a Comment