forked from qt-creator/qt-creator
		
	Signed-off-by: Abhishek Patil <abhishek.patil@vcreatelogic.com> Merge-request: 145 Reviewed-by: con <qtc-committer@nokia.com>
		
			
				
	
	
		
			330 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			330 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
/*!
 | 
						|
    \page qtc-arch.html
 | 
						|
    \title 4. Qt Creator Architecture
 | 
						|
		
 | 
						|
	Every large system has a well defined "system architecture" which if understood well makes it easy for us to find out
 | 
						|
	way in it. Qt Creator is no different. In this chapter we will understand the basic architecture of Qt Creator so that we
 | 
						|
	can continue our understanding of writing plugins.
 | 
						|
	
 | 
						|
	\section1 4.1 Nuts and Bolts of Qt Creator
 | 
						|
	
 | 
						|
	Qt Creator is Nokia's cross-platform IDE. Currently Qt Creator is mainly used for writing Qt/C++ code.
 | 
						|
	The core of Qt Creator is basically only a "plugin loader" All functionality is implemented in plugins.
 | 
						|
	
 | 
						|
	\inlineimage  qtc-pluginmanager-4.png
 | 
						|
	
 | 
						|
	
 | 
						|
	The core "personality"of Qt Creator is implemented in the \bold {Core Plugin (Core::ICore)}. We have already had a brush
 | 
						|
	with the core plugin in the previous chapter. In the rest of this document we will refer to "core plugin" as Core.
 | 
						|
	The plugin manager \bold{(ExtensionSystem::PluginManager)} provides simple means for plugin cooperation that
 | 
						|
	allow plugins to provide hooks for other plugin's extensions.
 | 
						|
	
 | 
						|
	\section1 4.2 What exactly is a plugin?
 | 
						|
	
 | 
						|
	At the most fundamental level plugin is a shared library (DLL file on Windows, SO file on Linux, DYLIB file on Mac). From
 | 
						|
	a developer's point of view plugin is a module that
 | 
						|
	\list 1
 | 
						|
	\o Implements the ExtensionSystem::IPlugin interface in a class. This class will be referred to as "Plugin Class" in the
 | 
						|
	   rest of the document.
 | 
						|
	\o Exports the Plugin Class using the Q_EXPORT_PLUGIN macro
 | 
						|
	\o Provides a pluginspec file that provides some meta information about the plugin
 | 
						|
	\o Registers one or more objects that might be of some interest to other plugins
 | 
						|
	\o Searches for the availability of one or more objects registered by other plugins.
 | 
						|
	\endlist
 | 
						|
	
 | 
						|
	We have already had some experience with the first three aspects listed above, but we have not touched upon the last
 | 
						|
	two.
 | 
						|
	\section2 4.2.1 What are registered objects?
 | 
						|
	
 | 
						|
	 objects are those that land up in the \bold {PluginManager's} object pool. The \bold {allObjects()} method in
 | 
						|
	\bold {PluginManager} returns the object pool as a list of QObject pointers. Shown below is the code that we can use to list
 | 
						|
	all objects in the object-pool in a \bold {QListWidget}.
 | 
						|
	
 | 
						|
	\code
 | 
						|
	#include <extensionsystem/pluginmanager.h>
 | 
						|
	
 | 
						|
	ExtensionSystem::PluginManager* pm = ExtensionSystem::PluginManager::instance();
 | 
						|
	QList<QObject*> objects = pm->allObjects();
 | 
						|
	QListWidget* listWidget = new QListWidget;
 | 
						|
	
 | 
						|
	Q_FOREACH(QObject* obj, objects)
 | 
						|
	{
 | 
						|
            QString objInfo = QString("%1 (%2)").arg(obj->objectName()).arg(obj->metaObject()->className());
 | 
						|
            listWidget->addItem(objInfo);
 | 
						|
	}
 | 
						|
	
 | 
						|
	listWidget->show();
 | 
						|
	\endcode
 | 
						|
	When such a list widget is constructed and shown; you will see a window as shown below.
 | 
						|
	
 | 
						|
    
 | 
						|
	\inlineimage qtc-objectlist-4.png
 | 
						|
	
 | 
						|
	
 | 
						|
	From the class names it is easy to picture the fact that each of those objects came from different plugins. 
 | 
						|
	
 | 
						|
	\bold {\underline {A registered object is an instance of QObject (or one of its subclasses) registered by a plugin and is available in the
 | 
						|
	object-pool for other plugins to make use of}}.
 | 
						|
	
 | 
						|
	\section2 4.2.2 How to "register" an object from a plugin?
 | 
						|
	There are three ways to register an object from a plugin:
 | 
						|
	
 | 
						|
	\list
 | 
						|
	
 | 
						|
	\o \bold {IPlugin::addAutoReleasedObject(QObject*)}
 | 
						|
	\o \bold {IPlugin::addObject(QObject*)}
 | 
						|
	\o \bold {PluginManager::addObject(QObject*)}
 | 
						|
	
 | 
						|
	\endlist
 | 
						|
	
 | 
						|
	
 | 
						|
	The \bold {IPlugin::addObject()} and \bold {IPlugin::addAutoReleasedObject()} essentially call the
 | 
						|
	\bold {PluginManager::addObject()} method. The \bold {IPlugin} methods are only provided for convenience. It is
 | 
						|
	recommended that plugins make use of the \bold {IPlugin} methods for adding objects.
 | 
						|
	
 | 
						|
	The only difference between \bold {addAutoReleasedObject()} and \bold {addObject()} is that objects added using the
 | 
						|
	former method are automatically removed and deleted in the reverse order of registration when the plugin is destroyed.
 | 
						|
	At anytime plugins can make use of the \bold {IPlugin::removeObject(QObject*)} method to remove its object from
 | 
						|
	the object pool.
 | 
						|
	
 | 
						|
	\section2 4.2.3 What objects to register?
 | 
						|
	
 | 
						|
	Plugins can register just about any object. Normally objects that provide some sort of functionality used by other
 | 
						|
	plugin(s) are registered. Functionalities in Qt Creator are defined by means of interfaces. Listed below are some interfaces
 | 
						|
    
 | 
						|
	\list
 | 
						|
	     
 | 
						|
	\o \bold {Core::INavigationWidgetFactory}
 | 
						|
	\o \bold {Core::IEditor}
 | 
						|
	\o \bold {Core::IOptionsPage}
 | 
						|
	\o \bold {Core::IWizard}
 | 
						|
	  
 | 
						|
	\endlist
 | 
						|
	
 | 
						|
	\bold{\underline { C++ developers normally assume interfaces to be classes with all its functions are public pure 
 | 
						|
	virtual functions. In Qt Creator interfaces are subclasses of QObject that offer one or more
 | 
						|
	methods are pure virtual}}.
 | 
						|
	
 | 
						|
	If a plugin has objects that implement an interface, then such an object has to be registered. For example if a plugin
 | 
						|
	implements the \bold{INavigationWidgetFactory} interface in an object and registered it, the Core will automatically use that
 | 
						|
	object to show the widget provided by it as navigation widget. Take a look at the code snippet below. We provide a
 | 
						|
	simple \bold{QTableWidget} as navigation widget via an implementation of \bold {Core::INavigationWidgetFactory}.
 | 
						|
	
 | 
						|
	\code
 | 
						|
    #include <coreplugin/inavigationwidgetfactory.h>
 | 
						|
 | 
						|
    class NavWidgetFactory : public Core::INavigationWidgetFactory
 | 
						|
    {
 | 
						|
    public:
 | 
						|
        NavWidgetFactory();
 | 
						|
        ~NavWidgetFactory();
 | 
						|
        Core::NavigationView createWidget();
 | 
						|
        QString displayName();
 | 
						|
    };
 | 
						|
 | 
						|
    #include <QTableWidget>
 | 
						|
 | 
						|
    NavWidgetFactory::NavWidgetFactory() { }
 | 
						|
    NavWidgetFactory::~NavWidgetFactory() { }
 | 
						|
 | 
						|
    Core::NavigationView NavWidgetFactory::createWidget()
 | 
						|
    {
 | 
						|
        Core::NavigationView view;
 | 
						|
        view.widget = new QTableWidget(50, 3);
 | 
						|
    }
 | 
						|
 | 
						|
    QString NavWidgetFactory::displayName()
 | 
						|
    {
 | 
						|
        return "Spreadsheet";
 | 
						|
    }
 | 
						|
 | 
						|
    bool MyPlugin::initialize(const QStringList& args, QString *errMsg)
 | 
						|
    {
 | 
						|
        Q_UNUSED(args);
 | 
						|
        Q_UNUSED(errMsg);
 | 
						|
        // Provide a navigation widget factory.
 | 
						|
        // Qt Creator's navigation widget will automatically
 | 
						|
        // hook to our INavigationWidgetFactory implementation, which
 | 
						|
        // is the NavWidgetFactory class, and show the QTableWidget
 | 
						|
        // created by it in the navigation panel.
 | 
						|
        addAutoReleasedObject(new NavWidgetFactory);
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
	\endcode
 | 
						|
	
 | 
						|
	The effect of the above code is
 | 
						|
	
 | 
						|
	\inlineimage qtc-codeeffect-4.png
 | 
						|
	
 | 
						|
	\section2 4.2.4 Becoming aware of registered objects
 | 
						|
	
 | 
						|
	Whenever the \bold {PluginManager::addObject()} is used to add an object, it \bold{(PluginManager)} emits the
 | 
						|
	\bold {objectAdded(QObject*)} signal. This signal can be used within our applications to figure out the objects that got
 | 
						|
	added.
 | 
						|
	
 | 
						|
	Obviously a plugin will begin receiving the signal only after it makes a connection to it. That happens only after the
 | 
						|
	plugin is initialized; which also means that the plugin will receive the \bold {objectAdded()} signal only for objects added
 | 
						|
	after the plugin was initialized.
 | 
						|
	
 | 
						|
	Usually the slot that is connected to the objectAdded() signal will look for one or more known interfaces. Suppose that
 | 
						|
	your plugin is looking for the INavigationWidgetFactory interface, the slot connected to objectAdded() will be like the
 | 
						|
	one shown below.
 | 
						|
	
 | 
						|
	\code
 | 
						|
    void Plugin::slotObjectAdded(QObject * obj)
 | 
						|
    {
 | 
						|
        INavigationWidgetFactory *factory = Aggregation::query<INavigationWidgetFactory>(obj);
 | 
						|
 | 
						|
        if(factory)
 | 
						|
        {
 | 
						|
        // use it here...
 | 
						|
        }
 | 
						|
    }
 | 
						|
	\endcode
 | 
						|
	
 | 
						|
	\section2 4.2.5 Searching for objects
 | 
						|
	
 | 
						|
	Sometimes a plugin might want to search for an object in the application that offers some functionality. We already
 | 
						|
	know by now that
 | 
						|
	
 | 
						|
	\list
 | 
						|
	\o \bold {PluginManager::allObjects()} returns the object pool as a \bold {QList<QObject*>}
 | 
						|
	\o Connecting to \bold {PluginManager::objectAdded()} signal helps in known objects as they get registered
 | 
						|
	\endlist
 | 
						|
	
 | 
						|
	Using both of the above mentioned methods you can look for objects. Lets now understand yet another way to find
 | 
						|
	objects.
 | 
						|
 | 
						|
	Suppose that you wanted to look for objects that implement the \bold {INavigationWidgetFactory} interface and show it in a
 | 
						|
	\bold {QListWidget}. You can make use of the \bold {PluginManager::getObjects<T>()} method for this purpose. The following code
 | 
						|
	snippet explains this
 | 
						|
	
 | 
						|
	\code
 | 
						|
    ExtensionSystem::PluginManager* pm = ExtensionSystem::PluginManager::instance();
 | 
						|
    QList<Core::INavigationWidgetFactory*> objects = pm->getObjects<Core::INavigationWidgetFactory>();
 | 
						|
    QListWidget* listWidget = new QListWidget();
 | 
						|
 | 
						|
    Q_FOREACH(Core::INavigationWidgetFactory* obj, objects)
 | 
						|
    {
 | 
						|
        QString objInfo = QString("%1 (%2)").arg(obj->displayName()).arg(obj->metaObject()->className());
 | 
						|
        listWidget->addItem(objInfo);
 | 
						|
    }
 | 
						|
	\endcode
 | 
						|
	
 | 
						|
	When the list widget is shown you will notice that the navigation widgets are shown in the same order as they are
 | 
						|
	shown in the navigation combo box. Take a look at the screenshot below.
 | 
						|
	
 | 
						|
	\inlineimage qtc-nevigationwidget-4.png
 | 
						|
	
 | 
						|
	
 | 
						|
	\section1 4.3 Aggregations
 | 
						|
	
 | 
						|
	Aggregations are provided by the \bold {Aggregation} namespace. It adds functionality for "glueing" \bold {QObjects} of different
 | 
						|
	types together, so you can "cast" between them. Using the classes and methods in this namespace you can bundle
 | 
						|
	related objects into a single entity. Objects that are bundled into an aggregate can be "cast" from the aggregate into the
 | 
						|
	object class type.
 | 
						|
	
 | 
						|
	\section2 4.3.1 Aggregations - the old fashioned way
 | 
						|
	
 | 
						|
	Suppose that you wanted an object that provided implementations of two interfaces. Normally we would go about
 | 
						|
	coding the object like this.
 | 
						|
	
 | 
						|
	\code
 | 
						|
    class Interface1
 | 
						|
    {
 | 
						|
        ....
 | 
						|
    };
 | 
						|
    Q_DECLARE_INTERFACE("Interface1", "Interface1");
 | 
						|
 | 
						|
    class Interface2
 | 
						|
    {
 | 
						|
        ....
 | 
						|
    };
 | 
						|
    Q_DECLARE_INTERFACE("Interface2", "Interface2");
 | 
						|
 | 
						|
    class Bundle : public QObject,public Interface1,public Interface2
 | 
						|
    {
 | 
						|
        Q_OBJECT(Interface1 Interface2)
 | 
						|
        ....
 | 
						|
    };
 | 
						|
    Bundle bundle;
 | 
						|
	
 | 
						|
	\endcode
 | 
						|
	
 | 
						|
	Now we can think of \bold {bundle} as an object that provides \bold {Interface1} and \bold {Interface2} implementations. We can
 | 
						|
	make use of casting operators on the bundle object to extract \bold{Interface1} and \bold {Interface2}.
 | 
						|
	
 | 
						|
	\code
 | 
						|
    Interface1* iface1Ptr = qobject_cast<Interface1*>(&bundle);
 | 
						|
    Interface2* iface2Ptr = qobject_cast<Interface2*>(&bundle);
 | 
						|
	\endcode
 | 
						|
	
 | 
						|
	\section2 4.3.2 Aggregations - the Qt Creator way
 | 
						|
	
 | 
						|
	Qt Creator's Aggregation library offers a cleaner way to define interfaces and bundle them into a single object. Instances
 | 
						|
	of Aggregation::Aggregate can be created and objects can be added to it. Each of the objects added to the aggregation
 | 
						|
	can implement an interface. The following code snippet shows how to create an aggregation.
 | 
						|
	
 | 
						|
	\code
 | 
						|
	
 | 
						|
    #include <aggregation/aggregate.h>
 | 
						|
 | 
						|
    class Interface1 : public QObject
 | 
						|
    {
 | 
						|
        Q_OBJECT
 | 
						|
        
 | 
						|
    public:
 | 
						|
        Interface1() { }
 | 
						|
        ~Interface1() { }
 | 
						|
    };
 | 
						|
 | 
						|
    class Interface2 : public QObject
 | 
						|
    {
 | 
						|
        Q_OBJECT
 | 
						|
        
 | 
						|
    public:
 | 
						|
        Interface2() { }
 | 
						|
        ~Interface2() { }
 | 
						|
    };
 | 
						|
 | 
						|
    Aggregation::Aggregate bundle;
 | 
						|
    bundle.add(new Interface1);
 | 
						|
    bundle.add(new Interface2);
 | 
						|
	
 | 
						|
	\endcode
 | 
						|
	
 | 
						|
	The aggregation instance "bundle" now conceptually contains implementations of two interfaces. To extract the
 | 
						|
	interfaces we can make use of the following code
 | 
						|
	
 | 
						|
	\code
 | 
						|
    Interface1* iface1Ptr = Aggregation::query<Interface1>( &bundle );
 | 
						|
    Interface2* iface2Ptr = Aggregation::query<Interface2>( &bundle );
 | 
						|
	\endcode
 | 
						|
	
 | 
						|
	With aggregation you can also several objects of the same interface into a single bundle. For example
 | 
						|
	
 | 
						|
	\code
 | 
						|
    Aggregation::Aggregate bundle;
 | 
						|
    bundle.add(new Interface1);
 | 
						|
    bundle.add(new Interface2);
 | 
						|
    bundle.add(new Interface1);
 | 
						|
    bundle.add(new Interface1);
 | 
						|
    QList<Interface1*> iface1Ptrs = Aggregation::query_all<Interface1>( &bundle );
 | 
						|
	\endcode
 | 
						|
	
 | 
						|
	Another key advantage of Aggregation is that, you can delete any one of the objects in the bundle to delete the whole
 | 
						|
	bundle. Example
 | 
						|
	
 | 
						|
	\code
 | 
						|
    Aggregation::Aggregate* bundle = new Aggregation::Aggregate;
 | 
						|
    bundle->add(new Interface1);
 | 
						|
    bundle->add(new Interface2);
 | 
						|
    Interface1* iface1Ptr = Aggregation::query<Interface1>(bundle);
 | 
						|
    delete iface1Ptr;
 | 
						|
    // deletes the bundle and all objects in it
 | 
						|
    // same as delete bundle
 | 
						|
	\endcode
 | 
						|
	
 | 
						|
	The use of aggregation will become clearer when we deal with real plugin examples in the coming chapters.
 | 
						|
*/
 |