Move shared code to a new QmlJSTools plugin.

Reviewed-by: Thomas Hartmann
This commit is contained in:
Christian Kamm
2010-11-11 10:05:05 +01:00
parent a4cbd970e5
commit f366754462
32 changed files with 381 additions and 51 deletions

View File

@@ -0,0 +1,20 @@
<plugin name=\"QmlJSTools\" version=\"$$QTCREATOR_VERSION\" compatVersion=\"$$QTCREATOR_VERSION\">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
Commercial Usage
Licensees holding valid Qt Commercial licenses may use this plugin 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 plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. 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.
</license>
<category>Qt Quick</category>
<description>Tools for analyzing Qml/JS code.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
<dependency name=\"TextEditor\" version=\"$$QTCREATOR_VERSION\"/>
<dependency name=\"ProjectExplorer\" version=\"$$QTCREATOR_VERSION\"/>
</dependencyList>
</plugin>

View File

@@ -0,0 +1,598 @@
/**************************************************************************
**
** 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 "qmljsmodelmanager.h"
#include "qmljstoolsconstants.h"
//#include "qmljseditor.h"
#include <coreplugin/icore.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/messagemanager.h>
#include <coreplugin/mimedatabase.h>
#include <qmljs/qmljsinterpreter.h>
#include <qmljs/qmljsbind.h>
#include <qmljs/parser/qmldirparser_p.h>
#include <texteditor/itexteditor.h>
#include <texteditor/basetexteditor.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QLibraryInfo>
#include <QtConcurrentRun>
#include <qtconcurrent/runextensions.h>
#include <QTextStream>
#include <QCoreApplication>
#include <QDebug>
using namespace QmlJS;
using namespace QmlJSTools;
using namespace QmlJSTools::Internal;
static QStringList environmentImportPaths();
ModelManager::ModelManager(QObject *parent):
ModelManagerInterface(parent),
m_core(Core::ICore::instance())
{
m_synchronizer.setCancelOnWait(true);
qRegisterMetaType<QmlJS::Document::Ptr>("QmlJS::Document::Ptr");
qRegisterMetaType<QmlJS::LibraryInfo>("QmlJS::LibraryInfo");
loadQmlTypeDescriptions();
m_defaultImportPaths << environmentImportPaths();
m_defaultImportPaths << QLibraryInfo::location(QLibraryInfo::ImportsPath);
}
void ModelManager::loadQmlTypeDescriptions()
{
loadQmlTypeDescriptions(Core::ICore::instance()->resourcePath());
loadQmlTypeDescriptions(Core::ICore::instance()->userResourcePath());
}
void ModelManager::loadQmlTypeDescriptions(const QString &resourcePath)
{
const QDir typeFileDir(resourcePath + QLatin1String("/qml-type-descriptions"));
const QStringList xmlExtensions = QStringList() << QLatin1String("*.xml");
const QFileInfoList xmlFiles = typeFileDir.entryInfoList(xmlExtensions,
QDir::Files,
QDir::Name);
const QStringList errors = Interpreter::CppQmlTypesLoader::load(xmlFiles);
foreach (const QString &error, errors)
qWarning() << qPrintable(error);
// disabled for now: Prefer the xml file until the type dumping functionality
// has been moved into Qt.
// loads the builtin types
//loadQmlPluginTypes(QString());
}
ModelManagerInterface::WorkingCopy ModelManager::workingCopy() const
{
WorkingCopy workingCopy;
Core::EditorManager *editorManager = m_core->editorManager();
foreach (Core::IEditor *editor, editorManager->openedEditors()) {
const QString key = editor->file()->fileName();
if (TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor*>(editor)) {
if (textEditor->context().contains(ProjectExplorer::Constants::LANG_QMLJS)) {
if (TextEditor::BaseTextEditor *ed = qobject_cast<TextEditor::BaseTextEditor *>(textEditor->widget())) {
workingCopy.insert(key, ed->toPlainText(), ed->document()->revision());
}
}
}
}
return workingCopy;
}
Snapshot ModelManager::snapshot() const
{
QMutexLocker locker(&m_mutex);
return _snapshot;
}
void ModelManager::updateSourceFiles(const QStringList &files,
bool emitDocumentOnDiskChanged)
{
refreshSourceFiles(files, emitDocumentOnDiskChanged);
}
QFuture<void> ModelManager::refreshSourceFiles(const QStringList &sourceFiles,
bool emitDocumentOnDiskChanged)
{
if (sourceFiles.isEmpty()) {
return QFuture<void>();
}
QFuture<void> result = QtConcurrent::run(&ModelManager::parse,
workingCopy(), sourceFiles,
this,
emitDocumentOnDiskChanged);
if (m_synchronizer.futures().size() > 10) {
QList<QFuture<void> > futures = m_synchronizer.futures();
m_synchronizer.clearFutures();
foreach (QFuture<void> future, futures) {
if (! (future.isFinished() || future.isCanceled()))
m_synchronizer.addFuture(future);
}
}
m_synchronizer.addFuture(result);
if (sourceFiles.count() > 1) {
m_core->progressManager()->addTask(result, tr("Indexing"),
Constants::TASK_INDEX);
}
return result;
}
void ModelManager::fileChangedOnDisk(const QString &path)
{
QtConcurrent::run(&ModelManager::parse,
workingCopy(), QStringList() << path,
this, true);
}
void ModelManager::removeFiles(const QStringList &files)
{
emit aboutToRemoveFiles(files);
QMutexLocker locker(&m_mutex);
foreach (const QString &file, files)
_snapshot.remove(file);
}
QList<ModelManager::ProjectInfo> ModelManager::projectInfos() const
{
QMutexLocker locker(&m_mutex);
return m_projects.values();
}
ModelManager::ProjectInfo ModelManager::projectInfo(ProjectExplorer::Project *project) const
{
QMutexLocker locker(&m_mutex);
return m_projects.value(project, ProjectInfo(project));
}
void ModelManager::updateProjectInfo(const ProjectInfo &pinfo)
{
if (! pinfo.isValid())
return;
Snapshot snapshot;
ProjectInfo oldInfo;
{
QMutexLocker locker(&m_mutex);
oldInfo = m_projects.value(pinfo.project);
m_projects.insert(pinfo.project, pinfo);
snapshot = _snapshot;
}
updateImportPaths();
// remove files that are no longer in the project and have been deleted
QStringList deletedFiles;
foreach (const QString &oldFile, oldInfo.sourceFiles) {
if (snapshot.document(oldFile)
&& !pinfo.sourceFiles.contains(oldFile)
&& !QFile::exists(oldFile)) {
deletedFiles += oldFile;
}
}
removeFiles(deletedFiles);
// parse any files not yet in the snapshot
QStringList newFiles;
foreach (const QString &file, pinfo.sourceFiles) {
if (!snapshot.document(file))
newFiles += file;
}
updateSourceFiles(newFiles, false);
}
void ModelManager::emitDocumentChangedOnDisk(Document::Ptr doc)
{ emit documentChangedOnDisk(doc); }
void ModelManager::updateDocument(Document::Ptr doc)
{
{
QMutexLocker locker(&m_mutex);
_snapshot.insert(doc);
}
emit documentUpdated(doc);
}
void ModelManager::updateLibraryInfo(const QString &path, const LibraryInfo &info)
{
{
QMutexLocker locker(&m_mutex);
_snapshot.insertLibraryInfo(path, info);
}
emit libraryInfoUpdated(path, info);
}
static QStringList qmlFilesInDirectory(const QString &path)
{
// ### It would suffice to build pattern once. This function needs to be thread-safe.
Core::MimeDatabase *db = Core::ICore::instance()->mimeDatabase();
Core::MimeType jsSourceTy = db->findByType(Constants::JS_MIMETYPE);
Core::MimeType qmlSourceTy = db->findByType(Constants::QML_MIMETYPE);
QStringList pattern;
foreach (const Core::MimeGlobPattern &glob, jsSourceTy.globPatterns())
pattern << glob.regExp().pattern();
foreach (const Core::MimeGlobPattern &glob, qmlSourceTy.globPatterns())
pattern << glob.regExp().pattern();
QStringList files;
const QDir dir(path);
foreach (const QFileInfo &fi, dir.entryInfoList(pattern, QDir::Files))
files += fi.absoluteFilePath();
return files;
}
static void findNewImplicitImports(const Document::Ptr &doc, const Snapshot &snapshot,
QStringList *importedFiles, QSet<QString> *scannedPaths)
{
// scan files that could be implicitly imported
// it's important we also do this for JS files, otherwise the isEmpty check will fail
if (snapshot.documentsInDirectory(doc->path()).isEmpty()) {
if (! scannedPaths->contains(doc->path())) {
*importedFiles += qmlFilesInDirectory(doc->path());
scannedPaths->insert(doc->path());
}
}
}
static void findNewFileImports(const Document::Ptr &doc, const Snapshot &snapshot,
QStringList *importedFiles, QSet<QString> *scannedPaths)
{
// scan files and directories that are explicitly imported
foreach (const Interpreter::ImportInfo &import, doc->bind()->imports()) {
const QString &importName = import.name();
if (import.type() == Interpreter::ImportInfo::FileImport) {
if (! snapshot.document(importName))
*importedFiles += importName;
} else if (import.type() == Interpreter::ImportInfo::DirectoryImport) {
if (snapshot.documentsInDirectory(importName).isEmpty()) {
if (! scannedPaths->contains(importName)) {
*importedFiles += qmlFilesInDirectory(importName);
scannedPaths->insert(importName);
}
}
}
}
}
static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snapshot,
ModelManager *modelManager,
QStringList *importedFiles, QSet<QString> *scannedPaths)
{
// scan library imports
const QStringList importPaths = modelManager->importPaths();
foreach (const Interpreter::ImportInfo &import, doc->bind()->imports()) {
if (import.type() != Interpreter::ImportInfo::LibraryImport)
continue;
foreach (const QString &importPath, importPaths) {
QDir dir(importPath);
dir.cd(import.name());
const QString targetPath = dir.absolutePath();
// if we know there is a library, done
if (snapshot.libraryInfo(targetPath).isValid())
break;
// if there is a qmldir file, we found a new library!
if (dir.exists("qmldir")) {
QFile qmldirFile(dir.filePath("qmldir"));
qmldirFile.open(QFile::ReadOnly);
QString qmldirData = QString::fromUtf8(qmldirFile.readAll());
QmlDirParser qmldirParser;
qmldirParser.setSource(qmldirData);
qmldirParser.parse();
modelManager->updateLibraryInfo(QFileInfo(qmldirFile).absolutePath(),
LibraryInfo(qmldirParser));
// scan the qml files in the library
foreach (const QmlDirParser::Component &component, qmldirParser.components()) {
if (! component.fileName.isEmpty()) {
QFileInfo componentFileInfo(dir.filePath(component.fileName));
const QString path = componentFileInfo.absolutePath();
if (! scannedPaths->contains(path)) {
*importedFiles += qmlFilesInDirectory(path);
scannedPaths->insert(path);
}
}
}
}
}
}
}
void ModelManager::parse(QFutureInterface<void> &future,
WorkingCopy workingCopy,
QStringList files,
ModelManager *modelManager,
bool emitDocChangedOnDisk)
{
Core::MimeDatabase *db = Core::ICore::instance()->mimeDatabase();
Core::MimeType jsSourceTy = db->findByType(QLatin1String("application/javascript"));
Core::MimeType qmlSourceTy = db->findByType(QLatin1String("application/x-qml"));
int progressRange = files.size();
future.setProgressRange(0, progressRange);
Snapshot snapshot = modelManager->_snapshot;
// paths we have scanned for files and added to the files list
QSet<QString> scannedPaths;
for (int i = 0; i < files.size(); ++i) {
future.setProgressValue(qreal(i) / files.size() * progressRange);
const QString fileName = files.at(i);
const QFileInfo fileInfo(fileName);
Core::MimeType fileMimeTy = db->findByFile(fileInfo);
bool isQmlFile = true;
if (matchesMimeType(fileMimeTy, jsSourceTy))
isQmlFile = false;
else if (! matchesMimeType(fileMimeTy, qmlSourceTy))
continue; // skip it. it's not a QML or a JS file.
QString contents;
int documentRevision = 0;
if (workingCopy.contains(fileName)) {
QPair<QString, int> entry = workingCopy.get(fileName);
contents = entry.first;
documentRevision = entry.second;
} else {
QFile inFile(fileName);
if (inFile.open(QIODevice::ReadOnly)) {
QTextStream ins(&inFile);
contents = ins.readAll();
inFile.close();
}
}
Document::Ptr doc = Document::create(fileName);
doc->setEditorRevision(documentRevision);
doc->setSource(contents);
doc->parse();
// get list of referenced files not yet in snapshot or in directories already scanned
QStringList importedFiles;
findNewImplicitImports(doc, snapshot, &importedFiles, &scannedPaths);
findNewFileImports(doc, snapshot, &importedFiles, &scannedPaths);
findNewLibraryImports(doc, snapshot, modelManager, &importedFiles, &scannedPaths);
// add new files to parse list
foreach (const QString &file, importedFiles) {
if (! files.contains(file))
files.append(file);
}
modelManager->updateDocument(doc);
if (emitDocChangedOnDisk)
modelManager->emitDocumentChangedOnDisk(doc);
}
future.setProgressValue(progressRange);
}
// Check whether fileMimeType is the same or extends knownMimeType
bool ModelManager::matchesMimeType(const Core::MimeType &fileMimeType, const Core::MimeType &knownMimeType)
{
Core::MimeDatabase *db = Core::ICore::instance()->mimeDatabase();
const QStringList knownTypeNames = QStringList(knownMimeType.type()) + knownMimeType.aliases();
foreach (const QString knownTypeName, knownTypeNames)
if (fileMimeType.matchesType(knownTypeName))
return true;
// recursion to parent types of fileMimeType
foreach (const QString &parentMimeType, fileMimeType.subClassesOf()) {
if (matchesMimeType(db->findByType(parentMimeType), knownMimeType))
return true;
}
return false;
}
QStringList ModelManager::importPaths() const
{
return m_allImportPaths;
}
static QStringList environmentImportPaths()
{
QStringList paths;
QByteArray envImportPath = qgetenv("QML_IMPORT_PATH");
#if defined(Q_OS_WIN)
QLatin1Char pathSep(';');
#else
QLatin1Char pathSep(':');
#endif
foreach (const QString &path, QString::fromLatin1(envImportPath).split(pathSep, QString::SkipEmptyParts)) {
QString canonicalPath = QDir(path).canonicalPath();
if (!canonicalPath.isEmpty() && !paths.contains(canonicalPath))
paths.append(canonicalPath);
}
return paths;
}
void ModelManager::loadPluginTypes(const QString &libraryPath, const QString &importPath, const QString &importUri)
{
// make sure loading is always triggered in ModelManager's thread
metaObject()->invokeMethod(this, "onLoadPluginTypes",
Q_ARG(QString, libraryPath),
Q_ARG(QString, importPath),
Q_ARG(QString, importUri));
}
void ModelManager::onLoadPluginTypes(const QString &libraryPath, const QString &importPath, const QString &importUri)
{
const QString canonicalLibraryPath = QDir::cleanPath(libraryPath);
if (m_runningQmldumps.values().contains(canonicalLibraryPath))
return;
if (_snapshot.libraryInfo(canonicalLibraryPath).isDumped())
return;
ProjectExplorer::Project *activeProject = ProjectExplorer::ProjectExplorerPlugin::instance()->startupProject();
if (!activeProject)
return;
ProjectInfo info = projectInfo(activeProject);
if (info.qmlDumpPath.isEmpty())
return;
QProcess *process = new QProcess(this);
process->setEnvironment(info.qmlDumpEnvironment.toStringList());
connect(process, SIGNAL(finished(int)), SLOT(qmlPluginTypeDumpDone(int)));
connect(process, SIGNAL(error(QProcess::ProcessError)), SLOT(qmlPluginTypeDumpError(QProcess::ProcessError)));
QStringList args;
args << importPath;
args << importUri;
process->start(info.qmlDumpPath, args);
m_runningQmldumps.insert(process, canonicalLibraryPath);
}
void ModelManager::updateImportPaths()
{
m_allImportPaths.clear();
QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects);
while (it.hasNext()) {
it.next();
m_allImportPaths += it.value().importPaths;
}
m_allImportPaths += m_defaultImportPaths;
m_allImportPaths.removeDuplicates();
// check if any file in the snapshot imports something new in the new paths
Snapshot snapshot = _snapshot;
QStringList importedFiles;
QSet<QString> scannedPaths;
foreach (const Document::Ptr &doc, snapshot)
findNewLibraryImports(doc, snapshot, this, &importedFiles, &scannedPaths);
updateSourceFiles(importedFiles, true);
}
static QString qmldumpErrorMessage(const QString &libraryPath, const QString &error)
{
return ModelManager::tr("Type dump of QML plugin in %0 failed.\nErrors:\n%1\n").arg(libraryPath, error);
}
void ModelManager::qmlPluginTypeDumpDone(int exitCode)
{
QProcess *process = qobject_cast<QProcess *>(sender());
if (!process)
return;
process->deleteLater();
const QString libraryPath = m_runningQmldumps.take(process);
LibraryInfo libraryInfo = _snapshot.libraryInfo(libraryPath);
libraryInfo.setDumped(true);
if (exitCode != 0) {
Core::MessageManager *messageManager = Core::MessageManager::instance();
messageManager->printToOutputPane(qmldumpErrorMessage(libraryPath, process->readAllStandardError()));
}
const QByteArray output = process->readAllStandardOutput();
QMap<QString, Interpreter::FakeMetaObject *> newObjects;
const QString error = Interpreter::CppQmlTypesLoader::parseQmlTypeXml(output, &newObjects);
if (exitCode == 0 && error.isEmpty()) {
// convert from QList<T *> to QList<const T *>
QList<const Interpreter::FakeMetaObject *> objectsList;
QMapIterator<QString, Interpreter::FakeMetaObject *> it(newObjects);
while (it.hasNext()) {
it.next();
objectsList.append(it.value());
}
libraryInfo.setMetaObjects(objectsList);
if (libraryPath.isEmpty())
Interpreter::CppQmlTypesLoader::builtinObjects.append(objectsList);
}
if (!libraryPath.isEmpty())
updateLibraryInfo(libraryPath, libraryInfo);
}
void ModelManager::qmlPluginTypeDumpError(QProcess::ProcessError)
{
QProcess *process = qobject_cast<QProcess *>(sender());
if (!process)
return;
process->deleteLater();
const QString libraryPath = m_runningQmldumps.take(process);
Core::MessageManager *messageManager = Core::MessageManager::instance();
messageManager->printToOutputPane(qmldumpErrorMessage(libraryPath, process->readAllStandardError()));
if (!libraryPath.isEmpty()) {
LibraryInfo libraryInfo = _snapshot.libraryInfo(libraryPath);
libraryInfo.setDumped(true);
updateLibraryInfo(libraryPath, libraryInfo);
}
}

View File

@@ -0,0 +1,120 @@
/**************************************************************************
**
** 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.
**
**************************************************************************/
#ifndef QMLJSMODELMANAGER_H
#define QMLJSMODELMANAGER_H
#include "qmljstools_global.h"
#include <qmljs/qmljsmodelmanagerinterface.h>
#include <qmljs/qmljsdocument.h>
#include <QFuture>
#include <QFutureSynchronizer>
#include <QMutex>
#include <QProcess>
namespace Core {
class ICore;
class MimeType;
}
namespace QmlJSTools {
namespace Internal {
class QMLJSTOOLS_EXPORT ModelManager: public QmlJS::ModelManagerInterface
{
Q_OBJECT
public:
ModelManager(QObject *parent = 0);
virtual WorkingCopy workingCopy() const;
virtual QmlJS::Snapshot snapshot() const;
virtual void updateSourceFiles(const QStringList &files,
bool emitDocumentOnDiskChanged);
virtual void fileChangedOnDisk(const QString &path);
virtual void removeFiles(const QStringList &files);
virtual QList<ProjectInfo> projectInfos() const;
virtual ProjectInfo projectInfo(ProjectExplorer::Project *project) const;
virtual void updateProjectInfo(const ProjectInfo &pinfo);
void updateDocument(QmlJS::Document::Ptr doc);
void updateLibraryInfo(const QString &path, const QmlJS::LibraryInfo &info);
void emitDocumentChangedOnDisk(QmlJS::Document::Ptr doc);
virtual QStringList importPaths() const;
virtual void loadPluginTypes(const QString &libraryPath, const QString &importPath, const QString &importUri);
Q_SIGNALS:
void projectPathChanged(const QString &projectPath);
private Q_SLOTS:
void onLoadPluginTypes(const QString &libraryPath, const QString &importPath, const QString &importUri);
void qmlPluginTypeDumpDone(int exitCode);
void qmlPluginTypeDumpError(QProcess::ProcessError error);
protected:
QFuture<void> refreshSourceFiles(const QStringList &sourceFiles,
bool emitDocumentOnDiskChanged);
static void parse(QFutureInterface<void> &future,
WorkingCopy workingCopy,
QStringList files,
ModelManager *modelManager,
bool emitDocChangedOnDisk);
void loadQmlTypeDescriptions();
void loadQmlTypeDescriptions(const QString &path);
void updateImportPaths();
private:
static bool matchesMimeType(const Core::MimeType &fileMimeType, const Core::MimeType &knownMimeType);
mutable QMutex m_mutex;
Core::ICore *m_core;
QmlJS::Snapshot _snapshot;
QStringList m_allImportPaths;
QStringList m_defaultImportPaths;
QHash<QProcess *, QString> m_runningQmldumps;
QFutureSynchronizer<void> m_synchronizer;
// project integration
QMap<ProjectExplorer::Project *, ProjectInfo> m_projects;
};
} // namespace Internal
} // namespace QmlJSTools
#endif // QMLJSMODELMANAGER_H

