forked from qt-creator/qt-creator
Initial import
This commit is contained in:
434
src/plugins/snippets/snippetswindow.cpp
Normal file
434
src/plugins/snippets/snippetswindow.cpp
Normal file
@@ -0,0 +1,434 @@
|
||||
/***************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Qt Software Information (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** Non-Open Source Usage
|
||||
**
|
||||
** Licensees may use this file in accordance with the Qt Beta Version
|
||||
** License Agreement, Agreement version 2.2 provided with the Software or,
|
||||
** alternatively, in accordance with the terms contained in a written
|
||||
** agreement between you and Nokia.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License versions 2.0 or 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the packaging
|
||||
** of this file. Please review the following information to ensure GNU
|
||||
** General Public Licensing requirements will be met:
|
||||
**
|
||||
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt GPL Exception version
|
||||
** 1.2, included in the file GPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
***************************************************************************/
|
||||
#include "snippetswindow.h"
|
||||
#include "snippetspec.h"
|
||||
#include "inputwidget.h"
|
||||
#include "snippetsplugin.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <texteditor/itexteditable.h>
|
||||
#include <texteditor/itexteditor.h>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtGui/QDragEnterEvent>
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QLabel>
|
||||
#include <QtCore/QMimeData>
|
||||
#include <QtGui/QHeaderView>
|
||||
|
||||
using namespace Snippets::Internal;
|
||||
|
||||
const QIcon SnippetsWindow::m_fileIcon = QIcon(":/snippets/images/file.png");
|
||||
const QIcon SnippetsWindow::m_dirIcon = QIcon(":/snippets/images/dir.png");
|
||||
const QIcon SnippetsWindow::m_dirOpenIcon = QIcon(":/snippets/images/diropen.png");
|
||||
|
||||
Q_DECLARE_METATYPE(Snippets::Internal::SnippetSpec *)
|
||||
|
||||
SnippetsWindow::SnippetsWindow()
|
||||
{
|
||||
m_core = SnippetsPlugin::core();
|
||||
|
||||
setWindowTitle(tr("Snippets"));
|
||||
setWindowIcon(QIcon(":/snippets/images/snippets.png"));
|
||||
setOrientation(Qt::Vertical);
|
||||
|
||||
m_snippetsTree = new SnippetsTree(this);
|
||||
addWidget(m_snippetsTree);
|
||||
|
||||
m_descLabel = new QLabel(this);
|
||||
m_descLabel->setAlignment(Qt::AlignTop|Qt::AlignLeft);
|
||||
m_descLabel->setFrameShape(QFrame::Panel);
|
||||
m_descLabel->setFrameShadow(QFrame::Raised);
|
||||
m_descLabel->setWordWrap(true);
|
||||
addWidget(m_descLabel);
|
||||
|
||||
m_snippetsDir = QDir::home();
|
||||
if (!initSnippetsDir())
|
||||
setDisabled(true);
|
||||
else {
|
||||
QDir defaultDir(m_core->resourcePath() + QLatin1String("/snippets"));
|
||||
if (defaultDir.exists())
|
||||
initSnippets(defaultDir);
|
||||
initSnippets(m_snippetsDir);
|
||||
}
|
||||
|
||||
connect(m_snippetsTree, SIGNAL(itemCollapsed(QTreeWidgetItem *)),
|
||||
this, SLOT(setClosedIcon(QTreeWidgetItem *)));
|
||||
|
||||
connect(m_snippetsTree, SIGNAL(itemExpanded(QTreeWidgetItem *)),
|
||||
this, SLOT(setOpenIcon(QTreeWidgetItem *)));
|
||||
|
||||
connect(m_snippetsTree, SIGNAL(itemActivated(QTreeWidgetItem *, int)),
|
||||
this, SLOT(activateSnippet(QTreeWidgetItem *, int)));
|
||||
|
||||
connect(m_snippetsTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
|
||||
this, SLOT(updateDescription(QTreeWidgetItem *)));
|
||||
}
|
||||
|
||||
SnippetsWindow::~SnippetsWindow()
|
||||
{
|
||||
qDeleteAll(m_snippets);
|
||||
}
|
||||
|
||||
|
||||
void SnippetsWindow::activateSnippet(QTreeWidgetItem *item, int column)
|
||||
{
|
||||
if (!item->parent())
|
||||
return;
|
||||
|
||||
TextEditor::ITextEditable *editor = 0;
|
||||
if (m_core->editorManager()->currentEditor())
|
||||
editor = qobject_cast<TextEditor::ITextEditable *>(
|
||||
m_core->editorManager()->currentEditor());
|
||||
if (editor) {
|
||||
SnippetSpec* spec = qVariantValue<SnippetSpec*>(item->data(0, Qt::UserRole));
|
||||
insertSnippet(editor, spec);
|
||||
}
|
||||
|
||||
Q_UNUSED(column);
|
||||
}
|
||||
|
||||
const QList<SnippetSpec *> &SnippetsWindow::snippets() const
|
||||
{
|
||||
return m_snippets;
|
||||
}
|
||||
|
||||
void SnippetsWindow::initSnippets(const QDir &dir)
|
||||
{
|
||||
QString name;
|
||||
QString category;
|
||||
|
||||
QMap<QString, QTreeWidgetItem *> categories;
|
||||
for (int i = 0; i < m_snippetsTree->topLevelItemCount(); ++i) {
|
||||
categories.insert(m_snippetsTree->topLevelItem(i)->text(0),
|
||||
m_snippetsTree->topLevelItem(i));
|
||||
}
|
||||
|
||||
foreach (const QString &snippet, dir.entryList(QStringList("*.snp"))) {
|
||||
SnippetSpec *spec = new SnippetSpec();
|
||||
if (spec->load(dir.filePath(snippet))) {
|
||||
if (!categories.contains(spec->category())) {
|
||||
QTreeWidgetItem *citem = new QTreeWidgetItem(m_snippetsTree);
|
||||
citem->setText(0, spec->category());
|
||||
citem->setIcon(0, m_dirIcon);
|
||||
categories.insert(spec->category(), citem);
|
||||
}
|
||||
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem(
|
||||
categories.value(spec->category()));
|
||||
item->setText(0, spec->name());
|
||||
item->setIcon(0, m_fileIcon);
|
||||
QVariant v;
|
||||
qVariantSetValue<SnippetSpec *>(v, spec);
|
||||
item->setData(0, Qt::UserRole, v);
|
||||
|
||||
m_snippets.append(spec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString SnippetsWindow::createUniqueFileName()
|
||||
{
|
||||
int fileNumber = 0;
|
||||
QString baseName = "snippet";
|
||||
while (m_snippetsDir.exists(baseName + QString::number(fileNumber) + ".snp")) {
|
||||
++fileNumber;
|
||||
}
|
||||
return baseName + QString::number(fileNumber) + ".snp";
|
||||
}
|
||||
|
||||
void SnippetsWindow::writeSnippet(const QMimeData *)
|
||||
{
|
||||
}
|
||||
|
||||
bool SnippetsWindow::initSnippetsDir()
|
||||
{
|
||||
if (!m_snippetsDir.exists(".qworkbench"))
|
||||
m_snippetsDir.mkdir(".qworkbench");
|
||||
if (!m_snippetsDir.cd(".qworkbench"))
|
||||
return false;
|
||||
|
||||
if (!m_snippetsDir.exists("snippets"))
|
||||
m_snippetsDir.mkdir("snippets");
|
||||
return m_snippetsDir.cd("snippets");
|
||||
}
|
||||
|
||||
void SnippetsWindow::getArguments()
|
||||
{
|
||||
QString contents = m_currentSnippet->contents();
|
||||
int index = 0;
|
||||
bool pc = false;
|
||||
QString nrstr;
|
||||
|
||||
QSet<int> requiredArgs;
|
||||
m_requiredArgs.clear();
|
||||
m_args.clear();
|
||||
|
||||
while (index < contents.length()) {
|
||||
QChar c = contents.at(index);
|
||||
if (c == QLatin1Char('%')) {
|
||||
pc = !pc;
|
||||
} else if (pc) {
|
||||
if (c.isNumber()) {
|
||||
nrstr += c;
|
||||
} else {
|
||||
pc = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pc && !nrstr.isEmpty()) {
|
||||
requiredArgs << nrstr.toInt();
|
||||
nrstr.clear();
|
||||
}
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
m_requiredArgs = requiredArgs.toList();
|
||||
m_requiredArgs.prepend(-1);
|
||||
|
||||
showInputWidget(false, QString());
|
||||
}
|
||||
|
||||
void SnippetsWindow::showInputWidget(bool canceled, const QString &value)
|
||||
{
|
||||
if (canceled)
|
||||
return;
|
||||
|
||||
TextEditor::ITextEditor *te = 0;
|
||||
if (m_core->editorManager()->currentEditor())
|
||||
te = qobject_cast<TextEditor::ITextEditor*>(
|
||||
m_core->editorManager()->currentEditor());
|
||||
|
||||
int arg = m_requiredArgs.takeFirst();
|
||||
if (arg != -1)
|
||||
m_args << value;
|
||||
|
||||
if (!te || m_requiredArgs.isEmpty()) {
|
||||
qDebug("replaceAndInsert");
|
||||
replaceAndInsert();
|
||||
} else {
|
||||
QString desc = m_currentSnippet->argumentDescription(m_requiredArgs.first());
|
||||
QString def = m_currentSnippet->argumentDefault(m_requiredArgs.first());
|
||||
foreach(QString arg, m_args) {
|
||||
desc = desc.arg(arg);
|
||||
def = def.arg(arg);
|
||||
}
|
||||
|
||||
InputWidget *iw = new InputWidget(desc, def);
|
||||
connect(iw, SIGNAL(finished(bool, const QString &)),
|
||||
this, SLOT(showInputWidget(bool, const QString &)));
|
||||
iw->showInputWidget(te->cursorRect().bottomRight());
|
||||
}
|
||||
}
|
||||
|
||||
void SnippetsWindow::replaceAndInsert()
|
||||
{
|
||||
QString result;
|
||||
QString keyWord;
|
||||
int setAnchor = -1;
|
||||
int setCursor = -1;
|
||||
int selLength = 0;
|
||||
|
||||
//clean up selection
|
||||
int startPos = m_currentEditor->position(TextEditor::ITextEditable::Anchor);
|
||||
int endPos = m_currentEditor->position();
|
||||
|
||||
if (startPos < 0) {
|
||||
startPos = endPos;
|
||||
} else {
|
||||
if (startPos > endPos) {
|
||||
int tmp = startPos;
|
||||
startPos = endPos;
|
||||
endPos = tmp;
|
||||
}
|
||||
selLength = endPos - startPos;
|
||||
}
|
||||
|
||||
//parse the contents
|
||||
m_currentEditor->setCurPos(startPos);
|
||||
QString editorIndent = getCurrentIndent(m_currentEditor);
|
||||
QString content = m_currentSnippet->contents();
|
||||
foreach (const QString &arg, m_args) {
|
||||
content = content.arg(arg);
|
||||
}
|
||||
|
||||
int startOfKey = -1;
|
||||
for (int i = 0; i<content.length(); ++i) {
|
||||
//handle windows,mac and linux new lines...
|
||||
if (content.at(i) == QLatin1Char('\n')) {
|
||||
if ((i <= 0) || content.at(i-1) != QLatin1Char('\r'))
|
||||
result += QLatin1Char('\n') + editorIndent;
|
||||
continue;
|
||||
} else if (content.at(i) == QLatin1Char('\r')) {
|
||||
result += QLatin1Char('\n') + editorIndent;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (content.at(i) == QChar('$')) {
|
||||
if (startOfKey != -1) {
|
||||
m_currentEditor->insert(result);
|
||||
if (keyWord == QLatin1String("selection")) {
|
||||
const QString &indent = indentOfString(content, i);
|
||||
int selStartPos = m_currentEditor->position();
|
||||
m_currentEditor->setCurPos(selStartPos + selLength);
|
||||
insertIdents(m_currentEditor, indent, selStartPos, m_currentEditor->position());
|
||||
} else if (keyWord == QLatin1String("anchor")) {
|
||||
setAnchor = m_currentEditor->position();
|
||||
} else if (keyWord == QLatin1String("cursor")) {
|
||||
setCursor = m_currentEditor->position();
|
||||
}
|
||||
result.clear();
|
||||
keyWord.clear();
|
||||
startOfKey = -1;
|
||||
} else {
|
||||
startOfKey = i;
|
||||
}
|
||||
} else {
|
||||
if (startOfKey != -1)
|
||||
keyWord += content.at(i).toLower();
|
||||
else
|
||||
result += content.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
m_currentEditor->insert(result);
|
||||
|
||||
if (setAnchor != -1) {
|
||||
m_currentEditor->setCurPos(setAnchor);
|
||||
m_currentEditor->select(setCursor);
|
||||
} else if (setCursor != -1) {
|
||||
m_currentEditor->setCurPos(setCursor);
|
||||
}
|
||||
}
|
||||
|
||||
void SnippetsWindow::insertSnippet(TextEditor::ITextEditable *editor, SnippetSpec *snippet)
|
||||
{
|
||||
m_currentEditor = editor;
|
||||
m_currentSnippet = snippet;
|
||||
getArguments();
|
||||
}
|
||||
|
||||
QString SnippetsWindow::getCurrentIndent(TextEditor::ITextEditor *editor)
|
||||
{
|
||||
const int startPos = editor->position(TextEditor::ITextEditor::StartOfLine);
|
||||
const int endPos = editor->position(TextEditor::ITextEditor::EndOfLine);
|
||||
if (startPos < endPos)
|
||||
return indentOfString(editor->textAt(startPos, endPos - startPos));
|
||||
return QString();
|
||||
}
|
||||
|
||||
void SnippetsWindow::insertIdents(TextEditor::ITextEditable *editor,
|
||||
const QString &indent, int fromPos, int toPos)
|
||||
{
|
||||
int offset = 0;
|
||||
const int startPos = editor->position();
|
||||
editor->setCurPos(toPos);
|
||||
int currentLinePos = editor->position(TextEditor::ITextEditor::StartOfLine);
|
||||
while (currentLinePos > fromPos) {
|
||||
editor->setCurPos(currentLinePos);
|
||||
editor->insert(indent);
|
||||
offset += indent.length();
|
||||
editor->setCurPos(currentLinePos-1);
|
||||
currentLinePos = editor->position(TextEditor::ITextEditor::StartOfLine);
|
||||
}
|
||||
editor->setCurPos(startPos + offset);
|
||||
}
|
||||
|
||||
QString SnippetsWindow::indentOfString(const QString &str, int at)
|
||||
{
|
||||
QString result;
|
||||
int startAt = at;
|
||||
if (startAt < 0)
|
||||
startAt = str.length() - 1;
|
||||
|
||||
// find start position
|
||||
while (startAt >= 0 && str.at(startAt) != QChar('\n')
|
||||
&& str.at(startAt) != QChar('\r')) --startAt;
|
||||
|
||||
for (int i = (startAt + 1); i < str.length(); ++i) {
|
||||
if (str.at(i) == QChar(' ') || str.at(i) == QChar('\t'))
|
||||
result += str.at(i);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void SnippetsWindow::setOpenIcon(QTreeWidgetItem *item)
|
||||
{
|
||||
item->setIcon(0, m_dirOpenIcon);
|
||||
}
|
||||
|
||||
void SnippetsWindow::setClosedIcon(QTreeWidgetItem *item)
|
||||
{
|
||||
item->setIcon(0, m_dirIcon);
|
||||
}
|
||||
|
||||
void SnippetsWindow::updateDescription(QTreeWidgetItem *item)
|
||||
{
|
||||
const SnippetSpec* spec = qVariantValue<SnippetSpec*>(item->data(0, Qt::UserRole));
|
||||
if (spec) {
|
||||
m_descLabel->setText(QLatin1String("<b>") + spec->name() + QLatin1String("</b><br>")
|
||||
+ spec->description());
|
||||
} else {
|
||||
m_descLabel->setText(QLatin1String("<b>") + item->text(0) + QLatin1String("</b><br>"));
|
||||
}
|
||||
}
|
||||
|
||||
SnippetsTree::SnippetsTree(QWidget *parent)
|
||||
: QTreeWidget(parent)
|
||||
{
|
||||
setColumnCount(1);
|
||||
header()->setVisible(false);
|
||||
setAlternatingRowColors(true);
|
||||
setAcceptDrops(true);
|
||||
}
|
||||
|
||||
void SnippetsTree::dropEvent(QDropEvent *)
|
||||
{
|
||||
//writeSnippet(event->mimeData());
|
||||
}
|
||||
|
||||
void SnippetsTree::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
if (event->mimeData()->hasText())
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
|
||||
void SnippetsTree::dragMoveEvent(QDragMoveEvent *)
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user