summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLeandro Melo <leandro.melo@nokia.com>2011-12-07 15:05:02 +0100
committerLeandro Melo <leandro.melo@nokia.com>2011-12-09 10:25:59 +0100
commitbeede7d7cff3e740ec0b0053ae9e382693e7f42c (patch)
tree74c0ffc3cad7569aa2f7946a2884dfd6d89c7361 /src
parent24b4c127372c6a9c496c8d0bd812696f6ad0f4d4 (diff)
downloadqt-creator-beede7d7cff3e740ec0b0053ae9e382693e7f42c.tar.gz
C++: Automatic Doxygen comment blocks generation
This improves our completion support for documentation comments. It's now possible to have a Doxygen block generated when hitting enter after a /** or /*! comment start. A couple other related options are also available. Task-number: QTCREATORBUG-2752 Task-number: QTCREATORBUG-3165 Change-Id: I1c81c0b4b370eb1d409ef72a9c7f22c357f202f4 Reviewed-by: Leena Miettinen <riitta-leena.miettinen@nokia.com> Reviewed-by: Christian Kamm <christian.d.kamm@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/cppeditor/cppeditor.cpp106
-rw-r--r--src/plugins/cppeditor/cppeditor.h7
-rw-r--r--src/plugins/cpptools/commentssettings.cpp46
-rw-r--r--src/plugins/cpptools/commentssettings.h35
-rw-r--r--src/plugins/cpptools/completionsettingspage.cpp43
-rw-r--r--src/plugins/cpptools/completionsettingspage.h16
-rw-r--r--src/plugins/cpptools/completionsettingspage.ui85
-rw-r--r--src/plugins/cpptools/cpptools.pro8
-rw-r--r--src/plugins/cpptools/cpptoolsplugin.cpp1
-rw-r--r--src/plugins/cpptools/cpptoolssettings.cpp25
-rw-r--r--src/plugins/cpptools/cpptoolssettings.h6
-rw-r--r--src/plugins/cpptools/doxygengenerator.cpp289
-rw-r--r--src/plugins/cpptools/doxygengenerator.h71
13 files changed, 723 insertions, 15 deletions
diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp
index 0885be8eae..0b5f2eaea1 100644
--- a/src/plugins/cppeditor/cppeditor.cpp
+++ b/src/plugins/cppeditor/cppeditor.cpp
@@ -69,6 +69,8 @@
#include <cpptools/cppcodestylesettings.h>
#include <cpptools/cpprefactoringchanges.h>
#include <cpptools/cpptoolsreuse.h>
+#include <cpptools/doxygengenerator.h>
+#include <cpptools/cpptoolssettings.h>
#include <coreplugin/icore.h>
#include <coreplugin/actionmanager/actionmanager.h>
@@ -415,6 +417,7 @@ CPPEditorWidget::CPPEditorWidget(QWidget *parent)
, m_inRenameChanged(false)
, m_firstRenameChange(false)
, m_objcEnabled(false)
+ , m_commentsSettings(CppTools::CppToolsSettings::instance()->commentsSettings())
{
m_initialized = false;
qRegisterMetaType<CppEditor::Internal::SemanticInfo>("CppEditor::Internal::SemanticInfo");
@@ -451,6 +454,11 @@ CPPEditorWidget::CPPEditorWidget(QWidget *parent)
m_declDefLinkFinder = new FunctionDeclDefLinkFinder(this);
connect(m_declDefLinkFinder, SIGNAL(foundLink(QSharedPointer<FunctionDeclDefLink>)),
this, SLOT(onFunctionDeclDefLinkFound(QSharedPointer<FunctionDeclDefLink>)));
+
+ connect(CppTools::CppToolsSettings::instance(),
+ SIGNAL(commentsSettingsChanged(CppTools::CommentsSettings)),
+ this,
+ SLOT(onCommentsSettingsChanged(CppTools::CommentsSettings)));
}
CPPEditorWidget::~CPPEditorWidget()
@@ -1552,7 +1560,8 @@ void CPPEditorWidget::contextMenuEvent(QContextMenuEvent *e)
void CPPEditorWidget::keyPressEvent(QKeyEvent *e)
{
if (m_currentRenameSelection == NoCurrentRenameSelection) {
- TextEditor::BaseTextEditorWidget::keyPressEvent(e);
+ if (!handleDocumentationComment(e))
+ TextEditor::BaseTextEditorWidget::keyPressEvent(e);
return;
}
@@ -2239,4 +2248,99 @@ void CPPEditorWidget::abortDeclDefLink()
m_declDefLink.clear();
}
+bool CPPEditorWidget::handleDocumentationComment(QKeyEvent *e)
+{
+ if (!m_commentsSettings.m_enableDoxygen
+ && !m_commentsSettings.m_leadingAsterisks) {
+ return false;
+ }
+
+ if (e->key() == Qt::Key_Return
+ || e->key() == Qt::Key_Enter) {
+ QTextCursor cursor = textCursor();
+ if (!autoCompleter()->isInComment(cursor))
+ return false;
+
+ // We are interested on two particular cases:
+ // 1) The cursor is right after a /** or /*! and the user pressed enter. If Doxygen
+ // is enabled we need to generate an entire comment block.
+ // 2) The cursor is already in the middle of a multi-line comment and the user pressed
+ // enter. If leading asterisk(s) is set we need to write a comment continuation
+ // with those.
+
+ if (m_commentsSettings.m_enableDoxygen
+ && cursor.positionInBlock() >= 3) {
+ const int pos = cursor.position();
+ if (characterAt(pos - 3) == QChar('/')
+ && characterAt(pos - 2) == QChar('*')
+ && (characterAt(pos - 1) == QChar('*')
+ || characterAt(pos - 1) == QChar('!'))) {
+ CppTools::DoxygenGenerator doxygen;
+ doxygen.setAddLeadingAsterisks(m_commentsSettings.m_leadingAsterisks);
+ doxygen.setGenerateBrief(m_commentsSettings.m_generateBrief);
+ doxygen.setStartComment(false);
+ if (characterAt(pos - 1) == QLatin1Char('!'))
+ doxygen.setStyle(CppTools::DoxygenGenerator::QtStyle);
+ else
+ doxygen.setStyle(CppTools::DoxygenGenerator::JavaStyle);
+
+ // Move until we reach any possibly meaningful content.
+ while (document()->characterAt(cursor.position()).isSpace())
+ cursor.movePosition(QTextCursor::NextCharacter);
+
+ const QString &comment = doxygen.generate(cursor);
+ if (!comment.isEmpty()) {
+ cursor.beginEditBlock();
+ cursor.setPosition(pos);
+ cursor.insertText(comment);
+ cursor.setPosition(pos - 3, QTextCursor::KeepAnchor);
+ indent(document(), cursor, QChar::Null);
+ cursor.endEditBlock();
+ e->accept();
+ return true;
+ }
+ cursor.setPosition(pos);
+ }
+ }
+
+ if (!m_commentsSettings.m_leadingAsterisks)
+ return false;
+
+ const QString &text = cursor.block().text();
+ const int length = text.length();
+ int offset = 0;
+ for (; offset < length; ++offset) {
+ const QChar &current = text.at(offset);
+ if (!current.isSpace())
+ break;
+ }
+ if (offset < length
+ && (text.at(offset) == QLatin1Char('*')
+ || (offset < length - 1
+ && text.at(offset) == QLatin1Char('/')
+ && text.at(offset + 1) == QLatin1Char('*')))) {
+ QString newLine(QLatin1Char('\n'));
+ newLine.append(QString(offset, QLatin1Char(' ')));
+ if (text.at(offset) == QLatin1Char('/')) {
+ newLine.append(QLatin1String(" *"));
+ } else {
+ int start = offset;
+ while (offset < length && text.at(offset) == QLatin1Char('*'))
+ ++offset;
+ newLine.append(QString(offset - start, QLatin1Char('*')));
+ }
+ cursor.insertText(newLine);
+ e->accept();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void CPPEditorWidget::onCommentsSettingsChanged(const CppTools::CommentsSettings &settings)
+{
+ m_commentsSettings = settings;
+}
+
#include "cppeditor.moc"
diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h
index 7d576c6599..f02c444f81 100644
--- a/src/plugins/cppeditor/cppeditor.h
+++ b/src/plugins/cppeditor/cppeditor.h
@@ -42,6 +42,7 @@
#include <cplusplus/LookupContext.h>
#include <texteditor/basetexteditor.h>
#include <texteditor/quickfix.h>
+#include <cpptools/commentssettings.h>
#include <QtCore/QThread>
#include <QtCore/QMutex>
@@ -250,6 +251,8 @@ private Q_SLOTS:
void onRefactorMarkerClicked(const TextEditor::RefactorMarker &marker);
+ void onCommentsSettingsChanged(const CppTools::CommentsSettings &settings);
+
private:
void markSymbols(const QTextCursor &tc, const SemanticInfo &info);
bool sortedOutline() const;
@@ -284,6 +287,8 @@ private:
QModelIndex indexForPosition(int line, int column, const QModelIndex &rootIndex = QModelIndex()) const;
+ bool handleDocumentationComment(QKeyEvent *e);
+
CPlusPlus::CppModelManagerInterface *m_modelManager;
QComboBox *m_outlineCombo;
@@ -325,6 +330,8 @@ private:
FunctionDeclDefLinkFinder *m_declDefLinkFinder;
QSharedPointer<FunctionDeclDefLink> m_declDefLink;
+
+ CppTools::CommentsSettings m_commentsSettings;
};
diff --git a/src/plugins/cpptools/commentssettings.cpp b/src/plugins/cpptools/commentssettings.cpp
new file mode 100644
index 0000000000..0cf2edfc96
--- /dev/null
+++ b/src/plugins/cpptools/commentssettings.cpp
@@ -0,0 +1,46 @@
+#include "commentssettings.h"
+
+#include <QtCore/QSettings>
+
+using namespace CppTools;
+
+namespace {
+
+const char kDocumentationCommentsGroup[] = "DocumentationComments";
+const char kEnableDoxygenBlocks[] = "EnableDoxygenBlocks";
+const char kGenerateBrief[] = "GenerateBrief";
+const char kAddLeadingAsterisks[] = "AddLeadingAsterisks";
+
+}
+
+CommentsSettings::CommentsSettings()
+ : m_enableDoxygen(true)
+ , m_generateBrief(true)
+ , m_leadingAsterisks(true)
+{}
+
+void CommentsSettings::toSettings(const QString &category, QSettings *s) const
+{
+ s->beginGroup(category + QLatin1String(kDocumentationCommentsGroup));
+ s->setValue(QLatin1String(kEnableDoxygenBlocks), m_enableDoxygen);
+ s->setValue(QLatin1String(kGenerateBrief), m_generateBrief);
+ s->setValue(QLatin1String(kAddLeadingAsterisks), m_leadingAsterisks);
+ s->endGroup();
+}
+
+void CommentsSettings::fromSettings(const QString &category, QSettings *s)
+{
+ s->beginGroup(category + QLatin1String(kDocumentationCommentsGroup));
+ m_enableDoxygen = s->value(QLatin1String(kEnableDoxygenBlocks), true).toBool();
+ m_generateBrief = m_enableDoxygen
+ && s->value(QLatin1String(kGenerateBrief), true).toBool();
+ m_leadingAsterisks = s->value(QLatin1String(kAddLeadingAsterisks), true).toBool();
+ s->endGroup();
+}
+
+bool CommentsSettings::equals(const CommentsSettings &other) const
+{
+ return m_enableDoxygen == other.m_enableDoxygen
+ && m_generateBrief == other.m_generateBrief
+ && m_leadingAsterisks == other.m_leadingAsterisks;
+}
diff --git a/src/plugins/cpptools/commentssettings.h b/src/plugins/cpptools/commentssettings.h
new file mode 100644
index 0000000000..2e6c140e1b
--- /dev/null
+++ b/src/plugins/cpptools/commentssettings.h
@@ -0,0 +1,35 @@
+#ifndef COMMENTSSETTINGS_H
+#define COMMENTSSETTINGS_H
+
+#include "cpptools_global.h"
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace CppTools {
+
+class CPPTOOLS_EXPORT CommentsSettings
+{
+public:
+ CommentsSettings();
+
+ void toSettings(const QString &category, QSettings *s) const;
+ void fromSettings(const QString &category, QSettings *s);
+
+ bool equals(const CommentsSettings &other) const;
+
+ bool m_enableDoxygen;
+ bool m_generateBrief;
+ bool m_leadingAsterisks;
+};
+
+inline bool operator==(const CommentsSettings &a, const CommentsSettings &b)
+{ return a.equals(b); }
+
+inline bool operator!=(const CommentsSettings &a, const CommentsSettings &b)
+{ return !(a == b); }
+
+} // namespace CppTools
+
+#endif // COMMENTSSETTINGS_H
diff --git a/src/plugins/cpptools/completionsettingspage.cpp b/src/plugins/cpptools/completionsettingspage.cpp
index 7af6d37709..dbb5cb33de 100644
--- a/src/plugins/cpptools/completionsettingspage.cpp
+++ b/src/plugins/cpptools/completionsettingspage.cpp
@@ -32,6 +32,7 @@
#include "completionsettingspage.h"
#include "ui_completionsettingspage.h"
+#include "cpptoolsconstants.h"
#include <coreplugin/icore.h>
#include <extensionsystem/pluginmanager.h>
@@ -40,11 +41,16 @@
#include <QtCore/QTextStream>
#include <QtCore/QCoreApplication>
+using namespace CppTools;
using namespace CppTools::Internal;
+using namespace CppTools::Constants;
-CompletionSettingsPage::CompletionSettingsPage()
- : m_page(0)
+CompletionSettingsPage::CompletionSettingsPage(QObject *parent)
+ : TextEditor::TextEditorOptionsPage(parent)
+ , m_page(0)
{
+ if (QSettings *s = Core::ICore::instance()->settings())
+ m_commentsSettings.fromSettings(QLatin1String(CPPTOOLS_SETTINGSGROUP), s);
}
CompletionSettingsPage::~CompletionSettingsPage()
@@ -103,6 +109,9 @@ QWidget *CompletionSettingsPage::createPage(QWidget *parent)
m_page->surroundSelectedText->setChecked(settings.m_surroundingAutoBrackets);
m_page->partiallyComplete->setChecked(settings.m_partiallyComplete);
m_page->spaceAfterFunctionName->setChecked(settings.m_spaceAfterFunctionName);
+ m_page->enableDoxygenCheckBox->setChecked(m_commentsSettings.m_enableDoxygen);
+ m_page->generateBriefCheckBox->setChecked(m_commentsSettings.m_generateBrief);
+ m_page->leadingAsterisksCheckBox->setChecked(m_commentsSettings.m_leadingAsterisks);
if (m_searchKeywords.isEmpty()) {
QTextStream(&m_searchKeywords) << m_page->caseSensitivityLabel->text()
@@ -110,10 +119,15 @@ QWidget *CompletionSettingsPage::createPage(QWidget *parent)
<< ' ' << m_page->surroundSelectedText->text()
<< ' ' << m_page->completionTriggerLabel->text()
<< ' ' << m_page->partiallyComplete->text()
- << ' ' << m_page->spaceAfterFunctionName->text();
+ << ' ' << m_page->spaceAfterFunctionName->text()
+ << ' ' << m_page->enableDoxygenCheckBox->text()
+ << ' ' << m_page->generateBriefCheckBox->text()
+ << ' ' << m_page->leadingAsterisksCheckBox->text();
m_searchKeywords.remove(QLatin1Char('&'));
}
+ m_page->generateBriefCheckBox->setEnabled(m_page->enableDoxygenCheckBox->isChecked());
+
return w;
}
@@ -130,6 +144,17 @@ void CompletionSettingsPage::apply()
settings.m_spaceAfterFunctionName = m_page->spaceAfterFunctionName->isChecked();
TextEditor::TextEditorSettings::instance()->setCompletionSettings(settings);
+
+ if (!requireCommentsSettingsUpdate())
+ return;
+
+ m_commentsSettings.m_enableDoxygen = m_page->enableDoxygenCheckBox->isChecked();
+ m_commentsSettings.m_generateBrief = m_page->generateBriefCheckBox->isChecked();
+ m_commentsSettings.m_leadingAsterisks = m_page->leadingAsterisksCheckBox->isChecked();
+ if (QSettings *s = Core::ICore::instance()->settings())
+ m_commentsSettings.toSettings(QLatin1String(CPPTOOLS_SETTINGSGROUP), s);
+
+ emit commentsSettingsChanged(m_commentsSettings);
}
bool CompletionSettingsPage::matches(const QString &s) const
@@ -168,3 +193,15 @@ void CompletionSettingsPage::finish()
delete m_page;
m_page = 0;
}
+
+const CommentsSettings &CompletionSettingsPage::commentsSettings() const
+{
+ return m_commentsSettings;
+}
+
+bool CompletionSettingsPage::requireCommentsSettingsUpdate() const
+{
+ return m_commentsSettings.m_enableDoxygen != m_page->enableDoxygenCheckBox->isChecked()
+ || m_commentsSettings.m_generateBrief != m_page->generateBriefCheckBox->isChecked()
+ || m_commentsSettings.m_leadingAsterisks != m_page->leadingAsterisksCheckBox->isChecked();
+}
diff --git a/src/plugins/cpptools/completionsettingspage.h b/src/plugins/cpptools/completionsettingspage.h
index 627125a4c8..590aebd512 100644
--- a/src/plugins/cpptools/completionsettingspage.h
+++ b/src/plugins/cpptools/completionsettingspage.h
@@ -33,13 +33,17 @@
#ifndef COMPLETIONSETTINGSPAGE_H
#define COMPLETIONSETTINGSPAGE_H
+#include "commentssettings.h"
+
#include <texteditor/completionsettings.h>
#include <texteditor/texteditoroptionspage.h>
namespace CppTools {
namespace Internal {
-namespace Ui { class CompletionSettingsPage; }
+namespace Ui {
+class CompletionSettingsPage;
+}
// TODO: Move this class to the text editor plugin
@@ -48,7 +52,7 @@ class CompletionSettingsPage : public TextEditor::TextEditorOptionsPage
Q_OBJECT
public:
- CompletionSettingsPage();
+ CompletionSettingsPage(QObject *parent);
~CompletionSettingsPage();
QString id() const;
@@ -59,12 +63,20 @@ public:
void finish();
virtual bool matches(const QString &) const;
+ const CommentsSettings &commentsSettings() const;
+
+signals:
+ void commentsSettingsChanged(const CppTools::CommentsSettings &settings);
+
private:
TextEditor::CaseSensitivity caseSensitivity() const;
TextEditor::CompletionTrigger completionTrigger() const;
+ bool requireCommentsSettingsUpdate() const;
+
Ui::CompletionSettingsPage *m_page;
QString m_searchKeywords;
+ CommentsSettings m_commentsSettings;
};
} // namespace Internal
diff --git a/src/plugins/cpptools/completionsettingspage.ui b/src/plugins/cpptools/completionsettingspage.ui
index 0be439363b..89e37c31d6 100644
--- a/src/plugins/cpptools/completionsettingspage.ui
+++ b/src/plugins/cpptools/completionsettingspage.ui
@@ -6,11 +6,11 @@
<rect>
<x>0</x>
<y>0</y>
- <width>393</width>
- <height>241</height>
+ <width>484</width>
+ <height>376</height>
</rect>
</property>
- <layout class="QVBoxLayout" name="verticalLayout">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
@@ -197,6 +197,65 @@
</widget>
</item>
<item>
+ <widget class="QGroupBox" name="docCommentsGroup">
+ <property name="title">
+ <string>Documentation Comments</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QCheckBox" name="enableDoxygenCheckBox">
+ <property name="toolTip">
+ <string>Automatically create a Doxygen comment upon pressing enter after a /** or /*!</string>
+ </property>
+ <property name="text">
+ <string>Enable Doxygen blocks</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <spacer name="horizontalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>30</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="generateBriefCheckBox">
+ <property name="toolTip">
+ <string>Generate a &lt;i&gt;brief&lt;/i&gt; command with an initial description for the corresponding declaration</string>
+ </property>
+ <property name="text">
+ <string>Generate brief description</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="leadingAsterisksCheckBox">
+ <property name="toolTip">
+ <string>Add leading asterisks when continuing comments on new lines</string>
+ </property>
+ <property name="text">
+ <string>Add leading asterisks</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -224,8 +283,8 @@
<y>131</y>
</hint>
<hint type="destinationlabel">
- <x>265</x>
- <y>182</y>
+ <x>333</x>
+ <y>206</y>
</hint>
</hints>
</connection>
@@ -245,5 +304,21 @@
</hint>
</hints>
</connection>
+ <connection>
+ <sender>enableDoxygenCheckBox</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>generateBriefCheckBox</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>153</x>
+ <y>272</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>204</x>
+ <y>293</y>
+ </hint>
+ </hints>
+ </connection>
</connections>
</ui>
diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro
index 42fe7721dc..cbf4d3cd70 100644
--- a/src/plugins/cpptools/cpptools.pro
+++ b/src/plugins/cpptools/cpptools.pro
@@ -35,7 +35,9 @@ HEADERS += completionsettingspage.h \
cppcodestylesettings.h \
cppcodestylepreferencesfactory.h \
cppcodestylepreferences.h \
- cpptoolsreuse.h
+ cpptoolsreuse.h \
+ doxygengenerator.h \
+ commentssettings.h
SOURCES += completionsettingspage.cpp \
cppclassesfilter.cpp \
@@ -62,7 +64,9 @@ SOURCES += completionsettingspage.cpp \
cppcodestylesettings.cpp \
cppcodestylepreferencesfactory.cpp \
cppcodestylepreferences.cpp \
- cpptoolsreuse.cpp
+ cpptoolsreuse.cpp \
+ doxygengenerator.cpp \
+ commentssettings.cpp
FORMS += completionsettingspage.ui \
cppfilesettingspage.ui \
diff --git a/src/plugins/cpptools/cpptoolsplugin.cpp b/src/plugins/cpptools/cpptoolsplugin.cpp
index 14b453a0cb..4873e8edf3 100644
--- a/src/plugins/cpptools/cpptoolsplugin.cpp
+++ b/src/plugins/cpptools/cpptoolsplugin.cpp
@@ -122,7 +122,6 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error)
addAutoReleasedObject(new CppClassesFilter(m_modelManager));
addAutoReleasedObject(new CppFunctionsFilter(m_modelManager));
addAutoReleasedObject(new CppCurrentDocumentFilter(m_modelManager, core->editorManager()));
- addAutoReleasedObject(new CompletionSettingsPage);
addAutoReleasedObject(new CppFileSettingsPage(m_fileSettings));
addAutoReleasedObject(new SymbolsFindFilter(m_modelManager));
addAutoReleasedObject(new CppCodeStyleSettingsPage);
diff --git a/src/plugins/cpptools/cpptoolssettings.cpp b/src/plugins/cpptools/cpptoolssettings.cpp
index 47d144ede5..08b68e5c93 100644
--- a/src/plugins/cpptools/cpptoolssettings.cpp
+++ b/src/plugins/cpptools/cpptoolssettings.cpp
@@ -34,11 +34,14 @@
#include "cpptoolsconstants.h"
#include "cppcodestylepreferences.h"
#include "cppcodestylepreferencesfactory.h"
+#include "commentssettings.h"
+#include "completionsettingspage.h"
#include <texteditor/texteditorsettings.h>
#include <texteditor/texteditorsettings.h>
#include <texteditor/tabsettings.h>
#include <texteditor/codestylepool.h>
+#include <extensionsystem/pluginmanager.h>
#include <utils/settingsutils.h>
#include <utils/qtcassert.h>
@@ -48,6 +51,7 @@
static const char *idKey = "CppGlobal";
using namespace CppTools;
+using namespace CppTools::Internal;
using TextEditor::TabSettings;
namespace CppTools {
@@ -56,7 +60,13 @@ namespace Internal {
class CppToolsSettingsPrivate
{
public:
+ CppToolsSettingsPrivate()
+ : m_globalCodeStyle(0)
+ , m_completionSettingsPage(0)
+ {}
+
CppCodeStylePreferences *m_globalCodeStyle;
+ CompletionSettingsPage *m_completionSettingsPage;
};
} // namespace Internal
@@ -70,8 +80,17 @@ CppToolsSettings::CppToolsSettings(QObject *parent)
{
QTC_ASSERT(!m_instance, return);
m_instance = this;
+
qRegisterMetaType<CppTools::CppCodeStyleSettings>("CppTools::CppCodeStyleSettings");
+ d->m_completionSettingsPage = new CompletionSettingsPage(this);
+ ExtensionSystem::PluginManager::instance()->addObject(d->m_completionSettingsPage);
+
+ connect(d->m_completionSettingsPage,
+ SIGNAL(commentsSettingsChanged(CppTools::CommentsSettings)),
+ this,
+ SIGNAL(commentsSettingsChanged(CppTools::CommentsSettings)));
+
TextEditor::TextEditorSettings *textEditorSettings = TextEditor::TextEditorSettings::instance();
// code style factory
@@ -224,6 +243,8 @@ CppToolsSettings::CppToolsSettings(QObject *parent)
CppToolsSettings::~CppToolsSettings()
{
+ ExtensionSystem::PluginManager::instance()->removeObject(d->m_completionSettingsPage);
+
delete d;
m_instance = 0;
@@ -239,3 +260,7 @@ CppCodeStylePreferences *CppToolsSettings::cppCodeStyle() const
return d->m_globalCodeStyle;
}
+const CommentsSettings &CppToolsSettings::commentsSettings() const
+{
+ return d->m_completionSettingsPage->commentsSettings();
+}
diff --git a/src/plugins/cpptools/cpptoolssettings.h b/src/plugins/cpptools/cpptoolssettings.h
index 62cb35bc8c..3444231d9b 100644
--- a/src/plugins/cpptools/cpptoolssettings.h
+++ b/src/plugins/cpptools/cpptoolssettings.h
@@ -40,7 +40,7 @@
namespace CppTools
{
class CppCodeStylePreferences;
-
+class CommentsSettings;
namespace Internal
{
@@ -61,6 +61,10 @@ public:
static CppToolsSettings *instance();
CppCodeStylePreferences *cppCodeStyle() const;
+ const CommentsSettings &commentsSettings() const;
+
+signals:
+ void commentsSettingsChanged(const CppTools::CommentsSettings &settings);
private:
Internal::CppToolsSettingsPrivate *d;
diff --git a/src/plugins/cpptools/doxygengenerator.cpp b/src/plugins/cpptools/doxygengenerator.cpp
new file mode 100644
index 0000000000..8e3df8d6b8
--- /dev/null
+++ b/src/plugins/cpptools/doxygengenerator.cpp
@@ -0,0 +1,289 @@
+#include "doxygengenerator.h"
+
+#include <cplusplus/SimpleLexer.h>
+#include <cplusplus/BackwardsScanner.h>
+#include <cplusplus/Token.h>
+#include <cplusplus/TranslationUnit.h>
+#include <cplusplus/AST.h>
+#include <cplusplus/Symbols.h>
+#include <cplusplus/CppDocument.h>
+#include <cplusplus/Scope.h>
+#include <cplusplus/LookupContext.h>
+
+#include <QtCore/QStringBuilder>
+#include <QtGui/QTextDocument>
+#include <QDebug>
+
+using namespace CppTools;
+using namespace CPlusPlus;
+
+DoxygenGenerator::DoxygenGenerator()
+ : m_addLeadingAsterisks(true)
+ , m_generateBrief(true)
+ , m_startComment(true)
+ , m_style(QtStyle)
+ , m_commentOffset(0)
+{}
+
+void DoxygenGenerator::setStyle(DocumentationStyle style)
+{
+ m_style = style;
+}
+
+void DoxygenGenerator::setStartComment(bool start)
+{
+ m_startComment = start;
+}
+
+void DoxygenGenerator::setGenerateBrief(bool get)
+{
+ m_generateBrief = get;
+}
+
+void DoxygenGenerator::setAddLeadingAsterisks(bool add)
+{
+ m_addLeadingAsterisks = add;
+}
+
+QString DoxygenGenerator::generate(QTextCursor cursor)
+{
+ const QChar &c = cursor.document()->characterAt(cursor.position());
+ if (!c.isLetter() && c != QLatin1Char('_'))
+ return QString();
+
+ // Try to find what would be the declaration we are interested in.
+ SimpleLexer lexer;
+ QTextBlock block = cursor.block();
+ while (block.isValid()) {
+ const QString &text = block.text();
+ const QList<Token> &tks = lexer(text);
+ foreach (const Token &tk, tks) {
+ if (tk.is(T_SEMICOLON) || tk.is(T_LBRACE)) {
+ // No need to continue beyond this, we might already have something meaningful.
+ cursor.setPosition(block.position() + tk.end(), QTextCursor::KeepAnchor);
+ break;
+ }
+ }
+
+ if (cursor.hasSelection())
+ break;
+
+ block = block.next();
+ }
+
+ if (!cursor.hasSelection())
+ return QString();
+
+ QString declCandidate = cursor.selectedText();
+ declCandidate.replace(QChar::ParagraphSeparator, QLatin1Char('\n'));
+
+ // Let's append a closing brace in the case we got content like 'class MyType {'
+ if (declCandidate.endsWith(QLatin1Char('{')))
+ declCandidate.append(QLatin1Char('}'));
+
+ Document::Ptr doc = Document::create(QLatin1String("<doxygen>"));
+ doc->setSource(declCandidate.toUtf8());
+ doc->parse(Document::ParseDeclaration);
+ doc->check(Document::FastCheck);
+
+ if (!doc->translationUnit()
+ || !doc->translationUnit()->ast()
+ || !doc->translationUnit()->ast()->asDeclaration()) {
+ return QString();
+ }
+
+ return generate(cursor, doc->translationUnit()->ast()->asDeclaration());
+}
+
+QString DoxygenGenerator::generate(QTextCursor cursor, CPlusPlus::DeclarationAST *decl)
+{
+ SpecifierAST *spec = 0;
+ DeclaratorAST *decltr = 0;
+ if (SimpleDeclarationAST *simpleDecl = decl->asSimpleDeclaration()) {
+ if (simpleDecl->declarator_list
+ && simpleDecl->declarator_list->value) {
+ decltr = simpleDecl->declarator_list->value;
+ } else if (simpleDecl->decl_specifier_list
+ && simpleDecl->decl_specifier_list->value) {
+ spec = simpleDecl->decl_specifier_list->value;
+ }
+ } else if (FunctionDefinitionAST * defDecl = decl->asFunctionDefinition()) {
+ decltr = defDecl->declarator;
+ }
+
+ assignCommentOffset(cursor);
+
+ QString comment;
+ if (m_startComment)
+ writeStart(&comment);
+ writeNewLine(&comment);
+ writeContinuation(&comment);
+
+ if (decltr
+ && decltr->core_declarator
+ && decltr->core_declarator->asDeclaratorId()
+ && decltr->core_declarator->asDeclaratorId()->name) {
+ CoreDeclaratorAST *coreDecl = decltr->core_declarator;
+ if (m_generateBrief)
+ writeBrief(&comment, m_printer.prettyName(coreDecl->asDeclaratorId()->name->name));
+ else
+ writeNewLine(&comment);
+
+ if (decltr->postfix_declarator_list
+ && decltr->postfix_declarator_list->value
+ && decltr->postfix_declarator_list->value->asFunctionDeclarator()) {
+ FunctionDeclaratorAST *funcDecltr =
+ decltr->postfix_declarator_list->value->asFunctionDeclarator();
+ if (funcDecltr->parameter_declaration_clause
+ && funcDecltr->parameter_declaration_clause->parameter_declaration_list) {
+ for (ParameterDeclarationListAST *it =
+ funcDecltr->parameter_declaration_clause->parameter_declaration_list;
+ it;
+ it = it->next) {
+ ParameterDeclarationAST *paramDecl = it->value;
+ if (paramDecl->declarator
+ && paramDecl->declarator->core_declarator
+ && paramDecl->declarator->core_declarator->asDeclaratorId()
+ && paramDecl->declarator->core_declarator->asDeclaratorId()->name) {
+ DeclaratorIdAST *paramId =
+ paramDecl->declarator->core_declarator->asDeclaratorId();
+ writeContinuation(&comment);
+ writeCommand(&comment,
+ ParamCommand,
+ m_printer.prettyName(paramId->name->name));
+ }
+ }
+ }
+ if (funcDecltr->symbol
+ && funcDecltr->symbol->returnType().type()
+ && !funcDecltr->symbol->returnType()->isVoidType()
+ && !funcDecltr->symbol->returnType()->isUndefinedType()) {
+ writeContinuation(&comment);
+ writeCommand(&comment, ReturnCommand);
+ }
+ }
+ } else if (spec && m_generateBrief) {
+ bool briefWritten = false;
+ if (ClassSpecifierAST *classSpec = spec->asClassSpecifier()) {
+ if (classSpec->name) {
+ QString aggregate;
+ if (classSpec->symbol->isClass())
+ aggregate = QLatin1String("class");
+ else if (classSpec->symbol->isStruct())
+ aggregate = QLatin1String("struct");
+ else
+ aggregate = QLatin1String("union");
+ writeBrief(&comment,
+ m_printer.prettyName(classSpec->name->name),
+ QLatin1String("The"),
+ aggregate);
+ briefWritten = true;
+ }
+ } else if (EnumSpecifierAST *enumSpec = spec->asEnumSpecifier()) {
+ if (enumSpec->name) {
+ writeBrief(&comment,
+ m_printer.prettyName(enumSpec->name->name),
+ QLatin1String("The"),
+ QLatin1String("enum"));
+ briefWritten = true;
+ }
+ }
+ if (!briefWritten)
+ writeNewLine(&comment);
+ } else {
+ writeNewLine(&comment);
+ }
+
+ writeEnd(&comment);
+
+ return comment;
+}
+
+QChar DoxygenGenerator::startMark() const
+{
+ if (m_style == QtStyle)
+ return QLatin1Char('!');
+ return QLatin1Char('*');
+}
+
+QChar DoxygenGenerator::styleMark() const
+{
+ if (m_style == QtStyle)
+ return QLatin1Char('\\');
+ return QLatin1Char('@');
+}
+
+QString DoxygenGenerator::commandSpelling(Command command)
+{
+ if (command == ParamCommand)
+ return QLatin1String("param ");
+ if (command == ReturnCommand)
+ return QLatin1String("return ");
+
+ Q_ASSERT(command == BriefCommand);
+ return QLatin1String("brief ");
+}
+
+void DoxygenGenerator::writeStart(QString *comment) const
+{
+ comment->append(offsetString() % QLatin1String("/*") % startMark());
+}
+
+void DoxygenGenerator::writeEnd(QString *comment) const
+{
+ comment->append(offsetString() % QLatin1String(" */"));
+}
+
+void DoxygenGenerator::writeContinuation(QString *comment) const
+{
+ if (m_addLeadingAsterisks)
+ comment->append(offsetString() % QLatin1String(" *"));
+ else
+ comment->append(offsetString() % QLatin1String(" "));
+}
+
+void DoxygenGenerator::writeNewLine(QString *comment) const
+{
+ comment->append(QLatin1Char('\n'));
+}
+
+void DoxygenGenerator::writeCommand(QString *comment,
+ Command command,
+ const QString &commandContent) const
+{
+ comment->append(QLatin1Char(' ')
+ % styleMark()
+ % commandSpelling(command)
+ % commandContent
+ % QLatin1Char('\n'));
+}
+
+void DoxygenGenerator::writeBrief(QString *comment,
+ const QString &brief,
+ const QString &prefix,
+ const QString &suffix)
+{
+ QString content = prefix % QLatin1Char(' ') % brief % QLatin1Char(' ') % suffix;
+ writeCommand(comment, BriefCommand, content.trimmed());
+}
+
+void DoxygenGenerator::assignCommentOffset(QTextCursor cursor)
+{
+ if (cursor.hasSelection()) {
+ if (cursor.anchor() < cursor.position())
+ cursor.setPosition(cursor.anchor());
+ }
+
+ m_commentOffset = cursor.positionInBlock();
+}
+
+QString DoxygenGenerator::offsetString() const
+{
+ // Note: Currently we don't indent comments, but simply preserve them in the original
+ // relative positions. What we do here is just to make sure that such positions are correct,
+ // although they might still be wrong from an indentation point of view (for instance,
+ // using spaces instead of tabs). Therefore, the content generated should still have
+ // the indentation strings fixed.
+
+ return QString(m_commentOffset, QLatin1Char(' '));
+}
diff --git a/src/plugins/cpptools/doxygengenerator.h b/src/plugins/cpptools/doxygengenerator.h
new file mode 100644
index 0000000000..78b6b6b914
--- /dev/null
+++ b/src/plugins/cpptools/doxygengenerator.h
@@ -0,0 +1,71 @@
+#ifndef DOXYGEGENERATOR_H
+#define DOXYGEGENERATOR_H
+
+#include "cpptools_global.h"
+
+#include <cplusplus/Overview.h>
+
+#include <QtCore/QLatin1String>
+#include <QtGui/QTextCursor>
+
+namespace CPlusPlus {
+class DeclarationAST;
+}
+
+namespace CppTools {
+
+class CPPTOOLS_EXPORT DoxygenGenerator
+{
+public:
+ DoxygenGenerator();
+
+ enum DocumentationStyle {
+ JavaStyle,
+ QtStyle
+ };
+
+ void setStyle(DocumentationStyle style);
+ void setStartComment(bool start);
+ void setGenerateBrief(bool gen);
+ void setAddLeadingAsterisks(bool add);
+
+ QString generate(QTextCursor cursor);
+ QString generate(QTextCursor cursor, CPlusPlus::DeclarationAST *decl);
+
+private:
+ QChar startMark() const;
+ QChar styleMark() const;
+
+ enum Command {
+ BriefCommand,
+ ParamCommand,
+ ReturnCommand
+ };
+ static QString commandSpelling(Command command);
+
+ void writeStart(QString *comment) const;
+ void writeEnd(QString *comment) const;
+ void writeContinuation(QString *comment) const;
+ void writeNewLine(QString *comment) const;
+ void writeCommand(QString *comment,
+ Command command,
+ const QString &commandContent = QString()) const;
+ void writeBrief(QString *comment,
+ const QString &brief,
+ const QString &prefix = QString(),
+ const QString &suffix = QString());
+
+ void assignCommentOffset(QTextCursor cursor);
+ QString offsetString() const;
+
+ bool m_addLeadingAsterisks;
+ bool m_generateBrief;
+ bool m_startComment;
+ DocumentationStyle m_style;
+ CPlusPlus::Overview m_printer;
+ int m_commentOffset;
+};
+
+} // CppTools
+
+#endif // DOXYGEGENERATOR_H