View File

@@ -0,0 +1,359 @@
/**************************************************************************
**
** 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 "qmljsqtstylecodeformatter.h"
#include <texteditor/tabsettings.h>
#include <QtCore/QDebug>
using namespace QmlJS;
using namespace QmlJSTools;
using namespace TextEditor;
QtStyleCodeFormatter::QtStyleCodeFormatter()
: m_indentSize(4)
{
}
QtStyleCodeFormatter::QtStyleCodeFormatter(const TextEditor::TabSettings &tabSettings)
: m_indentSize(tabSettings.m_indentSize)
{
setTabSize(tabSettings.m_tabSize);
}
void QtStyleCodeFormatter::setIndentSize(int size)
{
m_indentSize = size;
}
void QtStyleCodeFormatter::saveBlockData(QTextBlock *block, const BlockData &data) const
{
TextBlockUserData *userData = BaseTextDocumentLayout::userData(*block);
QmlJSCodeFormatterData *cppData = static_cast<QmlJSCodeFormatterData *>(userData->codeFormatterData());
if (!cppData) {
cppData = new QmlJSCodeFormatterData;
userData->setCodeFormatterData(cppData);
}
cppData->m_data = data;
}
bool QtStyleCodeFormatter::loadBlockData(const QTextBlock &block, BlockData *data) const
{
TextBlockUserData *userData = BaseTextDocumentLayout::testUserData(block);
if (!userData)
return false;
QmlJSCodeFormatterData *cppData = static_cast<QmlJSCodeFormatterData *>(userData->codeFormatterData());
if (!cppData)
return false;
*data = cppData->m_data;
return true;
}
void QtStyleCodeFormatter::saveLexerState(QTextBlock *block, int state) const
{
BaseTextDocumentLayout::setLexerState(*block, state);
}
int QtStyleCodeFormatter::loadLexerState(const QTextBlock &block) const
{
return BaseTextDocumentLayout::lexerState(block);
}
void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedIndentDepth) const
{
const State &parentState = state();
const Token &tk = currentToken();
const int tokenPosition = column(tk.begin());
const bool firstToken = (tokenIndex() == 0);
const bool lastToken = (tokenIndex() == tokenCount() - 1);
switch (newState) {
case objectdefinition_open: {
// special case for things like "gradient: Gradient {"
if (parentState.type == binding_assignment)
*savedIndentDepth = state(1).savedIndentDepth;
if (firstToken)
*savedIndentDepth = tokenPosition;
*indentDepth = *savedIndentDepth + m_indentSize;
break;
}
case binding_or_objectdefinition:
if (firstToken)
*indentDepth = *savedIndentDepth = tokenPosition;
break;
case binding_assignment:
if (lastToken)
*indentDepth = *savedIndentDepth + 4;
else
*indentDepth = column(tokenAt(tokenIndex() + 1).begin());
break;
case expression_or_objectdefinition:
*indentDepth = tokenPosition;
break;
case expression:
// expression_or_objectdefinition has already consumed the first token
// ternary already adjusts indents nicely
if (parentState.type != expression_or_objectdefinition
&& parentState.type != binding_assignment
&& parentState.type != ternary_op) {
*indentDepth += 2 * m_indentSize;
}
if (!firstToken && parentState.type != expression_or_objectdefinition) {
*indentDepth = tokenPosition;
}
break;
case expression_maybe_continuation:
// set indent depth to indent we'd get if the expression ended here
for (int i = 1; state(i).type != topmost_intro; ++i) {
const int type = state(i).type;
if (isExpressionEndState(type) && !isBracelessState(type)) {
*indentDepth = state(i - 1).savedIndentDepth;
break;
}
}
break;
case bracket_open:
if (parentState.type == expression && state(1).type == binding_assignment) {
*savedIndentDepth = state(2).savedIndentDepth;
*indentDepth = *savedIndentDepth + m_indentSize;
} else if (!lastToken) {
*indentDepth = tokenPosition + 1;
} else {
*indentDepth = *savedIndentDepth + m_indentSize;
}
break;
case function_start:
if (parentState.type == expression) {
// undo the continuation indent of the expression
*indentDepth = parentState.savedIndentDepth;
*savedIndentDepth = *indentDepth;
}
break;
case do_statement_while_paren_open:
case statement_with_condition_paren_open:
case signal_arglist_open:
case function_arglist_open:
case paren_open:
case condition_paren_open:
if (!lastToken)
*indentDepth = tokenPosition + 1;
else
*indentDepth += m_indentSize;
break;
case ternary_op:
if (!lastToken)
*indentDepth = tokenPosition + tk.length + 1;
else
*indentDepth += m_indentSize;
break;
case jsblock_open:
// closing brace should be aligned to case
if (parentState.type == case_cont) {
*savedIndentDepth = parentState.savedIndentDepth;
break;
}
// fallthrough
case substatement_open:
// special case for foo: {
if (parentState.type == binding_assignment && state(1).type == binding_or_objectdefinition)
*savedIndentDepth = state(1).savedIndentDepth;
*indentDepth = *savedIndentDepth + m_indentSize;
break;
case statement_with_condition:
case statement_with_block:
case if_statement:
case do_statement:
case switch_statement:
if (firstToken || parentState.type == binding_assignment)
*savedIndentDepth = tokenPosition;
// ### continuation
*indentDepth = *savedIndentDepth; // + 2*m_indentSize;
break;
case maybe_else: {
// set indent to outermost braceless savedIndent
int outermostBraceless = 0;
while (isBracelessState(state(outermostBraceless + 1).type))
++outermostBraceless;
*indentDepth = state(outermostBraceless).savedIndentDepth;
// this is where the else should go, if one appears - aligned to if_statement
*savedIndentDepth = state().savedIndentDepth;
break;
}
case condition_open:
// fixed extra indent when continuing 'if (', but not for 'else if ('
if (tokenPosition <= *indentDepth + m_indentSize)
*indentDepth += 2*m_indentSize;
else
*indentDepth = tokenPosition + 1;
break;
case case_start:
*savedIndentDepth = tokenPosition;
break;
case case_cont:
*indentDepth += m_indentSize;
break;
case multiline_comment_start:
*indentDepth = tokenPosition + 2;
break;
case multiline_comment_cont:
*indentDepth = tokenPosition;
break;
}
}
void QtStyleCodeFormatter::adjustIndent(const QList<Token> &tokens, int lexerState, int *indentDepth) const
{
Q_UNUSED(lexerState)
State topState = state();
State previousState = state(1);
// adjusting the indentDepth here instead of in enter() gives 'else if' the correct indentation
// ### could be moved?
if (topState.type == substatement)
*indentDepth += m_indentSize;
// keep user-adjusted indent in multiline comments
if (topState.type == multiline_comment_start
|| topState.type == multiline_comment_cont) {
if (!tokens.isEmpty()) {
*indentDepth = column(tokens.at(0).begin());
return;
}
}
const int kind = extendedTokenKind(tokenAt(0));
switch (kind) {
case LeftBrace:
if (topState.type == substatement
|| topState.type == binding_assignment
|| topState.type == case_cont) {
*indentDepth = topState.savedIndentDepth;
}
break;
case RightBrace: {
if (topState.type == jsblock_open && previousState.type == case_cont) {
*indentDepth = previousState.savedIndentDepth;
break;
}
for (int i = 0; state(i).type != topmost_intro; ++i) {
const int type = state(i).type;
if (type == objectdefinition_open
|| type == jsblock_open
|| type == substatement_open) {
*indentDepth = state(i).savedIndentDepth;
break;
}
}
break;
}
case RightBracket:
for (int i = 0; state(i).type != topmost_intro; ++i) {
const int type = state(i).type;
if (type == bracket_open) {
*indentDepth = state(i).savedIndentDepth;
break;
}
}
break;
case LeftBracket:
case LeftParenthesis:
case Delimiter:
if (topState.type == expression_maybe_continuation)
*indentDepth = topState.savedIndentDepth;
break;
case Else:
if (topState.type == maybe_else) {
*indentDepth = topState.savedIndentDepth;
} else if (topState.type == expression_maybe_continuation) {
bool hasElse = false;
for (int i = 1; state(i).type != topmost_intro; ++i) {
const int type = state(i).type;
if (type == else_clause)
hasElse = true;
if (type == if_statement) {
if (hasElse) {
hasElse = false;
} else {
*indentDepth = state(i).savedIndentDepth;
break;
}
}
}
}
break;
case Colon:
if (topState.type == ternary_op) {
*indentDepth -= 2;
}
break;
case Question:
if (topState.type == expression_maybe_continuation)
*indentDepth = topState.savedIndentDepth;
break;
case Default:
case Case:
for (int i = 0; state(i).type != topmost_intro; ++i) {
const int type = state(i).type;
if (type == switch_statement || type == case_cont) {
*indentDepth = state(i).savedIndentDepth;
break;
} else if (type == topmost_intro) {
break;
}
}
break;
}
}

View File

@@ -0,0 +1,74 @@
/**************************************************************************
**
** 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.
**
**************************************************************************/
#ifndef QMLJSQTSTYLECODEFORMATTER_H
#define QMLJSQTSTYLECODEFORMATTER_H
#include "qmljstools_global.h"
#include <texteditor/basetextdocumentlayout.h>
#include <qmljs/qmljscodeformatter.h>
namespace TextEditor {
class TabSettings;
}
namespace QmlJSTools {
class QMLJSTOOLS_EXPORT QtStyleCodeFormatter : public QmlJS::CodeFormatter
{
public:
QtStyleCodeFormatter();
explicit QtStyleCodeFormatter(const TextEditor::TabSettings &tabSettings);
void setIndentSize(int size);
protected:
virtual void onEnter(int newState, int *indentDepth, int *savedIndentDepth) const;
virtual void adjustIndent(const QList<QmlJS::Token> &tokens, int lexerState, int *indentDepth) const;
virtual void saveBlockData(QTextBlock *block, const BlockData &data) const;
virtual bool loadBlockData(const QTextBlock &block, BlockData *data) const;
virtual void saveLexerState(QTextBlock *block, int state) const;
virtual int loadLexerState(const QTextBlock &block) const;
private:
int m_indentSize;
class QmlJSCodeFormatterData: public TextEditor::CodeFormatterData
{
public:
QmlJS::CodeFormatter::BlockData m_data;
};
};
} // namespace QmlJSTools
#endif // QMLJSQTSTYLECODEFORMATTER_H

