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;
 };