diff options
author | Abhishek Patil <abhishek.patil@vcreatelogic.com> | 2010-06-21 15:27:59 +0200 |
---|---|---|
committer | con <qtc-committer@nokia.com> | 2010-06-21 17:32:15 +0200 |
commit | abcb9358c26c240c409df15300507a90aef37f48 (patch) | |
tree | 56f03e33746d3c9186b4a8b0f93565d149263c2c /doc/pluginhowto | |
parent | cdbe93285bee1d88518d9b002a908392f9c6bafb (diff) |
Qt Creator Plugin HOWTO documentation first and second cut
Signed-off-by: Abhishek Patil <abhishek.patil@vcreatelogic.com>
Merge-request: 145
Reviewed-by: con <qtc-committer@nokia.com>
Diffstat (limited to 'doc/pluginhowto')
68 files changed, 4605 insertions, 0 deletions
diff --git a/doc/pluginhowto/adv-find-filter.qdoc b/doc/pluginhowto/adv-find-filter.qdoc new file mode 100644 index 00000000000..52c133851fc --- /dev/null +++ b/doc/pluginhowto/adv-find-filter.qdoc @@ -0,0 +1,7 @@ +/*! + \page adv-find-filter.html + \title 15.Adding "advanced" find filter + + This page needs to be written still! + + */ diff --git a/doc/pluginhowto/classic.css b/doc/pluginhowto/classic.css new file mode 100644 index 00000000000..400ee71168c --- /dev/null +++ b/doc/pluginhowto/classic.css @@ -0,0 +1,102 @@ +h3.fn,span.fn +{ + margin-left: 1cm; + text-indent: -1cm; +} + +a:link +{ + color: #004faf; + text-decoration: none +} + +a:visited +{ + color: #672967; + text-decoration: none +} + +td.postheader +{ + font-family: sans-serif +} + +tr.address +{ + font-family: sans-serif +} + +body +{ + background: #ffffff; + color: black +} + +table tr.odd { + background: #f0f0f0; + color: black; +} + +table tr.even { + background: #e4e4e4; + color: black; +} + +table.annotated th { + padding: 3px; + text-align: left +} + +table.annotated td { + padding: 3px; +} + +table tr pre +{ + padding-top: none; + padding-bottom: none; + padding-left: none; + padding-right: none; + border: none; + background: none +} + +tr.qt-style +{ + background: #a2c511; + color: black +} + +body pre +{ + padding: 0.2em; + border: #e7e7e7 1px solid; + background: #f1f1f1; + color: black +} + +span.preprocessor, span.preprocessor a +{ + color: darkblue; +} + +span.comment +{ + color: darkred; + font-style: italic +} + +span.string,span.char +{ + color: darkgreen; +} + +.subtitle +{ + font-size: 0.8em +} + +.small-subtitle +{ + font-size: 0.65em +} diff --git a/doc/pluginhowto/editor-type.qdoc b/doc/pluginhowto/editor-type.qdoc new file mode 100644 index 00000000000..d877d39bf27 --- /dev/null +++ b/doc/pluginhowto/editor-type.qdoc @@ -0,0 +1,998 @@ +/*! + \page editor-type.html + \title 10. Adding editor type + + At the very basic level Qt Creator is a text editor. On top of supporting editing of text files, Qt Creator also allows users + to edit UI (Qt Designer) files, QRC (Resource) files, PRO/PRI (Project) files and EXE/DLL/SO (Binary) files. + + \inlineimage qtc-editor-10.png + + + In this chapter we will understand how to provide editors for custom file formats, specifically the HTML file format. + When we are done, we will be able to load HTML files from the local file system and view/edit them. + + \inlineimage qtc-fileformat-10.png + + \section1 10.1 Core Classes and Interfaces + + To support a new editor type, we need to + \list + \o Implement a plugin \bold {(Core::IPlugin} implementation) class that exposes an "editor factory". Chapter 2 in this + document provides a detailed description on creating plugins by implementing the \bold {Core::IPlugin interface}. + + \o Implement the editor factory, \bold {Core::IEditorFactory}, interface. This interface implementation provides + methods to help create instances of "editor" object for a specified mime-type. + \o Implement the editor, \bold {Core::IEditor}, interface. This interface implementation provides a widget that helps + edit a file type (for example: HTML, ODF etc). Editors must provide access to the "file" that it is currently being + shown or edited. + \o Implement the file, \bold{Core::IFile}, interface to help customize the loading and saving of data into disk files. + + \endlist + + In the following subsections, we will take a look at each of the above mentioned core interfaces. + + \section2 10.1.1 The Core::IFile interface + + This interface abstracts file operations from the user-interface point of view. It provides virtual methods to load and + save files, given a file name. It also helps in understanding the mime-type of file and value of certain flags like “modified” + and "read-only". The \bold{Core::IFile} interface is declared as follows in src/plugins/coreplugin/ifile.h + + \code + namespace Core + { + class IFile : public QObject + { + Q_OBJECT + + public: + enum ReloadBehavior { AskForReload, ReloadAll, ReloadPermissions, ReloadNone }; + IFile(QObject *parent = 0) : QObject(parent) {} + virtual ~IFile() {} + virtual bool save(const QString &fileName = QString()) = 0; + virtual QString fileName() const = 0; + virtual QString defaultPath() const = 0; + virtual QString suggestedFileName() const = 0; + virtual QString mimeType() const = 0; + virtual bool isModified() const = 0; + virtual bool isReadOnly() const = 0; + virtual bool isSaveAsAllowed() const = 0; + virtual void modified(ReloadBehavior *behavior) = 0; + virtual void checkPermissions() {} + + signals: + void changed(); + }; + } // namespace Core + + \endcode + + You may be wondering: "Why go for another interface called \bold {IFile} when we already have a class called \bold {QFile} that + provides the exact same functionality?" Good point. The responses to this question are listed below + + \list + \o \bold {IFile} has to take care of loading contents of a filename into an editor \bold {(Core::IEditor} interface discussed + next). \bold {QFile} on the other hand simply loads contents into a \bold {QByteArray}. + + \o \bold {IFile} has to emit the \bold {modified()} signal when the user edits the contents of the file in the editor, but the + actual disk-file contents have not been modified. \bold {QFile} emits the \bold {bytesWritten()} signal only when the + disk-file contents have been modified. + + \o \bold {IFile} has to handle how a modified file, on the disk, is reloaded. \bold {QFile} on the other-hand doesn’t need to + handle this. + \endlist + + We will learn more about implementing the \bold {Core::IFile} interface in a future section. + + \section2 10.1.2 The Core::IEditor interface + Implementations of the \bold {Core::IEditor} interface provide editors for different types of files. It is declared as follows + in src/plugins/coreplugin/editormanager/ieditor.h. + + \code + namespace Core + { + class IContext : public QObject + { + Q_OBJECT + + public: + IContext(QObject *parent = 0) : QObject(parent) {} + virtual ~IContext() {} + virtual QList<int> context() const = 0; + virtual QWidget *widget() = 0; + virtual QString contextHelpId() const { return QString(); } + }; + + class IEditor : public IContext + { + Q_OBJECT + + public: + IEditor(QObject *parent = 0) : IContext(parent) {} + virtual ~IEditor() {} + virtual bool createNew(const QString &contents = QString()) = 0; + virtual bool open(const QString &fileName = QString()) = 0; + virtual IFile *file() = 0; + virtual const char *kind() const = 0; + virtual QString displayName() const = 0; + virtual void setDisplayName(const QString &title) = 0; + virtual bool duplicateSupported() const = 0; + virtual IEditor *duplicate(QWidget *parent) = 0; + virtual QByteArray saveState() const = 0; + virtual bool restoreState(const QByteArray &state) = 0; + virtual int currentLine() const { return 0; } + virtual int currentColumn() const { return 0; } + virtual bool isTemporary() const = 0; + virtual QToolBar *toolBar() = 0; + + signals: + void changed(); + }; + } // namespace Core + + \endcode + + The \bold {Core::IEditor} interface primary provides access to + \list + \o An \underline{editor widget}\bold{ (Core::IEditor::widget()} method) that Qt Creator can use to display contents of the + file being edited. + + \o The file \bold {(Core::IEditor::file() } method), which is a \bold {Core::IFile} implementation, that Qt Creator + can use to trigger the loading and saving of data from disk-files. + + \o An optional custom toolbar that Qt Creator can show whenever the editor becomes active. + + \o The current position of the edit-cursor within the file \bold {(Core::IEditor::currentLine()} and + \bold {Core::IEditor::currentColumn())} + + \o The name that needs to be displayed in the \underline{open-files combo box}. + \endlist + + Take a look at the following screenshot to get a better understanding. + + \inlineimage qtc-ieditor-10.png + + + We will understand more about implementing the \bold {Core::IEditor} interface in a future section. + + + \section2 10.1.3 The Core::IEditorFactory interface + + Implementations of \bold {Core::IEditorFactory} interface provide methods to create instances of Core::IEditor + for a supported mime-type. It is declared as follows in src/plugins/coreplugin/editormanager/ieditorfactory.h. + + \code + namespace Core + { + class IFileFactory : public QObject + { + Q_OBJECT + + public: + IFileFactory(QObject *parent = 0) : QObject(parent) {} + virtual ~IFileFactory() {} + virtual QStringList mimeTypes() const = 0; + virtual QString kind() const = 0; + virtual Core::IFile *open(const QString &fileName) = 0; + }; + + class IEditorFactory : public Core::IFileFactory + { + Q_OBJECT + + public: + IEditorFactory(QObject *parent = 0) : IFileFactory(parent) {} + virtual ~IEditorFactory() {} + virtual IEditor *createEditor(QWidget *parent) = 0; + }; + } // namespace Core + + \endcode + + The \bold {IEditorFactory::mimeType()} method should be implemented to return the mime-type supported by the + editor for which the factory is implemented. The \bold {IEditorFactory::createEditor()} method should be + implemented to actually create a concrete editor and return the same. + + \section2 10.1.4 The Core::MimeDatabase class + + The \bold {Core::MimeDatabase} class keeps track of all the mime-types supported by Qt Creator. It also helps figure out + the mime-type of a given file. Take the following code for example: + + \code + #include <coreplugin/mimedatabase.h> + Core::ICore* core = Core::ICore::instance(); + Core::MimeDatabase* mdb = core->mimeDatabase(); + Core::MimeType type1 = mdb->findByFile( QFileInfo("C:/Temp/sample.html") ); + + qDebug("File Type for sample.html = %s", qPrintable(type1.type())); + Core::MimeType type2 = mdb->findByFile( QFileInfo("C:/Temp/TextEdit/Main.cpp") ); + + qDebug("File Type for Main.cpp = %s", qPrintable(type2.type())); + Core::MimeType type3 = mdb->findByFile( QFileInfo("C:/Temp/TextEdit/TextEdit.pro") ); + + qDebug("File Type for TextEdit.pro = %s", qPrintable(type3.type())); + \endcode + + When the above code is compiled and executed, we get the following as output. + \code + File Type for sample.html = text/plain + File Type for Main.cpp = text/x-c++src + File Type for TextEdit.pro = text/plain + \endcode + + The \bold { Core::MimeDatabase } uses filename suffix, glob patterns and "magic" matchers to figure out the mime-type of + a given filename. At this point however, lets not dig into how the mime-database manages to figure out the mime-type + from a filename; it is enough if we know that mime-type discovery is possible. + + The \bold Core::IEditorFactory interface, as described in the previous section, provides an editor \bold{(Core::IEditor} + implementation) for a specific mime-type. The following points help us understand how Qt Creator manages to pick the + appropriate \bold {Core::IEditorFactory} for a given filename. + + \list 1 + \o User selects File -> Open and chooses a file to open + + \o Qt Creator uses \bold {Core::MimeDatabase} to figure out the mime-type of the selected file + + \o Qt Creator runs through all \bold {Core::IEditorFactory} implementations and picks the editor-factory that + supports the mime-type evaluated in step 2 + + \o Qt Creator asks the selected editor factory to create an editor (Core::IEditor implementation) + + \o The widget returned by \bold {Core::IEditor::widget()} is then shown in the workspace area of the mainwindow + + \o The \bold {Core::IEditor::open()} method is then called to open the file selected in step 1. + + \endlist + + \section2 10.1.5 Adding a new mime-type + + If we wanted to support a new editor type, then we need to register the mime-type supported by the new editor with + the \bold {Core::MimeDatabase}. Several mechanisms can be used to register a new mime-type. In this chapter we will + learn the simplest way to register a new mime-type from an XML file. + Suppose that we wanted to register the \bold {text/html} mime-type and associate it with \bold {*.html} filenames. We create an XML + file as and save it as \bold {text-html-mimetype.xml}. + + \code + <?xml version="1.0" encoding="UTF-8"?> + <mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'> + <mime-type type="text/html"> + <sub-class-of type="text/plain"/> + <comment>HTML File</comment> + <glob pattern="*.html"/> + </mime-type> + </mime-info> + \endcode + + We then register the mime-type described in the XML file (above) using the + \bold {Core::MimeDatabase::addMimeTypes()} method. Take a look at the code snippet below + + \code + Core::ICore* core = Core::ICore::instance(); + Core::MimeDatabase* mdb = core->mimeDatabase(); + QString errMsg; + bool success = mdb->addMimeTypes("text-html-mimetype.xml", errMsg); + \endcode + + Once registered, Qt Creator will begin to map all *.html filenames to text/plain mime-type. + + \section1 10.2 Providing a HTML Editor in Qt Creator + + Let's implement a plugin for Qt Creator that provides support for viewing and editing HTML files. The following + screenshots show the expected results. + + The user select a HTML file to open using the standard File -> Open menuitem. + + \inlineimage qtc-menuitem-10.png + + + Upon selecting a HTML file, Qt Creator will show a custom editor as shown below. + + + \inlineimage qtc-customeditor-10.png + + + Notice that the editor has two tabs called "Preview" and "Source" at the bottom edge. + + + \inlineimage qtc-editortabs-10.png + + + Clicking on the "Source" tab shows the HTML code in a \bold { QPlainTextEdit} widget. + + \inlineimage qtc-plaintextedit-10.png + + + Users can edit the HTML in this tab, and when he moves back to the "preview" tab the changes are reflected. Users can + continue to make use of File -> Save menu item to save changes to the HTML file. + + For achieving the above we implement the following classes + + \table + \header + \o Class + \o Interface\\Baseclass + \o Description + + \row + \o \c{HtmlEditorWidget} + \o \bold {QTabWidget} + \o Provides a tab widget with two tabs, one for showing the + HTML preview and other for showing the HTML code. + + \row + \o \c{HtmlFile} + \o \bold {Core::IFile} + \o Implements the \bold {IFile} interface for the file shown in + \bold {HtmlEditorWidget}. + \row + \o \c {HtmlEditor} + \o \bold {Core::IEditor} + \o Implements the \bold{IEditor} interface for managing the + \bold{HtmlEditorWidget} and hooking up an \bold{IFile} with it. + \row + \o \c {HtmlEditorFactory} + \o \bold {Core::IEditorFactory} + \o Implements the \bold{IEditorFactory} interface for creating + instances of \bold{IEditor} for the "text/html" mime-type. + + \row + \o \c {HtmlEditorPlugin} + \o \bold {Core::IPlugin } + \o Implements the \bold{IPlugin} interface for hooking all of the + above into Qt Creator. + \endtable + + For every html file there is an instance each of \bold{HtmlEditorWidget},\bold{HtmlFile} and \bold{HtmlEditor} handling the + loading, editing and saving functionality. In our implementation we provide mechanisms to help establish association + between instances of the above classes that handle the same file. + + \section2 10.2.1 Implementing the HTML Editor Widget + By default, Qt Creator uses a plain-text editor widget to display the contents of the HTML file being edited. We would + like to offer a tabbed widget as editor. One of the tabs shows the HTML preview, the other shows the HTML code. The + class \bold {HtmlEditorWidget} is our editor; and it is declared as follows. + + \code + struct HtmlEditorWidgetData; + class HtmlEditorWidget : public QTabWidget + { + Q_OBJECT + + public: + HtmlEditorWidget(QWidget* parent = 0); + ~HtmlEditorWidget(); + void setContent(const QByteArray& ba, const QString& path=QString()); + QByteArray content() const; + QString title() const; + + protected slots: + void slotCurrentTabChanged(int tab); + void slotContentModified(); + + signals: + void contentModified(); + void titleChanged(const QString&); + + private: + HtmlEditorWidgetData* d; + }; + \endcode + + The constructor basically creates two different views from \bold{QWebView} and \bold {QPlainTextEdit} and adds them as tabs + at the bottom position of the tab widget. We will learn about the signal-slot connections later. + + \code + HtmlEditorWidget::HtmlEditorWidget(QWidget* parent):QTabWidget(parent) + { + d = new HtmlEditorWidgetData; + d->webView = new QWebView; + d->textEdit = new QPlainTextEdit; + + addTab(d->webView, "Preview"); + addTab(d->textEdit, "Source"); + + setTabPosition(QTabWidget::South); + setTabShape(QTabWidget::Triangular); + + d->textEdit->setFont( QFont("Courier", 12) ); + connect(this, SIGNAL(currentChanged(int)),this, SLOT(slotCurrentTabChanged(int))); + connect(d->textEdit, SIGNAL(textChanged()),this, SLOT(slotContentModified())); + connect(d->webView, SIGNAL(titleChanged(QString)),this, SIGNAL(titleChanged(QString))); + d->modified = false; + } + \endcode + + + The destructor does nothing other than deleting the private \bold{"d"} object. + + \code + HtmlEditorWidget::~HtmlEditorWidget() + { + delete d; + } + \endcode + + The setContent method simply sets the contents of html file to \bold{webView} and \bold {textEdit}. + + \code + void HtmlEditorWidget::setContent(const QByteArray& ba, const QString& path) + { + if(path.isEmpty()) + d->webView->setHtml(ba); + else + d->webView->setHtml(ba, "file:///" + path); + d->textEdit->setPlainText(ba); + d->modified = false; + d->path = path; + } + \endcode + + The \bold {content} method returns the contents of the \bold {textEdit}. + + \code + QByteArray HtmlEditorWidget::content() const + { + QString htmlText = d->textEdit->toPlainText(); + return htmlText.toAscii(); + } + \endcode + + The \bold {title()} method returns the title from the webView. The string returned from this method will be used in the + open-file combo box. + + \inlineimage qtc-title-10.png + + \code + QString HtmlEditorWidget::title() const + { + return d->webView->title(); + } + \endcode + + The following connection made in the constructor of \bold {HtmlEditorWidget} makes sure that when the user moves from + "source" to "preview" tab, the HTML content viewed in the preview tab is updated. + + \code + connect(this, SIGNAL(currentChanged(int)),this, SLOT(slotCurrentTabChanged(int))); + + void HtmlEditorWidget::slotCurrentTabChanged(int tab) + { + if(tab == 0 && d->modified) + setContent( content(), d->path ); + } + \endcode + + + Following connection makes sure that \bold {setContentModified()} slot is called whenever user edits the html source. + The slot \bold {setContentModified()} simply sets modified to true and emits the signal "contentModified" We will + know the usability of this signal later in the section while understanding \bold {HtmlFile} class. + + \code + connect(d->textEdit, SIGNAL(textChanged()), this, SLOT(slotContentModified())); + + void HtmlEditorWidget::slotContentModified() + { + d->modified = true; + emit contentModified(); + } + \endcode + + Following connection simply emits \bold {titleChanged()} signal on title change of \bold {webView}. We will know more about + this signal later. + + \code + connect(d->webView, SIGNAL(titleChanged(QString)),this, SIGNAL(titleChanged(QString))); + \endcode + + \section2 10.2.2 Implementing the Core::IFile interface + + We implement the \bold {Core::IFile} interface in the \bold {HtmlFile} class. Apart from implementing the pure virtual + functions from \bold {IFile} (introduced in section 5.1.1); the \bold {HtmlFile} class has methods to get/set the modified flag + which indicates the modification status of the file contents. + + \code + struct HtmlFileData; + class HtmlFile : public Core::IFile + { + Q_OBJECT + + public: + HtmlFile(HtmlEditor* editor, HtmlEditorWidget* editorWidget); + ~HtmlFile(); + void setModified(bool val=true); + // Declare all the virtual functions from IFile here.. + protected slots: + void modified() { setModified(true); } + private: + HtmlFileData* d; + }; + + struct HtmlFileData + { + HtmlFileData(): mimeType(HtmlEditorConstants::C_HTMLEDITOR_MIMETYPE),editorWidget(0), editor(0), modified(false) { } + const QString mimeType; + HtmlEditorWidget* editorWidget; + HtmlEditor* editor; + QString fileName; + bool modified; + }; + + \endcode + + In the constructor implementation is simple. It establishes the association between an instance of \bold {HtmlFile} with the + corresponding \bold {HtmlEditor} and the \bold {HtmlEditorWidget} instances. + + \code + + HtmlFile::HtmlFile(HtmlEditor* editor, HtmlEditorWidget* editorWidget): Core::IFile(editor) + { + d = new HtmlFileData; + d->editor = editor; + d->editorWidget = editorWidget; + } + \endcode + + The destructor does nothing other than deleting the private \bold {"d"} object. + + \code + HtmlFile::~HtmlFile() + { + delete d; + } + \endcode + + The \bold {setModified()} function stores the modification flag and emits the \bold {changed()} signal. + + \code + + void HtmlFile::setModified(bool val) + { + if(d->modified == val) + return; + d->modified = val; + emit changed(); + } + + bool HtmlFile::isModified() const + { + return d->modified; + } + + \endcode + + Returns the mime-type handled by this class. + + \code + + QString HtmlFile::mimeType() const + { + return d->mimeType; + } + \endcode + + The save method is called when file->save action (Ctrl+s) is triggered. This saves the contents of \bold {HtmlEditorWidget} + (the contents shown by plain text editor) in the file as shown below. The modified flag is set to false after the contents + are saved into the file. + + + \code + bool HtmlFile::save(const QString &fileName) + { + QFile file(fileName); + if(file.open(QFile::WriteOnly)) + { + d->fileName = fileName; + QByteArray content = d->editorWidget->content(); + file.write(content); + setModified(false); + return true; + } + return false; + } + \endcode + + The \bold {open} method is called when file->open action is triggered. This opens the file and calls the setContent() + method of \bold {HtmlEditorWidget}. The display name is set to the title of the html file. + + \code + bool HtmlFile::open(const QString &fileName) + { + QFile file(fileName); + if(file.open(QFile::ReadOnly)) + { + d->fileName = fileName; + QString path = QFileInfo(fileName).absolutePath(); + d->editorWidget->setContent(file.readAll(), path); + d->editor->setDisplayName(d->editorWidget->title()); + return true; + } + return false; + } + + \endcode + + The following methods implement the "filename" property. + + \code + void HtmlFile::setFilename(const QString& filename) + { + d->fileName = filename; + } + + QString HtmlFile::fileName() const + { + return d->fileName; + } + \endcode + + We implement the \bold {defaultPath()},\bold { suggestedFileName()},\bold {fileFilter()} and fileExtension() + methods to do nothing at the moment. + + \code + QString HtmlFile::defaultPath() const + { + return QString(); + } + + QString HtmlFile::suggestedFileName() const + { + return QString(); + } + + QString HtmlFile::fileFilter() const + { + return QString(); + } + + QString HtmlFile::fileExtension() const + { + return QString(); + } + \endcode + + Since we want to edit the file, we return false in \bold {isReadOnly()} method and true from \bold {isSaveAsAllowed()} + method. + + \code + bool HtmlFile::isReadOnly() const + { + return false; + } + + bool HtmlFile::isSaveAsAllowed() const + { + return true; + } + \endcode + + The \bold {modified()} function has to be implemented to customize the way in which the Html editor should handle + reloading of a modified file. This function is called if a html-file was modified outside of Qt Creator, while it is being + edited. For now we do nothing. + + \code + void HtmlFile::modified(ReloadBehavior* behavior) + { + Q_UNUSED(behavior); + } + \endcode + + \section2 10.2.3 Implementing the Core::IEditor interface + + The \bold {HtmlEditor} class implements \bold {IEditor} interface to provide an editor widget for html (*.html) files and + associate a \bold {HtmlFile} instance with it. + + + \code + #include <coreplugin/editormanager/ieditor.h> + struct HtmlEditorData; + class HtmlEditor : public Core::IEditor + { + Q_OBJECT + + public: + HtmlEditor(HtmlEditorWidget* editorWidget); + ~HtmlEditor(); + + bool createNew(const QString& contents = QString()); + QString displayName() const; + + IEditor* duplicate(QWidget* parent); + bool duplicateSupported() const; + Core::IFile* file(); + + + bool isTemporary() const; + const char* kind() const; + bool open(const QString& fileName = QString()) ; + bool restoreState(const QByteArray& state); + QByteArray saveState() const; + void setDisplayName(const QString &title); + QToolBar* toolBar(); + + // From Core::IContext + QWidget* widget(); + QList<int> context() const; + + protected slots: + void slotTitleChanged(const QString& title) + { setDisplayName(title); } + + private: + HtmlEditorData* d; + }; + + \endcode + + \bold {HtmlEditorData} holds object of \bold {HtmlEditorWidget} and \bold {HtmlFile}. displayName is used as visual + description of the document. + + \code + struct HtmlEditorData + { + HtmlEditorData() : editorWidget(0), file(0) { } + HtmlEditorWidget* editorWidget; + QString displayName; + HtmlFile* file; + QList<int> context; + }; + \endcode + + The constructor creates initializes itself on an \bold {HtmlEditorWidget}. It creates an \bold {HtmlFile} instance so that its + association with \bold {HtmlEditor} and widget is set. + + \code + HtmlEditor::HtmlEditor(HtmlEditorWidget* editorWidget): Core::IEditor(editorWidget) + { + d = new HtmlEditorData; + d->editorWidget = editorWidget; + d->file = new HtmlFile(this, editorWidget); + Core::UniqueIDManager* uidm = Core::UniqueIDManager::instance(); + d->context << uidm->uniqueIdentifier(HtmlEditorConstants::C_HTMLEDITOR); + + connect(d->editorWidget, SIGNAL(contentModified()),d->file,SLOT(modified())); + connect(d->editorWidget, SIGNAL(titleChanged(QString)),this,SLOT(slotTitleChanged(QString))); + connect(d->editorWidget, SIGNAL(contentModified()),this,SIGNAL(changed())); + } + \endcode + + The destructor does nothing other than deleting the private \bold {'d'} object. + + \code + HtmlEditor::~HtmlEditor() + { + delete d; + } + \endcode + + The following functions are self explanatory. + + \code + QWidget* HtmlEditor::widget() + { + return d->editorWidget; + } + + QList<int> HtmlEditor::context() const + { + return d->context; + } + + Core::IFile* HtmlEditor::file() + { + return d->file; + } + \endcode + + The \bold {createNew()} method is implemented to reset the contents of the \bold {HtmlEditorWidget} and \bold {HtmlFile} + objects. For now we ignore the contents parameter. + + \code + bool HtmlEditor::createNew(const QString& contents) + { + Q_UNUSED(contents); + d->editorWidget->setContent(QByteArray()); + d->file->setFilename(QString()); + return true; + } + \endcode + + The \bold {open()} method causes the \bold {HtmlFile} to open a given filename. It is assumed that the filename is a HTML + filename. + + \code + bool HtmlEditor::open(const QString &fileName) + { + return d->file->open(fileName); + } + + \endcode + + The following method returns the \bold {'kind'} of the editor. + + \code + namespace HtmlEditorConstants + { + const char* const C_HTMLEDITOR_MIMETYPE = "text/html"; + const char* const C_HTMLEDITOR = "HTML Editor"; + } + + const char* HtmlEditor::kind() const + { + return HtmlEditorConstants::C_HTMLEDITOR; + } + + \endcode + + The string returned by \bold {displayName} is used in the open-file combobox. The following methods help set and fetch the + display name. + + \code + QString HtmlEditor::displayName() const + { + return d->displayName; + } + + void HtmlEditor::setDisplayName(const QString& title) + { + if(d->displayName == title) + return; + d->displayName = title; + emit changed(); + } + \endcode + + We implement the following methods to do nothing in this example. + + \code + bool HtmlEditor::duplicateSupported() const + { + return false; + } + + Core::IEditor* HtmlEditor::duplicate(QWidget* parent) + { + Q_UNUSED(parent); + return 0; + } + + QByteArray HtmlEditor::saveState() const + { + return QByteArray(); + } + + bool HtmlEditor::restoreState(const QByteArray& state) + { + Q_UNUSED(state); + return false; + } + + QToolBar* HtmlEditor::toolBar() + { + return 0; + } + + bool HtmlEditor::isTemporary() const + { + return false; + } + \endcode + + \section2 10.2.4 Implementing the Core::IEditorFactory interface + + The \bold HtmlEditorFactory class implements the \bold Core::IEditorFactory interface; and is declared as follows. + + \code + #include <coreplugin/editormanager/ieditorfactory.h> + + struct HtmlEditorFactoryData; + + class HtmlEditorFactory : public Core::IEditorFactory + { + Q_OBJECT + + public: + HtmlEditorFactory(HtmlEditorPlugin* owner); + ~HtmlEditorFactory(); + QStringList mimeTypes() const; + QString kind() const; + Core::IEditor* createEditor(QWidget* parent); + Core::IFile* open(const QString &fileName); + + private: + HtmlEditorFactoryData* d; + }; + \endcode + + \bold {HtmlEditorFactoryData} structure holds the private data of the \bold {HtmlEditorFactory} class. Notice that the + constructor initializes the mime-types to \bold {HtmlEditorConstants::C_HTMLEDITOR_MYMETYPE}. It also + initializes the \bold {kind} of the editor. This kind should be same as \bold{kind} of \bold {HtmlEditor}. + + \code + namespace HtmlEditorConstants + { + const char* const C_HTMLEDITOR_MIMETYPE = "text/html"; + const char* const C_HTMLEDITOR = "HTML Editor"; + } + + struct HtmlEditorFactoryData + { + HtmlEditorFactoryData(): kind(HtmlEditorConstants::C_HTMLEDITOR) + { + mimeTypes << QString(HtmlEditorConstants::C_HTMLEDITOR_MIMETYPE); + } + + QString kind; + QStringList mimeTypes; + }; + \endcode + + The following methods are self-explanatory. + + \code + HtmlEditorFactory::HtmlEditorFactory(HtmlEditorPlugin* owner):Core::IEditorFactory(owner) + { + d = new HtmlEditorFactoryData; + } + + HtmlEditorFactory::~HtmlEditorFactory() + { + delete d; + } + + QStringList HtmlEditorFactory::mimeTypes() const + { + return d->mimeTypes; + } + + QString HtmlEditorFactory::kind() const + { + return d->kind; + } + \endcode + + + The \bold {open()} method should be implemented to return the IFile that is currently handling the given filename. If there + are none, then a new editor for the file is created and it's IFile is returned. To fully understand this process take a + look at the implementation of \bold {Core::EditorManager::openEditor()} method. + + \code + Core::IFile* HtmlEditorFactory::open(const QString& fileName) + { + Core::EditorManager* em = Core::EditorManager::instance(); + Core::IEditor* iface = em->openEditor(fileName, d->kind); + return iface ? iface->file() : 0; + } + \endcode + + This method creates and returns an instance of the \bold {HtmlEditor} class. + + \code + Core::IEditor* HtmlEditorFactory::createEditor(QWidget* parent) + { + HtmlEditorWidget* editorWidget = new HtmlEditorWidget(parent); + return new HtmlEditor(editorWidget); + } + \endcode + + \section2 10.2.5 Implementing the plugin + + We implement the \bold {HtmlEditorPlugin} plugin class using the same means described in Chapter 2. The only change is + the \bold {initialize()} method implementation. + + \code + bool HtmlEditorPlugin::initialize(const QStringList &arguments, QString* errMsg) + { + Q_UNUSED(arguments); + Core::ICore* core = Core::ICore::instance(); + Core::MimeDatabase* mdb = core->mimeDatabase(); + if(!mdb->addMimeTypes("text-html-mimetype.xml", errMsg)) + return false; + addAutoReleasedObject(new HtmlEditorFactory(this)); + return true; + } + \endcode + + When the plugin is compiled and Qt Creator is (re)started; we will be able to load HTML files using the newly + implemented editor plugin. + + \inlineimage qtc-htmleditor-10.png + +*/ diff --git a/doc/pluginhowto/find-filter.qdoc b/doc/pluginhowto/find-filter.qdoc new file mode 100644 index 00000000000..907dd07f579 --- /dev/null +++ b/doc/pluginhowto/find-filter.qdoc @@ -0,0 +1,549 @@ +/*! + \page find-filter.html + \title 9. Find Filter + + Qt Creator's find dialog box allows users to search for a text or regular expression in opened projects and unloaded disk + files. Clicking on "Edit -> Find/Replace -> Find Dialog" shows the find dialog box. + + \inlineimage qtc-finddialog-9.png + + + In the find dialog box the "scope" and "configuration widget" are extensible. It is possible to add more items to the + scope combo box and against every item it is possible to provide a configuration widget that needs to be shown below. + Each item in the "scope" combo box is called "find filter" in Qt Creator lingo. + + \section1 9.1 Find::IFindFilter interface + The \underline {find} plugin in Qt Creator exposes an interface called Find::IFindFilter. The interface is declared as follows in + the src/plugins/find/ifindfilter.h header. + + \code + class FIND_EXPORT IFindFilter : public QObject + { + Q_OBJECT + + public: + virtual ~IFindFilter() {} + virtual QString id() const = 0; + virtual QString name() const = 0; + virtual bool isEnabled() const = 0; + virtual QKeySequence defaultShortcut() const = 0; + virtual void findAll(const QString &txt, QTextDocument::FindFlags findFlags) = 0; + virtual QWidget *createConfigWidget() { return 0; } + virtual void writeSettings(QSettings *settings) { Q_UNUSED(settings); } + virtual void readSettings(QSettings *settings) { Q_UNUSED(settings); } + + signals: + void changed(); + }; + + \endcode + + By implementing the \bold {IFindFilter} interface and adding an instance of it to the object pool, we will be able to add a + new find-filter; which means another entry in the "scope" combo box of the find dialog box. + + \section1 9.2 Providing a custom filter + + Suppose that we wanted to provide a custom filter that will allow us to look for files in the loaded projects that include a + given header. In the following steps we will understand how to write a find filter for this. + + \section2 Step 1: Declaring the HeaderFilter class + + We first begin by declaring a class called HeaderFilter that implements the Find::IFindFilter interface. The class + definition is as follows. + \code + #include <find/ifindfilter.h> + class HeaderFilter : public Find::IFindFilter + { + Q_OBJECT + + public: + HeaderFilter(); + ~HeaderFilter(); + QString id() const; + QString name() const; + bool isEnabled() const; + QKeySequence defaultShortcut() const; + void findAll(const QString &txt, + QTextDocument::FindFlags findFlags); + QWidget *createConfigWidget(); + + private: + HeaderFilterData *d; + }; + \endcode + + \section2 Step 2: Implementing the HeaderFilter class + + The constructor and destructors are currently empty. We will fill in more code as we progress with our understanding of + the \bold {IFindFilter} interface. + + \code + struct HeaderFilterData + { + + }; + + HeaderFilter:: HeaderFilter() + { + d = new HeaderFilterData; + } + + HeaderFilter::~ HeaderFilter() + { + delete d; + } + + \endcode + The \bold{id()} method should be implemented to return a unique identifier for the find filter. + + + \code + QString HeaderFilter::id() const + { + return "HeaderFilter"; + } + + \endcode + + The \bold {name()} method should be implemented to return the string that gets shown in the "scope" combo box of the find + dialog box. + + \code + QString HeaderFilter::name() const + { + return tr("Header Filter"); + } + \endcode + + The \bold {isEnabled()} method should be implemented to return whether the find filter is enabled or not. In our case we + would like to show the filter enabled if projects are loaded in Qt Creator, false otherwise. To fully understand the + implementation of the function, we must first study the \bold {ProjectExplorer} namespace. For now let's just return true + and revisit the function after learning about the \bold {ProjectExplorer} namespace. + + \code + bool HeaderFilter::isEnabled() const + { + return true; + } + \endcode + + The \bold{defaultShortcut()} method should be implemented to return a key-sequence that the user can use to launch + the find dialog box with the "header filter" selected in "cope". In our implementation we return an invalid keysequence. + + \code + QKeySequence HeaderFilter::defaultShortcut() const + { + return QKeySequence(); + } + \endcode + + The \bold {createConfigWidget()} method should be implemented to return a configuration widget that gets shown at + the bottom edge of the find dialog box. + + + \inlineimage qtc-configwidget-9.png + + + For our header-filter; let's return a simple QLabel because we don't want to provide any configuration options. + + \code + QWidget *HeaderFilter::createConfigWidget() + { + return (new QLabel("This is a header filter")); + } + \endcode + + The \bold{findAll()} method should be implemented to perform the actual "find" or "search" operation. We need to + understand few key classes in the \bold {ProjectExplorer},\bold {TextEditor},\bold {Find }and \bold {Core::Utils} namespace before + attempting to implement the filter. For now implement the method to do nothing. + + \code + void HeaderFilter::findAll(const QString &text,QTextDocument::FindFlags findFlags) + { + // Do nothing + } + \endcode + + + \section2 Step 3: Implementing the "header-filter" plugin. + + We implement the header-filter plugin very similar to the \bold {DoNothingPlugin} class described in Chapter 2. Here we + only look at the implementation if the \bold {initialize()} method. + + \code + bool HeaderFilterPlugin::initialize(const QStringList& args,QString *errMsg) + { + Q_UNUSED(args); + Q_UNUSED(errMsg); + addAutoReleasedObject(new HeaderFilter); + return true; + } + \endcode + + \section2 Step 4: Testing the plugin + Upon compiling the plugin and restarting Qt Creator, we can notice the "Header Filter" item in the scope combo box of + the find dialog box. + + \inlineimage qtc-testplugin-9.png + + + Currently no "finding" or "searching" is done by our plugin because we have not yet implemented the + \bold {HeaderFilter::findAll()} method. + + \section1 9.3 The ProjectExplorer namespace + + The \bold {ProjectExplorer} namespace comprises of classes and interfaces that make up the project management + system in Qt Creator. This namespace is provided by the \bold {projectexplorer} plugin. Support for project types are provided + by plugins. For example + + \list + \o \bold {cmakeprojectmanager} plugin provides implementations of interfaces in \bold {ProjectExplorer} namespace for + supporting CMake projects + \o \bold {qt4projectmanager} plugin provides support for Qt 4 projects + \o \bold {qmlprojectmanager} plugin provides support for QML projects + \endlist + + \table + \header + \o Class/Interface + \o Description + + \row + \o \c {ProjectExplorer::IProjectManager} + \o This interface must be implemented to provide support for a kind of + project. Implementations of this interface help load projects into Qt + Creator. + + \row + \o \c {ProjectExplorer::Project} + \o This interface describes a project in terms of + \list + \o A file (Core::IFile) that describes the project. + \o A Boolean flag describing whether the project builds an + application or library + \o Build steps (ProjectExplorer:: BuildStep) that + need to be performed in order to build and clean the project + \o Run configurations that need to be used for running the + project + \o The environment within which the project needs to be run + \o The root node in the project explorer panel + \o Include paths and macros to be used while building the project + \endlist + + \row + \o \c {ProjectManager::} + \o This class is the implementation of the Core::IPlugin interface for the + + \row + \o \c {ProjectExplorerPlugin} + \o project explorer plugin. Through this class we can + \list + \o gain access to all the open projects + \o gain access the current project + \o gain access to the currently selected node (file/folder) in the + project explorer panel + \o gain access to the build manager + \bold {(ProjectManager::BuildManager)} + \endlist + \endtable + + \section2 9.3.1 Getting a list of open-projects + + Using the \bold {ProjectManager::ProjectExplorerPlugin} class we can catch hold of all the open-projects in Qt + Creator. The following code snippet shows how to do that + + \code + #include <extensionsystem/pluginmanager.h> + #include <projectexplorer/projectexplorer.h> + + // Catch hold of the plugin-manager + ExtensionSystem::PluginManager* pm = ExtensionSystem::PluginManager::instance(); + + // Look for the ProjectExplorerPlugin object + ProjectExplorer::ProjectExplorerPlugin* projectExplorerPlugin + = pm->getObject<ProjectExplorer::ProjectExplorerPlugin>(); + + // Fetch a list of all open projects + QList<ProjectExplorer::Project*> projects = d->projectPlugin->session()->projects(); + + \endcode + + + From the projects list we can gain access to the project file and all the other (source, header, resource etc) files in the + project. To gain access to the project file(s) we can + + \code + Q_FOREACH(ProjectExplorer::Project* project, projects) + { + QString name = project->name(); + Core::IFile* projectFile = project->file(); + // Do something with the above. For example: + qDebug("Project %s has project file as %s", + qPrintable(name), + qPrintable(projectFile->fileName())); + } + \endcode + + + While the above code snippet helps with fetching the project file (CMakeLists.txt, .pro etc..), it doesn't help us fetch all + the files associated with the project. + + \section2 9.3.2 Getting a list of files + + From the projects list we can get a string-list of all file names associated with the project using the following code + snippet. + + \code + // Make a list of files in each project + QStringList files; + + Q_FOREACH(ProjectManager::Project* project, projects) + files += project->files(Project::AllFiles); + \endcode + + \section2 9.3.3 Enabling the HeaderFilter conditionally + + Ideally the header-filter should be enabled only if there is atleast one open project. To make this happen, we upgrade + the HeaderFilter implementation as follows + + \code + struct HeaderFilterData + { + ProjectExplorer::ProjectExplorerPlugin* projectExplorer() + { + if(m_projectPlugin) + return m_projectPlugin; + + ExtensionSystem::PluginManager* pm = ExtensionSystem::PluginManager::instance(); + m_projectPlugin = pm->getObject<ProjectExplorer::ProjectExplorerPlugin>(); + return m_projectPlugin; + } + + private: + ProjectExplorer::ProjectExplorerPlugin* m_projectPlugin; + + }; + + bool HeaderFilter::isEnabled() const + { + QList<ProjectExplorer::Project*> projects = d->projectExplorer()->session()->projects(); + if(projects.count()) + return true; + return false; + } + + \endcode + + \section1 9.4 Searching in files + + In the previous section we understood how to gain access to the file names of all files associated with open projects. We + are now in a position to search within files. Let's begin the implementation of the \bold {HeaderFilter::findAll()} + method, and understand more concepts as we progress. + + \code + void HeaderFilter::findAll(const QString &text,QTextDocument::FindFlags findFlags) + { + // Fetch a list of all open projects + QList<Project*> projects = d->projectPlugin->session()->projects(); + + // Make a list of files in each project + QStringList files; + Q_FOREACH(Project* project, projects) + files += project->files(Project::AllFiles); + + // Remove duplicates + files.removeDuplicates(); + + // Search for text in "files" + // ... + } + \endcode + + The number of files that need to be searched can be varying. It may be as little as 1 and as high as 1000 or more! Hence + searching for something in files within the \bold {findAll()} method is a bad idea. If the \bold {findAll()} method takes too long + then it may cause Qt Creator to appear frozen until searching is finished. + + The solution to this is + \list + \o We make use of QtConcurrent and spawn multiple threads to perform the actual searching + \o We initialize a QFutureWatcher on the QFuture returned by QtConcurrent to emit signals as and when + search results are generated + \o We catch the signals generated by QFutureWatcher and list search results as they come + \endlist + + Qt Creator's core utils library provides a readymade function called \bold {findInFiles()} that looks for a string within a list + of files and returns a \bold {QFuture} to monitor search results. The function is declared as follows in src/libs/utils/filesearch.h + + \code + namespace Core { + namespace Utils { + + class FileSearchResult + { + public: + QString fileName; + int lineNumber; + QString matchingLine; + int matchStart; + int matchLength; + }; + + QFuture<FileSearchResult> findInFiles(const QString &searchTerm,const QStringList &files, + QTextDocument::FindFlags flags + ); + + QFuture<FileSearchResult> findInFilesRegExp(const QString &searchTerm,const QStringList &files, + QTextDocument::FindFlags flags + ); + + } // namespace Utils + } // namespace Core + \endcode + + Lets now continue with the implementation of \bold {HeaderFilter::findAll()} by making use of the + \bold {findInFiles()} method. + + \code + struct HeaderFilterData + { + QFutureWatcher<FileSearchResult> watcher; + + ProjectExplorer::ProjectExplorerPlugin* projectExplorer() { + ... + } + }; + + HeaderFilter::HeaderFilter() + { + d->watcher.setPendingResultsLimit(1); + connect(&d->watcher, SIGNAL(resultReadyAt(int)), + this, SLOT(displayResult(int))); + } + + void HeaderFilter::findAll(const QString &text,QTextDocument::FindFlags findFlags) + { + .... + // Remove duplicates + files.removeDuplicates(); + + // Begin searching + QString includeline = "#include <" + text + ">"; + Find::SearchResult *result = d->searchResultWindow()->startNewSearch(); + + // Let the watcher monitor the search results + d->watcher.setFuture(QFuture<FileSearchResult>()); + } + + void HeaderFilter::displayResult(int index) + { + // TODO + } + + \endcode + + In the revised \bold {findAll()} implementation we make use of the \bold {findInFiles()} method to spawn multiple + background threads to do all the finding. As search results are generated, the \bold {displayResult(int)} slot is called. In + this slot we can now show search results to the user. + + + \section1 9.5 Showing search results + + The "find" plugin provides an object of class \bold {Find::SearchResultWindow}. This class provides access to the widget + that displays search results. + + \inlineimage qtc-search-9.png + + + We would like to show our search results in the "search result window" as well. To do so, we modify the + \bold {HeaderFilter} code as follows + + \code + #include <find/searchresultwindow.h> + struct HeaderFilterData + { + // Method to search and return the search window + + Find::SearchResultWindow* searchResultWindow() + { + if(m_searchResultWindow) + return m_searchResultWindow; + + ExtensionSystem::PluginManager* pm = ExtensionSystem::PluginManager::instance(); + m_searchResultWindow = pm->getObject<Find::SearchResultWindow>(); + return m_searchResultWindow; + } + + private: + Find::SearchResultWindow *m_searchResultWindow; + }; + + HeaderFilter::HeaderFilter() + { + // displayResult(int) is called when every a new + // search result is generated + connect(&d->watcher, SIGNAL(resultReadyAt(int)),this, SLOT(displayResult(int))); + } + + void HeaderFilter::findAll(const QString &text,QTextDocument::FindFlags findFlags) + { + ... + //When result gets activated it invokes the openEditor function + connect(result, SIGNAL(activated(Find::SearchResultItem)), + this, SLOT(openEditor(Find::SearchResultItem))); + + d->searchResultWindow()->popup(true); + d->watcher.setFuture(Utils::findInFiles(includeline, files, findFlags)); + } + + void HeaderFilter::displayResult(int index) + { + FileSearchResult result = d->watcher.future().resultAt(index); + + d->searchResultWindow()->addResult(result.fileName, + result.lineNumber, + result.matchingLine, + result.matchStart, + result.matchLength); + } + + void HeaderFilter::openEditor(const QString &fileName, int line, int column) + { + // TODO + } + \endcode + + Whenever the user double clicks on the search results, the \bold {openEditor()} method is called. In that method we should + have Qt Creator open the corresponding file and mark the searched text. + + \section1 9.6 Opening the searched files + + Without going into too many details about the texteditor plugin, lets just take a look at the function that loads a named + file for us and moves the cursor to a specified location. The \bold {BaseTextEditor} class in the \bold {TextEditor} namespace + provides a static method called \bold {openEditorAt()} that serves our purpose. + + \code + namespace TextEditor { + class BaseTextEditor : public QPlainTextEdit + { + public: + .... + static ITextEditor *openEditorAt(const QString &fileName,int line, int column = 0, + const QString &editorKind); + .... + }; + } // TextEditor namespace + \endcode + + We now update the \bold {HeaderFilter::openEditor()} slot as follows + + \code + #include <texteditor/basetexteditor.h> + void HeaderFilter::openEditor(const Find::SearchResultItem &item) + { + TextEditor::BaseTextEditor::openEditorAt(item.fileName, item.lineNumber, item.index); + } + \endcode + + With this the \bold {HeaderFilter} is now complete. + +*/ diff --git a/doc/pluginhowto/find-support.qdoc b/doc/pluginhowto/find-support.qdoc new file mode 100644 index 00000000000..e377bb7f720 --- /dev/null +++ b/doc/pluginhowto/find-support.qdoc @@ -0,0 +1,6 @@ +/*! + \page find-support.html + \title 9.Find support + + This page needs to be written still! +*/ diff --git a/doc/pluginhowto/first-plugin.qdoc b/doc/pluginhowto/first-plugin.qdoc new file mode 100644 index 00000000000..b00f6c31c5d --- /dev/null +++ b/doc/pluginhowto/first-plugin.qdoc @@ -0,0 +1,327 @@ +/*! +\page first-plugin.html + itle 2. First Plugin +The best way to learn about writing Qt Creator plugins is to actually start by writing the very first plugin. + +There are two ways for writing plugins for Qt Creator: +\list +\o \l {Writing plugin inside the source tree.} +\o \l {Writing plugin outside the source tree.} +\endlist +For Writing plugin in the any of the above mentioned way Qt Creator source scould have been compiled. + +Lets keep our goals very simple for this one. We are going to provide a plugin for Qt Creator that does nothing. The purpose behind +this "Do nothing" plugin is to discover the basic classes in Qt Creator and to feel happy when our plugin shows up in the +"plugin list" + +\inlineimage qtc-aboutplugin-2.png + + + arget {Writing plugin inside the source tree.} +\section1 2.1 Create a plugin project in Qt Creator +Create a folder called DoNothing in $$QT_CREATOR_ROOT/src/plugins directory. The entire source code of +the plugin will be put into this directory. + +\bold {Note:}\underline {It may be possible to write and build Qt Creator plugins outside of its source tree, but it is +much easier to write plugins within the source tree}. + + +Lets first create the \c {DoNothing.pro} file with the following contents +\code +TEMPLATE = lib +TARGET = DoNothing + +PROVIDER = FooCompanyInc + +include(../../qtcreatorplugin.pri) +include(../../plugins/coreplugin/coreplugin.pri) + +HEADERS += DoNothingPlugin.h +SOURCES += DoNothingPlugin.cpp +OTHER_FILES += DoNothing.pluginspec +\endcode + +The project file configures the following aspects of the plugin: +\list 1 +\o Declares that DoNothing is a library. The output will be DoNothing.dll +\o Configures DoNothing to make use of settings defined in qtcreatorplugin.pri +\o Overrides the default destination directory to $$IDE_PLUGIN_PATH/FooCompanyInc. By default the value + will be to $$IDE_PLUGIN_PATH/Nokia +\o Configures DoNothing to make use of settings defined in coreplugin.pri +\o Provides information about the .h and .cpp files that make up the plugin +\endlist + +\section1 2.2 Marking the plugin for build +Edit the \c {$$QT_CREATOR_ROOT/src/plugins/plugins.pro } file and include the following lines at the end of +the file and save the changes. + +\code +SUBDIRS += plugin_DoNothing +plugin_DoNothing.subdir = DoNothing +\endcode + +The above lines make sure that the next time we build Qt Creator, the DoNothing plugin is compiled along with the rest +of Qt Creator plugins. + +\section1 2.3 Implementing the plugin +So far we have only written the project file and marked our plugin for compilation. We now do the actual +implementation of the plugin. All plugins implement the IPlugin interface. Lets take a look at how the DoNothing plugin +implements the interface and understand it in stages. + +In \c {$$QT_CREATOR_ROOT/src/plugins/DoNothing/DoNothingPluigin.h} enter the following code. +\code +#ifndef DONOTHINGPLUGIN_H +#define DONOTHINGPLUGIN_H +#include <extensionsystem/iplugin.h> + +class DoNothingPlugin : public ExtensionSystem::IPlugin +{ +public: + DoNothingPlugin(); + ~DoNothingPlugin(); + void extensionsInitialized(); + bool initialize(const QStringList & arguments, QString * errorString); + void shutdown(); +}; +#endif // DONOTHINGPLUGIN_H +\endcode + +As you can see the DoNothingPlugin class implements the IPlugin interface and nothing else. Lets look at how the +functions are implemented. + +\code +#include "DoNothingPlugin.h" +#include <QtPlugin> +#include <QStringList> + +DoNothingPlugin::DoNothingPlugin() +{ + // Do nothing +} + +DoNothingPlugin::~DoNothingPlugin() +{ + // Do notning +} +\endcode +Apart from initializing local (non widget and non action) variables; the constructor and destructor don't do much else. +\code + +bool DoNothingPlugin::initialize(const QStringList& args, QString *errMsg) +{ + Q_UNUSED(args); + Q_UNUSED(errMsg); + return true; +} +\endcode + +The \bold initialize() method is called when Qt Creator wants the plugin to initialize itself. This function is ideally used to +initialize the internal state of the plugin and register actions/objects with Qt Creator. The function is called after all the +dependencies of this plugin have been loaded. + +Since our plugin really does nothing, we return \bold {true} signifying that the initialization was successful. If the initialization +was unsuccessful (for some wired reason); the \bold {errMsg} string should be set to a human readable error message. + + +\code +void DoNothingPlugin::extensionsInitialized() +{ + // Do nothing +} +\endcode + +The \bold extensionsInitialized() method is called after this plugin has been initialized (ie. after initialize() method has been +called). This method is called on plugins that depend on this plugin first. +\code +void DoNothingPlugin::shutdown() +{ + // Do nothing +} +\endcode +The \bold shutdown() method is called when the plugin is about to be unloaded. +\code +Q_EXPORT_PLUGIN(DoNothingPlugin) +\endcode +Finally we export the plugin class by making use of the \bold {Q_EXPORT_PLUGIN()} macro. + +\section1 2.4 Writing the pluginspec file + +Each plugin should accompany a pluginspec file that provides some meta data about the plugin. For our plugin the +pluginspec file is as follows +\code +<plugin name="DoNothing" version="0.0.1"> + <vendor>FooCompanyInc</vendor> + <copyright>(C) 2009-2010 FooCompanyInc Pvt. Ltd.</copyright> + <license>Do anything you want</license> + <description>A plugin that does nothing</description> + <url>http://www.FooCompanyInc.com</url> + <dependencyList> + <dependency name="Core"/> + </dependencyList> +</plugin> +\endcode +The pluginspec file provides the following fields of information: + +\list 1 +\o Name of the plugin, which is also used as the name of the library file that provides the plugin implementation. + (In our case DoNothing.dll on Windows, libDoNothing.so on Unix) + +\o Version of the plugin + +\o Vendor name + +\o Copyright + +\o License text + +\o Description + +\o URL of the plugin vendor + +\o Dependency List provides all the plugins that this plugin depends on. Qt Creator ensures that dependencies + are loaded and initialized before this plugin. + +\endlist + +\bold {Note:}\underline {The pluginspec file should be in the same directory as the plugin's project file. Just to make things clear, the +contents of the DoNothing plugin directory is as shown below} + + +\inlineimage qtc-plugindirectory-2.png + + +\section1 2.5 Compiling the plugin + +Open a command prompt and move to the Qt Creator build directory (the same build directory you created in the +previous chapter). Execute the following commands +\code +qmake ..\qtcreator.pro -recursive +nmake +\endcode +After nmake returns, you will notice a FooCompanyInc folder within plugins folder whose contents are shown in the image +below. + +\inlineimage qtc-compiledplugin-2.png + + +\section1 2.6 Check out the new plugin +Launch (or relaunch) Qt Creator and notice that the "Installed Plugins" dialog box now reports that DoNothing plugin +was infact loaded and initialized. + + +\inlineimage qtc-installedplugin-2.png + + +In the coming chapters we will learn to write more complicated plugins for Qt Creator. + + arget {Writing plugin outside the source tree.} +\section1 2.7 Building out-of-source plugins + +Thus far we have understood how to build plugins within the source tree of Qt Creator. It may not be practical for us to +use the Qt Creator source tree for plugin development all the time. Suppose that you are the author of a specialized +library (or application) and you want integrate your product into Qt Creator. Since you are a 3rd party developer you +cannot expect to have your code in Qt Creator source tree all the time. In this section we will look at how to build +plugins that are outside the Qt Creator source tree. + +\section2 2.7.1 The plugin project file + +The whole magic of out-of-source plugin builds lies in the project (.pro) file of your plugin. Lets the DoNothing plugin +discussed in the previous section and modify (its ".pro" file) so that plugins can be built from a directory outside Qt +Creator source. + +The following table lists out the directory structure + + able +\header +\o Description +\o Directory + + \row + \o Qt Creator Source Code + \o C:\\Work\\QtCreator + + \row + \o Qt Creator Build Directory + \o C:\\Work\\QtCreator\\build + + \row + \o DoNothing Plugin Source + \o C:\\Work\\Research\\QtCreator\\Plugins\\DoNothing + + + This directory currently contains + \list + \o DoNothing.pluginspec + \o DoNothing.pro + \o DoNothingPlugin.cpp + \o DoNothingPlugin.h + \endlist +\row +\o Target plugin directory +\o C:\\Work\\QtCreator\\build\\lib\\qtcreator\\plugins\\FooCompanyInc + + \endtable + +Let's now modify the DoNothing.pro file in C:\\Work\\Research\\QtCreator\\Plugins\\DoNothing as follows. + +\code +QTC_SOURCE = C:/Work/QtCreator/ +QTC_BUILD = C:/Work/QtCreator/build/ + +TEMPLATE = lib +TARGET = DoNothing + +IDE_SOURCE_TREE = $$QTC_SOURCE +IDE_BUILD_TREE = $$QTC_BUILD + +PROVIDER = FooCompanyInc + +LIBS += -L$$IDE_PLUGIN_PATH/Nokia + +include($$QTC_SOURCE/src/qtcreatorplugin.pri) +include($$QTC_SOURCE/src/plugins/coreplugin/coreplugin.pri) + +HEADERS = DoNothingPlugin.h +SOURCES = DoNothingPlugin.cpp +OTHER_FILES = DoNothingPlugin.pluginspec +\endcode + +The \bold{QTC_SOURCE} and \bold {QTC_BUILD} variables in the project file point to the source and build directories of Qt Creator. +If you prefer setting these as environment variables, then use \bold{$$(QTC_BUILD)} instead of \bold{$$QTC_BUILD} in the +project file. + +The \bold {IDE_SOURCE_TREE} and \bold {IDE_BUILD_TREE} variables are used by qtcreatorplugin.pri to establish the include +and library paths. + +The \bold {PROVIDER} and \bold {DESTDIR} directories must be set before including qtcreatorplugin.pri. This is because the variables +will be provided default values are \bold {Nokia} and \bold {$$IDE_BUILD_TREE/lib/qtcreator/plugins/Nokia} otherwise. + +By default qtcreatorplugin.pri assumes that all the libs that a plugin may depend on are present inside the \bold {DESTDIR}. If +our \bold {DESTDIR} is different from the default (Nokia) one, then we will need to explicitly set that. The remaining things are +just the same. + + +\section2 2.7.2 Compiling the plugin + +Once the project file has been created, we make use of the standard qmake and make commands to compile the plugin. + +\code +C:\Work\Research\QtCreator\Plugins\DoNothing>qmake +C:\Work\Research\QtCreator\Plugins\DoNothing>nmake + +Microsoft (R) Program Maintenance Utility Version 8.00.50727.762 +Copyright (C) Microsoft Corporation. All rights reserved. + +"C:\Program Files\Microsoft Visual Studio 8\VC\BIN\nmake.exe" -f Makefile.Debug +Microsoft (R) Program Maintenance Utility Version 8.00.50727.762 +Copyright (C) Microsoft Corporation. All rights reserved. + +copy /y "DoNothing.pluginspec" +"..\..\..\..\QtCreator\build\lib\qtcreator\plugins\FooCompanyInc\DoNothing.pluginspec" +1 file(s) copied. +........................................ +mt.exe -nologo -manifest "debug\DoNothingd.intermediate.manifest" - +outputresource:..\..\..\..\QtCreator\build\lib\qtcreator\plugins\FooCompanyInc\DoNothingd.dll;2 +C:\Work\Research\QtCreator\Plugins\DoNothing> +\endcode +*/ diff --git a/doc/pluginhowto/images/qtc-aboutplugin-2.png b/doc/pluginhowto/images/qtc-aboutplugin-2.png Binary files differnew file mode 100644 index 00000000000..ce048ec86c7 --- /dev/null +++ b/doc/pluginhowto/images/qtc-aboutplugin-2.png diff --git a/doc/pluginhowto/images/qtc-codeeffect-4.png b/doc/pluginhowto/images/qtc-codeeffect-4.png Binary files differnew file mode 100644 index 00000000000..d318c54223c --- /dev/null +++ b/doc/pluginhowto/images/qtc-codeeffect-4.png diff --git a/doc/pluginhowto/images/qtc-compiledplugin-2.png b/doc/pluginhowto/images/qtc-compiledplugin-2.png Binary files differnew file mode 100644 index 00000000000..6dceac16043 --- /dev/null +++ b/doc/pluginhowto/images/qtc-compiledplugin-2.png diff --git a/doc/pluginhowto/images/qtc-configwidget-9.png b/doc/pluginhowto/images/qtc-configwidget-9.png Binary files differnew file mode 100644 index 00000000000..1c792ef74df --- /dev/null +++ b/doc/pluginhowto/images/qtc-configwidget-9.png diff --git a/doc/pluginhowto/images/qtc-customeditor-10.png b/doc/pluginhowto/images/qtc-customeditor-10.png Binary files differnew file mode 100644 index 00000000000..585ae7a78a3 --- /dev/null +++ b/doc/pluginhowto/images/qtc-customeditor-10.png diff --git a/doc/pluginhowto/images/qtc-customwizardone-8.png b/doc/pluginhowto/images/qtc-customwizardone-8.png Binary files differnew file mode 100644 index 00000000000..3dc3c762934 --- /dev/null +++ b/doc/pluginhowto/images/qtc-customwizardone-8.png diff --git a/doc/pluginhowto/images/qtc-customwizardtwo-8.png b/doc/pluginhowto/images/qtc-customwizardtwo-8.png Binary files differnew file mode 100644 index 00000000000..a26a956dcfd --- /dev/null +++ b/doc/pluginhowto/images/qtc-customwizardtwo-8.png diff --git a/doc/pluginhowto/images/qtc-designer-8.png b/doc/pluginhowto/images/qtc-designer-8.png Binary files differnew file mode 100644 index 00000000000..6d64ef3f06d --- /dev/null +++ b/doc/pluginhowto/images/qtc-designer-8.png diff --git a/doc/pluginhowto/images/qtc-dirview-6.png b/doc/pluginhowto/images/qtc-dirview-6.png Binary files differnew file mode 100644 index 00000000000..464600008ea --- /dev/null +++ b/doc/pluginhowto/images/qtc-dirview-6.png diff --git a/doc/pluginhowto/images/qtc-donothingleft-5.png b/doc/pluginhowto/images/qtc-donothingleft-5.png Binary files differnew file mode 100644 index 00000000000..96209198f8e --- /dev/null +++ b/doc/pluginhowto/images/qtc-donothingleft-5.png diff --git a/doc/pluginhowto/images/qtc-donothingright-5.png b/doc/pluginhowto/images/qtc-donothingright-5.png Binary files differnew file mode 100644 index 00000000000..2e6869cea96 --- /dev/null +++ b/doc/pluginhowto/images/qtc-donothingright-5.png diff --git a/doc/pluginhowto/images/qtc-editor-10.png b/doc/pluginhowto/images/qtc-editor-10.png Binary files differnew file mode 100644 index 00000000000..4904077774c --- /dev/null +++ b/doc/pluginhowto/images/qtc-editor-10.png diff --git a/doc/pluginhowto/images/qtc-editor-8.png b/doc/pluginhowto/images/qtc-editor-8.png Binary files differnew file mode 100644 index 00000000000..fc591208465 --- /dev/null +++ b/doc/pluginhowto/images/qtc-editor-8.png diff --git a/doc/pluginhowto/images/qtc-editortabs-10.png b/doc/pluginhowto/images/qtc-editortabs-10.png Binary files differnew file mode 100644 index 00000000000..0d5d36e114b --- /dev/null +++ b/doc/pluginhowto/images/qtc-editortabs-10.png diff --git a/doc/pluginhowto/images/qtc-fileformat-10.png b/doc/pluginhowto/images/qtc-fileformat-10.png Binary files differnew file mode 100644 index 00000000000..3b3e767be61 --- /dev/null +++ b/doc/pluginhowto/images/qtc-fileformat-10.png diff --git a/doc/pluginhowto/images/qtc-finddialog-9.png b/doc/pluginhowto/images/qtc-finddialog-9.png Binary files differnew file mode 100644 index 00000000000..beb36797002 --- /dev/null +++ b/doc/pluginhowto/images/qtc-finddialog-9.png diff --git a/doc/pluginhowto/images/qtc-firstnavigation-6.png b/doc/pluginhowto/images/qtc-firstnavigation-6.png Binary files differnew file mode 100644 index 00000000000..7dbac0194b7 --- /dev/null +++ b/doc/pluginhowto/images/qtc-firstnavigation-6.png diff --git a/doc/pluginhowto/images/qtc-help-5.png b/doc/pluginhowto/images/qtc-help-5.png Binary files differnew file mode 100644 index 00000000000..b021977d6d7 --- /dev/null +++ b/doc/pluginhowto/images/qtc-help-5.png diff --git a/doc/pluginhowto/images/qtc-helpdonothing-5.png b/doc/pluginhowto/images/qtc-helpdonothing-5.png Binary files differnew file mode 100644 index 00000000000..f823e877c1f --- /dev/null +++ b/doc/pluginhowto/images/qtc-helpdonothing-5.png diff --git a/doc/pluginhowto/images/qtc-htmleditor-10.png b/doc/pluginhowto/images/qtc-htmleditor-10.png Binary files differnew file mode 100644 index 00000000000..585ae7a78a3 --- /dev/null +++ b/doc/pluginhowto/images/qtc-htmleditor-10.png diff --git a/doc/pluginhowto/images/qtc-ieditor-10.png b/doc/pluginhowto/images/qtc-ieditor-10.png Binary files differnew file mode 100644 index 00000000000..7ba5448a7ae --- /dev/null +++ b/doc/pluginhowto/images/qtc-ieditor-10.png diff --git a/doc/pluginhowto/images/qtc-installedplugin-2.png b/doc/pluginhowto/images/qtc-installedplugin-2.png Binary files differnew file mode 100644 index 00000000000..6385e7f56fe --- /dev/null +++ b/doc/pluginhowto/images/qtc-installedplugin-2.png diff --git a/doc/pluginhowto/images/qtc-loggermode-13.png b/doc/pluginhowto/images/qtc-loggermode-13.png Binary files differnew file mode 100644 index 00000000000..d605f05a96a --- /dev/null +++ b/doc/pluginhowto/images/qtc-loggermode-13.png diff --git a/doc/pluginhowto/images/qtc-loggermodewidget-13.png b/doc/pluginhowto/images/qtc-loggermodewidget-13.png Binary files differnew file mode 100644 index 00000000000..2fb60db3f36 --- /dev/null +++ b/doc/pluginhowto/images/qtc-loggermodewidget-13.png diff --git a/doc/pluginhowto/images/qtc-loggerpage-13.png b/doc/pluginhowto/images/qtc-loggerpage-13.png Binary files differnew file mode 100644 index 00000000000..1bdca41d051 --- /dev/null +++ b/doc/pluginhowto/images/qtc-loggerpage-13.png diff --git a/doc/pluginhowto/images/qtc-menubar-5.png b/doc/pluginhowto/images/qtc-menubar-5.png Binary files differnew file mode 100644 index 00000000000..2c4182dcf0e --- /dev/null +++ b/doc/pluginhowto/images/qtc-menubar-5.png diff --git a/doc/pluginhowto/images/qtc-menuitem-10.png b/doc/pluginhowto/images/qtc-menuitem-10.png Binary files differnew file mode 100644 index 00000000000..7a55675cb9b --- /dev/null +++ b/doc/pluginhowto/images/qtc-menuitem-10.png diff --git a/doc/pluginhowto/images/qtc-menuitemposition-5.png b/doc/pluginhowto/images/qtc-menuitemposition-5.png Binary files differnew file mode 100644 index 00000000000..5dbf3d3556c --- /dev/null +++ b/doc/pluginhowto/images/qtc-menuitemposition-5.png diff --git a/doc/pluginhowto/images/qtc-menuresponse-5.png b/doc/pluginhowto/images/qtc-menuresponse-5.png Binary files differnew file mode 100644 index 00000000000..b610864fcb9 --- /dev/null +++ b/doc/pluginhowto/images/qtc-menuresponse-5.png diff --git a/doc/pluginhowto/images/qtc-modes-13.png b/doc/pluginhowto/images/qtc-modes-13.png Binary files differnew file mode 100644 index 00000000000..2e22406ef96 --- /dev/null +++ b/doc/pluginhowto/images/qtc-modes-13.png diff --git a/doc/pluginhowto/images/qtc-nevigationwidget-4.png b/doc/pluginhowto/images/qtc-nevigationwidget-4.png Binary files differnew file mode 100644 index 00000000000..1aadab3b41d --- /dev/null +++ b/doc/pluginhowto/images/qtc-nevigationwidget-4.png diff --git a/doc/pluginhowto/images/qtc-newitemmodel-8.png b/doc/pluginhowto/images/qtc-newitemmodel-8.png Binary files differnew file mode 100644 index 00000000000..c453e616021 --- /dev/null +++ b/doc/pluginhowto/images/qtc-newitemmodel-8.png diff --git a/doc/pluginhowto/images/qtc-newmode-13.png b/doc/pluginhowto/images/qtc-newmode-13.png Binary files differnew file mode 100644 index 00000000000..d8f75db6118 --- /dev/null +++ b/doc/pluginhowto/images/qtc-newmode-13.png diff --git a/doc/pluginhowto/images/qtc-newprojectdialog-8.png b/doc/pluginhowto/images/qtc-newprojectdialog-8.png Binary files differnew file mode 100644 index 00000000000..dbf7e8dc892 --- /dev/null +++ b/doc/pluginhowto/images/qtc-newprojectdialog-8.png diff --git a/doc/pluginhowto/images/qtc-objectlist-4.png b/doc/pluginhowto/images/qtc-objectlist-4.png Binary files differnew file mode 100644 index 00000000000..e6327ea03e3 --- /dev/null +++ b/doc/pluginhowto/images/qtc-objectlist-4.png diff --git a/doc/pluginhowto/images/qtc-options-5.png b/doc/pluginhowto/images/qtc-options-5.png Binary files differnew file mode 100644 index 00000000000..7b4dcc29149 --- /dev/null +++ b/doc/pluginhowto/images/qtc-options-5.png diff --git a/doc/pluginhowto/images/qtc-options-7.png b/doc/pluginhowto/images/qtc-options-7.png Binary files differnew file mode 100644 index 00000000000..d96513d0201 --- /dev/null +++ b/doc/pluginhowto/images/qtc-options-7.png diff --git a/doc/pluginhowto/images/qtc-options-keyboard-5.png b/doc/pluginhowto/images/qtc-options-keyboard-5.png Binary files differnew file mode 100644 index 00000000000..6b21187c516 --- /dev/null +++ b/doc/pluginhowto/images/qtc-options-keyboard-5.png diff --git a/doc/pluginhowto/images/qtc-plaintextedit-10.png b/doc/pluginhowto/images/qtc-plaintextedit-10.png Binary files differnew file mode 100644 index 00000000000..77da1a97027 --- /dev/null +++ b/doc/pluginhowto/images/qtc-plaintextedit-10.png diff --git a/doc/pluginhowto/images/qtc-plugindirectory-2.png b/doc/pluginhowto/images/qtc-plugindirectory-2.png Binary files differnew file mode 100644 index 00000000000..1e758cbc5b5 --- /dev/null +++ b/doc/pluginhowto/images/qtc-plugindirectory-2.png diff --git a/doc/pluginhowto/images/qtc-pluginmanager-4.png b/doc/pluginhowto/images/qtc-pluginmanager-4.png Binary files differnew file mode 100644 index 00000000000..ef4301b0a83 --- /dev/null +++ b/doc/pluginhowto/images/qtc-pluginmanager-4.png diff --git a/doc/pluginhowto/images/qtc-progressbar-11.png b/doc/pluginhowto/images/qtc-progressbar-11.png Binary files differnew file mode 100644 index 00000000000..521b67eb715 --- /dev/null +++ b/doc/pluginhowto/images/qtc-progressbar-11.png diff --git a/doc/pluginhowto/images/qtc-search-9.png b/doc/pluginhowto/images/qtc-search-9.png Binary files differnew file mode 100644 index 00000000000..39d397364e2 --- /dev/null +++ b/doc/pluginhowto/images/qtc-search-9.png diff --git a/doc/pluginhowto/images/qtc-searchprogress-11.png b/doc/pluginhowto/images/qtc-searchprogress-11.png Binary files differnew file mode 100644 index 00000000000..54e7f4364fd --- /dev/null +++ b/doc/pluginhowto/images/qtc-searchprogress-11.png diff --git a/doc/pluginhowto/images/qtc-secondnavigation-6.png b/doc/pluginhowto/images/qtc-secondnavigation-6.png Binary files differnew file mode 100644 index 00000000000..acf3a2881b2 --- /dev/null +++ b/doc/pluginhowto/images/qtc-secondnavigation-6.png diff --git a/doc/pluginhowto/images/qtc-testplugin-7.png b/doc/pluginhowto/images/qtc-testplugin-7.png Binary files differnew file mode 100644 index 00000000000..c04d8149630 --- /dev/null +++ b/doc/pluginhowto/images/qtc-testplugin-7.png diff --git a/doc/pluginhowto/images/qtc-testplugin-8.png b/doc/pluginhowto/images/qtc-testplugin-8.png Binary files differnew file mode 100644 index 00000000000..3fbcee58940 --- /dev/null +++ b/doc/pluginhowto/images/qtc-testplugin-8.png diff --git a/doc/pluginhowto/images/qtc-testplugin-9.png b/doc/pluginhowto/images/qtc-testplugin-9.png Binary files differnew file mode 100644 index 00000000000..9affcc4dbeb --- /dev/null +++ b/doc/pluginhowto/images/qtc-testplugin-9.png diff --git a/doc/pluginhowto/images/qtc-title-10.png b/doc/pluginhowto/images/qtc-title-10.png Binary files differnew file mode 100644 index 00000000000..25f662ef111 --- /dev/null +++ b/doc/pluginhowto/images/qtc-title-10.png diff --git a/doc/pluginhowto/location-filter.qdoc b/doc/pluginhowto/location-filter.qdoc new file mode 100644 index 00000000000..88bd85680ad --- /dev/null +++ b/doc/pluginhowto/location-filter.qdoc @@ -0,0 +1,6 @@ +/*! + \page location-filter.html + \title 14.Adding location filter + + This page needs to be written still! +*/ diff --git a/doc/pluginhowto/menu.qdoc b/doc/pluginhowto/menu.qdoc new file mode 100644 index 00000000000..5a491819425 --- /dev/null +++ b/doc/pluginhowto/menu.qdoc @@ -0,0 +1,304 @@ +/*! +\page menu.html +\title 5. Adding menu and menu-items + +In this chapter we will understand how to add entries to existing menus in Qt Creator. We will also learn how to add new +menu entries. Before moving ahead let's take a look at the menu bar in Qt Creator + +\inlineimage qtc-menubar-5.png + + +The menu bar consists of the following set of default menus +\list +\o File + \list + \o New + \o Open + \o Recent Files + \endlist +\o Edit + \list + \o Advanced + \endlist +\o Tools +\o Window + \list + \o Panes + \endlist +\o Help +\endlist + +\bold {Note:}\underline{Other menu items like Build and Debug come from plugins. They are not a part of the default menu set}. + +As Qt developers we know that the above menus are shown within a \bold {QMenuBar}; and that there is a \bold {QMenu} associated +with each of the above menus. + +\section1 5.1 Core::ActionManager + +The main Qt Creator program is nothing but a plugin loader. All of the functionality provided by Qt Creator is provided +by the plugins. The main plugin for Qt Creator is called "core" Without core, Qt Creator really doesn't have a personality + +One of the key components of the "core" is the \bold {ActionManager}.\bold {ActionManager} is responsible for registration of menus, +menu-items and keyboard shortcuts. So if we wanted to add a new menu-item or menu, we would have to use +\bold {ActionManager}. The coming subsections explain this better. + +To gain access to the \bold {ActionManager}, the following piece of code can be used. +\code +#include <coreplugin/actionmanager/actionmanager.h> +#include <coreplugin/icore.h> +Core::ActionManager* am = Core::ICore::instance()->actionManager(); +\endcode + +\section1 5.2 Core::ActionContainer + +ActionContianer represents menu or menubar in Qt Creator. Instances of ActionContainer are never created directly, +instead they are accessed using ActionManager::createMenu(), ActionManager::createMenuBar() etc; but more on that +later. +There is an ActionContainer associated with each of the default menus in Qt Creator. Fetching ActionContainer for a +given menu can be done using the following code snippet + +\code +#include <coreplugin/coreconstants.h> +#include <coreplugin/actionmanager/actionmanager.h> +#include <coreplugin/icore.h> + +Core::ActionManager* am = Core::ICore::instance()->actionManager(); +Core::ActionContainer* ac = am->actionContainer( ID ); +\endcode +The following table lists out the ID to use for each of the menus in Qt Creator. Each of the IDs are defined as \bold {const} +\bold {char*} static variables within the \bold {Core} namespace. + +\table +\header + \o Menu + \o ID +\row + \o File + \o Core::Constants::M_FILE +\row + \o File->New + \o Core::Constants::M_FILE_NEW +\row + \o File->Open + \o Core::Constants::M_FILE_OPEN +\row + \o Edit + \o Core::Constants::M_FILE_RECENTFILES +\row + \o Edit->Advanced + \o Core::Constants::M_EDIT_ADVANCED +\row + \o Tools + \o Core::Constants::M_TOOLS +\row + \o Window + \o Core::Constants::M_WINDOW +\row + \o Window Panes + \o Core::Constants::M_WINDOW_PANES +\row + \o Help + \o Core::Constants::M_HELP +\endtable + +So if we want to catch hold of the "Help" menu, we can use the code snippet as follows +\code +#include <coreplugin/coreconstants.h> +#include <coreplugin/actionmanager/actionmanager.h> +#include <coreplugin/icore.h> + +Core::ActionManager* am = Core::ICore::instance()->actionManager(); +Core::ActionContainer* ac = am->actionContainer( Core::Constants::M_HELP ); +\endcode + +\section1 5.3 Registering menu-items. + +The Core::Command class represents an action like a menu item, tool button, or shortcut. You don't create Command +objects directly, instead use we use ActionManager::registerAction() to register an action and retrieve a Command. The +Command object represents the user visible action and its properties. + +Shown below is the right way to add the "About DoNothing" menu-item from the DoNothing plugin. + +\code +#include <coreplugin/coreconstants.h> +#include <coreplugin/actionmanager/actionmanager.h> +#include <coreplugin/actionmanager/command.h> +#include <coreplugin/icore.h> +#include <QKeySequence> + +bool DoNothingPlugin::initialize(const QStringList& args, QString *errMsg) +{ + Q_UNUSED(args); + Q_UNUSED(errMsg); + + // Fetch the action manager + Core::ActionManager* am = Core::ICore::instance()->actionManager(); + + // Create a command for "About DoNothing". + Core::Command* cmd = am->registerAction( + new QAction(tr("About DoNothing"),this), + "DoNothingPlugin.AboutDoNothing", + QList<int>() <<Core::Constants::C_GLOBAL_ID + ); + + // Add the command to Help menu + am->actionContainer(Core::Constants::M_HELP)->addAction(cmd); + return true; +} +\endcode +\bold {Warning:}\underline { ac->menu()->addAction("About DoNothing") should never be used when adding menu items to Qt Creator.} + +After compiling the changes, we can notice that the "About DoNothing" action shows up in the "Help" menu; but at the +beginning. + +\inlineimage qtc-helpdonothing-5.png + + +If the "About DoNothing" menu item is to be placed in between specified menu item the we will make a small update in the code block +\code +bool DoNothingPlugin::initialize(const QStringList& args, QString *errMsg) +{ + ..... + // Add the command to Help menu + am->actionContainer(Core::Constants::M_HELP)->addAction(showCmd, Core::Constants::G_HELP_HELP); + return true; +} +\endcode + +The effect of the change in code can be seen in the image below. + +\inlineimage qtc-menuitemposition-5.png + + +When added this way, we will be able to find the "About DoNothing" action in the "Keyboard Shortcuts" dialog box and +also associate a keyboard shortcut with it. + +\inlineimage qtc-options-keyboard-5.png + + +\section1 5.4 Responding to menu-items +Since menu-items are QActions, we can connect to their triggered(bool) or toggled(bool) signal and respond to +trigger/toggled events. The code below shows how to do this +\code +class DoNothingPlugin : public ExtensionSystem::IPlugin +{ + Q_OBJECT + +private slots: + void about(); +}; + +bool DoNothingPlugin::initialize(const QStringList& args, QString *errMsg) +{ + ...... + QAction *action = new QAction(tr("About DoNothing"),this); + Core::Command* cmd = am->registerAction(action, + "DoNothingPlugin.AboutDoNothing", + QList<int>() << 0); + ...... + connect(action, SIGNAL(triggered(bool)), this, SLOT(about())); + return true; +} + +void DoNothingPlugin::about() +{ + QMessageBox::information(0, "About DoNothing Plugin", + "Seriously dude, this plugin does nothing"); +} +\endcode + +After compiling the changes and clicking on the "About DoNothing" menu-item, we can see the information dialog box +as shown below. + +\inlineimage qtc-menuresponse-5.png + + +If you wanted the message box to have the Qt Creator main window as its parent, then you can use the following code +for the about() slot. + +\code +void DoNothingPlugin::about() +{ + QMessageBox::information(Core::ICore::instance()->mainWindow(), + "About DoNothing Plugin", + "Seriously dude, this plugin does nothing"); +} +\endcode + +\section1 5.5 Adding menus +The procedure for adding menus is the same. Instead of creating a \bold {Core::Command}, we create a \bold {Core::ActionContainer} +and add it to the \bold {MENU_BAR}. The following code snippet highlights the changes from our previous version. +\code +bool DoNothingPlugin::initialize(const QStringList& args, QString *errMsg) +{ + Q_UNUSED(args); + Q_UNUSED(errMsg); + + // Fetch the action manager + Core::ActionManager* am = Core::ICore::instance()->actionManager(); + + // Create a DoNothing menu + Core::ActionContainer* ac = am->createMenu("DoNothingPlugin.DoNothingMenu"); + ac->menu()->setTitle("DoNothing"); + + // Create a command for "About DoNothing". + QAction *action = new QAction(tr("About DoNothing",this)); + Core::Command* cmd = am->registerAction(action,"DoNothingPlugin.AboutDoNothing",QList<int>() << 0); + + // Add DoNothing menu to the menubar + am->actionContainer(Core::Constants::MENU_BAR)->addMenu(ac); + + // Add the "About DoNothing" action to the DoNothing menu + ac->addAction(cmd); + + // Connect the action + connect(action, SIGNAL(triggered(bool)), this, SLOT(about())); + return true; +} +\endcode +After recompiling the changes, you will be able to notice the DoNothing menu as shown in the screenshot below. + +\inlineimage qtc-donothingleft-5.png + +\section1 5.6 Placing menus and menu-items +It is possible to insert menus and menu-items anywhere you want. Shown below is a code snippet that inserts the +"DoNothing" menu before the "Help" menu. +\code +bool DoNothingPlugin::initialize(const QStringList& args, QString *errMsg) +{ + Q_UNUSED(args); + Q_UNUSED(errMsg); + + // Fetch the action manager + Core::ActionManager* am = Core::ICore::instance()->actionManager(); + + // Create a DoNothing menu + Core::ActionContainer* ac = am->createMenu("DoNothingPlugin.DoNothingMenu"); + ac->menu()->setTitle("DoNothing"); + + // Create a command for "About DoNothing". + QAction *action = new QAction(tr("About DoNothing"),this); + Core::Command* cmd = am->registerAction(action,"DoNothingPlugin.AboutDoNothing",QList<int>() << 0); + + // Insert the "DoNothing" menu between "Window" and "Help". + QMenu* windowMenu = am->actionContainer(Core::Constants::M_HELP)->menu(); + QMenuBar* menuBar = am->actionContainer(Core::Constants::MENU_BAR)->menuBar(); + menuBar->insertMenu(windowMenu->menuAction(), ac->menu()); + + // Add the "About DoNothing" action to the DoNothing menu + ac->addAction(cmd); + + // Connect the action + connect(action, SIGNAL(triggered(bool)), this, SLOT(about())); + return true; +} +\endcode + +After compiling the changes, we can now notice that change in position of the "DoNothing" menu. + +\inlineimage qtc-donothingright-5.png + + +You can use a similar technique for customizing the position of menu-items. + +*/ diff --git a/doc/pluginhowto/mode.qdoc b/doc/pluginhowto/mode.qdoc new file mode 100644 index 00000000000..bf421e949a3 --- /dev/null +++ b/doc/pluginhowto/mode.qdoc @@ -0,0 +1,537 @@ +/*! +\page mode.html +\title 13. Adding a mode + +When we are working in Qt Creator then we in one of the six modes below. + +\list +\o Welcome +\o Edit +\o Debug +\o Project +\o Help +\o Output +\endlist + +By selecting different modes in Qt creator we can quickly switch between different task spaces, such +as editing, browsing the Qt Creator manual, setting up the build environment, etc. +Different modes can be selected either by clicking on the mode selectors or through keyboard shortcuts. + +The following figure shows the mode selectors in the Qt Creator. + +\inlineimage qtc-modes-13.png + + +Now in this chapter we are concerned about learning to add a new mode and a "LoggerMode" mode selector will be availble in Qt Creator. + +\section1 13.1 Core Classes and Interfaces + +To support a new mode we need to +\list +\o Implement a plugin \bold {(ExtensionSystem::IPlugin } implementation) class that exposes the new mode.Chapter 2 in this + document provides a detailed description on creating plugins by implementing the ExtensionSystem::IPlugin interface. +\o Implement the \bold{(Core::IMode)} interface. This interface allows us to add a new mode in Qt creator +\endlist + + +\section2 Step 1. Core::IMode interface +This interface abstracts the creation of a mode, adding an icon to the mode selector, setting the mode priority, +setting a unique made name. The \bold {Core::IMode} interface is declared as follows in scr/plugins/coreplugin/imode.h +\code +namespace Core { + + class CORE_EXPORT IMode : public IContext + { + Q_OBJECT + + public: + IMode(QObject *parent = 0) : IContext(parent) {} + virtual ~IMode() {} + + virtual QString name() const = 0; + virtual QIcon icon() const = 0; + virtual int priority() const = 0; + virtual const char *uniqueModeName() const = 0; + }; +} // namespace Core +\endcode + +Notice that Core::IMode inherits Core::IContext. Core::IContext is an interface through which +Qt Creator picks up the widget corresponding to the mode. The Core::IContext interface is declared +as follows. + +\code +namespace Core +{ + + class CORE_EXPORT IContext : public QObject + { + Q_OBJECT + + public: + IContext(QObject *parent = 0) : QObject(parent) {} + virtual ~IContext() {} + + virtual QList<int> context() const = 0; + virtual QWidget *widget() = 0; + virtual QString contextHelpId() const { return QString(); } + }; +} +\endcode + +\section1 13.2 Adding a new mode +Lets add a mode to Qt Creator called "LoggerMode". LoggerMode allows the user (developer) to log the number of hours he/she +has worked on a project. The following steps explain how the new mode "LoggerMode" is added. + +\section2 Step 1. Declaring the LoggerMode class +We first begin by declaring a class called LoggerMode that implements the Core::IMode interface. +The class definition is as follows. +\code +#include <coreplugin/imode.h> + +struct LoggerModeData; +class LoggerMode : public Core::IMode +{ + Q_OBJECT + +public: + LoggerMode(); + ~LoggerMode(); + + QString name() const; + QIcon icon() const; + int priority() const; + QWidget *widget(); + const char *uniqueModeName() const; + QList<int> context() const; + void activated(); + QString contextHelpId() const { return QLatin1String("Qt Creator"); } + +private: + LoggerModeData *d; +}; +\endcode + +\section2 Step 2. Implementing the LoggerMode class +Declaring the private variables of the LoggerMode class. +\code +struct LoggerModeData +{ + QWidget *m_widget; +}; +\endcode +The constructor creates a new blank widget just for now to get started with the mode. +The constructor and the destructor are implemented as follows +\code +LoggerMode::LoggerMode() +{ + d = new LoggerModeData; + d->m_widget = new QWidget; +} + +LoggerMode::~LoggerMode() +{ + delete d->m_widget; + delete d; +} +\endcode +The \bold {name()} method returns a name for the new mode selector. +\code +QString LoggerMode::name() const +{ + return tr("LoggerMode"); +} +\endcode + +The \bold {icon()} method returns a logo for the new mode selector. +\code +QIcon LoggerMode::icon() const +{ + return QIcon(QLatin1String(":/core/images/qtcreator_logo_32.png")); +} +\endcode + +The \bold {priority()} method is implemented to return a priority for the mode. Modes of higher +priority are shown above modes of lower priority. The highest priority in Qt Creator is currently +100 and is associated with the Welcome mode. We return 0 from LoggerMode, becasue we want this +mode to appear at the end. +\code +int LoggerMode::priority() const +{ + return 0; +} +\endcode +Thw \bold {widget()} method returns a widget to the new mode. +\code +QWidget* LoggerMode::widget() +{ + return d->m_widget; +} +\endcode + +The \bold {uniqueModeName()} returns the name of the mode to the "LoggerMode" Class. +\code +const char* LoggerMode::uniqueModeName() const +{ + return "LoggerMode" ; +} +\endcode +The \bold {context()} method returns an empty list of integers to tne "LoggerMode" class. +\code +QList<int> LoggerMode::context() const +{ + return QList<int>(); +} +\endcode + +\section2 Step 3. Implementing the "LoggerMode" plugin +We implement the "LoggerMode" plugin very similar to the DoNothingPlugin class described in Chapter 2. +Here we only look at the implementation of the initialize() method. +\code +bool LoggerModePlugin::initialize(const QStringList& args, QString *errMsg) +{ + Q_UNUSED(args); + Q_UNUSED(errMsg); + + loggerMode = new LoggerMode; + addAutoReleasedObject(loggerMode); + + return true; +} +\endcode +\section2 Step 4. Testing the plugin. +Upon compiling the plugin and restarting Qt Creator, we can notice the "LoggerMode" mode selector in the Qt creator. + +\inlineimage qtc-loggermode-13.png + +\section1 13.3 Adding Functionality to the "LoggerMode" +The actual function of the "LoggerMode" is to log data in a text file about a project, such as progress , hours worked, +description etc. + +\section2 Step 1. Modifying the "LoggerMode" Class + +To add the functionalities, the LoggerMode class is further modified. +The code block is given as follows. + +\code +struct LoggerModeData; +class LoggerMode :public Core::IMode +{ + Q_OBJECT + +public: + LoggerMode(); + ~LoggerMode(); + ... + ... + +protected slots: + void addNewStackWidgetPage(const QString projectName); + void addItem(); + +private: + ... +}; +\endcode + +The constructor of the \bold {LoggerMode} class is modified as follows. +\code +LoggerMode::LoggerMode() +{ + d = new LoggerModeData; + d->m_widget = new QWidget; + + //Current Projects Label and combobox widget are created. + + d->currentProjectsLabel = new QLabel("Current projects :"); + d->currentProjectsLabel->setFixedWidth(90); + d->currentProjectsCombobox = new QComboBox; + d->currentProjectsCombobox->setSizePolicy(QSizePolicy::Preferred, + QSizePolicy::Preferred); + + //Add Projects Label and combobox widget are created. + + d->addProjectLabel = new QLabel("Add Project :"); + d->addProjectLabel->setAlignment(Qt::AlignRight); + d->addProjectComboBox = new QComboBox; + d->addProjectComboBox->setSizePolicy(QSizePolicy::Preferred, + QSizePolicy::Preferred); + d->addProjectComboBox->setEditable(true); + + d->addToProjectButton = new QPushButton(tr("Add Project")); + d->addToProjectButton->setFixedWidth(80); + + //Creating a horizontal Layout + + QHBoxLayout *hLayout = new QHBoxLayout; + hLayout->addWidget(d->currentProjectsLabel); + hLayout->addWidget(d->currentProjectsCombobox); + hLayout->addWidget(d->addProjectLabel); + hLayout->addWidget(d->addProjectComboBox); + hLayout->addWidget(d->addToProjectButton); + + //creating a stackedWidget + + d->stackedWidget = new QStackedWidget; + + //creating a vertical layout + + QVBoxLayout* layout = new QVBoxLayout; + layout->addLayout(hLayout); + layout->addWidget(d->stackedWidget); + + d->m_widget->setLayout(layout); + + d->addProjectComboBox->addItem("Project 1"); + d->addProjectComboBox->addItem("Project 2"); + d->addProjectComboBox->addItem("Project 3"); + + connect(d->addToProjectButton,SIGNAL(clicked()), + this,SLOT(addItem())); + + connect(d->currentProjectsCombobox, SIGNAL(currentIndexChanged(int)), + d->stackedWidget, SLOT(setCurrentIndex(int))); +} + +\endcode + +Implementation of the \bold{addNewStackWidgetPage()} slot of \bold {LoggerMode} class +\code +void LoggerMode::addNewStackWidgetPage(const QString projectName) +{ + d->stackedWidget->addWidget(new LoggerModeWidget(projectName)); +} +\endcode + +Implementation of the \bold{addItem()} slot of \bold {LoggerMode} class +\code +void LoggerMode::addItem() +{ + d->currentProjectsCombobox->addItem(d->addProjectComboBox->currentText()); + addNewStackWidgetPage(d->currentProjectsCombobox->itemText(0)); +} +\endcode + +The effect of the above block of code can be seen in the following image. + +\inlineimage qtc-loggerpage-13.png + + +\section2 Step 2. Declaration of the "LoggerModeWidget" class +Reffering to the above image, when ever we select a project from the \bold {Add Project} combobox and click +\bold {Add Project} button a new project is added to the \bold {Current projects} list and and a corresponding +\bold {LoggerModeWidget} is opened, for logging different informations about the project. +The declaration of the \bold {LoggerModeWidget} class is shown in the following code block. + + \code +#include <QWidget> + +struct LoggerModeWidgetData; +class LoggerModeWidget : public QWidget +{ + Q_OBJECT + +public: + LoggerModeWidget(const QString projectName, QWidget* parent = 0); + ~LoggerModeWidget(); + +public slots: + void setProjectName(QString name); + +protected slots: + bool saveToFile(); + void startTimeLog(); + void endTimeLog(); + void updateTime(); + +private: + LoggerModeWidgetData* d; +}; +\endcode + +\section2 Step 3. Implementing the "LoggerModeWidget" class +Declaring the private member variables in the structure called \bold {LoggerModeWidgetData} +\code +struct LoggerModeWidgetData +{ + QLabel *progressLabel; + QLabel *hoursWorkedLabel; + QLabel *dateLabel; + QLabel *descriptionLabel; + QCalendarWidget *calendar; + QComboBox *progressComboBox; + QLineEdit *hoursWorkedLineEdit; + QPushButton *startTimerButton; + QPushButton *stopTimerButton; + QPushButton *saveButton; + QTimer *timer; + QTextEdit *textEdit; + QString projectName; + int totalTime; +}; +\endcode +Implementation of the constructor and destructor of the \bold {LoggerModeWidget} class +\code +LoggerModeWidget::LoggerModeWidget(const QString projectName, QWidget* parent) +:QWidget(parent) +{ + d = new LoggerModeWidgetData; + d->projectName = projectName; + d->totalTime = 0; + + QStringList percentList; + percentList <<"10%" <<"20%" <<"30%" <<"40%" <<"50%" + <<"60%" <<"70%" <<"80%" <<"90%" <<"100%" ; + d->progressLabel = new QLabel("Progress:"); + d->hoursWorkedLabel = new QLabel("Hours Worked:"); + d->dateLabel = new QLabel("Date:"); + d->descriptionLabel = new QLabel("Description :"); + d->hoursWorkedLineEdit = new QLineEdit; + d->hoursWorkedLineEdit->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + d->progressComboBox = new QComboBox; + d->progressComboBox->addItems(percentList); + d->progressComboBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + d->startTimerButton = new QPushButton(tr("Start Timer")); + d->startTimerButton->setFixedWidth(80); + d->stopTimerButton = new QPushButton(tr("Pause Timer")); + d->stopTimerButton->setFixedWidth(80); + d->stopTimerButton->setCheckable(true); + d->textEdit = new QTextEdit(this); + d->textEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + d->calendar = new QCalendarWidget; + d->saveButton = new QPushButton(tr("Save To File")); + d->saveButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + + QGroupBox *timeLoggerBox = new QGroupBox(tr("Time Logger")); + + QGridLayout *gLayout = new QGridLayout; + gLayout->addWidget(d->dateLabel, 0, 0, 1, 1); + gLayout->addWidget(d->calendar, 1, 0, 1, 3); + gLayout->addWidget(d->progressLabel, 2, 0, 1, 1); + gLayout->addWidget(d->progressComboBox, 2, 1, 1, 1); + gLayout->addWidget(d->hoursWorkedLabel, 3, 0, 1, 1); + gLayout->addWidget(d->hoursWorkedLineEdit, 3, 1, 1, 1); + gLayout->addWidget(d->startTimerButton, 4, 1, 1, 1); + gLayout->addWidget(d->stopTimerButton, 4, 2, 1, 1); + + timeLoggerBox->setLayout(gLayout); + + d->timer = new QTimer(this); + + // connection of SIGNALS and SLOTS + + connect(d->timer, SIGNAL(timeout()), this, SLOT(updateTime())); + connect(d->startTimerButton,SIGNAL(clicked()),this,SLOT(startTimeLog())); + connect(d->stopTimerButton,SIGNAL(clicked()),this,SLOT(endTimeLog())); + connect(d->saveButton, SIGNAL(clicked()), this, SLOT(saveToFile())); + + QVBoxLayout *vLayout = new QVBoxLayout; + vLayout->addWidget(d->descriptionLabel); + vLayout->addWidget(d->textEdit); + + QHBoxLayout * hLayout = new QHBoxLayout; + hLayout->addWidget(timeLoggerBox); + hLayout->addLayout(vLayout); + + QHBoxLayout *bLayout = new QHBoxLayout; + bLayout->addStretch(1); + bLayout->addWidget(d->saveButton); + + QVBoxLayout *mainLayout = new QVBoxLayout(this); + mainLayout->addLayout(hLayout); + mainLayout->addLayout(bLayout); + mainLayout->addStretch(1); + +} + +LoggerModeWidget::~LoggerModeWidget() +{ + delete d; +} + +\endcode + +The \bold {saveToFile()} slot is used by the "SaveTofile" button to save the contents of the "LoggerModeWidget" to a +text file. +\code +bool LoggerModeWidget::saveToFile() +{ + QString fileName = QFileDialog::getSaveFileName(this); + if (fileName.isEmpty()) + return false; + + QFile file(fileName); + if (!file.open(QFile::WriteOnly | QFile::Text)) { + QMessageBox::critical(this, tr("Application"), + tr("Unable to open file %1 for writing :\n%2.") + .arg(fileName) + .arg(file.errorString())); + return false; + } + + QTextStream out(&file); + +#ifndef QT_NO_CURSOR + QApplication::setOverrideCursor(Qt::WaitCursor); +#endif + out << "Project name : " << d->projectName << "\n"; + out << "Date : " << d->calendar->selectedDate().toString() << "\n"; + out << "Progress : " << d->progressComboBox->currentText() << "\n"; + out << "Duration : " << d->hoursWorkedLineEdit->text() << "\n\n"; + out << "Description : " << d->textEdit->toPlainText(); +#ifndef QT_NO_CURSOR + QApplication::restoreOverrideCursor(); +#endif + + return true; +} +\endcode +The \bold {startTimeLog()} slot is used by the \bold {Start Timer} button to start the timer. +\code +void LoggerModeWidget::startTimeLog() +{ + d->totalTime = 0; + d->timer->start(1000); +} +\endcode + +The \bold {endTimeLog()} slot is used by the \bold (Pause Timer } button to pause and resume the timer. +\code +void LoggerModeWidget::endTimeLog() +{ + if(d->stopTimerButton->isChecked()) + { + d->stopTimerButton->setText("Continue Timer"); + d->timer->stop(); + } + else + { + d->stopTimerButton->setText("Pause Timer"); + d->timer->start(1000); + } +} +\endcode + +The \bold {updateTime()} slot is used to update the time. +\code +void LoggerModeWidget::updateTime() +{ + d->totalTime++; + QTime time(0,0,0); + time = time.addSecs(d->totalTime); + d->hoursWorkedLineEdit->setText(time.toString()); +} +\endcode + +\section1 13.4 Testing the final LoggerMode plugin. + +\section2 Step 1. A "LoggerMode" mode selector can be seen int the Qt Creator. +\inlineimage qtc-loggermode-13.png + +\section2 Step 2. A LoggerMode widget opens with options to "Add Projects" +\inlineimage qtc-loggerpage-13.png + +\section2 Step 3. The "Add Project" button adds a project to the "Current Project list and opens the the "LoggerModeWidget" +\inlineimage qtc-loggermodewidget-13.png + +*/ diff --git a/doc/pluginhowto/nav-widget.qdoc b/doc/pluginhowto/nav-widget.qdoc new file mode 100644 index 00000000000..e1274bd0118 --- /dev/null +++ b/doc/pluginhowto/nav-widget.qdoc @@ -0,0 +1,171 @@ +/*! + \page nav-widget.html + \title 6. Adding Navigation Widget + + Navigation panel in Qt Creator is the area where Project, File System, Bookmark and Open Documents siderbars are + shown. Sidebar is one of the widgets in the "Navigation Panel" Take a look at the marked area in the screenshot below. + + \inlineimage qtc-firstnavigation-6.png + + + Qt Creator makes it possible for us to divide the navigation panel into windows and view more than one side bar at the + same time. Take a look at the screenshot below. + + + \inlineimage qtc-secondnavigation-6.png + + + In this chapter we will understand how to add a new side bar to Qt Creator. + + \section1 6.1 Core::INavigationWidgetFactory interface + + The Core of Qt Creator exposes an interface called Core::INavigationWidgetFactory. The interface is defined as follows in + plugins/corelib/inavigationwidgetfactory.h + + \code + class CORE_EXPORT INavigationWidgetFactory : public QObject + { + Q_OBJECT + + public: + INavigationWidgetFactory(); + virtual ~INavigationWidgetFactory(); + virtual QString displayName() = 0; + virtual QKeySequence activationSequence(); + virtual NavigationView createWidget() = 0; + virtual void saveSettings(int position, QWidget *widget); + virtual void restoreSettings(int position, QWidget *widget); + }; + \endcode + + And NavigationView (the return type of createWidget()) is + + \code + struct NavigationView + { + QWidget *widget; + QList<QToolButton *> doockToolBarWidgets; + }; + + \endcode + + Plugins that provide a navigation siderbar (or widget) must implement this interface. In addition to implementing the + interface, the plugin has to use "expose" an instance of that interface using methods described in section 4.2.2. + + \section1 6.2 Preparing a navigation sidebar (widget) + + Suppose that we wanted to provide a Directory browser as a side bar widget from our plugin. + + \section2 Step 1: Let's Implement FileSystemModel such that it will show only one column. + + The Implementation of FileSystemModel is as follows: + \code + #include <QFileSystemModel> + + class FileSystemModel : public QFileSystemModel + { + public: + FileSystemModel(QObject* parent=0); + ~FileSystemModel(); + int columnCount(const QModelIndex &parent = QModelIndex()}const; + }; + \endcode + + General Constructor and Destructor + \code + FileSystemModel::FileSyatemModel(QObject *parent) + :QFileSystemModel(parent) + { + } + + FileSystemModel::~FileSystemModel() + { + } + \endcode + + Implement the virtual function columnCount to return only one column. + + \code + int FileSystemModel::columnCount(const QModelIndex &parent)const + { + Q_UNUSED(parent) + return 1; + } + \endcode + With this FileSystemModel is ready. + + \section2 Step 2: Implementing the INavigationWidgetFactory Interface + We implement the INavigationWidgetFactory interface in a class whose defination is as follows + + \code + #include<coreplugin/inavigationwidgetfactory.h> + + class DirNavigationFactory:: public Core::INavigationWidgetFactory + { + public: + DirNavigationFactory(){} + ~DirNavigationFactory(){} + Core::NavigationView createWidget(); + QString displayName(); + }; + + \endcode + + The createWidget() method is implemented to return an instance of the QTreeView which uses + FileSystemModel that was explained in previous step. + \code + Core::NavigationView DirNavigationFactory::createWidget() + { + Core::NavigationView view; + + // Create FileSystemModel and set the defauls path as home path + FileSystemModel* model = new FileSystemModel; + model->setRootPath(QDir::homePath()); + + // Create TreeView and set model + QTreeView* tree = new QTreeView; + tree->setModel(model); + + view.widget = tree; + + return view; + } + \endcode + + The \bold {displayName()} method is implemented to return a descriptive name that Qt Creator should use for showing the + side-bar. + + \code + QString DirNavigationFactory::displayName() + { + return "Dir View"; + } + \endcode + + With this the \bold {INavigationWidgetFactory} implementation is ready. + + \section2 Step 3: Implementing the Dir-view plugin + We implement the Dir-view plugin class similar to the \bold {DoNothingPlugin} class described in Chapter 2. Hence, we only + describe the implementation of the initialize method of the \bold {DirModelPluginPlugin} class here. + + \code + bool DirModelPluginPlugin::initialize(const QStringList& args, QString *errMsg) + { + Q_UNUSED(args); + Q_UNUSED(errMsg); + addAutoReleasedObject(new DirNavigationFactory); + return true; + } + \endcode + + In the \bold {initialize()} method an instance of the \bold {INavigationWidgetFactory} implementation is created and added to the object + pool. Once the object is added to the pool, \bold {ExtensionSystem::PluginManager} emits the \bold {objectAdded()} signal, which is + then trapped by the Core of Qt Creator. The Core then makes use of our implementation of \bold {INavigationWidgetFactory} + interface and places an instance of DirExplorerSideBar in the navigation panel. + + \section2 Step 4: Testing the plugin + Upon compiling the plugin and restarting Qt Creator, we can notice the "Dir View" side bar as shown below. + + \inlineimage qtc-dirview-6.png + +*/ diff --git a/doc/pluginhowto/pref-pane.qdoc b/doc/pluginhowto/pref-pane.qdoc new file mode 100644 index 00000000000..122134c462f --- /dev/null +++ b/doc/pluginhowto/pref-pane.qdoc @@ -0,0 +1,205 @@ +/*! + \page pref-pane.html + \title 7. Adding Preferences Pane + Preferences dialog in Qt Creator is used to configure the Qt Creator settings. Since Qt Creator is just a plugin loader that + loads all the relevant plugins, the preferences dialog shows pages that configure plugins. You can get to it by clicking + Tools->Options. + + \inlineimage qtc-options-7.png + + + Each plugin provides one or more options pages that get shown in the preferences dialog. In the following sub-sections + we will learn how to add our own pages to the dialog. + + \section1 7.1 Core::IOptionsPage interface + + The Core of Qt Creator exposes an interface called \bold{Core::IOptionsPage}. The interface is defined in + plugins/coreplugin/dialogs/ioptionspage.h. + + \code + class CORE_EXPORT IOptionsPage : public QObject + { + Q_OBJECT + + public: + IOptionsPage( *parent = 0) : QObject(parent) {} + virtual ~IOptionsPage() {} + virtual QString id() const = 0; + virtual QString trName() const = 0; + virtual QString category() const = 0; + virtual QString trCategory() const = 0; + virtual QWidget *createPage(QWidget *parent) = 0; + virtual void apply() = 0; + virtual void finish() = 0; + }; + \endcode + + By implementing the above interface and exposing an instance of it, we will be able to register new pages with the + preferences dialog. + + \section1 7.2 Preparing the options-page + Let's implement a plugin that shows an options page that lists out all the open and modified files. + + \section2 Step 1: Implementing the "modified file" list widget + The modified file list widget is simply a \bold{QListWidget} that shows all the modified files from the project manager. The + class declaration is as follows + + \code + #include <QListWidget> + class ModifiedFileListWidget: public QListWidget + { + Q_OBJECT + + public: + ModifiedFileListWidget(QWidget* parent=0); + ~ModifiedFileListWidget(); + }; + \endcode + + Within the constructor we populate the list widget with names of the modified pages + + \code + #include <coreplugin/filemanager.h> + #include <coreplugin/icore.h> + #include <coreplugin/ifile.h> + + ModifiedFileListWidget::ModifiedFileListWidget(QWidget* parent):QListWidget(parent) + { + // Show the list of modified pages + Core::FileManager* fm = Core::ICore::instance()->fileManager(); + QList<Core::IFile*> files = fm->modifiedFiles(); + + for(int i=0; i<files.count();i++) + this->addItem(files.at(i)->fileName()); + } + \endcode + + The destructor does nothing. + + \code + ModifiedFileListerPage::~ModifiedFileListerPage() + { + + } + \endcode + + \section2 Step 2: Implementing the Core::IOptionsPage interface + We implement the \bold {Core::IOptionsPage} interface in a class called \bold {ModifiedFileLister}. The class declaration + is as follows + + \code + #include <coreplugin/dialogs/ioptionspage.h> + class ModifiedFileLister : public Core::IOptionsPage + { + Q_OBJECT + + public: + ModifiedFileLister(QObject *parent = 0); + ~ModifiedFileLister(); + // IOptionsPage implementation + QString id() const; + QString trName() const; + QString category() const; + QString trCategory() const; + QWidget *createPage(QWidget *parent); + void apply(); + void finish(); + }; + \endcode + + The constructor and destructor are straightforward and easy to understand. + + \code + ModifiedFileLister::ModifiedFileLister(QObject *parent): IOptionsPage(parent) + { + + } + + ModifiedFileLister::~ModifiedFileLister() + { + + } + \endcode + + The \bold{id()} method should be implemented to return a unique identifier for the options page provided by this class. The + string will be used internally to \underline{\bold{id}}entify the page. + + \code + QString ModifiedFileLister::id() const + { + return "ModifiedFiles"; + } + \endcode + + The \bold {trName()} method should be implemented to return a translated string name that will be shown in the options + dialog. + + \code + QString ModifiedFileLister::trName() const + { + return tr("Modified Files"); + } + \endcode + + The \bold{category()} and \bold{trCategory()} methods should be implemented to return the group under which we want to + show the page. The latter returns the translated version of the string returned by the former. + + \code + QString ModifiedFileLister::category() const + { + return "Help"; + } + + QString ModifiedFileLister::trCategory() const + { + return tr("Help"); + } + \endcode + + The \bold{createPage()} method should be implemented to return a new instance of the page implemented in step 1. + + \code + QWidget *ModifiedFileLister::createPage(QWidget *parent) + { + return new ModifiedFileListWidget(parent); + } + \endcode + + The methods \bold {apply()} and \bold {finish()} can be implemented to accept the changes made by the user made on the + page. In our case we don't have any changes to accept, so we leave the methods empty. + + \code + void ModifiedFileLister::apply() + { + // Do nothing + } + + void ModifiedFileLister::finish() + { + // Do nothing + } + \endcode + + \section2 Step 3: Implementing the modified-file-lister plugin + + We implement the plugin class similar to the \bold {DoNothingPlugin} class described in Chapter 2. Hence, we only + describe the implementation of the initialize method of the \bold {ModifiedFileListerPlugin} class here. + + \code + bool ModifiedFileListerPlugin::initialize(const QStringList& args, QString *errMsg) + { + Q_UNUSED(args); + Q_UNUSED(errMsg); + addAutoReleasedObject(new ModifiedFileLister); + return true; + } + \endcode + + \section2 Step 4: Testing the plugin + Upon compiling the plugin and restarting Qt Creator, we can notice in the options dialog the newly added "Modified + Files" page. + + + \inlineimage qtc-testplugin-7.png + + */ diff --git a/doc/pluginhowto/progress.qdoc b/doc/pluginhowto/progress.qdoc new file mode 100644 index 00000000000..d65dd78f07d --- /dev/null +++ b/doc/pluginhowto/progress.qdoc @@ -0,0 +1,111 @@ +/*! + \page progress.html + \title 11.Showing and reacting to progress information + The progress bars give us the information about the progress status of a current task.We can find + progress bar showing up in the Qt Creator window at the left side. Whenever a task is executed + a progress bar pops up showing the progress status until the task is completed. + + \inlineimage qtc-progressbar-11.png + + \section1 11.1 Creating a progress bar + First we will declare the methods required for implementing a "Progress Bar" widget and then we will attach the widget with "Header Filter" in "Find/Replace" + and see it working according to the search progress status. + + \section2 Step 1. Modification of "HeaderFilter" class + The "HeaderFilter" class discussed in Chapter 9. is further modified. + So we will now declare the methods required for a "Progress Bar" in the following block of code. + \code + struct HeaderFilterData; + class HeaderFilter : public Find::IFindFilter + { + Q_OBJECT + public: + HeaderFilter(); + ~HeaderFilter(); + ... + QWidget *createProgressWidget(); + + private: + HeaderFilterData *d; + }; + \endcode + + Here \bold {createProgressWidget()} is not implemented from Find::IFindFilter. It is a custom function written within HeaderFilter class, + which takes up the onus of returning a progress display widget. + + \section2 Step 2. Implementation of the "HeaderFilter" class + The private member variables of the \bold {HeaderFilter} class are declared in the structure \bold {HeaderFilterData} + \code + struct HeaderFilterData + { + QFutureWatcher<FileSearchResult> watcher; + QLabel *resultLabel; + ... + ... + }; + \endcode + The \bold {constructor} and the \bold {destructor} are as follows. + \code + HeaderFilter::HeaderFilter() + { + + d = new HeaderFilterProgressData; + d->watcher.setPendingResultsLimit(1); + d->resultLabel = 0 ; + ... + } + + HeaderFilter::~HeaderFilter() + { + delete d; + } + \endcode + + The \bold {findAll()} method is further modified to create a progress bar popup the bar while searching + is going on. + \code + void HeaderFilter::findAll(const QString &text,QTextDocument::FindFlags findFlags) + { + ... + ... + ... + + //The "progress" is the instance of FutureProgress class. + //The "progress" is the pointer to the progress bar created + //Creates and shows the "progress" bar for searching task. + Core::FutureProgress *progress = + Core::ICore::instance()->progressManager()->addTask(d->watcher.future(), + "MySearch", + Find::Constants::TASK_SEARCH, + Core::ProgressManager::KeepOnFinish + ); + + progress->setWidget(createProgressWidget()); + connect(progress, SIGNAL(clicked()), d->searchResultWindow(), SLOT(popup())); + } + \endcode + + The \bold {createProgressWidget()} function creates the progress widget.It shows + the number of searched items found below and is placed below the progress bar. + \code + QWidget *HeaderFilter::createProgressWidget() + { + d->resultLabel = new QLabel; + d->resultLabel->setAlignment(Qt::AlignCenter); + QFont f = d->resultLabel->font(); + f.setBold(true); + f.setPointSizeF(StyleHelper::sidebarFontSize()); + d->resultLabel->setFont(f); + d->resultLabel->setPalette(StyleHelper::sidebarFontPalette(d->resultLabel->palette())); + d->resultLabel->setText(tr("%1 found").arg(d->searchResultWindow()->numberOfResults())); + return d->resultLabel; + } + \endcode + + \section2 Step 3.Testing the plugin. + Now its the time to test the plugin. For searching we use our "HeaderFilter" and the searched result is shown in the + "Search Results" window and the progress bar pops up while searching. + + \inlineimage qtc-searchprogress-11.png + +*/ diff --git a/doc/pluginhowto/project-file-wizard.qdoc b/doc/pluginhowto/project-file-wizard.qdoc new file mode 100644 index 00000000000..69c663df8ac --- /dev/null +++ b/doc/pluginhowto/project-file-wizard.qdoc @@ -0,0 +1,667 @@ +/*! + \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’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 + + */ diff --git a/doc/pluginhowto/qtc-arch.qdoc b/doc/pluginhowto/qtc-arch.qdoc new file mode 100644 index 00000000000..f33f2a36449 --- /dev/null +++ b/doc/pluginhowto/qtc-arch.qdoc @@ -0,0 +1,329 @@ +/*! + \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. +*/ diff --git a/doc/pluginhowto/qtc-project-plugin.qdoc b/doc/pluginhowto/qtc-project-plugin.qdoc new file mode 100644 index 00000000000..09fa8a39e80 --- /dev/null +++ b/doc/pluginhowto/qtc-project-plugin.qdoc @@ -0,0 +1,6 @@ +/*! + \page qtc-project-plugin.html + \title 3. Creating plugins using Qt Creator + + This page needs to be written still! +*/ diff --git a/doc/pluginhowto/qtcreator-compile.qdoc b/doc/pluginhowto/qtcreator-compile.qdoc new file mode 100644 index 00000000000..678829196f0 --- /dev/null +++ b/doc/pluginhowto/qtcreator-compile.qdoc @@ -0,0 +1,25 @@ +/*! + \page qtcreator-compile.html + \title 1. Compiling Qt Creator + +To start with building Qt creator, you need to get the Qt Creator source. The Qt Creator source is avaiable +from the following locations: +\list +\o Nokia Website: \l {http://qt.nokia.com/downloads} +\o GIT Repository: \l {http://qt.gitorious.org/qt-creator} +\endlist +It is recommended that you build Qt Creator in a separate directory. + +The following steps will guide you to get Qt Creator source compiled: +\list +\o Step 1: Create "build" directory inside main source directory +\o Step 2: Run qmake ../qtcreator.pro -recursive command to get makefile. +\o Step 3: Finally run make (or mingw32-make or nmake, depending on your platform). +\endlist +After successful compilation, you should be able to find \bold {qtcreator.exe} inside \bold {build/bin} directory. +You can now launch Qt Creator. + +\bold {Note:}\underline{It is important that you compile Qt Creator from its sources. Otherwise you wont be able to write +and test plugins for Qt Creator}. + +*/ diff --git a/doc/pluginhowto/qtcreator-pluginhowto.qdoc b/doc/pluginhowto/qtcreator-pluginhowto.qdoc new file mode 100644 index 00000000000..4cd182dba11 --- /dev/null +++ b/doc/pluginhowto/qtcreator-pluginhowto.qdoc @@ -0,0 +1,28 @@ +/*! + \page index.html + \title Qt Creator Plugin HOWTO + + Qt Creator is not only a great developer tool, it is also a tool + can accomodate plugins to help...... + + Qt Creator plugin development can be understood by going through + the following chapters in this manual + + \list 1 + \o \l {qtcreator-compile.html} {Compiling Qt Creator} + \o \l {first-plugin.html} {First Plugin} + \o \l {qtc-project-plugin.html} {Creating plugins using Qt Creator} + \o \l {qtc-arch.html} {Qt Creator Architecture} + \o \l {menu.html} {Adding menu and menu-items} + \o \l {nav-widget.html} {Adding Navigation Widget} + \o \l {pref-pane.html} {Adding Preferences Pane} + \o \l {project-file-wizard.html} {Project/File Wizards} + \o \l {find-filter.html} {Find Filter} + \o \l {editor-type.html} {Adding editor type} + \o \l {progress.html} {Showing and reacting to progress information} + \o \l {vcs.html} {Implementing version control system} + \o \l {mode.html} {Adding a mode} + \o \l {location-filter.html} {Adding location filter} + \o \l {adv-find-filter.html} {Adding "advanced" find filter} + \endlist +*/ diff --git a/doc/pluginhowto/qtcreator-pluginhowto.qdocconf b/doc/pluginhowto/qtcreator-pluginhowto.qdocconf new file mode 100644 index 00000000000..fa083253237 --- /dev/null +++ b/doc/pluginhowto/qtcreator-pluginhowto.qdocconf @@ -0,0 +1,221 @@ +project = Qt Creator Plugin HOWTO API +description = Qt Creator Plugin HOWTO Documentation + +language = Cpp + +sources.fileextensions = "*.qdoc" +sourcedirs = . + +imagedirs = images + +indexes = $QTDIR/doc/html/qt.index + +outputdir = ./html +base = file:./html +versionsym = 1.3.1 +codeindent = 1 +tabsize = 4 + +## compat.qdocconf +alias.i = e +alias.include = input + +macro.0 = "\\\\0" +macro.b = "\\\\b" +macro.n = "\\\\n" +macro.r = "\\\\r" +macro.i = "\\o" +macro.i11 = "\\o{1,1}" +macro.i12 = "\\o{1,2}" +macro.i13 = "\\o{1,3}" +macro.i14 = "\\o{1,4}" +macro.i15 = "\\o{1,5}" +macro.i16 = "\\o{1,6}" +macro.i17 = "\\o{1,7}" +macro.i18 = "\\o{1,8}" +macro.i19 = "\\o{1,9}" +macro.i21 = "\\o{2,1}" +macro.i31 = "\\o{3,1}" +macro.i41 = "\\o{4,1}" +macro.i51 = "\\o{5,1}" +macro.i61 = "\\o{6,1}" +macro.i71 = "\\o{7,1}" +macro.i81 = "\\o{8,1}" +macro.i91 = "\\o{9,1}" +macro.img = "\\image" +macro.endquote = "\\endquotation" +macro.relatesto = "\\relates" + +spurious = "Missing comma in .*" \ + "Missing pattern .*" + +## macros.qdocconf +macro.aring.HTML = "å" +macro.Auml.HTML = "Ä" +macro.author = "\\bold{Author:}" +macro.br.HTML = "<br />" +macro.BR.HTML = "<br />" +macro.aacute.HTML = "á" +macro.eacute.HTML = "é" +macro.iacute.HTML = "í" +macro.gui = "\\bold" +macro.hr.HTML = "<hr />" +macro.key = "\\bold" +macro.menu = "\\bold" +macro.note = "\\bold{Note:}" +macro.oslash.HTML = "ø" +macro.ouml.HTML = "ö" +macro.QA = "\\e{Qt Assistant}" +macro.QD = "\\e{Qt Designer}" +macro.QL = "\\e{Qt Linguist}" +macro.QC = "\\e{Qt Creator}" +macro.param = "\\e" +macro.raisedaster.HTML = "<sup>*</sup>" +macro.reg.HTML = "<sup>®</sup>" +macro.return = "Returns" +macro.starslash = "\\c{*/}" +macro.uuml.HTML = "ü" +macro.mdash.HTML = "—" + +## qt-cpp-ignore.qdocconf +Cpp.ignoretokens = QAXFACTORY_EXPORT \ + QDESIGNER_COMPONENTS_LIBRARY \ + QDESIGNER_EXTENSION_LIBRARY \ + QDESIGNER_SDK_LIBRARY \ + QDESIGNER_SHARED_LIBRARY \ + QDESIGNER_UILIB_LIBRARY \ + QM_EXPORT_CANVAS \ + QM_EXPORT_DNS \ + QM_EXPORT_DOM \ + QM_EXPORT_FTP \ + QM_EXPORT_HTTP \ + QM_EXPORT_ICONVIEW \ + QM_EXPORT_NETWORK \ + QM_EXPORT_OPENGL \ + QM_EXPORT_SQL \ + QM_EXPORT_TABLE \ + QM_EXPORT_WORKSPACE \ + QM_EXPORT_XML \ + QT_ASCII_CAST_WARN \ + QT_ASCII_CAST_WARN_CONSTRUCTOR \ + QT_BEGIN_HEADER \ + QT_DESIGNER_STATIC \ + QT_END_HEADER \ + QT_FASTCALL \ + QT_WIDGET_PLUGIN_EXPORT \ + Q_COMPAT_EXPORT \ + Q_CORE_EXPORT \ + Q_EXPLICIT \ + Q_EXPORT \ + Q_EXPORT_CODECS_CN \ + Q_EXPORT_CODECS_JP \ + Q_EXPORT_CODECS_KR \ + Q_EXPORT_PLUGIN \ + Q_GFX_INLINE \ + Q_AUTOTEST_EXPORT \ + Q_GUI_EXPORT \ + Q_GUI_EXPORT_INLINE \ + Q_GUI_EXPORT_STYLE_CDE \ + Q_GUI_EXPORT_STYLE_COMPACT \ + Q_GUI_EXPORT_STYLE_MAC \ + Q_GUI_EXPORT_STYLE_MOTIF \ + Q_GUI_EXPORT_STYLE_MOTIFPLUS \ + Q_GUI_EXPORT_STYLE_PLATINUM \ + Q_GUI_EXPORT_STYLE_POCKETPC \ + Q_GUI_EXPORT_STYLE_SGI \ + Q_GUI_EXPORT_STYLE_WINDOWS \ + Q_GUI_EXPORT_STYLE_WINDOWSXP \ + QHELP_EXPORT \ + Q_INLINE_TEMPLATE \ + Q_INTERNAL_WIN_NO_THROW \ + Q_NETWORK_EXPORT \ + Q_OPENGL_EXPORT \ + Q_OUTOFLINE_TEMPLATE \ + Q_SQL_EXPORT \ + Q_SVG_EXPORT \ + Q_SCRIPT_EXPORT \ + Q_SCRIPTTOOLS_EXPORT \ + Q_TESTLIB_EXPORT \ + Q_TYPENAME \ + Q_XML_EXPORT \ + Q_XMLSTREAM_EXPORT \ + Q_XMLPATTERNS_EXPORT \ + QDBUS_EXPORT \ + QT_BEGIN_NAMESPACE \ + QT_BEGIN_INCLUDE_NAMESPACE \ + QT_END_NAMESPACE \ + QT_END_INCLUDE_NAMESPACE \ + PHONON_EXPORT +Cpp.ignoredirectives = Q_DECLARE_HANDLE \ + Q_DECLARE_INTERFACE \ + Q_DECLARE_METATYPE \ + Q_DECLARE_OPERATORS_FOR_FLAGS \ + Q_DECLARE_PRIVATE \ + Q_DECLARE_PUBLIC \ + Q_DECLARE_SHARED \ + Q_DECLARE_TR_FUNCTIONS \ + Q_DECLARE_TYPEINFO \ + Q_DISABLE_COPY \ + QT_FORWARD_DECLARE_CLASS \ + Q_DUMMY_COMPARISON_OPERATOR \ + Q_ENUMS \ + Q_FLAGS \ + Q_INTERFACES \ + __attribute__ \ + K_DECLARE_PRIVATE \ + PHONON_OBJECT \ + PHONON_HEIR + +## qt-html-templates.qdocconf +HTML.stylesheets = classic.css +HTML.postheader = "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n" \ + "<tr>\n" \ + "<td align=\"left\" valign=\"top\" width=\"32\">" \ + "<a href=\"http://www.trolltech.com/products/qt\"><img src=\"images/qt-logo.png\" align=\"left\" border=\"0\" /></a>" \ + "</td>\n" \ + "<td width=\"1\"> </td>" \ + "<td class=\"postheader\" valign=\"center\">" \ + "<a href=\"index.html\">" \ + "<font color=\"#004faf\">Home</font></a> ·" \ + " <a href=\"namespaces.html\">" \ + "<font color=\"#004faf\">All Namespaces</font></a> ·" \ + " <a href=\"classes.html\">" \ + "<font color=\"#004faf\">All Classes</font></a> ·" \ + " <a href=\"mainclasses.html\">" \ + "<font color=\"#004faf\">Main Classes</font></a> ·" \ + " <a href=\"groups.html\">" \ + "<font color=\"#004faf\">Grouped Classes</font></a> ·" \ + " <a href=\"modules.html\">" \ + "<font color=\"#004faf\">Modules</font></a> ·" \ + " <a href=\"functions.html\">" \ + "<font color=\"#004faf\">Functions</font></a>" \ + "</td>\n" \ + "<td align=\"right\" valign=\"top\" width=\"230\"></td></tr></table>" + +HTML.footer = "<p /><address><hr /><div align=\"center\">\n" \ + "<table width=\"100%\" cellspacing=\"0\" border=\"0\"><tr class=\"address\">\n" \ + "<td width=\"30%\" align=\"left\">Copyright © 2010 Nokia Corporation " \ + "and/or its subsidiary(-ies)</td>\n" \ + "<td width=\"40%\" align=\"center\"><a href=\"trademarks.html\">Trademarks</a></td>\n" \ + "<td width=\"30%\" align=\"right\"><div align=\"right\">Qt Creator Plugin HOWTO\\version</div></td>\n" \ + "</tr></table></div></address>" + +## qt-defines.qdocconf +defines = Q_QDOC \ + QT_.*_SUPPORT \ + QT_.*_LIB \ + QT_COMPAT \ + QT_KEYPAD_NAVIGATION \ + QT3_SUPPORT \ + Q_WS_.* \ + Q_OS_.* \ + Q_BYTE_ORDER \ + QT_DEPRECATED \ + Q_NO_USING_KEYWORD \ + __cplusplus + +# Files not referenced in any qdoc file (last four needed by qtdemo) +# See also qhp.Qt.extraFiles +extraimages.HTML = qt-logo \ + trolltech-logo + diff --git a/doc/pluginhowto/vcs.qdoc b/doc/pluginhowto/vcs.qdoc new file mode 100644 index 00000000000..03be51a54ed --- /dev/null +++ b/doc/pluginhowto/vcs.qdoc @@ -0,0 +1,6 @@ +/*! + \page vcs.html + \title 12.Implementing version control system + + This page needs to be written still! +*/ |