View File

@@ -0,0 +1,143 @@
/**************************************************************************
**
** 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 "qmljsrefactoringchanges.h"
#include "qmljsqtstylecodeformatter.h"
#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
#include <texteditor/texteditorsettings.h>
#include <texteditor/tabsettings.h>
using namespace QmlJS;
using namespace QmlJSTools;
QmlJSRefactoringChanges::QmlJSRefactoringChanges(ModelManagerInterface *modelManager,
const Snapshot &snapshot)
: m_modelManager(modelManager)
, m_snapshot(snapshot)
{
Q_ASSERT(modelManager);
}
const Snapshot &QmlJSRefactoringChanges::snapshot() const
{
return m_snapshot;
}
QmlJSRefactoringFile QmlJSRefactoringChanges::file(const QString &fileName)
{
return QmlJSRefactoringFile(fileName, this);
}
void QmlJSRefactoringChanges::indentSelection(const QTextCursor &selection) const
{
// ### shares code with QmlJSTextEditor::indent
QTextDocument *doc = selection.document();
QTextBlock block = doc->findBlock(selection.selectionStart());
const QTextBlock end = doc->findBlock(selection.selectionEnd()).next();
const TextEditor::TabSettings &tabSettings(TextEditor::TextEditorSettings::instance()->tabSettings());
QtStyleCodeFormatter codeFormatter(tabSettings);
codeFormatter.updateStateUntil(block);
do {
tabSettings.indentLine(block, codeFormatter.indentFor(block));
codeFormatter.updateLineStateChange(block);
block = block.next();
} while (block.isValid() && block != end);
}
void QmlJSRefactoringChanges::fileChanged(const QString &fileName)
{
m_modelManager->updateSourceFiles(QStringList(fileName), true);
}
QmlJSRefactoringFile::QmlJSRefactoringFile()
{ }
QmlJSRefactoringFile::QmlJSRefactoringFile(const QString &fileName, QmlJSRefactoringChanges *refactoringChanges)
: RefactoringFile(fileName, refactoringChanges)
{ }
QmlJSRefactoringFile::QmlJSRefactoringFile(TextEditor::BaseTextEditor *editor, QmlJS::Document::Ptr document)
: RefactoringFile()
, m_qmljsDocument(document)
{
m_fileName = document->fileName();
m_editor = editor;
}
Document::Ptr QmlJSRefactoringFile::qmljsDocument() const
{
if (!m_qmljsDocument) {
const QString source = document()->toPlainText();
const QString name = fileName();
const Snapshot &snapshot = refactoringChanges()->snapshot();
m_qmljsDocument = snapshot.documentFromSource(source, name);
m_qmljsDocument->parse();
}
return m_qmljsDocument;
}
unsigned QmlJSRefactoringFile::startOf(const AST::SourceLocation &loc) const
{
return position(loc.startLine, loc.startColumn);
}
bool QmlJSRefactoringFile::isCursorOn(AST::UiObjectMember *ast) const
{
const unsigned pos = cursor().position();
return ast->firstSourceLocation().begin() <= pos
&& pos <= ast->lastSourceLocation().end();
}
bool QmlJSRefactoringFile::isCursorOn(AST::UiQualifiedId *ast) const
{
const unsigned pos = cursor().position();
if (ast->identifierToken.begin() > pos)
return false;
AST::UiQualifiedId *last = ast;
while (last->next)
last = last->next;
return pos <= ast->identifierToken.end();
}
QmlJSRefactoringChanges *QmlJSRefactoringFile::refactoringChanges() const
{
return static_cast<QmlJSRefactoringChanges *>(m_refactoringChanges);
}

View File

@@ -0,0 +1,93 @@
/**************************************************************************
**
** 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.
**
**************************************************************************/
#ifndef QMLREFACTORINGCHANGES_H
#define QMLREFACTORINGCHANGES_H
#include "qmljstools_global.h"
#include <qmljs/qmljsdocument.h>
#include <texteditor/refactoringchanges.h>
namespace QmlJS {
class ModelManagerInterface;
} // namespace QmlJS
namespace QmlJSTools {
class QmlJSRefactoringChanges;
class QMLJSTOOLS_EXPORT QmlJSRefactoringFile: public TextEditor::RefactoringFile
{
public:
QmlJSRefactoringFile();
QmlJSRefactoringFile(const QString &fileName, QmlJSRefactoringChanges *refactoringChanges);
QmlJSRefactoringFile(TextEditor::BaseTextEditor *editor, QmlJS::Document::Ptr document);
QmlJS::Document::Ptr qmljsDocument() const;
/*!
\returns the offset in the document for the start position of the given
source location.
*/
unsigned startOf(const QmlJS::AST::SourceLocation &loc) const;
bool isCursorOn(QmlJS::AST::UiObjectMember *ast) const;
bool isCursorOn(QmlJS::AST::UiQualifiedId *ast) const;
private:
QmlJSRefactoringChanges *refactoringChanges() const;
mutable QmlJS::Document::Ptr m_qmljsDocument;
};
class QMLJSTOOLS_EXPORT QmlJSRefactoringChanges: public TextEditor::RefactoringChanges
{
public:
QmlJSRefactoringChanges(QmlJS::ModelManagerInterface *modelManager,
const QmlJS::Snapshot &snapshot);
const QmlJS::Snapshot &snapshot() const;
QmlJSRefactoringFile file(const QString &fileName);
private:
virtual void indentSelection(const QTextCursor &selection) const;
virtual void fileChanged(const QString &fileName);
private:
QmlJS::ModelManagerInterface *m_modelManager;
QmlJS::Snapshot m_snapshot;
};
} // namespace QmlJSTools
#endif // QMLREFACTORINGCHANGES_H

