1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "snippetssettingspage.h"
35 #include "snippeteditor.h"
36 #include "isnippetprovider.h"
38 #include "snippetscollection.h"
39 #include "snippetssettings.h"
41 #include "ui_snippetssettingspage.h"
43 #include <coreplugin/icore.h>
44 #include <extensionsystem/pluginmanager.h>
46 #include <QtCore/QModelIndex>
47 #include <QtCore/QAbstractTableModel>
48 #include <QtCore/QList>
49 #include <QtCore/QSettings>
50 #include <QtCore/QTextStream>
51 #include <QtCore/QHash>
52 #include <QtGui/QMessageBox>
54 namespace TextEditor {
58 class SnippetsTableModel : public QAbstractTableModel
62 SnippetsTableModel(QObject *parent);
63 virtual ~SnippetsTableModel() {}
65 virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
66 virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
67 virtual Qt::ItemFlags flags(const QModelIndex &modelIndex) const;
68 virtual QVariant data(const QModelIndex &modelIndex, int role = Qt::DisplayRole) const;
69 virtual bool setData(const QModelIndex &modelIndex, const QVariant &value,
70 int role = Qt::EditRole);
71 virtual QVariant headerData(int section, Qt::Orientation orientation,
72 int role = Qt::DisplayRole) const;
74 QList<QString> groupIds() const;
75 void load(const QString &groupId);
77 QModelIndex createSnippet();
78 QModelIndex insertSnippet(const Snippet &snippet);
79 void removeSnippet(const QModelIndex &modelIndex);
80 const Snippet &snippetAt(const QModelIndex &modelIndex) const;
81 void setSnippetContent(const QModelIndex &modelIndex, const QString &content);
82 void revertBuitInSnippet(const QModelIndex &modelIndex);
83 void restoreRemovedBuiltInSnippets();
87 void replaceSnippet(const Snippet &snippet, const QModelIndex &modelIndex);
88 static bool isValidTrigger(const QString &s);
90 SnippetsCollection* m_collection;
91 QString m_activeGroupId;
94 SnippetsTableModel::SnippetsTableModel(QObject *parent) :
95 QAbstractTableModel(parent),
96 m_collection(SnippetsCollection::instance())
99 int SnippetsTableModel::rowCount(const QModelIndex &) const
101 return m_collection->totalActiveSnippets(m_activeGroupId);
104 int SnippetsTableModel::columnCount(const QModelIndex &) const
109 Qt::ItemFlags SnippetsTableModel::flags(const QModelIndex &index) const
111 Qt::ItemFlags itemFlags = QAbstractTableModel::flags(index);
113 itemFlags |= Qt::ItemIsEditable;
117 QVariant SnippetsTableModel::data(const QModelIndex &modelIndex, int role) const
119 if (!modelIndex.isValid())
122 if (role == Qt::DisplayRole || role == Qt::EditRole) {
123 const Snippet &snippet = m_collection->snippet(modelIndex.row(), m_activeGroupId);
124 if (modelIndex.column() == 0)
125 return snippet.trigger();
127 return snippet.complement();
133 bool SnippetsTableModel::setData(const QModelIndex &modelIndex, const QVariant &value, int role)
135 if (modelIndex.isValid() && role == Qt::EditRole) {
136 Snippet snippet(m_collection->snippet(modelIndex.row(), m_activeGroupId));
137 if (modelIndex.column() == 0) {
138 const QString &s = value.toString();
139 if (!isValidTrigger(s)) {
140 QMessageBox::critical(0, tr("Error"), tr("Not a valid trigger."));
141 if (snippet.trigger().isEmpty())
142 removeSnippet(modelIndex);
145 snippet.setTrigger(s);
147 snippet.setComplement(value.toString());
150 replaceSnippet(snippet, modelIndex);
156 QVariant SnippetsTableModel::headerData(int section, Qt::Orientation orientation, int role) const
158 if (role != Qt::DisplayRole || orientation != Qt::Horizontal)
162 return tr("Trigger");
164 return tr("Trigger Variant");
167 void SnippetsTableModel::load(const QString &groupId)
169 m_activeGroupId = groupId;
173 QList<QString> SnippetsTableModel::groupIds() const
175 return m_collection->groupIds();
178 QModelIndex SnippetsTableModel::createSnippet()
180 Snippet snippet(m_activeGroupId);
181 return insertSnippet(snippet);
184 QModelIndex SnippetsTableModel::insertSnippet(const Snippet &snippet)
186 const SnippetsCollection::Hint &hint = m_collection->computeInsertionHint(snippet);
187 beginInsertRows(QModelIndex(), hint.index(), hint.index());
188 m_collection->insertSnippet(snippet, hint);
191 return index(hint.index(), 0);
194 void SnippetsTableModel::removeSnippet(const QModelIndex &modelIndex)
196 beginRemoveRows(QModelIndex(), modelIndex.row(), modelIndex.row());
197 m_collection->removeSnippet(modelIndex.row(), m_activeGroupId);
201 const Snippet &SnippetsTableModel::snippetAt(const QModelIndex &modelIndex) const
203 return m_collection->snippet(modelIndex.row(), m_activeGroupId);
206 void SnippetsTableModel::setSnippetContent(const QModelIndex &modelIndex, const QString &content)
208 m_collection->setSnippetContent(modelIndex.row(), m_activeGroupId, content);
211 void SnippetsTableModel::revertBuitInSnippet(const QModelIndex &modelIndex)
213 const Snippet &snippet = m_collection->revertedSnippet(modelIndex.row(), m_activeGroupId);
214 if (snippet.id().isEmpty()) {
215 QMessageBox::critical(0, tr("Error"), tr("Error reverting snippet."));
218 replaceSnippet(snippet, modelIndex);
221 void SnippetsTableModel::restoreRemovedBuiltInSnippets()
223 m_collection->restoreRemovedSnippets(m_activeGroupId);
227 void SnippetsTableModel::resetSnippets()
229 m_collection->reset(m_activeGroupId);
233 void SnippetsTableModel::replaceSnippet(const Snippet &snippet, const QModelIndex &modelIndex)
235 const int row = modelIndex.row();
236 const SnippetsCollection::Hint &hint =
237 m_collection->computeReplacementHint(row, snippet);
238 if (modelIndex.row() == hint.index()) {
239 m_collection->replaceSnippet(row, snippet, hint);
240 if (modelIndex.column() == 0)
241 emit dataChanged(modelIndex, modelIndex.sibling(row, 1));
243 emit dataChanged(modelIndex.sibling(row, 0), modelIndex);
245 if (row < hint.index())
246 // Rows will be moved down.
247 beginMoveRows(QModelIndex(), row, row, QModelIndex(), hint.index() + 1);
249 beginMoveRows(QModelIndex(), row, row, QModelIndex(), hint.index());
250 m_collection->replaceSnippet(row, snippet, hint);
255 bool SnippetsTableModel::isValidTrigger(const QString &s)
259 for (int i = 0; i < s.length(); ++i)
260 if (!s.at(i).isLetter())
265 // SnippetsSettingsPagePrivate
266 class SnippetsSettingsPagePrivate : public QObject
270 SnippetsSettingsPagePrivate(const QString &id);
271 ~SnippetsSettingsPagePrivate() { delete m_model; }
273 const QString &id() const { return m_id; }
274 const QString &displayName() const { return m_displayName; }
275 bool isKeyword(const QString &s) const { return m_keywords.contains(s, Qt::CaseInsensitive); }
276 void configureUi(QWidget *parent);
282 void loadSnippetGroup(int index);
283 void markSnippetsCollection();
285 void removeSnippet();
286 void revertBuiltInSnippet();
287 void restoreRemovedBuiltInSnippets();
288 void resetAllSnippets();
289 void selectSnippet(const QModelIndex &parent, int row);
290 void selectMovedSnippet(const QModelIndex &, int, int, const QModelIndex &, int row);
291 void setSnippetContent();
292 void updateCurrentSnippetDependent(const QModelIndex &modelIndex = QModelIndex());
295 SnippetEditorWidget *currentEditor() const;
296 SnippetEditorWidget *editorAt(int i) const;
299 bool settingsChanged() const;
300 void writeSettings();
303 const QString m_displayName;
304 const QString m_settingsPrefix;
305 SnippetsTableModel *m_model;
306 bool m_snippetsCollectionChanged;
308 SnippetsSettings m_settings;
309 Ui::SnippetsSettingsPage m_ui;
312 SnippetsSettingsPagePrivate::SnippetsSettingsPagePrivate(const QString &id) :
314 m_displayName(tr("Snippets")),
315 m_settingsPrefix(QLatin1String("Text")),
316 m_model(new SnippetsTableModel(0)),
317 m_snippetsCollectionChanged(false)
320 SnippetEditorWidget *SnippetsSettingsPagePrivate::currentEditor() const
322 return editorAt(m_ui.snippetsEditorStack->currentIndex());
325 SnippetEditorWidget *SnippetsSettingsPagePrivate::editorAt(int i) const
327 return static_cast<SnippetEditorWidget *>(m_ui.snippetsEditorStack->widget(i));
330 void SnippetsSettingsPagePrivate::configureUi(QWidget *w)
334 const QList<ISnippetProvider *> &providers =
335 ExtensionSystem::PluginManager::instance()->getObjects<ISnippetProvider>();
336 foreach (ISnippetProvider *provider, providers) {
337 m_ui.groupCombo->addItem(provider->displayName(), provider->groupId());
338 SnippetEditorWidget *snippetEditor = new SnippetEditorWidget(w);
339 provider->decorateEditor(snippetEditor);
340 m_ui.snippetsEditorStack->insertWidget(m_ui.groupCombo->count() - 1, snippetEditor);
341 connect(snippetEditor, SIGNAL(snippetContentChanged()), this, SLOT(setSnippetContent()));
344 m_ui.snippetsTable->setSelectionBehavior(QAbstractItemView::SelectRows);
345 m_ui.snippetsTable->setSelectionMode(QAbstractItemView::SingleSelection);
346 m_ui.snippetsTable->horizontalHeader()->setStretchLastSection(true);
347 m_ui.snippetsTable->horizontalHeader()->setHighlightSections(false);
348 m_ui.snippetsTable->verticalHeader()->setVisible(false);
349 m_ui.snippetsTable->verticalHeader()->setDefaultSectionSize(20);
350 m_ui.snippetsTable->setModel(m_model);
352 m_ui.revertButton->setEnabled(false);
354 QTextStream(&m_keywords) << m_displayName;
357 loadSnippetGroup(m_ui.groupCombo->currentIndex());
359 connect(m_model, SIGNAL(rowsInserted(QModelIndex, int, int)),
360 this, SLOT(selectSnippet(QModelIndex,int)));
361 connect(m_model, SIGNAL(rowsInserted(QModelIndex, int, int)),
362 this, SLOT(markSnippetsCollection()));
363 connect(m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)),
364 this, SLOT(markSnippetsCollection()));
365 connect(m_model, SIGNAL(rowsMoved(QModelIndex, int, int, QModelIndex, int)),
366 this, SLOT(selectMovedSnippet(QModelIndex,int,int,QModelIndex,int)));
367 connect(m_model, SIGNAL(rowsMoved(QModelIndex, int, int, QModelIndex, int)),
368 this, SLOT(markSnippetsCollection()));
369 connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
370 this, SLOT(markSnippetsCollection()));
371 connect(m_model, SIGNAL(modelReset()), this, SLOT(updateCurrentSnippetDependent()));
372 connect(m_model, SIGNAL(modelReset()), this, SLOT(markSnippetsCollection()));
374 connect(m_ui.groupCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(loadSnippetGroup(int)));
375 connect(m_ui.addButton, SIGNAL(clicked()), this, SLOT(addSnippet()));
376 connect(m_ui.removeButton, SIGNAL(clicked()), this, SLOT(removeSnippet()));
377 connect(m_ui.resetAllButton, SIGNAL(clicked()), this, SLOT(resetAllSnippets()));
378 connect(m_ui.restoreRemovedButton, SIGNAL(clicked()),
379 this, SLOT(restoreRemovedBuiltInSnippets()));
380 connect(m_ui.revertButton, SIGNAL(clicked()), this, SLOT(revertBuiltInSnippet()));
381 connect(m_ui.snippetsTable->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
382 this, SLOT(updateCurrentSnippetDependent(QModelIndex)));
385 void SnippetsSettingsPagePrivate::apply()
387 if (settingsChanged())
390 if (currentEditor()->document()->isModified())
393 if (m_snippetsCollectionChanged) {
394 SnippetsCollection::instance()->synchronize();
395 m_snippetsCollectionChanged = false;
399 void SnippetsSettingsPagePrivate::finish()
401 if (m_snippetsCollectionChanged) {
402 SnippetsCollection::instance()->reload();
403 m_snippetsCollectionChanged = false;
407 void SnippetsSettingsPagePrivate::loadSettings()
409 if (m_ui.groupCombo->count() == 0)
412 if (QSettings *s = Core::ICore::instance()->settings()) {
413 m_settings.fromSettings(m_settingsPrefix, s);
414 const QString &lastGroupName = m_settings.lastUsedSnippetGroup();
415 const int index = m_ui.groupCombo->findText(lastGroupName);
417 m_ui.groupCombo->setCurrentIndex(index);
419 m_ui.groupCombo->setCurrentIndex(0);
423 void SnippetsSettingsPagePrivate::writeSettings()
425 if (m_ui.groupCombo->count() == 0)
428 if (QSettings *s = Core::ICore::instance()->settings()) {
429 m_settings.setLastUsedSnippetGroup(m_ui.groupCombo->currentText());
430 m_settings.toSettings(m_settingsPrefix, s);
434 bool SnippetsSettingsPagePrivate::settingsChanged() const
436 if (m_settings.lastUsedSnippetGroup() != m_ui.groupCombo->currentText())
441 void SnippetsSettingsPagePrivate::loadSnippetGroup(int index)
446 m_ui.snippetsEditorStack->setCurrentIndex(index);
447 currentEditor()->clear();
448 m_model->load(m_ui.groupCombo->itemData(index).toString());
451 void SnippetsSettingsPagePrivate::markSnippetsCollection()
453 if (!m_snippetsCollectionChanged)
454 m_snippetsCollectionChanged = true;
457 void SnippetsSettingsPagePrivate::addSnippet()
459 const QModelIndex &modelIndex = m_model->createSnippet();
460 selectSnippet(QModelIndex(), modelIndex.row());
461 m_ui.snippetsTable->edit(modelIndex);
464 void SnippetsSettingsPagePrivate::removeSnippet()
466 const QModelIndex &modelIndex = m_ui.snippetsTable->selectionModel()->currentIndex();
467 if (!modelIndex.isValid()) {
468 QMessageBox::critical(0, tr("Error"), tr("No snippet selected."));
471 m_model->removeSnippet(modelIndex);
474 void SnippetsSettingsPagePrivate::restoreRemovedBuiltInSnippets()
476 m_model->restoreRemovedBuiltInSnippets();
479 void SnippetsSettingsPagePrivate::revertBuiltInSnippet()
481 m_model->revertBuitInSnippet(m_ui.snippetsTable->selectionModel()->currentIndex());
484 void SnippetsSettingsPagePrivate::resetAllSnippets()
486 m_model->resetSnippets();
489 void SnippetsSettingsPagePrivate::selectSnippet(const QModelIndex &parent, int row)
491 QModelIndex topLeft = m_model->index(row, 0, parent);
492 QModelIndex bottomRight = m_model->index(row, 1, parent);
493 QItemSelection selection(topLeft, bottomRight);
494 m_ui.snippetsTable->selectionModel()->select(selection, QItemSelectionModel::SelectCurrent);
495 m_ui.snippetsTable->setCurrentIndex(topLeft);
496 m_ui.snippetsTable->scrollTo(topLeft);
499 void SnippetsSettingsPagePrivate::selectMovedSnippet(const QModelIndex &,
502 const QModelIndex &destinationParent,
505 QModelIndex modelIndex;
506 if (sourceRow < destinationRow)
507 modelIndex = m_model->index(destinationRow - 1, 0, destinationParent);
509 modelIndex = m_model->index(destinationRow, 0, destinationParent);
510 m_ui.snippetsTable->scrollTo(modelIndex);
511 currentEditor()->setPlainText(m_model->snippetAt(modelIndex).content());
514 void SnippetsSettingsPagePrivate::updateCurrentSnippetDependent(const QModelIndex &modelIndex)
516 if (modelIndex.isValid()) {
517 const Snippet &snippet = m_model->snippetAt(modelIndex);
518 currentEditor()->setPlainText(snippet.content());
519 m_ui.revertButton->setEnabled(snippet.isBuiltIn());
521 currentEditor()->clear();
522 m_ui.revertButton->setEnabled(false);
526 void SnippetsSettingsPagePrivate::setSnippetContent()
528 const QModelIndex &modelIndex = m_ui.snippetsTable->selectionModel()->currentIndex();
529 if (modelIndex.isValid()) {
530 m_model->setSnippetContent(modelIndex, currentEditor()->toPlainText());
531 markSnippetsCollection();
535 // SnippetsSettingsPage
536 SnippetsSettingsPage::SnippetsSettingsPage(const QString &id, QObject *parent) :
537 TextEditorOptionsPage(parent),
538 m_d(new SnippetsSettingsPagePrivate(id))
541 SnippetsSettingsPage::~SnippetsSettingsPage()
546 QString SnippetsSettingsPage::id() const
551 QString SnippetsSettingsPage::displayName() const
553 return m_d->displayName();
556 bool SnippetsSettingsPage::matches(const QString &s) const
558 return m_d->isKeyword(s);
561 QWidget *SnippetsSettingsPage::createPage(QWidget *parent)
563 QWidget *w = new QWidget(parent);
568 void SnippetsSettingsPage::apply()
573 void SnippetsSettingsPage::finish()
581 #include "snippetssettingspage.moc"