added possibility to specify modules dependencies
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@39677 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -49,6 +49,7 @@ All:
|
||||
- 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
|
||||
|
@@ -1,14 +1,16 @@
|
||||
\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.
|
||||
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.
|
||||
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.
|
||||
|
||||
@@ -18,17 +20,31 @@ For example:
|
||||
// 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(); };
|
||||
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}
|
||||
@@ -41,28 +57,47 @@ For example:
|
||||
|
||||
\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.
|
||||
|
||||
|
@@ -14,11 +14,17 @@
|
||||
|
||||
#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)
|
||||
@@ -48,7 +54,7 @@ public:
|
||||
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
|
||||
|
||||
@@ -57,6 +63,40 @@ public:
|
||||
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)
|
||||
};
|
||||
|
||||
|
@@ -65,6 +65,7 @@
|
||||
#define TEST_LOCALE
|
||||
#define TEST_LOG
|
||||
#define TEST_MIME
|
||||
#define TEST_MODULE
|
||||
#define TEST_PATHLIST
|
||||
#define TEST_ODBC
|
||||
#define TEST_PRINTF
|
||||
@@ -85,7 +86,7 @@
|
||||
#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
|
||||
@@ -1381,6 +1382,80 @@ static void TestMimeAssociate()
|
||||
|
||||
#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
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@@ -36,6 +36,7 @@ wxModuleList wxModule::m_modules;
|
||||
|
||||
void wxModule::RegisterModule(wxModule* module)
|
||||
{
|
||||
module->m_state = State_Registered;
|
||||
m_modules.Append(module);
|
||||
}
|
||||
|
||||
@@ -69,42 +70,133 @@ void wxModule::RegisterModules()
|
||||
}
|
||||
}
|
||||
|
||||
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(_("Module \"%s\" initialization failed"),
|
||||
wxLogError(_("Circular dependency involving module \"%s\" detected."),
|
||||
module->GetClassInfo()->GetClassName());
|
||||
|
||||
// clean up already initialized modules - process in reverse order
|
||||
wxModuleList::compatibility_iterator n;
|
||||
for ( n = node->GetPrevious(); n; n = n->GetPrevious() )
|
||||
{
|
||||
n->GetData()->OnExit();
|
||||
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() )
|
||||
{
|
||||
if ( node->GetData()->GetClassInfo() == cinfo )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( node )
|
||||
{
|
||||
// this dependency is already initialized, nothing to do
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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 )
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user