View File

@@ -0,0 +1,20 @@
!dll {
DEFINES += QMLJSTOOLS_STATIC
}
DEPENDPATH += $$PWD
INCLUDEPATH += $$PWD/..
HEADERS += \
$$PWD/qmljstools_global.h \
$$PWD/qmljstoolsplugin.h \
$$PWD/qmljstoolsconstants.h \
$$PWD/qmljsmodelmanager.h \
$$PWD/qmljsqtstylecodeformatter.h \
$$PWD/qmljsrefactoringchanges.h
SOURCES += \
$$PWD/qmljstoolsplugin.cpp \
$$PWD/qmljsmodelmanager.cpp \
$$PWD/qmljsqtstylecodeformatter.cpp \
$$PWD/qmljsrefactoringchanges.cpp

View File

@@ -0,0 +1,6 @@
include(qmljstools_dependencies.pri)
DEPENDPATH += $$PWD
INCLUDEPATH += $$PWD/..
LIBS *= -l$$qtLibraryName(QmlJSTools)

View File

@@ -0,0 +1,10 @@
TEMPLATE = lib
TARGET = QmlJSTools
include(../../qtcreatorplugin.pri)
include(qmljstools_dependencies.pri)
# DEFINES += QT_NO_CAST_FROM_ASCII
DEFINES += QT_NO_CAST_TO_ASCII
DEFINES += QMLJSTOOLS_LIBRARY
include(qmljstools-lib.pri)

