forked from qt-creator/qt-creator
		
	
		
			
	
	
		
			668 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			668 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | /*! | |||
|  |     \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 | |||
|  | 	 | |||
|  | 	The \bold{readFile()} method is implemented to read a file and return its contents as a string. Before returning the file<6C>s | |||
|  | 	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 | |||
|  | 	 | |||
|  | 	*/ |