Delta3d插件机制

Delta3d插件机制主要通过以下两个类实现:

class MainWindow;

   /**
      Abstract interface class for STAGE plugins
    */
   class Plugin
   {
      public:

      virtual ~Plugin() {}   

      /** Is called after instantiation */
      virtual void Create() {}

      /** Is called before destruction */
      virtual void Destroy() {}
    
   };

   /** 
     A plugin factory is used by the plugin manager to identify available
     plugins and instantiate them.
   */
   class PluginFactory
   {
   public:

      PluginFactory()
         : mIsSystemPlugin(false)
      {
      }

      virtual ~PluginFactory() {}

      /** construct the plugin and return a pointer to it */
      virtual Plugin* Create(MainWindow* mw) = 0;

      /** delete the plugin */
      virtual void Destroy() = 0;
      
      /** get the name of the plugin */
      virtual std::string GetName() = 0;

      /** get a description of the plugin */
      virtual std::string GetDescription() = 0;

      /** 
        fill list with names of all plugins this plugin depends on.
        WARNING: circular dependencies are not handled and
        will cause a crash!
      */
      virtual void GetDependencies(std::list<std::string>&) {};

      /** 
         get the version of STAGE that the plugin is compiled against 
         Only plugins compiled against the current version of STAGE are started
      */
      virtual std::string GetExpectedSTAGEVersion() 
      { 
         // should be replaced by SVN to give version number
         return "$Revision$"; 
      }

      /** Should plugin be started autmatically? */
      bool IsSystemPlugin() { return mIsSystemPlugin; }

   protected:

      // set this to true if plugin should always be started
      bool mIsSystemPlugin;

   };
class MainWindow;

   class DT_EDITQT_EXPORT PluginManager : public QObject
   {
      Q_OBJECT

   public:

      PluginManager(MainWindow* mw);

      typedef std::map<std::string,PluginFactory*> PluginFactoryMap;
      typedef std::map<std::string, Plugin*> ActivePluginMap;

      /** load all libraries in dir and check for plugin factories */
      void LoadPluginsInDir(const std::string& path);

      /** start all plugins that are saved as active in the config file */
      void StartPluginsInConfigFile();

      /**
       * write the list of active plugins to config file so 
       * they can be started next time
       */
      void StoreActivePluginsToConfigFile();

      /** get names of all plugins */
      void GetAvailablePlugins(std::list<std::string>& toFill) const;

      /** get names of all currently instantiated plugins */
      void GetActivePlugins(std::list<std::string>& toFill) const;

      /** is there a factory for a plugin with this name? */
      bool FactoryExists(const std::string& name);

      /** Get PluginFactory for Plugin with this name.
       * @throw dtUtil::Exception if no PluginFactory exists with that Plugin name
       * @param name The name of the Plugin/PluginFactory to get
       */
      PluginFactory* GetPluginFactory(const std::string& name);

      /** is this plugin currently running? */
      bool IsInstantiated(const std::string& name);

      /** is this plugin a system plugin? */
      bool IsSystemPlugin(const std::string& name);

      /** return instance of plugin or NULL if not active */
      Plugin* GetPlugin(const std::string& name);

      /** returns all dependencies for a given plugin */
      std::list<std::string> GetPluginDependencies(const std::string& name);

   public slots:

      /** instantiate plugin with given name 
          @param name Name of plugin to start
          @param storeToConfig Store list of active plugins to config file?
      */
      void StartPlugin(const std::string& name, bool storeToConfig = true);

      /** stop and remove plugin with given name 
          @param name Name of plugin to stop
          @param storeToConfig Store list of active plugins to config file?
      */
      void StopPlugin(const std::string& name, bool storeToConfig = true);

   private:

      /** load plugin factory from library given by path */
      PluginFactory* LoadPluginFactory(const std::string& baseLibName);


      /** map from plugin name -> plugin factory */
      PluginFactoryMap mFactories;

      /** map from plugin name -> plugin instance */
      ActivePluginMap mActivePlugins;

      /** give plugins acces to GUI */
      MainWindow* mMainWindow;

   };