View File

@@ -0,0 +1,3 @@
include($$IDE_SOURCE_TREE/src/libs/qmljs/qmljs.pri)
include($$IDE_SOURCE_TREE/src/plugins/projectexplorer/projectexplorer.pri)
include($$IDE_SOURCE_TREE/src/plugins/texteditor/texteditor.pri)

View File

@@ -0,0 +1,43 @@
/**************************************************************************
**
** 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.
**
**************************************************************************/
#ifndef QMLJSTOOLS_GLOBAL_H
#define QMLJSTOOLS_GLOBAL_H
#include <QtGlobal>
#if defined(QMLJSTOOLS_LIBRARY)
# define QMLJSTOOLS_EXPORT Q_DECL_EXPORT
#elif defined(QMLJSTOOLS_STATIC)
# define QMLJSTOOLS_EXPORT
#else
# define QMLJSTOOLS_EXPORT Q_DECL_IMPORT
#endif
#endif // QMLJSTOOLS_GLOBAL_H

View File

@@ -0,0 +1,46 @@
/**************************************************************************
**
** 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.
**
**************************************************************************/
#ifndef QMLJSTOOLS_CONSTANTS_H
#define QMLJSTOOLS_CONSTANTS_H
#include <QtCore/QtGlobal>
namespace QmlJSTools {
namespace Constants {
const char * const QML_MIMETYPE = "application/x-qml";
const char * const JS_MIMETYPE = "application/javascript";
const char * const TASK_INDEX = "QmlJSEditor.TaskIndex";
} // namespace Constants
} // namespace QmlJSEditor
#endif // QMLJSTOOLS_CONSTANTS_H

