Просмотр исходного кода

Added ctkPluginTracker class (plus helper classes).

Sascha Zelzer лет назад: 14
Родитель
Сommit
ee75507602

+ 4 - 0
Libs/PluginFramework/CMakeLists.txt

@@ -60,6 +60,8 @@ SET(KIT_SRCS
   ctkPluginManager.cpp
   ctkPluginManifest.cpp
   ctkPluginPrivate.cpp
+  ctkPluginTracker.cpp
+  ctkPluginTrackerPrivate.cpp
   ctkPlugins.cpp
   ctkQtServiceRegistration.cpp
   ctkQtServiceRegistrationPrivate.cpp
@@ -76,6 +78,7 @@ SET(KIT_SRCS
   ctkServiceTrackerPrivate.cpp
   ctkServices.cpp
   ctkServiceSlotEntry.cpp
+  ctkTrackedPlugin.cpp
   ctkTrackedService.cpp
   ctkPluginStorage.cpp
   ctkVersion.cpp
@@ -92,6 +95,7 @@ SET(KIT_SRCS
 SET(KIT_MOC_SRCS
   ctkPluginFrameworkListeners_p.h
   ctkServiceFactory.h
+  ctkTrackedPlugin_p.h
   ctkTrackedService_p.h
 )
 

+ 208 - 0
Libs/PluginFramework/ctkPluginTracker.cpp

@@ -0,0 +1,208 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) 2010 German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+
+#include "ctkPluginTracker.h"
+
+#include "ctkPluginTrackerPrivate.h"
+#include "ctkTrackedPlugin_p.h"
+
+#include <QDebug>
+
+ctkPluginTracker::~ctkPluginTracker()
+{
+
+}
+
+ctkPluginTracker::ctkPluginTracker(ctkPluginContext* context, ctkPlugin::States stateMask,
+                 ctkPluginTrackerCustomizer* customizer)
+  : d_ptr(new ctkPluginTrackerPrivate(this, context, stateMask, customizer))
+{
+
+}
+
+void ctkPluginTracker::open()
+{
+  Q_D(ctkPluginTracker);
+  QSharedPointer<ctkTrackedPlugin> t;
+  {
+    QMutexLocker lock(&d->mutex);
+    if (d->trackedPlugin)
+    {
+      return;
+    }
+
+    if (d->DEBUG)
+    {
+      qDebug() << "ctkPluginTracker::open";
+    }
+
+    t = QSharedPointer<ctkTrackedPlugin>(new ctkTrackedPlugin(this, d->customizer));
+    {
+      QMutexLocker lockT(t.data());
+      d->context->connectPluginListener(t.data(), SLOT(pluginChanged(ctkPluginEvent)), Qt::DirectConnection);
+      QList<ctkPlugin*> plugins = d->context->getPlugins();
+      int length = plugins.size();
+      for (int i = 0; i < length; i++)
+      {
+        ctkPlugin::State state = plugins[i]->getState();
+        if ((d->mask & state) == 0)
+        {
+          /* null out plugins whose states are not interesting */
+          plugins[i] = 0;
+        }
+      }
+      plugins.removeAll(0);
+      /* set tracked with the initial bundles */
+      t->setInitial(plugins);
+    }
+    d->trackedPlugin = t;
+  }
+  /* Call tracked outside of synchronized region */
+  t->trackInitial(); /* process the initial references */
+}
+
+void ctkPluginTracker::close()
+{
+  Q_D(ctkPluginTracker);
+  QList<ctkPlugin*> plugins;
+  QSharedPointer<ctkTrackedPlugin> outgoing;
+  {
+    QMutexLocker lock(&d->mutex);
+    outgoing = d->trackedPlugin;
+    if (outgoing.isNull())
+    {
+      return;
+    }
+
+    if (d->DEBUG)
+    {
+      qDebug() << "ctkPluginTracker::close";
+    }
+
+    outgoing->close();
+    plugins = getPlugins();
+    d->trackedPlugin.clear();;
+
+    outgoing->disconnect(SLOT(pluginChanged(ctkPluginEvent)));
+  }
+
+  foreach (ctkPlugin* plugin, plugins)
+  {
+    outgoing->untrack(plugin, ctkPluginEvent());
+  }
+}
+
+QList<ctkPlugin*> ctkPluginTracker::getPlugins() const
+{
+  Q_D(const ctkPluginTracker);
+  QSharedPointer<ctkTrackedPlugin> t = d->tracked();
+  if (t.isNull())
+  { /* if ctkPluginTracker is not open */
+    return QList<ctkPlugin*>();
+  }
+
+  {
+    QMutexLocker lock(t.data());
+    return t->getTracked();
+  }
+}
+
+QVariant ctkPluginTracker::getObject(ctkPlugin* plugin) const
+{
+  Q_D(const ctkPluginTracker);
+  QSharedPointer<ctkTrackedPlugin> t = d->tracked();
+  if (t.isNull())
+  {
+    return QVariant();
+  }
+
+  {
+    QMutexLocker lock(t.data());
+    return t->getCustomizedObject(plugin);
+  }
+}
+
+void ctkPluginTracker::remove(ctkPlugin* plugin)
+{
+  Q_D(ctkPluginTracker);
+  QSharedPointer<ctkTrackedPlugin> t = d->tracked();
+  if (t.isNull())
+  {
+    return;
+  }
+  t->untrack(plugin, ctkPluginEvent());
+}
+
+int ctkPluginTracker::size() const
+{
+  Q_D(const ctkPluginTracker);
+  QSharedPointer<ctkTrackedPlugin> t = d->tracked();
+  if (t.isNull())
+  {
+    return 0;
+  }
+
+  {
+    QMutexLocker lock(t.data());
+    return t->size();
+  }
+}
+
+int ctkPluginTracker::getTrackingCount() const
+{
+  Q_D(const ctkPluginTracker);
+  QSharedPointer<ctkTrackedPlugin> t = d->tracked();
+  if (t.isNull())
+  {
+    return -1;
+  }
+
+  {
+    QMutexLocker lock(t.data());
+    return t->getTrackingCount();
+  }
+}
+
+QVariant ctkPluginTracker::addingPlugin(ctkPlugin* plugin, const ctkPluginEvent& event)
+{
+  Q_UNUSED(event)
+
+  QVariant var;
+  var.setValue(plugin);
+  return var;
+}
+
+void ctkPluginTracker::modifiedPlugin(ctkPlugin* plugin, const ctkPluginEvent& event, QVariant object)
+{
+  Q_UNUSED(plugin)
+  Q_UNUSED(event)
+  Q_UNUSED(object)
+  /* do nothing */
+}
+
+void ctkPluginTracker::removedPlugin(ctkPlugin* plugin, const ctkPluginEvent& event, QVariant object)
+{
+  Q_UNUSED(plugin)
+  Q_UNUSED(event)
+  Q_UNUSED(object)
+  /* do nothing */
+}

+ 254 - 0
Libs/PluginFramework/ctkPluginTracker.h

@@ -0,0 +1,254 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) 2010 German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+
+#ifndef CTKPLUGINTRACKER_H
+#define CTKPLUGINTRACKER_H
+
+#include <QScopedPointer>
+
+#include "CTKPluginFrameworkExport.h"
+
+#include "ctkPlugin.h"
+#include "ctkPluginTrackerCustomizer.h"
+
+class ctkPluginTrackerPrivate;
+
+/**
+ * The <code>ctkPluginTracker</code> class simplifies tracking plugins much like
+ * the <code>ctkServiceTracker</code> simplifies tracking services.
+ * <p>
+ * A <code>ctkPluginTracker</code> is constructed with state criteria and a
+ * <code>ctkPluginTrackerCustomizer</code> object. A <code>ctkPluginTracker</code> can
+ * use the <code>ctkPluginTrackerCustomizer</code> to select which plugins are
+ * tracked and to create a customized object to be tracked with the plugin. The
+ * <code>ctkPluginTracker</code> can then be opened to begin tracking all plugins
+ * whose state matches the specified state criteria.
+ * <p>
+ * The <code>getPlugins</code> method can be called to get the
+ * <code>ctkPlugin</code> objects of the plugins being tracked. The
+ * <code>getObject</code> method can be called to get the customized object for
+ * a tracked plugin.
+ * <p>
+ * The <code>ctkPluginTracker</code> class is thread-safe. It does not call a
+ * <code>ctkPluginTrackerCustomizer</code> while holding any locks.
+ * <code>ctkPluginTrackerCustomizer</code> implementations must also be
+ * thread-safe.
+ *
+ * @ThreadSafe
+ */
+class CTK_PLUGINFW_EXPORT ctkPluginTracker : protected ctkPluginTrackerCustomizer
+{
+public:
+
+  ~ctkPluginTracker();
+
+  /**
+   * Create a <code>ctkPluginTracker</code> for plugins whose state is present in
+   * the specified state mask.
+   *
+   * <p>
+   * Plugins whose state is present on the specified state mask will be
+   * tracked by this <code>ctkPluginTracker</code>.
+   *
+   * @param context The <code>ctkPluginContext</code> against which the tracking
+   *        is done.
+   * @param stateMask The bit mask of the <code>OR</code>ing of the plugin
+   *        states to be tracked.
+   * @param customizer The customizer object to call when plugins are added,
+   *        modified, or removed in this <code>ctkPluginTracker</code>. If
+   *        customizer is <code>null</code>, then this
+   *        <code>ctkPluginTracker</code> will be used as the
+   *        <code>ctkPluginTrackerCustomizer</code> and this
+   *        <code>ctkPluginTracker</code> will call the
+   *        <code>ctkPluginTrackerCustomizer</code> methods on itself. If the
+   *        customizer is not <code>null</code>, this <code>ctkPluginTracker</code>
+   *        takes ownership of the customizer.
+   * @see ctkPlugin#getState()
+   */
+  ctkPluginTracker(ctkPluginContext* context, ctkPlugin::States stateMask,
+                   ctkPluginTrackerCustomizer* customizer = 0);
+
+  /**
+   * Open this <code>ctkPluginTracker</code> and begin tracking plugins.
+   *
+   * <p>
+   * ctkPlugin's which match the state criteria specified when this
+   * <code>ctkPluginTracker</code> was created are now tracked by this
+   * <code>ctkPluginTracker</code>.
+   *
+   * @throws std::logic_error If the <code>ctkPluginContext</code>
+   *         with which this <code>ctkPluginTracker</code> was created is no
+   *         longer valid.
+   */
+  void open();
+
+  /**
+   * Close this <code>ctkPluginTracker</code>.
+   *
+   * <p>
+   * This method should be called when this <code>ctkPluginTracker</code> should
+   * end the tracking of plugins.
+   *
+   * <p>
+   * This implementation calls getPlugins() to get the list of
+   * tracked plugins to remove.
+   */
+  void close();
+
+  /**
+   * Return a list of <code>ctkPlugin</code>s for all plugins being tracked by
+   * this <code>ctkPluginTracker</code>.
+   *
+   * @return A list of <code>ctkPlugin</code>s.
+   */
+  QList<ctkPlugin*> getPlugins() const;
+
+  /**
+   * Returns the customized object for the specified <code>ctkPlugin</code> if
+   * the specified plugin is being tracked by this <code>ctkPluginTracker</code>.
+   *
+   * @param plugin The <code>ctkPlugin</code> being tracked.
+   * @return The customized object for the specified <code>ctkPlugin</code> or
+   *         <code>null</code> if the specified <code>ctkPlugin</code> is not
+   *         being tracked.
+   */
+  QVariant getObject(ctkPlugin* plugin) const;
+
+  /**
+   * Remove a plugin from this <code>ctkPluginTracker</code>.
+   *
+   * The specified plugin will be removed from this <code>ctkPluginTracker</code>.
+   * If the specified plugin was being tracked then the
+   * <code>ctkPluginTrackerCustomizer::removedPlugin</code> method will be called
+   * for that plugin.
+   *
+   * @param plugin The <code>ctkPlugin</code> to be removed.
+   */
+  void remove(ctkPlugin* plugin);
+
+  /**
+   * Return the number of plugins being tracked by this
+   * <code>ctkPluginTracker</code>.
+   *
+   * @return The number of plugins being tracked.
+   */
+  int size() const;
+
+  /**
+   * Returns the tracking count for this <code>ctkPluginTracker</code>.
+   *
+   * The tracking count is initialized to 0 when this
+   * <code>ctkPluginTracker</code> is opened. Every time a plugin is added,
+   * modified or removed from this <code>ctkPluginTracker</code> the tracking
+   * count is incremented.
+   *
+   * <p>
+   * The tracking count can be used to determine if this
+   * <code>ctkPluginTracker</code> has added, modified or removed a plugin by
+   * comparing a tracking count value previously collected with the current
+   * tracking count value. If the value has not changed, then no plugin has
+   * been added, modified or removed from this <code>ctkPluginTracker</code>
+   * since the previous tracking count was collected.
+   *
+   * @return The tracking count for this <code>ctkPluginTracker</code> or -1 if
+   *         this <code>ctkPluginTracker</code> is not open.
+   */
+  int getTrackingCount() const;
+
+protected:
+
+  /**
+   * Default implementation of the
+   * <code>ctkPluginTrackerCustomizer::addingPlugin</code> method.
+   *
+   * <p>
+   * This method is only called when this <code>ctkPluginTracker</code> has been
+   * constructed with a <code>null</code> ctkPluginTrackerCustomizer argument.
+   *
+   * <p>
+   * This implementation simply returns the specified <code>ctkPlugin*</code> in
+   * a QVariant.
+   *
+   * <p>
+   * This method can be overridden in a subclass to customize the object to be
+   * tracked for the plugin being added.
+   *
+   * @param plugin The <code>ctkPlugin</code> being added to this
+   *        <code>ctkPluginTracker</code> object.
+   * @param event The plugin event which caused this customizer method to be
+   *        called or an invalid event if there is no plugin event associated
+   *        with the call to this method.
+   * @return The specified plugin.
+   * @see ctkPluginTrackerCustomizer::addingPlugin(ctkPlugin*, const ctkPluginEvent&)
+   */
+  QVariant addingPlugin(ctkPlugin* plugin, const ctkPluginEvent& event);
+
+  /**
+   * Default implementation of the
+   * <code>ctkPluginTrackerCustomizer::modifiedPlugin</code> method.
+   *
+   * <p>
+   * This method is only called when this <code>ctkPluginTracker</code> has been
+   * constructed with a <code>null</code> ctkPluginTrackerCustomizer argument.
+   *
+   * <p>
+   * This implementation does nothing.
+   *
+   * @param plugin The <code>ctkPlugin</code> whose state has been modified.
+   * @param event The plugin event which caused this customizer method to be
+   *        called or an invalid event if there is no plugin event associated
+   *        with the call to this method.
+   * @param object The customized object for the specified ctkPlugin.
+   * @see ctkPluginTrackerCustomizer::modifiedPlugin(ctkPlugin*, const ctkPluginEvent&, QVariant)
+   */
+  void modifiedPlugin(ctkPlugin* plugin, const ctkPluginEvent& event, QVariant object);
+
+  /**
+   * Default implementation of the
+   * <code>ctkPluginTrackerCustomizer::removedPlugin</code> method.
+   *
+   * <p>
+   * This method is only called when this <code>ctkPluginTracker</code> has been
+   * constructed with a <code>null</code> ctkPluginTrackerCustomizer argument.
+   *
+   * <p>
+   * This implementation does nothing.
+   *
+   * @param plugin The <code>ctkPlugin</code> being removed.
+   * @param event The plugin event which caused this customizer method to be
+   *        called or an invalid event if there is no plugin event associated
+   *        with the call to this method.
+   * @param object The customized object for the specified plugin.
+   * @see ctkPluginTrackerCustomizer::removedPlugin(ctkPlugin*, const ctkPluginEvent&, QVariant)
+   */
+  void removedPlugin(ctkPlugin* plugin, const ctkPluginEvent& event, QVariant object);
+
+private:
+
+  friend class ctkTrackedPlugin;
+
+  Q_DECLARE_PRIVATE(ctkPluginTracker)
+
+  const QScopedPointer<ctkPluginTrackerPrivate> d_ptr;
+};
+
+#endif // CTKPLUGINTRACKER_H

+ 121 - 0
Libs/PluginFramework/ctkPluginTrackerCustomizer.h

@@ -0,0 +1,121 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) 2010 German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+
+#ifndef CTKPLUGINTRACKERCUSTOMIZER_H
+#define CTKPLUGINTRACKERCUSTOMIZER_H
+
+#include <QVariant>
+
+#include "ctkPluginEvent.h"
+
+class QObject;
+class ctkPlugin;
+
+/**
+ * The <code>ctkPluginTrackerCustomizer</code> interface allows a
+ * <code>ctkPluginTracker</code> to customize the <code>Plugin</code>s that are
+ * tracked. A <code>ctkPluginTrackerCustomizer</code> is called when a plugin is
+ * being added to a <code>ctkPluginTracker</code>. The
+ * <code>ctkPluginTrackerCustomizer</code> can then return an object for the
+ * tracked plugin. A <code>ctkPluginTrackerCustomizer</code> is also called when a
+ * tracked plugin is modified or has been removed from a
+ * <code>ctkPluginTracker</code>.
+ *
+ * <p>
+ * The methods in this interface may be called as the result of a
+ * <code>ctkPluginEvent</code> being received by a <code>ctkPluginTracker</code>.
+ * Since <code>ctkPluginEvent</code>s are received synchronously by the
+ * <code>ctkPluginTracker</code>, it is highly recommended that implementations of
+ * these methods do not alter plugin states while being synchronized on any
+ * object.
+ *
+ * <p>
+ * The <code>ctkPluginTracker</code> class is thread-safe. It does not call a
+ * <code>ctkPluginTrackerCustomizer</code> while holding any locks.
+ * <code>ctkPluginTrackerCustomizer</code> implementations must also be
+ * thread-safe.
+ *
+ * @ThreadSafe
+ */
+struct ctkPluginTrackerCustomizer {
+
+  virtual ~ctkPluginTrackerCustomizer() {}
+
+  /**
+   * A plugin is being added to the <code>ctkPluginTracker</code>.
+   *
+   * <p>
+   * This method is called before a plugin which matched the search parameters
+   * of the <code>ctkPluginTracker</code> is added to the
+   * <code>ctkPluginTracker</code>. This method should return the object to be
+   * tracked for the specified <code>ctkPlugin</code>. The returned object is
+   * stored in the <code>ctkPluginTracker</code> and is available from the
+   * ctkPluginTracker::getObject(ctkPlugin*) method.
+   *
+   * @param plugin The <code>ctkPlugin</code> being added to the
+   *        <code>ctkPluginTracker</code>.
+   * @param event The plugin event which caused this customizer method to be
+   *        called or an invalid event (ctkPluginEvent::isNull() returns <code>true</code>)
+   *        if there is no plugin event associated
+   *        with the call to this method.
+   * @return The object to be tracked for the specified <code>ctkPlugin</code>
+   *         object or <code>null</code> if the specified <code>ctkPlugin</code>
+   *         object should not be tracked.
+   */
+  virtual QVariant addingPlugin(ctkPlugin* plugin, const ctkPluginEvent& event) = 0;
+
+  /**
+   * A plugin tracked by the <code>ctkPluginTracker</code> has been modified.
+   *
+   * <p>
+   * This method is called when a plugin being tracked by the
+   * <code>ctkPluginTracker</code> has had its state modified.
+   *
+   * @param plugin The <code>ctkPlugin</code> whose state has been modified.
+   * @param event The plugin event which caused this customizer method to be
+   *        called or an invalid event (ctkPluginEvent::isNull() returns <code>true</code>)
+   *        if there is no plugin event associated
+   *        with the call to this method.
+   * @param object The tracked object for the specified plugin.
+   */
+  virtual void modifiedPlugin(ctkPlugin* plugin, const ctkPluginEvent& event,
+      QVariant object) = 0;
+
+  /**
+   * A plugin tracked by the <code>ctkPluginTracker</code> has been removed.
+   *
+   * <p>
+   * This method is called after a plugin is no longer being tracked by the
+   * <code>ctkPluginTracker</code>.
+   *
+   * @param plugin The <code>ctkPlugin</code> that has been removed.
+   * @param event The plugin event which caused this customizer method to be
+   *        called or an invalid event (ctkPluginEvent::isNull() returns <code>true</code>)
+   *        if there is no plugin event associated
+   *        with the call to this method.
+   * @param object The tracked object for the specified plugin.
+   */
+  virtual void removedPlugin(ctkPlugin* plugin, const ctkPluginEvent& event,
+      QVariant object) = 0;
+};
+
+#endif // CTKPLUGINTRACKERCUSTOMIZER_H

