Commands
To modify the data of a document, it is recommended to use the Application Framework command mechanism, which provides the following advantages:
Undo/Redo mechanism - The Undo, Redo, and Repeat actions are automatically processed, as well as their state.
The modification state of a document is automatically managed. Adding a command to an unmodified document will mark the document as modified (a star will appear in the title of the frames that contain views associated with this document). Similarly, undoing this command will restore the unmodified state of the document (and will remove the star from the title of the same frames).
Keeps a log of all modifications made to the document.
Consider the following document class:
class MyDocument
: public IlvDvDocument
{
...
void setX(int x) { _x = x; }
int getX() const { return _x; }
protected:
int _x;
};
To modify the X property of the document while processing either a document view event/action or a document action, it is not recommended to call directly the setX method of the document. It is more appropriate to implement a command class (called ChangeXPropertyCommand in this example) that will modify this property:
class ChangeXPropertyCommand
: public IlvDvCommand
{
ChangeXPropertyCommand(MyDocument* document, int newX)
: _document(document),
_newX(newX)
{
_oldX = document->getX();
}
virtual void doIt() { setX(_newX); }
virtual void undo() { setX(_oldX); }
void setX(int x) { _document->setX(x); }
protected:
MyDocument* _document;
int _newX;
int _oldX;
};
Therefore, the implementation of a view or the document itself should invoke the following code to change the X property (instead of calling directly the setX method of the document):
document->doCommand(new ChangeXPropertyCommand(document, newX));
This code will execute the ChangeXPropertyCommand command by calling its doIt method, and will store it within a command history internally managed by the document.
Use the following method of the
IlvDvDocument class to manage commands:
void doCommand(IlvDvCommand* cmd,
IlBoolean updateUI = IlTrue,
IlBoolean bSetModified = IlTrue);
This method is called to add the command object
cmd to the history of internal commands. Then, the command is executed by calling its
IlvDvCommand::doIt method. The
updateUI parameter specifies that the UI of the Undo, Redo, and Repeat commands must be updated. The
bSetModified parameter specifies whether the modification flag of the document must be set to true.
Undo / Redo / Repeat Actions
The Undo, Redo, and Repeat actions are automatically managed by the document. To process these actions, the document invokes the following methods (which can be overridden for specific uses):
virtual IlBoolean canUndo() const; This method returns true if the command that has just been executed can be undone. If there is no command that can be undone, for example if the document has not been modified, this method returns false.
virtual void undo(IlBoolean bUpdateUI = IlTrue); This method calls the undo method of the last command executed. The bUpdateUI parameter specifies that the UI of the Undo, Redo, and Repeat commands must be updated.
virtual IlBoolean canRedo() const; This method returns true if the command that has just been undone can be redone by calling the
IlvDvCommand::doIt method. If there is no command that can be done, for example if the document has not been modified, this method returns false.
virtual void redo(IlBoolean bUpdateUI = IlTrue); This method calls the doIt method of the last undone command. The bUpdateUI parameter specifies that the UI of the Undo, Redo, and Repeat commands must be updated.
virtual void repeat(IlBoolean bUpdateUI = IlTrue); This method repeats the last command executed. This command is copied by calling its
IlvDvCommand::copy method. The copy is added to the commands history and then executed. The
bUpdateUI parameter specifies that the UI of the Undo, Redo, and Repeat commands must be updated.
Reflecting Changes Made In the Data to Associated Views
You have seen how to modify the data of a document by using commands. However, you still need to see how to notify the views associated with the document to reflect these changes.
A document can have several views of different types. Therefore, to communicate with its views, a document sends generic messages that are interpreted by each view depending on their type. To send generic messages to its views, a document uses the following method:
void notifyViews(const char* messageName,
IlvDvDocViewInterface* exceptView, ...);
The name of the message is
messageName. It must not be the name of an action (such as Copy, OpenDocument, and so on).
The
exceptView parameter specifies a view that must not be notified. The value of this parameter is usually 0. It can also be the view returned by the call to
getCurrentCallerView() (this method returns the view that is currently notifying the document of an event). In this case, you may want this view
not to be notified because it may have already modified its contents before it notified the document.
The variable list of parameters that follows depends on the message name. For example, if a document contains information on an employee and that a command has just changed the name of that employee, the document notifies its views of this change as follows:
void EmployeeDocument::changeName(const char* name)
{
_employeeName = name;
notifyViews("NameChanged", 0 /* Notify all views */, name);
}
To receive a message, a view (or any other class that implements the
IlvDvInterface interface) must specify an entry in its interface declaration. This entry makes a message name and its parameters correspond with a method of the class. This is explained in more detail in
Application Framework Interfaces.
The sample can now be completed so that the view of an employee document can receive the message NameChanged:
IlvDvBeginInterface(EmployeeView)
/* The message "NameChanged" with one parameter const char* name
is processed by the method:
EmployeeView::nameChanged with one parameter const char* name */
Method1(NameChanged, nameChanged, const char*, name)
IlvDvEndInterface1(IlvDvFormView)
/* The nameChanged method is automatically called when an EmployeeDocument
notifies its views giving the message name "NameChanged" */
void EmployeeView::nameChanged(const char* name)
{
IlvTextField* nameField = getEmployeeNameField();
nameField->setLabel(name, IlvTrue);
}
Version 5.6
Copyright © 2012, Rogue Wave Software, Inc. All Rights Reserved.