2.1.5 UI Retrieving Model

Motivation

An important constraint about the Model that we stressed throughout the book is that it should never be involved in GUI-related business. UI Retrieving Model breaks this rule.

Among a Model’s task is the need to retrieve information from a data source, such as a file, memory, or database. In some cases, the Model may have to retrieve information that only a direct session with the User can provide. We can break the rules and let the Model create a UI dialog to inquire the User for this information. In other words, the Model consider the User as a database, whose API involves the use of graphical widgets.

Design

The interaction diagram design of a UI retrieving Model is depicted in Figure

The core of the design is the short-lived UserUI object. In its most basic form this object is a modal dialog, prompted to the User and awaiting for input. The modal nature of the dialog guarantees a synchronous handling of the operation.

Once the dialog is closed, the value is gathered and returned to the requesting client. Depending on the nature of the retrieved information, it might be useful for the Model to cache it instead of prompting the User again.

Practical example

One trivial example of this pattern would be a Model object representing the User session, with a password field initially set to None. When the program starts the session, it will ask for the credentials to the Model layer. Asking the username will return the proper string, but asking the password may return None if no password has been set yet. The Model is then authorized to retrieve this information from the User by a GUI dialog, maybe trying some non-interactive strategies first, like checking in a configuration file.

class Model(object):
    def get_password(self):
        if self._password is None:
            password, ok = QtGui.QInputDialog.getText(
                None, 
                "Please input your password", 
                "Password:", 
                QtGui.QLineEdit.Password)                                                
            
            if ok:
                self._password = password
                
        return self._password    

    def clear_password(self):
        self._password = None

When the user acts on the dialog, the Model stores the password and returns it to the Presenter layer, which then proceeds with the authentication logic if the result is a string. If the password is found to be incorrect, the Controller will ask the Model to clear_password(), and the user will be prompted again.