+ 49 - 0
Libs/PluginFramework/ctkPluginTrackerPrivate.cpp

@@ -0,0 +1,49 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) 2010 German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+
+#include "ctkPluginTrackerPrivate.h"
+
+#include "ctkTrackedPlugin_p.h"
+#include "ctkPluginTracker.h"
+
+const bool ctkPluginTrackerPrivate::DEBUG = true;
+
+ctkPluginTrackerPrivate::ctkPluginTrackerPrivate(
+    ctkPluginTracker* pt, ctkPluginContext* context,
+    ctkPlugin::States stateMask, ctkPluginTrackerCustomizer* customizer)
+  : context(context), customizer(customizer), mask(stateMask), q_ptr(pt)
+{
+  this->customizer = customizer ? customizer : q_func();
+}
+
+ctkPluginTrackerPrivate::~ctkPluginTrackerPrivate()
+{
+  if (customizer != q_func())
+  {
+    delete customizer;
+  }
+}
+
+QSharedPointer<ctkTrackedPlugin> ctkPluginTrackerPrivate::tracked() const
+{
+  return trackedPlugin;
+}

+ 88 - 0
Libs/PluginFramework/ctkPluginTrackerPrivate.h

@@ -0,0 +1,88 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) 2010 German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+
+#ifndef CTKPLUGINTRACKERPRIVATE_H
+#define CTKPLUGINTRACKERPRIVATE_H
+
+#include "ctkPlugin.h"
+
+#include <QSharedPointer>
+#include <QMutex>
+
+class ctkPluginTracker;
+class ctkPluginContext;
+class ctkTrackedPlugin;
+class ctkPluginTrackerCustomizer;
+
+class ctkPluginTrackerPrivate
+{
+public:
+  ctkPluginTrackerPrivate(ctkPluginTracker* pt,
+                          ctkPluginContext* context, ctkPlugin::States stateMask,
+                          ctkPluginTrackerCustomizer* customizer);
+
+  ~ctkPluginTrackerPrivate();
+
+  /**
+   * Accessor method for the current ctkTrackedPlugin object. This method is only
+   * intended to be used by the unsynchronized methods which do not modify the
+   * trackedPlugin field.
+   *
+   * @return The current ctkTrackedPlugin object.
+   */
+  QSharedPointer<ctkTrackedPlugin> tracked() const;
+
+  /* set this to true to compile in debug messages */
+  static const bool DEBUG; //	= false;
+
+  /**
+   * The Bundle Context used by this <code>ctkPluginTracker</code>.
+   */
+  ctkPluginContext* const context;
+
+  /**
+   * The <code>ctkPluginTrackerCustomizer</code> object for this tracker.
+   */
+  ctkPluginTrackerCustomizer* customizer;
+
+  /**
+   * Tracked plugins: <code>ctkPlugin</code> object -> customized Object and
+   * plugin listener slot.
+   */
+  QSharedPointer<ctkTrackedPlugin> trackedPlugin;
+
+  /**
+   * State mask for plugins being tracked. This field contains the ORed values
+   * of the plugin states being tracked.
+   */
+  ctkPlugin::States mask;
+
+  mutable QMutex mutex;
+
+private:
+
+  Q_DECLARE_PUBLIC(ctkPluginTracker)
+
+  ctkPluginTracker * const q_ptr;
+};
+
+#endif // CTKPLUGINTRACKERPRIVATE_H

