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 wxStandardPaths::GetDocumentsDir() (Ken Thomases)
|
||||||
- Added wxStringTokenizer::GetLastDelimiter(); improved documentation.
|
- Added wxStringTokenizer::GetLastDelimiter(); improved documentation.
|
||||||
- Fixed wxTextFile in Unicode build
|
- 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
|
- Speed improvements to wxRegEx when matching is done in a loop such as
|
||||||
during a search and replace.
|
during a search and replace.
|
||||||
- Fix regerror and regfree name conficts when built-in regex and system regex
|
- Fix regerror and regfree name conficts when built-in regex and system regex
|
||||||
|
@@ -1,14 +1,16 @@
|
|||||||
\section{\class{wxModule}}\label{wxmodule}
|
\section{\class{wxModule}}\label{wxmodule}
|
||||||
|
|
||||||
The module system is a very simple mechanism to allow applications (and parts of wxWidgets itself) to
|
The module system is a very simple mechanism to allow applications (and parts
|
||||||
define initialization and cleanup functions that are automatically called on wxWidgets
|
of wxWidgets itself) to define initialization and cleanup functions that are
|
||||||
startup and exit.
|
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,
|
To define a new kind of module, derive a class from wxModule, override the
|
||||||
and add the DECLARE\_DYNAMIC\_CLASS and IMPLEMENT\_DYNAMIC\_CLASS to header and implementation files
|
\helpref{OnInit}{wxmoduleoninit} and \helpref{OnExit}{wxmoduleonexit}
|
||||||
(which can be the same file). On initialization, wxWidgets will find all classes derived from wxModule,
|
functions, and add the DECLARE\_DYNAMIC\_CLASS and IMPLEMENT\_DYNAMIC\_CLASS to
|
||||||
create an instance of each, and call each OnInit function. On exit, wxWidgets will call the OnExit
|
header and implementation files (which can be the same file). On
|
||||||
function for each module instance.
|
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.
|
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
|
// A module to allow DDE initialization/cleanup
|
||||||
// without calling these functions from app.cpp or from
|
// without calling these functions from app.cpp or from
|
||||||
// the user's application.
|
// the user's application.
|
||||||
|
|
||||||
class wxDDEModule: public wxModule
|
class wxDDEModule: public wxModule
|
||||||
{
|
{
|
||||||
DECLARE_DYNAMIC_CLASS(wxDDEModule)
|
|
||||||
public:
|
public:
|
||||||
wxDDEModule() { }
|
wxDDEModule() { }
|
||||||
bool OnInit() { wxDDEInitialize(); return true; };
|
virtual bool OnInit() { wxDDEInitialize(); return true; };
|
||||||
void OnExit() { wxDDECleanUp(); };
|
virtual void OnExit() { wxDDECleanUp(); };
|
||||||
|
|
||||||
|
private:
|
||||||
|
DECLARE_DYNAMIC_CLASS(wxDDEModule)
|
||||||
};
|
};
|
||||||
|
|
||||||
IMPLEMENT_DYNAMIC_CLASS(wxDDEModule, wxModule)
|
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}
|
\end{verbatim}
|
||||||
|
|
||||||
\wxheading{Derived from}
|
\wxheading{Derived from}
|
||||||
@@ -41,28 +57,47 @@ For example:
|
|||||||
|
|
||||||
\latexignore{\rtfignore{\wxheading{Members}}}
|
\latexignore{\rtfignore{\wxheading{Members}}}
|
||||||
|
|
||||||
|
|
||||||
\membersection{wxModule::wxModule}\label{wxmodulector}
|
\membersection{wxModule::wxModule}\label{wxmodulector}
|
||||||
|
|
||||||
\func{}{wxModule}{\void}
|
\func{}{wxModule}{\void}
|
||||||
|
|
||||||
Constructs a wxModule object.
|
Constructs a wxModule object.
|
||||||
|
|
||||||
|
|
||||||
\membersection{wxModule::\destruct{wxModule}}\label{wxmoduledtor}
|
\membersection{wxModule::\destruct{wxModule}}\label{wxmoduledtor}
|
||||||
|
|
||||||
\func{}{\destruct{wxModule}}{\void}
|
\func{}{\destruct{wxModule}}{\void}
|
||||||
|
|
||||||
Destructor.
|
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}
|
\membersection{wxModule::OnExit}\label{wxmoduleonexit}
|
||||||
|
|
||||||
\func{virtual void}{OnExit}{\void}
|
\func{virtual void}{OnExit}{\void}
|
||||||
|
|
||||||
Provide this function with appropriate cleanup for your module.
|
Provide this function with appropriate cleanup for your module.
|
||||||
|
|
||||||
|
|
||||||
\membersection{wxModule::OnInit}\label{wxmoduleoninit}
|
\membersection{wxModule::OnInit}\label{wxmoduleoninit}
|
||||||
|
|
||||||
\func{virtual bool}{OnInit}{\void}
|
\func{virtual bool}{OnInit}{\void}
|
||||||
|
|
||||||
Provide this function with appropriate initialization for your module. If the function
|
Provide this function with appropriate initialization for your module. If the function
|
||||||
returns false, wxWidgets will exit immediately.
|
returns false, wxWidgets will exit immediately.
|
||||||
|
|
||||||
|
@@ -14,11 +14,17 @@
|
|||||||
|
|
||||||
#include "wx/object.h"
|
#include "wx/object.h"
|
||||||
#include "wx/list.h"
|
#include "wx/list.h"
|
||||||
|
#include "wx/dynarray.h"
|
||||||
|
|
||||||
// declare a linked list of modules
|
// declare a linked list of modules
|
||||||
class WXDLLIMPEXP_BASE wxModule;
|
class WXDLLIMPEXP_BASE wxModule;
|
||||||
WX_DECLARE_USER_EXPORTED_LIST(wxModule, wxModuleList, WXDLLIMPEXP_BASE);
|
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
|
// declaring a class derived from wxModule will automatically create an
|
||||||
// instance of this class on program startup, call its OnInit() method and call
|
// instance of this class on program startup, call its OnInit() method and call
|
||||||
// OnExit() on program termination (but only if OnInit() succeeded)
|
// OnExit() on program termination (but only if OnInit() succeeded)
|
||||||
@@ -48,7 +54,7 @@ public:
|
|||||||
static void RegisterModule(wxModule *module);
|
static void RegisterModule(wxModule *module);
|
||||||
static void RegisterModules();
|
static void RegisterModules();
|
||||||
static bool InitializeModules();
|
static bool InitializeModules();
|
||||||
static void CleanUpModules();
|
static void CleanUpModules() { DoCleanUpModules(m_modules); }
|
||||||
|
|
||||||
// used by wxObjectLoader when unloading shared libs's
|
// used by wxObjectLoader when unloading shared libs's
|
||||||
|
|
||||||
@@ -57,6 +63,40 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
static wxModuleList m_modules;
|
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)
|
DECLARE_CLASS(wxModule)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -65,6 +65,7 @@
|
|||||||
#define TEST_LOCALE
|
#define TEST_LOCALE
|
||||||
#define TEST_LOG
|
#define TEST_LOG
|
||||||
#define TEST_MIME
|
#define TEST_MIME
|
||||||
|
#define TEST_MODULE
|
||||||
#define TEST_PATHLIST
|
#define TEST_PATHLIST
|
||||||
#define TEST_ODBC
|
#define TEST_ODBC
|
||||||
#define TEST_PRINTF
|
#define TEST_PRINTF
|
||||||
@@ -85,7 +86,7 @@
|
|||||||
#define TEST_WCHAR
|
#define TEST_WCHAR
|
||||||
#define TEST_ZIP
|
#define TEST_ZIP
|
||||||
#else // #if TEST_ALL
|
#else // #if TEST_ALL
|
||||||
#define TEST_STDPATHS
|
#define TEST_MODULE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// some tests are interactive, define this to run them
|
// some tests are interactive, define this to run them
|
||||||
@@ -1381,6 +1382,80 @@ static void TestMimeAssociate()
|
|||||||
|
|
||||||
#endif // TEST_MIME
|
#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
|
// misc information functions
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@@ -36,6 +36,7 @@ wxModuleList wxModule::m_modules;
|
|||||||
|
|
||||||
void wxModule::RegisterModule(wxModule* module)
|
void wxModule::RegisterModule(wxModule* module)
|
||||||
{
|
{
|
||||||
|
module->m_state = State_Registered;
|
||||||
m_modules.Append(module);
|
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
|
if ( module->m_state == State_Initializing )
|
||||||
wxModuleList::compatibility_iterator node;
|
|
||||||
for ( node = m_modules.GetFirst(); node; node = node->GetNext() )
|
|
||||||
{
|
{
|
||||||
wxModule *module = node->GetData();
|
wxLogError(_("Circular dependency involving module \"%s\" detected."),
|
||||||
if ( !module->Init() )
|
|
||||||
{
|
|
||||||
wxLogError(_("Module \"%s\" initialization failed"),
|
|
||||||
module->GetClassInfo()->GetClassName());
|
module->GetClassInfo()->GetClassName());
|
||||||
|
return false;
|
||||||
// clean up already initialized modules - process in reverse order
|
|
||||||
wxModuleList::compatibility_iterator n;
|
|
||||||
for ( n = node->GetPrevious(); n; n = n->GetPrevious() )
|
|
||||||
{
|
|
||||||
n->GetData()->OnExit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxModule::CleanUpModules()
|
// Initialize user-defined modules
|
||||||
|
bool wxModule::InitializeModules()
|
||||||
{
|
{
|
||||||
// Cleanup user-defined modules
|
wxModuleList initializedModules;
|
||||||
wxModuleList::compatibility_iterator node;
|
|
||||||
for ( node = m_modules.GetFirst(); node; node = node->GetNext() )
|
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"),
|
wxLogTrace(TRACE_MODULE, wxT("Cleanup module %s"),
|
||||||
node->GetData()->GetClassInfo()->GetClassName());
|
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);
|
WX_CLEAR_LIST(wxModuleList, m_modules);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user