diff --git a/src/plugins/qt4projectmanager/qtoutputformatter.cpp b/src/plugins/qt4projectmanager/qtoutputformatter.cpp
index 017adc442e68fc162344964f810762ecc417eb1c..0878d6aa0bbd31a809c95c604688c24b235e0763 100644
--- a/src/plugins/qt4projectmanager/qtoutputformatter.cpp
+++ b/src/plugins/qt4projectmanager/qtoutputformatter.cpp
@@ -31,6 +31,7 @@
 
 #include <texteditor/basetexteditor.h>
 #include <qt4projectmanager/qt4project.h>
+#include <utils/qtcassert.h>
 
 #include <QtCore/QFileInfo>
 #include <QtCore/QUrl>
@@ -172,6 +173,48 @@ 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()) {
@@ -181,7 +224,7 @@ void QtOutputFormatter::handleLink(const QString &href)
             const QString fileName = QUrl(qmlErrorLink.cap(1)).toLocalFile();
             const int line = qmlErrorLink.cap(2).toInt();
             const int column = qmlErrorLink.cap(3).toInt();
-            TextEditor::BaseTextEditor::openEditorAt(fileName, line, column - 1);
+            TextEditor::BaseTextEditor::openEditorAt(pathInSourceDirectory(fileName), line, column - 1);
             return;
         }
 
@@ -221,6 +264,9 @@ void QtOutputFormatter::handleLink(const QString &href)
                         }
                     }
                 }
+            } else if (!fi.exists()) {
+                // map possible on-device path to source path
+                fileName = pathInSourceDirectory(fileName);
             }
             TextEditor::BaseTextEditor::openEditorAt(fileName, line, 0);
             return;
diff --git a/src/plugins/qt4projectmanager/qtoutputformatter.h b/src/plugins/qt4projectmanager/qtoutputformatter.h
index a62b1c1d7a032bbc569eac2313275d407fa8efe3..f1ba774d6f9bf018371bfde841e75d7090a2afed 100644
--- a/src/plugins/qt4projectmanager/qtoutputformatter.h
+++ b/src/plugins/qt4projectmanager/qtoutputformatter.h
@@ -63,6 +63,7 @@ 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;