+ 87 - 0
Libs/PluginFramework/ctkTrackedPlugin.cpp

@@ -0,0 +1,87 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) 2010 German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+
+#include "ctkTrackedPlugin_p.h"
+
+#include "ctkPluginTracker.h"
+#include "ctkPluginTrackerPrivate.h"
+
+ctkTrackedPlugin::ctkTrackedPlugin(ctkPluginTracker* pluginTracker,
+                 ctkPluginTrackerCustomizer* customizer)
+  : pluginTracker(pluginTracker), customizer(customizer)
+{
+
+}
+
+void ctkTrackedPlugin::pluginChanged(const ctkPluginEvent& event)
+{
+  /*
+   * Check if we had a delayed call (which could happen when we
+   * close).
+   */
+  if (closed)
+  {
+    return;
+  }
+
+  ctkPlugin* plugin = event.getPlugin();
+  ctkPlugin::State state = plugin->getState();
+  if (pluginTracker->d_func()->DEBUG)
+  {
+    qDebug() << "ctkTrackedPlugin::pluginChanged[" << state << "]: " << *plugin;
+  }
+
+  if (pluginTracker->d_func()->mask & state)
+  {
+    track(plugin, event);
+    /*
+     * If the customizer throws an exception, it is safe
+     * to let it propagate
+     */
+  }
+  else
+  {
+    untrack(plugin, event);
+    /*
+     * If the customizer throws an exception, it is safe
+     * to let it propagate
+     */
+  }
+}
+
+QVariant ctkTrackedPlugin::customizerAdding(ctkPlugin* item,
+    ctkPluginEvent related)
+{
+  return customizer->addingPlugin(item, related);
+}
+
+void ctkTrackedPlugin::customizerModified(ctkPlugin* item,
+    ctkPluginEvent related, QVariant object)
+{
+  customizer->modifiedPlugin(item, related, object);
+}
+
+void ctkTrackedPlugin::customizerRemoved(ctkPlugin* item,
+    ctkPluginEvent related, QVariant object)
+{
+  customizer->removedPlugin(item, related, object);
+}