View File

@@ -0,0 +1,89 @@
/**************************************************************************
**
** 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 "qmljstoolsplugin.h"
#include "qmljsmodelmanager.h"
#include <extensionsystem/pluginmanager.h>
#include <coreplugin/icore.h>
#include <QtCore/QtPlugin>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtCore/QDebug>
#include <QtCore/QSettings>
using namespace QmlJSTools::Internal;
enum { debug = 0 };
QmlJSToolsPlugin *QmlJSToolsPlugin::m_instance = 0;
QmlJSToolsPlugin::QmlJSToolsPlugin()
: m_modelManager(0)
{
m_instance = this;
}
QmlJSToolsPlugin::~QmlJSToolsPlugin()
{
m_instance = 0;
m_modelManager = 0; // deleted automatically
}
bool QmlJSToolsPlugin::initialize(const QStringList &arguments, QString *error)
{
Q_UNUSED(arguments)
Q_UNUSED(error)
// Core::ICore *core = Core::ICore::instance();
// Objects
m_modelManager = new ModelManager(this);
// Core::VCSManager *vcsManager = core->vcsManager();
// Core::FileManager *fileManager = core->fileManager();
// connect(vcsManager, SIGNAL(repositoryChanged(QString)),
// m_modelManager, SLOT(updateModifiedSourceFiles()));
// connect(fileManager, SIGNAL(filesChangedInternally(QStringList)),
// m_modelManager, SLOT(updateSourceFiles(QStringList)));
addAutoReleasedObject(m_modelManager);
return true;
}
void QmlJSToolsPlugin::extensionsInitialized()
{
}
ExtensionSystem::IPlugin::ShutdownFlag QmlJSToolsPlugin::aboutToShutdown()
{
return SynchronousShutdown;
}
Q_EXPORT_PLUGIN(QmlJSToolsPlugin)

View File

@@ -0,0 +1,73 @@
/**************************************************************************
**
** 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.
**
**************************************************************************/
#ifndef QMLJSTOOLS_H
#define QMLJSTOOLS_H
#include <extensionsystem/iplugin.h>
#include <projectexplorer/projectexplorer.h>
#include <QtGui/QTextDocument>
#include <QtCore/QSharedPointer>
QT_BEGIN_NAMESPACE
class QFileInfo;
class QDir;
QT_END_NAMESPACE
namespace QmlJSTools {
namespace Internal {
class ModelManager;
class QmlJSToolsPlugin : public ExtensionSystem::IPlugin
{
Q_DISABLE_COPY(QmlJSToolsPlugin)
Q_OBJECT
public:
static QmlJSToolsPlugin *instance() { return m_instance; }
QmlJSToolsPlugin();
~QmlJSToolsPlugin();
bool initialize(const QStringList &arguments, QString *error_message);
void extensionsInitialized();
ShutdownFlag aboutToShutdown();
ModelManager *modelManager() { return m_modelManager; }
private:
ModelManager *m_modelManager;
static QmlJSToolsPlugin *m_instance;
};
} // namespace Internal
} // namespace CppTools
#endif // QMLJSTOOLS_H