| 
									
										
										
										
											2010-06-21 15:27:59 +02:00
										 |  |  | /*! | 
					
						
							|  |  |  |     \page project-file-wizard.html | 
					
						
							|  |  |  |     \title 8. Project/File Wizards | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	New projects in Qt Creator can be created by clicking on the "File -> New" menu item and selecting the required project | 
					
						
							|  |  |  | 	type. Shown below is the new project dialog box. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\inlineimage qtc-newprojectdialog-8.png | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	In this chapter we will learn how to add new project types into the dialog box above. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\section1 8.1 Core::IWizard interface | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Qt Creator provides a Core::IWizard interface that can be implemented to support new project types. The interface is | 
					
						
							|  |  |  | 	defined as follows in \bold {src/plugins/coreplugin/dialogs/iwizard.h}. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     class CORE_EXPORT IWizard : public QObject | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Q_OBJECT | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         enum Kind {FileWizard,ClassWizard,ProjectWizard}; | 
					
						
							|  |  |  |         virtual Kind kind() const = 0; | 
					
						
							|  |  |  |         virtual QIcon icon() const = 0; | 
					
						
							|  |  |  |         virtual QString description() const = 0; | 
					
						
							|  |  |  |         virtual QString name() const = 0; | 
					
						
							|  |  |  |         virtual QString category() const = 0; | 
					
						
							|  |  |  |         virtual QString trCategory() const = 0; | 
					
						
							|  |  |  |         virtual QStringList runWizard(const QString &path, QWidget *parent) = 0; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Qt Creator supports the following types of new entities | 
					
						
							|  |  |  | 	\list | 
					
						
							|  |  |  | 	\o File | 
					
						
							|  |  |  |     \o Class | 
					
						
							|  |  |  | 	\o Project | 
					
						
							|  |  |  | 	\endlist | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\bold {Core::IWizard} has to be implemented to support any of the above project types. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\section2 8.1.1 Sample implementation of Core::IWizard | 
					
						
							|  |  |  | 	Let's implement the \bold {IWizard} interface to support a new project type called "Custom Project". The idea is to see the | 
					
						
							|  |  |  | 	new project type listed in the new project wizard that shows up on clicking "File -> New". | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\section3 Step 1: Implementing the Core::IWizard interface | 
					
						
							|  |  |  | 	Lets create a class called \bold {CustomProjectWizard} and subclass it from \bold {Core::IWizard}. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     class CustomProjectWizard : public Core::IWizard | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         CustomProjectWizard() { } | 
					
						
							|  |  |  |         ~CustomProjectWizard() { } | 
					
						
							|  |  |  |         Core::IWizard::Kind kind() const; | 
					
						
							|  |  |  |         QIcon icon() const; | 
					
						
							|  |  |  |         QString description() const; | 
					
						
							|  |  |  |         QString name() const; | 
					
						
							|  |  |  |         QString category() const; | 
					
						
							|  |  |  |         QString trCategory() const; | 
					
						
							|  |  |  |         QStringList runWizard(const QString &path, QWidget *parent); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Below we will discuss the implementation of each of the functions. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\bold{The kind()} function should be implemented to return the type of "new" project we support in our implementation of | 
					
						
							|  |  |  | 	\bold {IWizard}. Valid values are \bold {FileWizard},\bold{ClassWizard} and \bold {ProjectWizard}. In our implementation we return | 
					
						
							|  |  |  | 	\bold{ProjectWizard}. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     Core::IWizard::Kind CustomProjectWizard::kind() const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return IWizard::ProjectWizard; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	The \bold{icon()} implementation must return an icon to use against the project type in the New project dialog box. In our | 
					
						
							|  |  |  | 	implementation we return the Qt Creator icon itself. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     QIcon CustomProjectWizard::icon() const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return qApp->windowIcon(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	The \bold {description()},\bold {name()} and \bold {category()} methods must return some meta data of the new project/file/class | 
					
						
							|  |  |  | 	type we are providing in the \bold {IWizard} implementation. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     QString CustomProjectWizard::description() const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return "A custom project"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QString CustomProjectWizard::name() const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return "CustomProject"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QString CustomProjectWizard::category() const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return "FooCompanyInc"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	The \bold{trCategory()} method should be implemented to return a translated category string. This is the name that is | 
					
						
							|  |  |  | 	shown on the "New.." dialog box. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     QString CustomProjectWizard::trCategory() const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return tr("FooCompanyInc"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	If the user selects the "CustomProject" category supported by our implementation of \bold{IWizard} and selects Ok in the | 
					
						
							|  |  |  | 	"New.." dialog box; then the \bold{runWizard()} method is called. This method must be implemented to show a dialog box | 
					
						
							|  |  |  | 	or \bold{QWizard}, ask questions from the user about the new project/file/class being created and return a list of newly | 
					
						
							|  |  |  | 	created files. In our implementation of the \bold{IWizard} we will return an empty string list. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     QStringList CustomProjectWizard::runWizard(const QString &path, QWidget *parent) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Q_UNUSED(path); | 
					
						
							|  |  |  |         Q_UNUSED(parent); | 
					
						
							|  |  |  |         QMessageBox::information(parent, "Custom Wizard Dialog", "Hi there!"); | 
					
						
							|  |  |  |         return QStringList(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\section3 Step 2: Providing the wizard from a plugin | 
					
						
							|  |  |  | 	We implement a custom-project plugin using the same means as described in Chapter 2. The only change is in the | 
					
						
							|  |  |  | 	\bold{initialize()} method implementation of the plugin. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     bool CustomProjectPlugin::initialize(const QStringList& args, QString *errMsg) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Q_UNUSED(args); | 
					
						
							|  |  |  |         Q_UNUSED(errMsg); | 
					
						
							|  |  |  |         addAutoReleasedObject(new CustomProjectWizard); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\section3 Step 3: Testing the plugin | 
					
						
							|  |  |  | 	Upon compiling the plugin and restarting Qt Creator, we can notice the new project type in the "New.." dialog box. Take | 
					
						
							|  |  |  | 	a look at the screenshot below. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\inlineimage qtc-testplugin-8.png | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\section1 8.2 Predefined IWizard implementation - Core::BaseFileWizard | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Qt Creator's core provides a default implementation of the \bold{IWizard} interface in the form of the | 
					
						
							|  |  |  | 	\bold {Core::BaseFileWizard} class. This class implements provides default implementation of all the methods in the | 
					
						
							|  |  |  | 	\bold {IWizard} interface and adds some virtual methods of its own. To make use of the class, we need to subclass from it and | 
					
						
							|  |  |  | 	implement one or more methods. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\section2 8.2.1 Core::GeneratedFile and Core::GeneratedFiles | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Normally a new wizard (\bold{IWizard} implementation) is implemented to allow the user to provide some hints and have | 
					
						
							|  |  |  | 	one or more files automatically generated. The \bold{Core::GeneratedFile} helps abstract each of the files that need | 
					
						
							|  |  |  | 	generation. We will learn later on that within subclasses of \bold{Core::BaseFileWizard}, we create an instance of | 
					
						
							|  |  |  | 	\bold{Core::GeneratedFile} for each file that is automatically generated. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	The \bold{Core::GeneratedFile} class is defined as follows in \bold{coreplugin/basefilewizard.h} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     class GeneratedFile | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         GeneratedFile(); | 
					
						
							|  |  |  |         explicit GeneratedFile(const QString &path); | 
					
						
							|  |  |  |         GeneratedFile(const GeneratedFile &); | 
					
						
							|  |  |  |         GeneratedFile &operator=(const GeneratedFile &); | 
					
						
							|  |  |  |         ~GeneratedFile(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         QString path() const; | 
					
						
							|  |  |  |         void setPath(const QString &p); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         QString contents() const; | 
					
						
							|  |  |  |         void setContents(const QString &c); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         QString editorKind() const; | 
					
						
							|  |  |  |         void setEditorKind(const QString &k); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bool write(QString *errorMessage) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private: | 
					
						
							|  |  |  |         QSharedDataPointer<GeneratedFilePrivate> m_d; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     typedef QList<GeneratedFile> GeneratedFiles;	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Files that need to be generated by subclasses of \bold {Core::BaseFileWizard} are represented by the | 
					
						
							|  |  |  | 	\bold {Core::GeneratedFile} class. The class contains three key properties of a file that needs generation | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\list 1 | 
					
						
							|  |  |  | 	\o Name of the file (with its absolute path). | 
					
						
							|  |  |  | 	\o The kind of editor needed for editing the file. Some valid values for editor kind are | 
					
						
							|  |  |  | 		\list a | 
					
						
							|  |  |  | 		\o \bold{CppEditor::Constants::CPPEDITOR_KIND} | 
					
						
							|  |  |  | 		\o \bold{GenericProjectManager::Constants::PROJECT_KIND} | 
					
						
							|  |  |  | 		\o \bold{Git::Constants:: GIT_COMMAND_LOG_EDITOR_KIND} | 
					
						
							|  |  |  | 		\o \bold {Git::Constants:: C_GIT_COMMAND_LOG_EDITOR} | 
					
						
							|  |  |  | 	    \endlist | 
					
						
							|  |  |  | 	\o Contents of the file. | 
					
						
							|  |  |  | 	\endlist | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Suppose that we wanted to generate a C++ source file with the following contents | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     #include <iostream> | 
					
						
							|  |  |  |     int main() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         cout << "Hello World\n"; | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	We would use \bold{Core::GeneratedFile} for generating the above contents as follows | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     #include <coreplugin/basefilewizard.h> | 
					
						
							|  |  |  |     #include <cppeditor/cppeditorconstants.h> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Core::GeneratedFile genFile("C:/Path/To/Source.cpp"); | 
					
						
							|  |  |  |     genFile.setEditorKind(CppEditor::Constants::CPPEDITOR_KIND); | 
					
						
							|  |  |  |     genFile.setContents( | 
					
						
							|  |  |  |                             "#include <iostream>\n" | 
					
						
							|  |  |  |                             "\n" | 
					
						
							|  |  |  |                             "int main()\n" | 
					
						
							|  |  |  |                             "{\n" | 
					
						
							|  |  |  |                             " cout << \"Hello World\n\";\n" | 
					
						
							|  |  |  |                             " \n" | 
					
						
							|  |  |  |                             " return 0;\n" | 
					
						
							|  |  |  |                             "} | 
					
						
							|  |  |  |                       ); | 
					
						
							|  |  |  |     genFile.write(); | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\section2 8.2.2 The "Item Model" class wizard | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Suppose that we wanted to provide a new class wizard that helps automatically generate the skeleton of an item model | 
					
						
							|  |  |  | 	based on few hints like | 
					
						
							|  |  |  | 	\list | 
					
						
							|  |  |  | 	\o  Model Class Name | 
					
						
							|  |  |  | 	\o  Base Class Name (can be \bold {QAbstractItemModel},\bold QAbstractListModel and | 
					
						
							|  |  |  | 		\bold{QAbstractTableModel}) | 
					
						
							|  |  |  | 	\o  Header file name and | 
					
						
							|  |  |  |     \o  Source file name | 
					
						
							|  |  |  | 	\endlist | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Lets implement a plugin that will provide the new "Item Model" class wizard in Qt Creator. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\section3 Step 1: Design the class wizard page | 
					
						
							|  |  |  | 	Lets design a simple page in Qt Designer that accepts hints as described above. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\inlineimage qtc-designer-8.png | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	The design is saved as ModelNamePage.ui. | 
					
						
							|  |  |  | 	\section3 Step 2: Implement the class wizard page | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Lets import the UI in a Qt/C++ and provide easy to use methods to help fetch information from the page. First we design | 
					
						
							|  |  |  | 	a structure that captures all the "item model" class hints. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     struct ModelClassParameters | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QString className; | 
					
						
							|  |  |  |         QString headerFile; | 
					
						
							|  |  |  |         QString sourceFile; | 
					
						
							|  |  |  |         QString baseClass; | 
					
						
							|  |  |  |         QString path; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Next we declare a wizard page class that imports the UI designed in the previous step and provides methods to access | 
					
						
							|  |  |  | 	the hints provided by the user in the page. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     #include <QWizardPage> | 
					
						
							|  |  |  |     #include "ui_ModelNamePage.h" | 
					
						
							|  |  |  |     class ModelNamePage : public QWizardPage | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Q_OBJECT | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         ModelNamePage(QWidget* parent=0); | 
					
						
							|  |  |  |         ~ModelNamePage(); | 
					
						
							|  |  |  |         void setPath(const QString& path); | 
					
						
							|  |  |  |         ModelClassParameters parameters() const; | 
					
						
							|  |  |  |     private slots: | 
					
						
							|  |  |  |         void on_txtModelClass_textEdited(const QString& txt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private: | 
					
						
							|  |  |  |         Ui::ModelNamePage ui; | 
					
						
							|  |  |  |         QString path; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The constructor and destructor are straight forward and easy to understand. | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     ModelNamePage::ModelNamePage(QWidget* parent) | 
					
						
							|  |  |  |     :QWizardPage(parent) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         setTitle("Enter model class information"); | 
					
						
							|  |  |  |         setSubTitle("The header and source file names will be derived from the class name"); | 
					
						
							|  |  |  |         ui.setupUi(this); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  |     ModelNamePage::~ModelNamePage() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	The \bold{setPath()} method basically stores the path in the private variable. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     void ModelNamePage::setPath(const QString& path) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         this->path = path; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	The \bold{on_txtModelClass_textEdited()} slot computes the header and source file names based on the | 
					
						
							|  |  |  | 	classname. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     void ModelNamePage::on_txtModelClass_textEdited(const QString& txt) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         ui.txtHeaderFile->setText(txt + ".h"); | 
					
						
							|  |  |  |         ui.txtImplFile->setText(txt + ".cpp"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Finally the \bold{parameters()} method returns all the hints entered by the user in a ModelClassParameters | 
					
						
							|  |  |  | 	instance. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     ModelClassParameters ModelNamePage::parameters() const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         ModelClassParameters params; | 
					
						
							|  |  |  |         params.className = ui.txtModelClass->text(); | 
					
						
							|  |  |  |         params.headerFile = ui.txtHeaderFile->text(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         params.sourceFile = ui.txtImplFile->text(); | 
					
						
							|  |  |  |         params.baseClass = ui.cmbBaseClass->currentText(); | 
					
						
							|  |  |  |         params.path = path; | 
					
						
							|  |  |  |         return params; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\section3 Step 3: Subclass Core::BaseFileWizard | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	The\bold {Core::BaseFileWizard} class is defined as follows in \bold{coreplugin/basefilewizard.h} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     class CORE_EXPORT BaseFileWizard : public IWizard | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     public:     | 
					
						
							|  |  |  |         virtual ~BaseFileWizard(); | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         // IWizard | 
					
						
							|  |  |  |         virtual Kind kind() const; | 
					
						
							|  |  |  |         virtual QIcon icon() const; | 
					
						
							|  |  |  |         virtual QString description() const; | 
					
						
							|  |  |  |         virtual QString name() const; | 
					
						
							|  |  |  |         virtual QString category() const; | 
					
						
							|  |  |  |         virtual QString trCategory() const; | 
					
						
							|  |  |  |         virtual QStringList runWizard(const QString &path, QWidget *parent); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     protected: | 
					
						
							|  |  |  |         typedef QList<QWizardPage *> WizardPageList; | 
					
						
							|  |  |  |         explicit BaseFileWizard(const BaseFileWizardParameters ¶meters,QObject *parent = 0); | 
					
						
							|  |  |  |                      | 
					
						
							|  |  |  |         virtual QWizard *createWizardDialog(QWidget *parent,const QString &defaultPath, | 
					
						
							|  |  |  |                                             const WizardPageList &extensionPages) const = 0; | 
					
						
							|  |  |  |                                  | 
					
						
							|  |  |  |         virtual GeneratedFiles generateFiles(const QWizard *w,QString *errorMessage) const = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         virtual bool postGenerateFiles(const GeneratedFiles &l,QString *errorMessage); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\underline {\bold{Note: Some methods from the actual BaseFileWizard class are not shown here.}} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	The \bold{BaseFileWizard} class implements the \bold{IWizard} interface and offers three new functions | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\list | 
					
						
							|  |  |  | 	\o  \bold{createWizardDialog} - This function can be over-ridden by subclasses to provide a wizard that the | 
					
						
							|  |  |  | 		\bold{runWizard()} method is supposed to show. | 
					
						
							|  |  |  |         \list  | 
					
						
							|  |  |  | 	    \o The \bold{parent} parameter should be used as the parent widget of the returned QWizard | 
					
						
							|  |  |  |         \o The \bold{defaultPath} parameter should be the default location for generated files | 
					
						
							|  |  |  |         \o The \bold{extensionPages} parameter lists out all the pages that should be shown in the wizard by default. | 
					
						
							|  |  |  | 	    \endlist | 
					
						
							|  |  |  | 	\o 	\bold{generateFiles} - This method is called after the user is done with the wizard. Implementations of this | 
					
						
							|  |  |  | 		method must create the required files as instances of \bold{Core::GeneratedFile} class. | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  | 	\o \bold{postGenerateFiles} - This method is called after \bold{generateFiles()} returns. The default | 
					
						
							|  |  |  | 	   implementation opens the newly generated files; however subclasses can choose to do anything they want. | 
					
						
							|  |  |  | 	\endlist | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	We subclass the BaseFileWizard as follows for our "item model" wizard | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     #include <coreplugin/basefilewizard.h> | 
					
						
							|  |  |  |     class ModelClassWizard : public Core::BaseFileWizard | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Q_OBJECT | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         ModelClassWizard(const Core::BaseFileWizardParameters ¶meters, | 
					
						
							|  |  |  |         QObject *parent = 0); | 
					
						
							|  |  |  |         ~ModelClassWizard(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         QWizard *createWizardDialog(QWidget *parent, | 
					
						
							|  |  |  |         const QString &defaultPath, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const WizardPageList &extensionPages) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Core::GeneratedFiles generateFiles(const QWizard *w, | 
					
						
							|  |  |  |         QString *errorMessage) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private: | 
					
						
							|  |  |  |         QString readFile(const QString& fileName, | 
					
						
							|  |  |  |         const QMap<QString,QString>& replacementMap) const; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	The constructor and destructor methods are straight forward and easy to understand. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     ModelClassWizard::ModelClassWizard( | 
					
						
							|  |  |  |     const Core::BaseFileWizardParameters ¶meters,QObject *parent) | 
					
						
							|  |  |  |     : Core::BaseFileWizard(parameters, parent) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     ModelClassWizard::~ModelClassWizard() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	The \bold{createWizardDialog()} method is implemented to create a \bold{QWizard} with its first page as the | 
					
						
							|  |  |  | 	\bold{ModelNamePage} class implemented step 2. Other default pages are added as usual. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     QWizard* ModelClassWizard::createWizardDialog( | 
					
						
							|  |  |  |     QWidget *parent, | 
					
						
							|  |  |  |     const QString &defaultPath, | 
					
						
							|  |  |  |     const WizardPageList &extensionPages) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // Create a wizard | 
					
						
							|  |  |  |         QWizard* wizard = new QWizard(parent); | 
					
						
							|  |  |  |         wizard->setWindowTitle("Model Class Wizard"); | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         // Make our page as first page | 
					
						
							|  |  |  |         ModelNamePage* page = new ModelNamePage(wizard); | 
					
						
							|  |  |  |         int pageId = wizard->addPage(page); | 
					
						
							|  |  |  |         wizard->setProperty("_PageId_", pageId); | 
					
						
							|  |  |  |         page->setPath(defaultPath); | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         // Now add the remaining pages | 
					
						
							|  |  |  |         foreach (QWizardPage *p, extensionPages) | 
					
						
							|  |  |  |         wizard->addPage(p); | 
					
						
							|  |  |  |         return wizard; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2011-05-31 15:53:35 +00:00
										 |  |  | 	The \bold{readFile()} method is implemented to read a file and return its contents as a string. Before returning the file's | 
					
						
							| 
									
										
										
										
											2010-06-21 15:27:59 +02:00
										 |  |  | 	contents as string, the function uses the replacement table passed as second parameter to fix the string. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     QString ModelClassWizard::readFile(const QString& fileName, const QMap<QString,QString>& | 
					
						
							|  |  |  |     replacementMap) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QFile file(fileName); | 
					
						
							|  |  |  |         file.open(QFile::ReadOnly); | 
					
						
							|  |  |  |         QString retStr = file.readAll(); | 
					
						
							|  |  |  |         QMap<QString,QString>::const_iterator it = replacementMap.begin(); | 
					
						
							|  |  |  |         QMap<QString,QString>::const_iterator end = replacementMap.end(); | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         while(it != end) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             retStr.replace(it.key(), it.value()); | 
					
						
							|  |  |  |             ++it; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return retStr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Suppose we have a file (\bold{sample.txt}) whose contents are as follows | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     #ifndef {{UPPER_CLASS_NAME}}_H | 
					
						
							|  |  |  |     #define {{UPPER_CLASS_NAME}}_H | 
					
						
							|  |  |  |     #include <{{BASE_CLASS_NAME}}> | 
					
						
							|  |  |  |     struct {{CLASS_NAME}}Data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class {{CLASS_NAME}} : public {{BASE_CLASS_NAME}} | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Q_OBJECT | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         {{CLASS_NAME}}(QObject* parent=0); | 
					
						
							|  |  |  |         ~{{CLASS_NAME}}(); | 
					
						
							|  |  |  |         int rowCount(const QModelIndex& parent) const; | 
					
						
							|  |  |  |         QVariant data(const QModelIndex& index, int role) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private: | 
					
						
							|  |  |  |         {{CLASS_NAME}}Data* d; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #endif // {{UPPER_CLASS_NAME}}_H | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Lets say we wanted to replace the hints in {{xyz}} with something more appropriate, we could use the following code | 
					
						
							|  |  |  | 	snippet. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  | 	QMap<QString,QString> replacementMap; | 
					
						
							|  |  |  | 	replacementMap["{{UPPER_CLASS_NAME}}"] = "LIST_MODEL"; | 
					
						
							|  |  |  | 	replacementMap["{{BASE_CLASS_NAME}}"] = "QAbstractListModel"; | 
					
						
							|  |  |  | 	replacementMap["{{CLASS_NAME}}"] = "ListModel"; | 
					
						
							|  |  |  | 	QString contents = readFile("Sample.txt", replacementTable); | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	When the above code is executed, the contents string will contain | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     #ifndef LIST_MODEL_H | 
					
						
							|  |  |  |     #define LIST_MODEL_H | 
					
						
							|  |  |  |     #include <QAbstractListModel> | 
					
						
							|  |  |  |     struct ListModelData; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class ListModel : public QAbstractListModel | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Q_OBJECT | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         ListModel(QObject* parent=0); | 
					
						
							|  |  |  |         ~ListModel(); | 
					
						
							|  |  |  |         int rowCount(const QModelIndex& parent) const; | 
					
						
							|  |  |  |         QVariant data(const QModelIndex& index, int role) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private: | 
					
						
							|  |  |  |         ListModelData* d; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     #endif // LIST_MODEL_H | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Seems like magic isnt it? ?. We create similar "template"  header and source files for item, list and table model classes | 
					
						
							|  |  |  | 	and create a resource for use in our project. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Now, lets look at the implementation of the \bold{generateFiles()} method. This method basically creates two | 
					
						
							|  |  |  | 	\bold{Core::GeneratedFile} instances and populates them with appropriate data before returning them in a list. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     Core::GeneratedFiles ModelClassWizard::generateFiles( | 
					
						
							|  |  |  |     const QWizard *w,QString *errorMessage) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Q_UNUSED(errorMessage); | 
					
						
							|  |  |  |         Core::GeneratedFiles ret; | 
					
						
							|  |  |  |         int pageId = w->property("_PageId_").toInt(); | 
					
						
							|  |  |  |         ModelNamePage* page = qobject_cast<ModelNamePage*>(w->page(pageId)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if(!page) | 
					
						
							|  |  |  |         return ret; | 
					
						
							|  |  |  |         ModelClassParameters params = page->parameters(); | 
					
						
							|  |  |  |         QMap<QString,QString> replacementMap; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         replacementMap["{{UPPER_CLASS_NAME}}"] = params.className.toUpper(); | 
					
						
							|  |  |  |         replacementMap["{{BASE_CLASS_NAME}}"] = params.baseClass; | 
					
						
							|  |  |  |         replacementMap["{{CLASS_NAME}}"] = params.className; | 
					
						
							|  |  |  |         replacementMap["{{CLASS_HEADER}}"] = QFileInfo(params.headerFile).fileName(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Core::GeneratedFile headerFile(params.path + "/" + params.headerFile); | 
					
						
							|  |  |  |         headerFile.setEditorKind(CppEditor::Constants::CPPEDITOR_KIND); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Core::GeneratedFile sourceFile(params.path + "/" + params.sourceFile); | 
					
						
							|  |  |  |         sourceFile.setEditorKind(CppEditor::Constants::CPPEDITOR_KIND); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if(params.baseClass == "QAbstractItemModel") | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             headerFile.setContents(readFile(":/CustomProject/ItemModelHeader", replacementMap) ); | 
					
						
							|  |  |  |             sourceFile.setContents(readFile(":/CustomProject/ItemModelSource", replacementMap) ); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         else if(params.baseClass == "QAbstractTableModel") | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             headerFile.setContents(readFile(":/CustomProject/TableModelHeader", replacementMap) ); | 
					
						
							|  |  |  |             sourceFile.setContents(readFile(":/CustomProject/TableModelSource", replacementMap) ); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         else if(params.baseClass == "QAbstractListModel") | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             headerFile.setContents(readFile(":/CustomProject/ListModelHeader", replacementMap) ); | 
					
						
							|  |  |  |             sourceFile.setContents(readFile(":/CustomProject/ListModelSource", replacementMap) ); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ret << headerFile << sourceFile; | 
					
						
							|  |  |  |         return ret; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\section3 Step 4: Implementing the plugin | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	We implement the item model wizard plugin using the same means as described in Chapter 2. The only change is in the | 
					
						
							|  |  |  | 	\bold {initialize()} method implementation of the plugin. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\code | 
					
						
							|  |  |  |     bool ItemModelWizard::initialize(const QStringList& args, QString *errMsg) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Q_UNUSED(args); | 
					
						
							|  |  |  |         Q_UNUSED(errMsg); | 
					
						
							|  |  |  |         Core::BaseFileWizardParameters params; | 
					
						
							|  |  |  |         params.setKind(Core::IWizard::ClassWizard); | 
					
						
							|  |  |  |         params.setIcon(qApp->windowIcon()); | 
					
						
							|  |  |  |         params.setDescription("Generates an item-model class"); | 
					
						
							|  |  |  |         params.setName("Item Model"); | 
					
						
							|  |  |  |         params.setCategory("FooCompany"); | 
					
						
							|  |  |  |         params.setTrCategory(tr("FooCompany")); | 
					
						
							|  |  |  |         addAutoReleasedObject(new ModelClassWizard(params, this)); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 	\endcode | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\section3 Step 5: Testing the plugin | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Upon compiling the plugin and restarting Qt Creator, we can notice the new project type in the "New.." dialog box. The | 
					
						
							|  |  |  | 	following screenshots showcase the wizard that was just implemented. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\inlineimage qtc-newitemmodel-8.png | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Upon selecting the "Item Model" class wizard, we can see the ModelNamePage in a custom wizard. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\inlineimage qtc-customwizardone-8.png | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	We enter the appropriate details and click "Next" Qt Creator then shows us a built-in page to allow addition of the | 
					
						
							|  |  |  | 	newly generated files into the current project. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\inlineimage qtc-customwizardtwo-8.png | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Upon clicking "Finish", we can notice the newly generated files in the editor. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	\inlineimage qtc-editor-8.png | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	*/ |