实现文件如下:
PluginManager::PluginManager(MainWindow* mw)
      : mMainWindow(mw)
   {
   }


   /** load all dlls in dir and check for plugin factories */
   void PluginManager::LoadPluginsInDir(const std::string& path)
   {
      // find out library extension for this system
      // take care of debug/release library stuff on windows
      #if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) || defined( __BCPLUSPLUS__)  || defined( __MWERKS__)
         std::string libExtension = ".dll";
      #else
         std::string libExtension = ".so";
      #endif

      // get libs from directory
      FileExtensionList ext;
      ext.push_back(libExtension);
      DirectoryContents files;

      try
      {
         files = FileUtils::GetInstance().DirGetFiles(path, ext);
      }
      catch (const dtUtil::Exception& e)
      {
         //in case the path is bogus
         DTUNREFERENCED_PARAMETER(e);
      }


      if (!files.empty())
      {
         //add the path to the list of paths to search for libraries.
         LibrarySharingManager::GetInstance().AddToSearchPath(path);
      }

      // for each library in dir
      DirectoryContents::const_iterator i;
      for(i = files.begin(); i != files.end(); ++i)
      {
         std::string fileName = *i;

         try
         {
            // load the plugin library
            const std::string basePluginName = LibrarySharingManager::GetPlatformIndependentLibraryName(fileName);
            PluginFactory* factory = LoadPluginFactory(basePluginName);
            std::string name = factory->GetName();

            // check if a plugin with this name already exists
            if(mActivePlugins.find(name) != mActivePlugins.end())
            {
               std::ostringstream msg;
               msg << "Unable to load plugin " << name <<": A plugin with that name was already loaded!";
               throw Exception(msg.str(), __FILE__, __LINE__);
            }

            // insert factory into factory list
            mFactories[name] = factory;

            // factory exists, but plugin is not instantiated yet
            mActivePlugins[name] = NULL;

            // start system plugins immediately
            if(factory->IsSystemPlugin())
            {
               StartPlugin(name, false);
            }
         }
         catch(Exception& e)
         {
            LOG_ERROR("Can't load plugin " + (*i) + " because " + e.ToString());
         }
      }
   }


   PluginFactory* PluginManager::LoadPluginFactory(const std::string& baseLibName)
   {
      // use library sharing manager to do the actual library loading
      LibrarySharingManager& lsm = LibrarySharingManager::GetInstance();

      dtCore::RefPtr<LibrarySharingManager::LibraryHandle> libHandle;
      try
      {
         libHandle = lsm.LoadSharedLibrary(baseLibName, true);
      }
      catch (const Exception&)
      {
         std::ostringstream msg;
         msg << "Unable to load plugin " << baseLibName;
         throw Exception(msg.str(), __FILE__, __LINE__);
      }

      LibrarySharingManager::LibraryHandle::SYMBOL_ADDRESS createFn;
      createFn = libHandle->FindSymbol("CreatePluginFactory");

      //Make sure the plugin actually implemented these functions and they
      //have been exported.
      if (!createFn)
      {
         std::ostringstream msg;
         msg << "Plugin " << baseLibName << " does not contain symbol 'CreatePluginFactory'";
         throw Exception(msg.str(), __FILE__, __LINE__);
      }

      // typedef for function pointer to get factory from library
      typedef PluginFactory* (*CreatePluginFactoryFn)();

      // instantiate factory
      CreatePluginFactoryFn fn = (CreatePluginFactoryFn) createFn;
      PluginFactory* factory = fn();

      // check if the library was compiled against this revision of STAGE
      if(factory->GetExpectedSTAGEVersion() != "$Revision$")
      {
         std::ostringstream msg;
         msg << "Can't load plugin " << baseLibName << ": Built against wrong version";
         throw Exception(msg.str(), __FILE__, __LINE__);
      }
      else
      {
         return factory;
      }
   }


   /** get the list of plugins to start from config file and start them */
   void PluginManager::StartPluginsInConfigFile()
   {
      dtEditQt::EditorSettings settings;

      settings.beginGroup(EditorSettings::ACTIVE_PLUGINS);
      std::string activated =
         settings.value(EditorSettings::ACTIVE_PLUGINS).toString().toStdString();
      settings.endGroup();

      if(activated == "")
      {
         return;
      }

      // split config string by slashes
      std::vector<std::string> tokens;
      StringTokenizer<IsSlash>::tokenize(tokens, activated);

      // for each token
      std::vector<std::string>::iterator iter;
      for(iter = tokens.begin(); iter != tokens.end(); ++iter)
      {
         std::string name = *iter;
         //if the plugin can be started and was not yet started
         if(FactoryExists(name) && !IsInstantiated(name))
         {
            // start it!
            StartPlugin(name, false);
         }
      }
   }


   /**
    * write the list of active plugins to config file so
    * they can be started next time
    */
   void PluginManager::StoreActivePluginsToConfigFile()
   {
      // create string with names of active plugins separated by slash
      std::ostringstream os;
      std::list<std::string> plugins;
      GetActivePlugins(plugins);
      for(std::list<std::string>::iterator i = plugins.begin(); i != plugins.end(); ++i)
      {
         // system plugins are always started, so no need to include them
         if(!IsSystemPlugin(*i))
         {
            os << *i << "/";
         }
      }

      dtEditQt::EditorSettings settings;
      settings.beginGroup(EditorSettings::ACTIVE_PLUGINS);
      settings.setValue(EditorSettings::ACTIVE_PLUGINS, os.str().c_str());
      settings.endGroup();
   }


   PluginFactory* PluginManager::GetPluginFactory(const std::string& name)
   {
      PluginFactoryMap::iterator i = mFactories.find(name);
      if(i == mFactories.end())
      {
         throw Exception("Plugin not found with name " + name , __FILE__, __LINE__);
      }
      return i->second;
   }


   bool PluginManager::FactoryExists(const std::string& name)
   {
      return (mFactories.find(name) != mFactories.end());
   }


   void PluginManager::GetAvailablePlugins(std::list<std::string>& toFill) const
   {
      PluginFactoryMap::const_iterator iter;
      for(iter = mFactories.begin(); iter != mFactories.end(); ++iter)
      {
         PluginFactory* factory = (*iter).second;
         toFill.push_back(factory->GetName());
      }
   }


   void PluginManager::GetActivePlugins(std::list<std::string>& toFill) const
   {
      ActivePluginMap::const_iterator iter;
      for(iter = mActivePlugins.begin(); iter != mActivePlugins.end(); ++iter)
      {
         if((*iter).second != NULL)
         {
            toFill.push_back((*iter).first);
         }
      }
   }


   std::list<std::string> PluginManager::GetPluginDependencies(const std::string& name)
   {
      std::list<std::string> deps;
      PluginFactory* factory = GetPluginFactory(name);

      if (factory)
      {
         factory->GetDependencies(deps);
      }

      return deps;
   }


   void PluginManager::StartPlugin(const std::string& name, bool storeToConfig)
   {
      LOG_ALWAYS("Starting plugin " + name);
      PluginFactory* factory = GetPluginFactory(name);

      // start all plugins this plugin depends on
      std::list<std::string> deps;
      factory->GetDependencies(deps);

      while(!deps.empty())
      {
         std::string dependency = deps.front();
         deps.pop_front();

         // check if dependency can be fulfilled
         if(!FactoryExists(dependency))
         {
            std::ostringstream os;
            os << "Cannot start plugin " << name << ": It depends on plugin ";
            os << dependency << " which was not found.";
            QMessageBox::critical(mMainWindow, "Error", os.str().c_str(), "Ok");
            return;
         }

         // only start dependency if it is not running now
         if(!IsInstantiated(dependency))
         {
            StartPlugin(dependency, false);
         }
      }

      // use factory to create the plugin
      mActivePlugins[name] = factory->Create(mMainWindow);

      // call Create() callback of plugin
      mActivePlugins[name]->Create();

   }


   void PluginManager::StopPlugin(const std::string& name, bool storeToConfig)
   {
      // first check if plugin is actually running
      if(!IsInstantiated(name))
      {
         return;
      }

      // Check if any other plugins depend on this one, and stop them as well.
      std::list<std::string> activePlugins;
      GetActivePlugins(activePlugins);
      while(!activePlugins.empty())
      {
         std::string plugin = activePlugins.front();
         activePlugins.pop_front();

         PluginFactory* factory = GetPluginFactory(plugin);

         // start all plugins this plugin depends on
         std::list<std::string> deps;
         factory->GetDependencies(deps);
         while(!deps.empty())
         {
            std::string dependency = deps.front();
            deps.pop_front();

            // If the active plugin depends on this plugin, then we need to stop that one too.
            if (dependency == name)
            {
               StopPlugin(plugin);
               break;
            }
         }
      }

      LOG_ALWAYS("Stopping plugin " + name);

      Plugin* plugin = GetPlugin(name);

      // call Destroy() callback of plugin
      plugin->Destroy();

      // tell factory to delete the plugin
      GetPluginFactory(name)->Destroy();

      // erase plugin from list of active plugins
      mActivePlugins.erase(mActivePlugins.find(name));

   }


   bool PluginManager::IsInstantiated(const std::string& name)
   {
      // all plugin names are in mActivePlugins, but names of non-active plugins
      // are mapped to NULL
      return mActivePlugins[name] != NULL;
   }


   /** is the plugin a system plugin? */
   bool PluginManager::IsSystemPlugin(const std::string& name)
   {
      return GetPluginFactory(name)->IsSystemPlugin();
   }


   Plugin* PluginManager::GetPlugin(const std::string& name)
   {
      // first check if plugin exists. return NULL if it doesn't
      ActivePluginMap::iterator i = mActivePlugins.find(name);
      if(i == mActivePlugins.end())
      {
         return NULL;
      }
      return i->second;
   }

通过继承自抽象类Plugin实现自定义的插件,同时继承自PluginFactory重写主要函数实现自定义插件工厂(负责插件的生成),可以方便的对UI进行扩展;

 /** construct the plugin and return a pointer to it */
      virtual Plugin* Create(MainWindow* mw) = 0;

      /** delete the plugin */
      virtual void Destroy() = 0;
      
      /** get the name of the plugin */
      virtual std::string GetName() = 0;

      /** get a description of the plugin */
      virtual std::string GetDescription() = 0;


自定义插件实现如下:

class XX_EXPORT CustomPlugin : public Plugin
{
public :
         void Create(){};
         void Destroy(){};
};
public XX_EXPORT CustomPluginFactory :public PluginFactory
{
     public :
Plugin* Create(MainWindow* mw)
{   
     mPlugin = new CustomPlugin(mv);
     return mPlugin;
}

   void Destory()
{
    delete mPlugin;
}

private:
  Plugin* mPlugin;
};

在Dll中导出全局函数:

extern "C" XX_EXPORT PluginFactory* CreatePluginFactory()
{
    return new PluginFactory();
}




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值