diff options
author | Leandro Melo <leandro.melo@nokia.com> | 2010-10-27 17:38:22 +0200 |
---|---|---|
committer | Leandro Melo <leandro.melo@nokia.com> | 2010-12-08 17:22:07 +0100 |
commit | 7528c6d617c60acfdc2d82e2a7f8d1ec2de87a02 (patch) | |
tree | 48a2dc39d8653aa8653998f6513fd06d183e7097 /src/plugins/texteditor/snippets/snippetssettingspage.cpp | |
parent | 27bab4e811bf5a3fd476738c35769573cd7b5ef3 (diff) | |
download | qt-creator-7528c6d617c60acfdc2d82e2a7f8d1ec2de87a02.tar.gz |
Snippets: Feature enhancement start...
Provide an interface so users can create/edit/remove snippets.
Diffstat (limited to 'src/plugins/texteditor/snippets/snippetssettingspage.cpp')
-rw-r--r-- | src/plugins/texteditor/snippets/snippetssettingspage.cpp | 512 |
1 files changed, 512 insertions, 0 deletions
diff --git a/src/plugins/texteditor/snippets/snippetssettingspage.cpp b/src/plugins/texteditor/snippets/snippetssettingspage.cpp new file mode 100644 index 0000000000..3302e1298c --- /dev/null +++ b/src/plugins/texteditor/snippets/snippetssettingspage.cpp @@ -0,0 +1,512 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "snippetssettingspage.h" +#include "snippetsmanager.h" +#include "snippeteditor.h" +#include "isnippeteditordecorator.h" +#include "snippet.h" +#include "snippetscollection.h" +#include "snippetssettings.h" +#include "reuse.h" +#include "ui_snippetssettingspage.h" + +#include <coreplugin/icore.h> +#include <extensionsystem/pluginmanager.h> + +#include <QtCore/QSharedPointer> +#include <QtCore/QModelIndex> +#include <QtCore/QAbstractTableModel> +#include <QtCore/QList> +#include <QtCore/QSettings> +#include <QtCore/QTextStream> +#include <QtGui/QMessageBox> + +namespace TextEditor { +namespace Internal { + +// SnippetsTableModel +class SnippetsTableModel : public QAbstractTableModel +{ + Q_OBJECT +public: + SnippetsTableModel(QObject *parent); + virtual ~SnippetsTableModel() {} + + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; + virtual Qt::ItemFlags flags(const QModelIndex &modelIndex) const; + virtual QVariant data(const QModelIndex &modelIndex, int role = Qt::DisplayRole) const; + virtual bool setData(const QModelIndex &modelIndex, const QVariant &value, + int role = Qt::EditRole); + virtual QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + + void load(Snippet::Group group); + + QModelIndex createSnippet(); + QModelIndex insertSnippet(const Snippet &snippet); + void removeSnippet(const QModelIndex &modelIndex); + const Snippet &snippetAt(const QModelIndex &modelIndex) const; + void setSnippetContent(const QModelIndex &modelIndex, const QString &content); + +private: + static bool isValidTrigger(const QString &s); + + Snippet::Group m_activeGroup; + QSharedPointer<SnippetsCollection> m_collection; +}; + +SnippetsTableModel::SnippetsTableModel(QObject *parent) : + QAbstractTableModel(parent), + m_activeGroup(Snippet::Cpp), + m_collection(SnippetsManager::instance()->snippetsCollection()) +{} + +int SnippetsTableModel::rowCount(const QModelIndex &) const +{ + if (m_collection.isNull()) + return 0; + return m_collection->totalActiveSnippets(m_activeGroup); +} + +int SnippetsTableModel::columnCount(const QModelIndex &) const +{ + if (m_collection.isNull()) + return 0; + return 2; +} + +Qt::ItemFlags SnippetsTableModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags itemFlags = QAbstractTableModel::flags(index); + if (index.isValid()) + itemFlags |= Qt::ItemIsEditable; + return itemFlags; +} + +QVariant SnippetsTableModel::data(const QModelIndex &modelIndex, int role) const +{ + if (!modelIndex.isValid()) + return QVariant(); + + if (role == Qt::DisplayRole || role == Qt::EditRole) { + const Snippet &snippet = m_collection->snippet(modelIndex.row(), m_activeGroup); + if (modelIndex.column() == 0) + return snippet.trigger(); + else + return snippet.complement(); + } else { + return QVariant(); + } +} + +bool SnippetsTableModel::setData(const QModelIndex &modelIndex, const QVariant &value, int role) +{ + if (modelIndex.isValid() && role == Qt::EditRole) { + const int row = modelIndex.row(); + Snippet snippet(m_collection->snippet(row, m_activeGroup)); + if (modelIndex.column() == 0) { + const QString &s = value.toString(); + if (!isValidTrigger(s)) { + QMessageBox::critical(0, tr("Error"), tr("Not a valid trigger.")); + if (snippet.trigger().isEmpty()) + removeSnippet(modelIndex); + return false; + } + snippet.setTrigger(s); + } else { + snippet.setComplement(value.toString()); + } + + const SnippetsCollection::Hint &hint = + m_collection->computeReplacementHint(row, snippet, m_activeGroup); + if (modelIndex.row() == hint.index()) { + m_collection->replaceSnippet(row, snippet, m_activeGroup, hint); + emit dataChanged(modelIndex, modelIndex); + } else { + if (row < hint.index()) + // Rows will be moved down. + beginMoveRows(QModelIndex(), row, row, QModelIndex(), hint.index() + 1); + else + beginMoveRows(QModelIndex(), row, row, QModelIndex(), hint.index()); + m_collection->replaceSnippet(row, snippet, m_activeGroup, hint); + endMoveRows(); + } + + return true; + } + return false; +} + +QVariant SnippetsTableModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole || orientation != Qt::Horizontal) + return QVariant(); + + if (section == 0) + return tr("Trigger"); + else + return tr("Complement"); +} + +void SnippetsTableModel::load(Snippet::Group group) +{ + m_activeGroup = group; + reset(); +} + +QModelIndex SnippetsTableModel::createSnippet() +{ + Snippet snippet; + snippet.setGroup(m_activeGroup); + return insertSnippet(snippet); +} + +QModelIndex SnippetsTableModel::insertSnippet(const Snippet &snippet) +{ + const SnippetsCollection::Hint &hint = + m_collection->computeInsertionHint(snippet, m_activeGroup); + beginInsertRows(QModelIndex(), hint.index(), hint.index()); + m_collection->insertSnippet(snippet, m_activeGroup, hint); + endInsertRows(); + + return index(hint.index(), 0); +} + +void SnippetsTableModel::removeSnippet(const QModelIndex &modelIndex) +{ + beginRemoveRows(QModelIndex(), modelIndex.row(), modelIndex.row()); + m_collection->removeSnippet(modelIndex.row(), m_activeGroup); + endRemoveRows(); +} + +const Snippet &SnippetsTableModel::snippetAt(const QModelIndex &modelIndex) const +{ + return m_collection->snippet(modelIndex.row(), m_activeGroup); +} + +void SnippetsTableModel::setSnippetContent(const QModelIndex &modelIndex, const QString &content) +{ + m_collection->setSnippetContent(modelIndex.row(), m_activeGroup, content); +} + +bool SnippetsTableModel::isValidTrigger(const QString &s) +{ + if (s.isEmpty()) + return false; + for (int i = 0; i < s.length(); ++i) + if (!s.at(i).isLetter()) + return false; + return true; +} + +// SnippetsSettingsPagePrivate +class SnippetsSettingsPagePrivate : public QObject +{ + Q_OBJECT +public: + SnippetsSettingsPagePrivate(const QString &id); + ~SnippetsSettingsPagePrivate() { delete m_model; } + + const QString &id() const { return m_id; } + const QString &displayName() const { return m_displayName; } + bool isKeyword(const QString &s) const { return m_keywords.contains(s, Qt::CaseInsensitive); } + void configureUi(QWidget *parent); + + void apply(); + void finish(); + +private slots: + void loadSnippetGroup(int index); + void markSnippetsCollection(); + void addSnippet(); + void removeSnippet(); + void selectSnippet(const QModelIndex &parent, int row); + void selectMovedSnippet(const QModelIndex &, int, int, const QModelIndex &, int row); + void previewSnippet(const QModelIndex &modelIndex); + void updateSnippetContent(); + +private: + SnippetEditor *currentEditor() const; + SnippetEditor *editorAt(int i) const; + + static void decorateEditor(SnippetEditor *editor, Snippet::Group group); + + void loadSettings(); + bool settingsChanged() const; + void writeSettings(); + + const QString m_id; + const QString m_displayName; + const QString m_settingsPrefix; + SnippetsTableModel *m_model; + bool m_snippetsCollectionChanged; + QString m_keywords; + SnippetsSettings m_settings; + Ui::SnippetsSettingsPage m_ui; +}; + +SnippetsSettingsPagePrivate::SnippetsSettingsPagePrivate(const QString &id) : + m_id(id), + m_displayName(tr("Snippets")), + m_settingsPrefix(QLatin1String("Text")), + m_model(new SnippetsTableModel(0)), + m_snippetsCollectionChanged(false) +{} + +SnippetEditor *SnippetsSettingsPagePrivate::currentEditor() const +{ + return editorAt(m_ui.snippetsEditorStack->currentIndex()); +} + +SnippetEditor *SnippetsSettingsPagePrivate::editorAt(int i) const +{ + return static_cast<SnippetEditor *>(m_ui.snippetsEditorStack->widget(i)); +} + +void SnippetsSettingsPagePrivate::configureUi(QWidget *w) +{ + m_ui.setupUi(w); + + m_ui.groupCombo->insertItem(Snippet::Cpp, fromSnippetGroup(Snippet::Cpp)); + m_ui.groupCombo->insertItem(Snippet::Qml, fromSnippetGroup(Snippet::Qml)); + m_ui.groupCombo->insertItem(Snippet::PlainText, fromSnippetGroup(Snippet::PlainText)); + + m_ui.snippetsTable->setSelectionBehavior(QAbstractItemView::SelectRows); + m_ui.snippetsTable->setSelectionMode(QAbstractItemView::SingleSelection); + m_ui.snippetsTable->horizontalHeader()->setStretchLastSection(true); + m_ui.snippetsTable->horizontalHeader()->setHighlightSections(false); + m_ui.snippetsTable->verticalHeader()->setVisible(false); + m_ui.snippetsTable->verticalHeader()->setDefaultSectionSize(20); + m_ui.snippetsTable->setModel(m_model); + + m_ui.snippetsEditorStack->insertWidget(Snippet::Cpp, new SnippetEditor(w)); + m_ui.snippetsEditorStack->insertWidget(Snippet::Qml, new SnippetEditor(w)); + m_ui.snippetsEditorStack->insertWidget(Snippet::PlainText, new SnippetEditor(w)); + decorateEditor(editorAt(Snippet::Cpp), Snippet::Cpp); + decorateEditor(editorAt(Snippet::Qml), Snippet::Qml); + decorateEditor(editorAt(Snippet::PlainText), Snippet::PlainText); + + QTextStream(&m_keywords) << m_displayName; + + loadSettings(); + loadSnippetGroup(m_ui.groupCombo->currentIndex()); + + connect(editorAt(Snippet::Cpp), SIGNAL(snippetContentChanged()), + this, SLOT(updateSnippetContent())); + connect(editorAt(Snippet::Qml), SIGNAL(snippetContentChanged()), + this, SLOT(updateSnippetContent())); + connect(editorAt(Snippet::PlainText), SIGNAL(snippetContentChanged()), + this, SLOT(updateSnippetContent())); + + connect(m_model, SIGNAL(rowsInserted(QModelIndex, int, int)), + this, SLOT(selectSnippet(QModelIndex,int))); + connect(m_model, SIGNAL(rowsInserted(QModelIndex, int, int)), + this, SLOT(markSnippetsCollection())); + connect(m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)), + this, SLOT(markSnippetsCollection())); + connect(m_model, SIGNAL(rowsMoved(QModelIndex, int, int, QModelIndex, int)), + this, SLOT(selectMovedSnippet(QModelIndex,int,int,QModelIndex,int))); + connect(m_model, SIGNAL(rowsMoved(QModelIndex, int, int, QModelIndex, int)), + this, SLOT(markSnippetsCollection())); + connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), + this, SLOT(markSnippetsCollection())); + + connect(m_ui.groupCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(loadSnippetGroup(int))); + connect(m_ui.addButton, SIGNAL(clicked()), this, SLOT(addSnippet())); + connect(m_ui.removeButton, SIGNAL(clicked()), this, SLOT(removeSnippet())); + connect(m_ui.snippetsTable->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, SLOT(previewSnippet(QModelIndex))); +} + +void SnippetsSettingsPagePrivate::decorateEditor(SnippetEditor *editor, Snippet::Group group) +{ + const QList<ISnippetEditorDecorator *> &decorators = + ExtensionSystem::PluginManager::instance()->getObjects<ISnippetEditorDecorator>(); + foreach (ISnippetEditorDecorator *decorator, decorators) + if (decorator->supports(group)) + decorator->apply(editor); +} + +void SnippetsSettingsPagePrivate::apply() +{ + if (settingsChanged()) + writeSettings(); + + if (m_snippetsCollectionChanged) + SnippetsManager::instance()->persistSnippetsCollection(); +} + +void SnippetsSettingsPagePrivate::finish() +{ + if (m_snippetsCollectionChanged) { + SnippetsManager::instance()->reloadSnippetsCollection(); + m_snippetsCollectionChanged = false; + } +} + +void SnippetsSettingsPagePrivate::loadSettings() +{ + if (QSettings *s = Core::ICore::instance()->settings()) { + m_settings.fromSettings(m_settingsPrefix, s); + m_ui.groupCombo->setCurrentIndex(toSnippetGroup(m_settings.lastUsedSnippetGroup())); + } +} + +void SnippetsSettingsPagePrivate::writeSettings() +{ + if (QSettings *s = Core::ICore::instance()->settings()) { + m_settings.setLastUsedSnippetGroup(m_ui.groupCombo->currentText()); + m_settings.toSettings(m_settingsPrefix, s); + } +} + +bool SnippetsSettingsPagePrivate::settingsChanged() const +{ + if (m_settings.lastUsedSnippetGroup() != m_ui.groupCombo->currentText()) + return true; + return false; +} + +void SnippetsSettingsPagePrivate::loadSnippetGroup(int index) +{ + m_ui.snippetsEditorStack->setCurrentIndex(index); + currentEditor()->clear(); + m_model->load(Snippet::Group(index)); +} + +void SnippetsSettingsPagePrivate::markSnippetsCollection() +{ + if (!m_snippetsCollectionChanged) + m_snippetsCollectionChanged = true; +} + +void SnippetsSettingsPagePrivate::addSnippet() +{ + const QModelIndex &modelIndex = m_model->createSnippet(); + selectSnippet(QModelIndex(), modelIndex.row()); + m_ui.snippetsTable->edit(modelIndex); +} + +void SnippetsSettingsPagePrivate::removeSnippet() +{ + const QModelIndex &modelIndex = m_ui.snippetsTable->selectionModel()->currentIndex(); + if (!modelIndex.isValid()) { + QMessageBox::critical(0, tr("Error"), tr("No snippet selected.")); + return; + } + m_model->removeSnippet(modelIndex); +} + +void SnippetsSettingsPagePrivate::selectSnippet(const QModelIndex &parent, int row) +{ + QModelIndex topLeft = m_model->index(row, 0, parent); + QModelIndex bottomRight = m_model->index(row, 1, parent); + QItemSelection selection(topLeft, bottomRight); + m_ui.snippetsTable->selectionModel()->select(selection, QItemSelectionModel::SelectCurrent); + m_ui.snippetsTable->setCurrentIndex(topLeft); + m_ui.snippetsTable->scrollTo(topLeft); +} + +void SnippetsSettingsPagePrivate::selectMovedSnippet(const QModelIndex &, + int sourceRow, + int, + const QModelIndex &destinationParent, + int destinationRow) +{ + QModelIndex modelIndex; + if (sourceRow < destinationRow) + modelIndex = m_model->index(destinationRow - 1, 0, destinationParent); + else + modelIndex = m_model->index(destinationRow, 0, destinationParent); + m_ui.snippetsTable->scrollTo(modelIndex); +} + +void SnippetsSettingsPagePrivate::previewSnippet(const QModelIndex &modelIndex) +{ + currentEditor()->setPlainText(m_model->snippetAt(modelIndex).content()); +} + +void SnippetsSettingsPagePrivate::updateSnippetContent() +{ + const QModelIndex &modelIndex = m_ui.snippetsTable->selectionModel()->currentIndex(); + if (modelIndex.isValid()) { + m_model->setSnippetContent(modelIndex, currentEditor()->toPlainText()); + markSnippetsCollection(); + } +} + +// SnippetsSettingsPage +SnippetsSettingsPage::SnippetsSettingsPage(const QString &id, QObject *parent) : + TextEditorOptionsPage(parent), + m_d(new SnippetsSettingsPagePrivate(id)) +{} + +SnippetsSettingsPage::~SnippetsSettingsPage() +{ + delete m_d; +} + +QString SnippetsSettingsPage::id() const +{ + return m_d->id(); +} + +QString SnippetsSettingsPage::displayName() const +{ + return m_d->displayName(); +} + +bool SnippetsSettingsPage::matches(const QString &s) const +{ + return m_d->isKeyword(s); +} + +QWidget *SnippetsSettingsPage::createPage(QWidget *parent) +{ + QWidget *w = new QWidget(parent); + m_d->configureUi(w); + return w; +} + +void SnippetsSettingsPage::apply() +{ + m_d->apply(); +} + +void SnippetsSettingsPage::finish() +{ + m_d->finish(); +} + +} // Internal +} // TextEditor + +#include "snippetssettingspage.moc" |