wxMPService class
wxPMDocument class
Listener interfaces
wxPMProject class
wxPMWorkplace class
This important class is introduced to reduce the diversity of PMF classes, by making them comply to a common interface. It serves as an interface (or mix-in class in C++ terms), which cannot itself represent an independent object. It should be inherited as a second (or third) base class. Such multiple inheritance is necessitated by the fact that it is impossible to derive all possible service classes from a common base. A typical example of such case is wxPMView class, which is a kind of wxDocument; however, the latter cannot be made a derivative of wxPMService. To solve this dilemma, wxPMView becomes a service by inheriting the wxPMService interface as a second base class. This class defines methods essential to any service, so it's important to describe it first:
virtual bool Start(); virtual bool Stop(); virtual bool IsStarted(); virtual void SetIsStarted( bool isStarted ); virtual wxPMMergableMenuChain* GetMergableMenuChain(); virtual bool SerializeState( wxPMSerializer& ser ); virtual wxObject* GetObject()The first four functions describe themselves. The first two are overridden to move any complex code from the constructor and destructor to these virtual methods, which can be overridden/mutated in the subclasses. Within them the service class may perform subscription of events, locate relevant services or initialize its GUI objects.
GetMergableMenuChain returns a non-NULL value if the service wishes to add its specific menu commands, which can be inserted into virtually any part of the menu hierarchy.
SerializeState can be overridden to save data, related only to the current visual state of another service. For example a text editor may save X-Y position of the cursor. There should not be any data saved or loaded which relates to a project or a particular storable document. The wxPMSerializer argument is a derivative of wxConfigBase which will provide human-readable storage for the state. There will be more about this class later.
First it is assumed and required that a service class will always have wxObject as its possibly distant base class. A service class is also derived from wxPMService (the latter is derived from nothing as mentioned). For that reason, code in PMF cannot cast a reference to wxPMService to wxObject in order to know the exact class of the service (using wxObject::IsKindOf()). For example, the fragment
void foo( wxPMService* ref ) { wxObject* objPtr = (wxObject*)ref; }will compile correctly, but the cast produces a reference to an incorrect vtable. Therefore the only solution is to have each service override:
virtual wxObject* GetObject()of the inherited service interfaces, to return a properly casted pointer, because such a cast is correct only in the case when, the leaf class of the reference is known to compiler, e.g.
virtual wxObject* wxView::GetObject() { return (wxObject*)this; // the type of this is known, thus // compiler "adjusts" pointer to // the correct virtual table }This method should be overridden by all classes which comply with wxPMService interfaces.
A document can be hierarchically composed of further documents, the nesting level of which is not limited. Methods:
virtual void SetParentDocument( wxPMDocument* pParent ); virtual wxPMDocument* GetParentDocument(); virtual void AddSubdocument( wxPMDocument* pSubdoc ); virtual void RemoveSubdocument( wxPMDocument* pSubdoc ); virtual PMDocumentListT& GetSubdocuments(); // overidables: virtual bool UseSerializer(); virtual bool SavePMDocument( wxOutputStream& s ); virtual bool LoadPMDocument( wxInputStream& s ); virtual bool SerializePMDocument( wxPMSerializer& ser ); virtual bool SerializeState( wxPMSerializer& ser );It is important to note that all methods related to accessing and saving/loading of this run-time hierarchy are mostly defined in this base class. Its subclasses override them or add only a few more methods specific to the subclass.
UseSerializer returns TRUE by default, indicating that saving/loading of documents non-visual data should proceed using wxPMSerializer, which as provides human-readable storage. Using this approach, methods:
virtual bool SerializePMDocument( wxPMSerializer& ser ); virtual bool SerializeState( wxPMSerializer& ser );should be overridden instead of
virtual bool SavePMDocument( wxOutputStream& s ); virtual bool LoadPMDocument( wxInputStream& s );which semantically should do the same, except the non-visual data is stored/loaded using using binary streams.
The SaveDocument and LoadDocument members of the wxDocument class are not used by PMF.
virtual bool SerializeState( wxPMSerializer& ser );is an overridden method of wxPMService, which stores data related to the document's current visual state. Notice that state serialization in PMF is never done by storing data into streams, because it is usually bad practice to store configuration information into a binary file. In addition, wxPMSerializer provides Exchange(..) methods which allow serialization to be performed consistently and more briefly within one method, without "if"'s for loading or saving.
virtual void SetFileInfo( wxPMFileInfo* pFile ); virtual wxPMFileInfo* GetFileInfo();are used for associating document with a storage file, described in the details section.
Before describing derivatives of wxPMDocument, it is worthwhile to mention listener interfaces, which are used by other services for reacting to the actions performed on the document or workplace objects, since each action of potential interest is routed to these interfaces.
wxPMWorkplaceListener receives notification about the following:
virtual void OnWorkplaceOpened( wxPMWorkplace& workplace ); virtual void OnWorkplaceClosing( wxPMWorkplace& workplace ); virtual void OnProjectAdded( wxPMProject& project ); virtual void OnProjectRemoved( wxPMProject& project ); virtual void OnProjectActivated( wxPMProject& project, wxPMProject* pPrevProject ); virtual void OnFileAdded( wxPMFileInfo& file, wxPMProject* pToProject ); virtual void OnFileRemoved( wxPMFileInfo& file, wxPMProject* pFromProject ); virtual void OnViewActivated( wxPMView& view, wxPMView* pPrevView ); virtual void OnActiveProjectSet( wxPMProject& project );Most of these notifications are acted upon in GUI-related classes, such as wxPMWorkplaceBrowserPane class which mirrors a composition of workplace and its project into nodes of its tree control. This implies that document-related, non-visual information is not managed by these extension classes; instead it is maintained within the classes of PMF's core category.
wxPMBootstrapServiceListener receives notifications about the following:
virtual void OnServiceStarted( wxPMService& service ); virtual void OnServiceStopped( wxPMService& service ); virtual void OnPaneShown( wxPMPane& pane ); virtual void OnPaneHidden( wxPMPane& pane );The first two can be used by classes which, for some reason, have to monitor activation and deactivation of services, perhaps internally using IsKindOf() to see if the given service is of interest. They could be used by services which are started earlier than those about which notifications are required, because subscription is not possible while the service which sends them is not started yet.
The latter two are taken by wxPMLayoutAlgorithm class, which does layout of corresponding windows in the main frame to match changes in pane visibility.
For more details of why listeners are not meant to receive actions in an ordered manner of notifications and subscriptions, as can be achieved using the wxEvtHandler mechanism, see the details section.
This derives from wxPMDocument, and adds the following methods specific only to the project document:
virtual void AddMultipleFiles( PMFileInfoListT& lst ); virtual void AddFile( wxPMFileInfo* pFile ); virtual void RemoveFile( wxPMFileInfo* pFile ); virtual bool ActivateFileInEditor( wxPMFileInfo* pFile ); virtual PMFileInfoListT& GetFiles();These manipulate the aggregated array of wxPMFileInfo objects. After that is done, its notifications are sent to all subscribed wxPMWorkplaceListener listeners.
Overridden methods of wxPMDocument:
virtual bool UseSerializer(); virtual bool SerializePMDocument( wxPMSerializer& ser );The first returns TRUE to indicate that class prefers to store non-visual project data in a human-readable format, and consequently implements SerializePMDocument() which takes a serializer argument. It is still possible to override the first method to store custom projects into binary streams, but as mentioned, this is not recommended.
SerializePMDocument stores/loads its list of wxPMFileInfo* objects. By overriding it, the method of the base class should be invoked first to store the file list and other possible contents common to any type of project; after that they serialize their specific data.
The class does not override this method of wxPMDocument:
virtual bool SerializeState( wxPMSerializer& ser );since project documents have no visual appearance, and thus they do not possess any visual state.
As mentioned, only one workplace can stay opened at a time. This has the effect that an instance of wxPMWorkplace is always a top-level document of the run-time document containment hierarchy.
virtual void SetActiveProject( wxPMProject* pPrj ); virtual wxPMProject* GetActiveProject(); virtual void AddProject( wxPMProject* pPrj ); virtual void RemoveProject( wxPMProject* pPrj ); // type-safe methods for accessing components of the workplace // (ie. instances of wxPMProject) virtual size_t GetProjectCount(); virtual wxPMProject& GetProject( size_t index ); virtual void UpdateUIForView( wxPMView* pView ); virtual void AddListener( wxPMWorkplaceListener* pListener ); virtual void RemoveListener( wxPMWorkplaceListener* pListener );