- Added wxStandardPaths::GetDocumentsDir() (Ken Thomases)
- Added wxStringTokenizer::GetLastDelimiter(); improved documentation.
- Fixed wxTextFile in Unicode build
+- Added possibility to specify dependencies for a wxModule
- Speed improvements to wxRegEx when matching is done in a loop such as
during a search and replace.
- Fix regerror and regfree name conficts when built-in regex and system regex
\section{\class{wxModule}}\label{wxmodule}
-The module system is a very simple mechanism to allow applications (and parts of wxWidgets itself) to
-define initialization and cleanup functions that are automatically called on wxWidgets
-startup and exit.
-
-To define a new kind of module, derive a class from wxModule, override the OnInit and OnExit functions,
-and add the DECLARE\_DYNAMIC\_CLASS and IMPLEMENT\_DYNAMIC\_CLASS to header and implementation files
-(which can be the same file). On initialization, wxWidgets will find all classes derived from wxModule,
-create an instance of each, and call each OnInit function. On exit, wxWidgets will call the OnExit
-function for each module instance.
+The module system is a very simple mechanism to allow applications (and parts
+of wxWidgets itself) to define initialization and cleanup functions that are
+automatically called on wxWidgets startup and exit.
+
+To define a new kind of module, derive a class from wxModule, override the
+\helpref{OnInit}{wxmoduleoninit} and \helpref{OnExit}{wxmoduleonexit}
+functions, and add the DECLARE\_DYNAMIC\_CLASS and IMPLEMENT\_DYNAMIC\_CLASS to
+header and implementation files (which can be the same file). On
+initialization, wxWidgets will find all classes derived from wxModule, create
+an instance of each, and call each OnInit function. On exit, wxWidgets will
+call the OnExit function for each module instance.
Note that your module class does not have to be in a header file.
// A module to allow DDE initialization/cleanup
// without calling these functions from app.cpp or from
// the user's application.
-
class wxDDEModule: public wxModule
{
- DECLARE_DYNAMIC_CLASS(wxDDEModule)
public:
- wxDDEModule() {}
- bool OnInit() { wxDDEInitialize(); return true; };
- void OnExit() { wxDDECleanUp(); };
+ wxDDEModule() { }
+ virtual bool OnInit() { wxDDEInitialize(); return true; };
+ virtual void OnExit() { wxDDECleanUp(); };
+
+ private:
+ DECLARE_DYNAMIC_CLASS(wxDDEModule)
};
IMPLEMENT_DYNAMIC_CLASS(wxDDEModule, wxModule)
+
+
+ // Another module which uses DDE in its OnInit()
+ class MyModule: public wxModule
+ {
+ public:
+ wxDDEModule() { AddDependency(CLASSINFO(wxDDEModule)); }
+ virtual bool OnInit() { ... code using DDE ... }
+ virtual void OnExit() { ... }
+
+ private:
+ DECLARE_DYNAMIC_CLASS(wxDDEModule)
+ };
\end{verbatim}
\wxheading{Derived from}
\latexignore{\rtfignore{\wxheading{Members}}}
+
\membersection{wxModule::wxModule}\label{wxmodulector}
\func{}{wxModule}{\void}
Constructs a wxModule object.
+
\membersection{wxModule::\destruct{wxModule}}\label{wxmoduledtor}
\func{}{\destruct{wxModule}}{\void}
Destructor.
+
+\membersection{wxModule::AddDependency}\label{wxmoduleoninit}
+
+\func{void}{AddDependency}{\param{wxClassInfo * }{dep}}
+
+Call this function from the constructor of the derived class. \arg{dep} must be
+the \helpref{CLASSINFO}{classinfo} of a wxModule-derived class and the
+corresponding module will be loaded \emph{before} and unloaded \emph{after}
+this module.
+
+Note that circular dependencies are detected and result in a fatal error.
+
+\wxheading{Parameters}
+
+\docparam{dep}{The class information object for the dependent module.}
+
+
\membersection{wxModule::OnExit}\label{wxmoduleonexit}
\func{virtual void}{OnExit}{\void}
Provide this function with appropriate cleanup for your module.
+
\membersection{wxModule::OnInit}\label{wxmoduleoninit}
\func{virtual bool}{OnInit}{\void}
Provide this function with appropriate initialization for your module. If the function
returns false, wxWidgets will exit immediately.
-
#include "wx/object.h"
#include "wx/list.h"
+#include "wx/dynarray.h"
// declare a linked list of modules
class WXDLLIMPEXP_BASE wxModule;
WX_DECLARE_USER_EXPORTED_LIST(wxModule, wxModuleList, WXDLLIMPEXP_BASE);
+// and an array of class info objects
+WX_DEFINE_USER_EXPORTED_ARRAY_PTR(wxClassInfo *, wxArrayClassInfo,
+ class WXDLLIMPEXP_BASE);
+
+
// declaring a class derived from wxModule will automatically create an
// instance of this class on program startup, call its OnInit() method and call
// OnExit() on program termination (but only if OnInit() succeeded)
static void RegisterModule(wxModule *module);
static void RegisterModules();
static bool InitializeModules();
- static void CleanUpModules();
+ static void CleanUpModules() { DoCleanUpModules(m_modules); }
// used by wxObjectLoader when unloading shared libs's
protected:
static wxModuleList m_modules;
+ // the function to call from constructor of a deriving class add module
+ // dependency which will be initialized before the module and unloaded
+ // after that
+ void AddDependency(wxClassInfo *dep)
+ {
+ wxCHECK_RET( dep, _T("NULL module dependency") );
+
+ m_dependencies.Add(dep);
+ }
+
+private:
+ // initialize module and Append it to initializedModules list recursively
+ // calling itself to satisfy module dependencies if needed
+ static bool
+ DoInitializeModule(wxModule *module, wxModuleList &initializedModules);
+
+ // cleanup the modules in the specified list (which may not contain all
+ // modules if we're called during initialization because not all modules
+ // could be initialized) and also empty m_modules itself
+ static void DoCleanUpModules(const wxModuleList& modules);
+
+
+ // module dependencies: contains
+ wxArrayClassInfo m_dependencies;
+
+ // used internally while initiliazing/cleaning up modules
+ enum
+ {
+ State_Registered, // module registered but not initialized yet
+ State_Initializing, // we're initializing this module but not done yet
+ State_Initialized // module initialized successfully
+ } m_state;
+
+
DECLARE_CLASS(wxModule)
};
#define TEST_LOCALE
#define TEST_LOG
#define TEST_MIME
+ #define TEST_MODULE
#define TEST_PATHLIST
#define TEST_ODBC
#define TEST_PRINTF
#define TEST_WCHAR
#define TEST_ZIP
#else // #if TEST_ALL
- #define TEST_STDPATHS
+ #define TEST_MODULE
#endif
// some tests are interactive, define this to run them
#endif // TEST_MIME
+// ----------------------------------------------------------------------------
+// module dependencies feature
+// ----------------------------------------------------------------------------
+
+#ifdef TEST_MODULE
+
+#include "wx/module.h"
+
+class wxTestModule : public wxModule
+{
+protected:
+ virtual bool OnInit() { wxPrintf(_T("Load module: %s\n"), GetClassInfo()->GetClassName()); return true; }
+ virtual void OnExit() { wxPrintf(_T("Unload module: %s\n"), GetClassInfo()->GetClassName()); }
+};
+
+class wxTestModuleA : public wxTestModule
+{
+public:
+ wxTestModuleA();
+private:
+ DECLARE_DYNAMIC_CLASS(wxTestModuleA)
+};
+
+class wxTestModuleB : public wxTestModule
+{
+public:
+ wxTestModuleB();
+private:
+ DECLARE_DYNAMIC_CLASS(wxTestModuleB)
+};
+
+class wxTestModuleC : public wxTestModule
+{
+public:
+ wxTestModuleC();
+private:
+ DECLARE_DYNAMIC_CLASS(wxTestModuleC)
+};
+
+class wxTestModuleD : public wxTestModule
+{
+public:
+ wxTestModuleD();
+private:
+ DECLARE_DYNAMIC_CLASS(wxTestModuleD)
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxTestModuleC, wxModule)
+wxTestModuleC::wxTestModuleC()
+{
+ AddDependency(CLASSINFO(wxTestModuleD));
+}
+
+IMPLEMENT_DYNAMIC_CLASS(wxTestModuleA, wxModule)
+wxTestModuleA::wxTestModuleA()
+{
+ AddDependency(CLASSINFO(wxTestModuleB));
+ AddDependency(CLASSINFO(wxTestModuleD));
+}
+
+IMPLEMENT_DYNAMIC_CLASS(wxTestModuleD, wxModule)
+wxTestModuleD::wxTestModuleD()
+{
+}
+
+IMPLEMENT_DYNAMIC_CLASS(wxTestModuleB, wxModule)
+wxTestModuleB::wxTestModuleB()
+{
+ AddDependency(CLASSINFO(wxTestModuleD));
+ AddDependency(CLASSINFO(wxTestModuleC));
+}
+
+#endif // TEST_MODULE
+
// ----------------------------------------------------------------------------
// misc information functions
// ----------------------------------------------------------------------------
void wxModule::RegisterModule(wxModule* module)
{
+ module->m_state = State_Registered;
m_modules.Append(module);
}
}
}
-bool wxModule::InitializeModules()
+bool wxModule::DoInitializeModule(wxModule *module,
+ wxModuleList &initializedModules)
{
- // Initialize user-defined modules
- wxModuleList::compatibility_iterator node;
- for ( node = m_modules.GetFirst(); node; node = node->GetNext() )
+ if ( module->m_state == State_Initializing )
{
- wxModule *module = node->GetData();
- if ( !module->Init() )
+ wxLogError(_("Circular dependency involving module \"%s\" detected."),
+ module->GetClassInfo()->GetClassName());
+ return false;
+ }
+
+ module->m_state = State_Initializing;
+
+ const wxArrayClassInfo& dependencies = module->m_dependencies;
+
+ // satisfy module dependencies by loading them before the current module
+ for ( unsigned int i = 0; i < dependencies.size(); ++i )
+ {
+ wxClassInfo * cinfo = dependencies[i];
+
+ // Check if the module is already initialized
+ wxModuleList::compatibility_iterator node;
+ for ( node = initializedModules.GetFirst(); node; node = node->GetNext() )
{
- wxLogError(_("Module \"%s\" initialization failed"),
- module->GetClassInfo()->GetClassName());
+ if ( node->GetData()->GetClassInfo() == cinfo )
+ break;
+ }
+
+ if ( node )
+ {
+ // this dependency is already initialized, nothing to do
+ continue;
+ }
- // clean up already initialized modules - process in reverse order
- wxModuleList::compatibility_iterator n;
- for ( n = node->GetPrevious(); n; n = n->GetPrevious() )
+ // find the module in the registered modules list
+ for ( node = m_modules.GetFirst(); node; node = node->GetNext() )
+ {
+ wxModule *moduleDep = node->GetData();
+ if ( moduleDep->GetClassInfo() == cinfo )
{
- n->GetData()->OnExit();
+ if ( !DoInitializeModule(moduleDep, initializedModules ) )
+ {
+ // failed to initialize a dependency, so fail this one too
+ return false;
+ }
+
+ break;
}
+ }
+ if ( !node )
+ {
+ wxLogError(_("Dependency \"%s\" of module \"%s\" doesn't exist."),
+ cinfo->GetClassName(),
+ module->GetClassInfo()->GetClassName());
return false;
}
}
+ if ( !module->Init() )
+ {
+ wxLogError(_("Module \"%s\" initialization failed"),
+ module->GetClassInfo()->GetClassName());
+ return false;
+ }
+
+ wxLogTrace(TRACE_MODULE, wxT("Module \"%s\" initialized"),
+ module->GetClassInfo()->GetClassName());
+
+ module->m_state = State_Initialized;
+ initializedModules.Append(module);
+
return true;
}
-void wxModule::CleanUpModules()
+// Initialize user-defined modules
+bool wxModule::InitializeModules()
{
- // Cleanup user-defined modules
- wxModuleList::compatibility_iterator node;
- for ( node = m_modules.GetFirst(); node; node = node->GetNext() )
+ wxModuleList initializedModules;
+
+ for ( wxModuleList::compatibility_iterator node = m_modules.GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ wxModule *module = node->GetData();
+
+ // the module could have been already initialized as dependency of
+ // another one
+ if ( module->m_state == State_Registered )
+ {
+ if ( !DoInitializeModule( module, initializedModules ) )
+ {
+ // failed to initialize all modules, so clean up the already
+ // initialized ones
+ DoCleanUpModules(initializedModules);
+
+ return false;
+ }
+ }
+ }
+
+ // remember the real initialisation order
+ m_modules = initializedModules;
+
+ return true;
+}
+
+// Clean up all currently initialized modules
+void wxModule::DoCleanUpModules(const wxModuleList& modules)
+{
+ // cleanup user-defined modules in the reverse order compared to their
+ // initialization -- this ensures that dependencies are respected
+ for ( wxModuleList::compatibility_iterator node = modules.GetLast();
+ node;
+ node = node->GetPrevious() )
{
wxLogTrace(TRACE_MODULE, wxT("Cleanup module %s"),
node->GetData()->GetClassInfo()->GetClassName());
- node->GetData()->Exit();
+
+ wxModule * module = node->GetData();
+
+ wxASSERT_MSG( module->m_state == State_Initialized,
+ _T("not initialized module being cleaned up") );
+
+ module->Exit();
+ module->m_state = State_Registered;
}
+ // clear all modules, even the non-initialized ones
WX_CLEAR_LIST(wxModuleList, m_modules);
}