+ 94 - 0
Libs/PluginFramework/ctkTrackedPlugin_p.h

@@ -0,0 +1,94 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) 2010 German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+
+#ifndef CTKTRACKEDPLUGIN_P_H
+#define CTKTRACKEDPLUGIN_P_H
+
+#include "ctkPluginAbstractTracked_p.h"
+#include "ctkPluginEvent.h"
+
+class ctkPluginTracker;
+class ctkPluginTrackerCustomizer;
+
+class ctkTrackedPlugin : public QObject,
+    public ctkPluginAbstractTracked<ctkPlugin*, ctkPluginEvent>
+{
+  Q_OBJECT
+
+public:
+  ctkTrackedPlugin(ctkPluginTracker* pluginTracker,
+                   ctkPluginTrackerCustomizer* customizer);
+
+private slots:
+
+  /**
+   * Slot for the <code>ctkPluginTracker</code>
+   * class. This method must NOT be synchronized to avoid deadlock
+   * potential.
+   *
+   * @param event <code>ctkPluginEvent</code> object from the framework.
+   */
+  void pluginChanged(const ctkPluginEvent& event);
+
+private:
+
+  typedef ctkPluginAbstractTracked<ctkPlugin*, ctkPluginEvent> Superclass;
+
+  ctkPluginTracker* pluginTracker;
+  ctkPluginTrackerCustomizer* customizer;
+
+  /**
+   * Call the specific customizer adding method. This method must not be
+   * called while synchronized on this object.
+   *
+   * @param item Item to be tracked.
+   * @param related Action related object.
+   * @return Customized object for the tracked item or <code>null</code>
+   *         if the item is not to be tracked.
+   */
+  QVariant customizerAdding(ctkPlugin* item,
+                            ctkPluginEvent related);
+
+  /**
+   * Call the specific customizer modified method. This method must not be
+   * called while synchronized on this object.
+   *
+   * @param item Tracked item.
+   * @param related Action related object.
+   * @param object Customized object for the tracked item.
+   */
+  void customizerModified(ctkPlugin* item,
+                          ctkPluginEvent related, QVariant object);
+
+  /**
+   * Call the specific customizer removed method. This method must not be
+   * called while synchronized on this object.
+   *
+   * @param item Tracked item.
+   * @param related Action related object.
+   * @param object Customized object for the tracked item.
+   */
+  void customizerRemoved(ctkPlugin* item,
+                         ctkPluginEvent related, QVariant object);
+};
+
+#endif // CTKTRACKEDPLUGIN_P_H