diff --git a/src/libs/utils/fileinprojectfinder.cpp b/src/libs/utils/fileinprojectfinder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..141c78e7329130a8b47f5bc4f1ba1a4902526bde --- /dev/null +++ b/src/libs/utils/fileinprojectfinder.cpp @@ -0,0 +1,122 @@ +/************************************************************************** +** +** 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 "fileinprojectfinder.h" +#include <utils/qtcassert.h> + +#include <QFileInfo> + +namespace Utils { + +/** + \class FileInProjectFinder + + Helper class to find the 'original' file in the project directory for a given file path. + + Often files are copied in the build + deploy process. findFile() searches for an existing file + in the project directory for a given file path: + + E.g. following file paths: + C:/app-build-desktop/qml/app/main.qml (shadow build directory) + C:/Private/e3026d63/qml/app/main.qml (Application data folder on Symbian device) + /Users/x/app-build-desktop/App.app/Contents/Resources/qml/App/main.qml (folder on Mac OS X) + should all be mapped to + $PROJECTDIR/qml/app/main.qml + */ +FileInProjectFinder::FileInProjectFinder() +{ +} + +void FileInProjectFinder::setProjectDirectory(const QString &absoluteProjectPath) +{ + QTC_ASSERT(QFileInfo(absoluteProjectPath).exists() + && QFileInfo(absoluteProjectPath).isAbsolute(), return); + + if (absoluteProjectPath == m_projectDir) + return; + + m_projectDir = absoluteProjectPath; + while (m_projectDir.endsWith(QLatin1Char('/'))) + m_projectDir.remove(m_projectDir.length() - 1, 1); + + m_cache.clear(); +} + +QString FileInProjectFinder::projectDirectory() const +{ + return m_projectDir; +} + +/** + Returns the best match for the given originalPath in the project directory. + + The method first checks whether the originalPath inside the project directory exists. + If not, the leading directory in the path is stripped, and the - now shorter - path is + checked for existence. This continues until either the file is found, or the relative path + does not contain any directories any more: In this case the originalPath is returned. + */ +QString FileInProjectFinder::findFile(const QString &originalPath, bool *success) const +{ + if (m_projectDir.isEmpty()) + return originalPath; + + const QChar separator = QLatin1Char('/'); + if (originalPath.startsWith(m_projectDir + separator)) { + return originalPath; + } + + if (m_cache.contains(originalPath)) + return m_cache.value(originalPath); + + // Strip directories one by one from the beginning of the path, + // and see if the new relative path exists in the build directory. + if (originalPath.contains(separator)) { + for (int pos = originalPath.indexOf(separator); pos != -1; + pos = originalPath.indexOf(separator, pos + 1)) { + QString candidate = originalPath; + candidate.remove(0, pos); + candidate.prepend(m_projectDir); + QFileInfo candidateInfo(candidate); + if (candidateInfo.exists() && candidateInfo.isFile()) { + if (success) + *success = true; + + m_cache.insert(originalPath, candidate); + return candidate; + } + } + } + + if (success) + *success = false; + + return originalPath; +} + +} // namespace Utils diff --git a/src/libs/utils/fileinprojectfinder.h b/src/libs/utils/fileinprojectfinder.h new file mode 100644 index 0000000000000000000000000000000000000000..878693f5f752bc5735c2b5b2913651c5da95c424 --- /dev/null +++ b/src/libs/utils/fileinprojectfinder.h @@ -0,0 +1,57 @@ +/************************************************************************** +** +** 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 FILEINPROJECTFINDER_H +#define FILEINPROJECTFINDER_H + +#include <utils/utils_global.h> + +#include <QtCore/QHash> +#include <QtCore/QString> + +namespace Utils { + +class QTCREATOR_UTILS_EXPORT FileInProjectFinder +{ +public: + FileInProjectFinder(); + + void setProjectDirectory(const QString &absoluteProjectPath); + QString projectDirectory() const; + + QString findFile(const QString &originalPath, bool *success = 0) const; + +private: + QString m_projectDir; + QHash<QString,QString> m_cache; +}; + +} // namespace Utils + +#endif // FILEINPROJECTFINDER_H diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri index 245bb7ecdd279fe7450ff5ddcb6b7c5adbbdc0c3..857844aa2b27858bb78c9cd56e9bbd52eab65ed0 100644 --- a/src/libs/utils/utils-lib.pri +++ b/src/libs/utils/utils-lib.pri @@ -52,7 +52,8 @@ SOURCES += $$PWD/environment.cpp \ $$PWD/debuggerlanguagechooser.cpp \ $$PWD/historycompleter.cpp \ $$PWD/buildablehelperlibrary.cpp \ - $$PWD/annotateditemdelegate.cpp + $$PWD/annotateditemdelegate.cpp \ + $$PWD/fileinprojectfinder.cpp win32 { SOURCES += $$PWD/abstractprocess_win.cpp \ @@ -115,7 +116,8 @@ HEADERS += $$PWD/environment.h \ $$PWD/debuggerlanguagechooser.h \ $$PWD/historycompleter.h \ $$PWD/buildablehelperlibrary.h \ - $$PWD/annotateditemdelegate.h + $$PWD/annotateditemdelegate.h \ + $$PWD/fileinprojectfinder.h FORMS += $$PWD/filewizardpage.ui \ $$PWD/projectintropage.ui \ diff --git a/src/plugins/qmljsinspector/qmljsinspector.cpp b/src/plugins/qmljsinspector/qmljsinspector.cpp index a9bd4ea35a03d3e0323e770e25a0aa2f79b06dda..542826809f95d1522b801c4d125d0e3fc143ec37 100644 --- a/src/plugins/qmljsinspector/qmljsinspector.cpp +++ b/src/plugins/qmljsinspector/qmljsinspector.cpp @@ -302,6 +302,7 @@ void InspectorUi::connected(ClientProxy *clientProxy) } connect(m_debugProject, SIGNAL(destroyed()), SLOT(currentDebugProjectRemoved())); + m_projectFinder.setProjectDirectory(m_debugProject->projectDirectory()); setupToolbar(true); resetViews(); @@ -562,12 +563,7 @@ void InspectorUi::gotoObjectReferenceDefinition(const QDeclarativeDebugObjectRef if (source.lineNumber() < 0 || !QFile::exists(fileName)) return; - - // do some extra checking for filenames with shadow builds - we don't want to - // open the shadow build file, but the real one by default. - if (isShadowBuildProject()) { - fileName = filenameForShadowBuildFile(fileName); - } + fileName = m_projectFinder.findFile(fileName); Core::EditorManager *editorManager = Core::EditorManager::instance(); Core::IEditor *editor = editorManager->openEditor(fileName); @@ -582,37 +578,6 @@ void InspectorUi::gotoObjectReferenceDefinition(const QDeclarativeDebugObjectRef } } -QString InspectorUi::filenameForShadowBuildFile(const QString &filename) const -{ - if (!debugProject() || !isShadowBuildProject()) - return filename; - - QDir projectDir(debugProject()->projectDirectory()); - QDir buildDir(debugProjectBuildDirectory()); - QFileInfo fileInfo(filename); - - if (projectDir.exists() && buildDir.exists() && fileInfo.exists()) { - if (fileInfo.absoluteFilePath().startsWith(buildDir.canonicalPath())) { - QString fileRelativePath - = fileInfo.canonicalFilePath().mid(debugProjectBuildDirectory().length()); - -#ifdef Q_OS_MACX - // Qt Quick Applications by default copy the qml directory to - // buildDir()/X.app/Contents/Resources - static QRegExp resourceBundlePattern(QLatin1String("^.*\\.app/Contents/Resources/")); - fileRelativePath.remove(resourceBundlePattern); -#endif - - QFileInfo projectFile(projectDir.canonicalPath() + QLatin1Char('/') + fileRelativePath); - - if (projectFile.exists()) - return projectFile.canonicalFilePath(); - } - - } - return filename; -} - bool InspectorUi::addQuotesForData(const QVariant &value) const { switch (value.type()) { diff --git a/src/plugins/qmljsinspector/qmljsinspector.h b/src/plugins/qmljsinspector/qmljsinspector.h index 6d379ea04619a7755339c2abdd4daee6dea07236..15acda68a970abab8a8972645ae31816897950c5 100644 --- a/src/plugins/qmljsinspector/qmljsinspector.h +++ b/src/plugins/qmljsinspector/qmljsinspector.h @@ -35,6 +35,7 @@ #include <coreplugin/basemode.h> #include <debugger/debuggerconstants.h> #include <qmlprojectmanager/qmlprojectrunconfiguration.h> +#include <utils/fileinprojectfinder.h> #include <qmljs/qmljsdocument.h> #include <qmljs/parser/qmljsastfwd_p.h> @@ -173,6 +174,7 @@ private: QString m_debugProjectBuildDir; QStringList m_pendingPreviewDocumentNames; + Utils::FileInProjectFinder m_projectFinder; static InspectorUi *m_instance; }; diff --git a/src/plugins/qt4projectmanager/qtoutputformatter.cpp b/src/plugins/qt4projectmanager/qtoutputformatter.cpp index 98dc10b044dc8f99a2de666892b82afce8936f43..15a92262871b44129bc5768beb2e8d2d8a268a9f 100644 --- a/src/plugins/qt4projectmanager/qtoutputformatter.cpp +++ b/src/plugins/qt4projectmanager/qtoutputformatter.cpp @@ -52,6 +52,8 @@ QtOutputFormatter::QtOutputFormatter(ProjectExplorer::Project *project) , m_qtTestFail(QLatin1String("^ Loc: \\[(.*)\\]$")) , m_project(project) { + if(project) + m_projectFinder.setProjectDirectory(project->projectDirectory()); } LinkResult QtOutputFormatter::matchLine(const QString &line) const @@ -177,48 +179,6 @@ void QtOutputFormatter::appendLine(QTextCursor &cursor, LinkResult lr, const QSt cursor.insertText(line.mid(lr.end), normalFormat); } -// Map absolute path in shadow build / in the deployment folder to the path in the project directory -// -// Input is e.g. -// C:/app-build-desktop/qml/app/main.qml (shadow build directory) -// C:/Private/e3026d63/qml/app/main.qml (Application data folder on Symbian device) -// /Users/x/app-build-desktop/App.app/Contents/Resources/qml/App/main.qml (folder on Mac OS X) -// which should be mapped to -// $PROJECTDIR/qml/app/main.qml -QString QtOutputFormatter::pathInSourceDirectory(const QString &originalFilePath) -{ - QTC_ASSERT(QFileInfo(originalFilePath).isAbsolute(), return originalFilePath); - - if (!m_project) - return originalFilePath; - - const QString projectDirectory = m_project.data()->projectDirectory(); - - QTC_ASSERT(!projectDirectory.isEmpty(), return originalFilePath); - QTC_ASSERT(!projectDirectory.endsWith(QLatin1Char('/')), return originalFilePath); - - const QChar separator = QLatin1Char('/'); - - if (originalFilePath.startsWith(projectDirectory + separator)) { - return originalFilePath; - } - - // Strip directories one by one from the beginning of the path, - // and see if the new relative path exists in the build directory. - if (originalFilePath.contains(separator)) { - for (int pos = originalFilePath.indexOf(separator); pos != -1; pos = originalFilePath.indexOf(separator, pos + 1)) { - QString candidate = originalFilePath; - candidate.remove(0, pos); - candidate.prepend(projectDirectory); - QFileInfo candidateInfo(candidate); - if (candidateInfo.exists() && candidateInfo.isFile()) - return candidate; - } - } - - return originalFilePath; -} - void QtOutputFormatter::handleLink(const QString &href) { if (!href.isEmpty()) { @@ -230,7 +190,7 @@ void QtOutputFormatter::handleLink(const QString &href) const QString fileName = QUrl(qmlLineColumnLink.cap(1)).toLocalFile(); const int line = qmlLineColumnLink.cap(2).toInt(); const int column = qmlLineColumnLink.cap(3).toInt(); - TextEditor::BaseTextEditor::openEditorAt(pathInSourceDirectory(fileName), line, column - 1); + TextEditor::BaseTextEditor::openEditorAt(m_projectFinder.findFile(fileName), line, column - 1); return; } @@ -241,7 +201,7 @@ void QtOutputFormatter::handleLink(const QString &href) if (qmlLineLink.indexIn(href) != -1) { const QString fileName = QUrl(qmlLineLink.cap(1)).toLocalFile(); const int line = qmlLineLink.cap(2).toInt(); - TextEditor::BaseTextEditor::openEditorAt(pathInSourceDirectory(fileName), line); + TextEditor::BaseTextEditor::openEditorAt(m_projectFinder.findFile(fileName), line); return; } @@ -283,7 +243,7 @@ void QtOutputFormatter::handleLink(const QString &href) } } else if (!fi.exists()) { // map possible on-device path to source path - fileName = pathInSourceDirectory(fileName); + fileName = m_projectFinder.findFile(fileName); } TextEditor::BaseTextEditor::openEditorAt(fileName, line, 0); return; diff --git a/src/plugins/qt4projectmanager/qtoutputformatter.h b/src/plugins/qt4projectmanager/qtoutputformatter.h index a5e4aff8f9755e0a874187d790692c804ed98149..8941ab4c1b0697f3a89fc35f02939cdeeb6e1caa 100644 --- a/src/plugins/qt4projectmanager/qtoutputformatter.h +++ b/src/plugins/qt4projectmanager/qtoutputformatter.h @@ -33,6 +33,7 @@ #include "qt4projectmanager_global.h" #include <projectexplorer/outputformatter.h> +#include <utils/fileinprojectfinder.h> #include <QtCore/QRegExp> #include <QtCore/QWeakPointer> @@ -65,7 +66,6 @@ public: private: LinkResult matchLine(const QString &line) const; void appendLine(QTextCursor & cursor, LinkResult lr, const QString &line, bool onStdError); - QString pathInSourceDirectory(const QString &originalFilePath); QRegExp m_qmlError; QRegExp m_qtError; @@ -74,6 +74,7 @@ private: QWeakPointer<ProjectExplorer::Project> m_project; QString m_lastLine; QString m_deferedText; + Utils::FileInProjectFinder m_projectFinder; };