diff --git a/src/plugins/coreplugin/coreconstants.h b/src/plugins/coreplugin/coreconstants.h
index 4122b1afb51ec36abd685448824295c49e8610f0..a21e52ab06149a07f3de5b0464ea3f0e1850173c 100644
--- a/src/plugins/coreplugin/coreconstants.h
+++ b/src/plugins/coreplugin/coreconstants.h
@@ -180,6 +180,7 @@ const char * const G_EDIT_OTHER          = "QtCreator.Group.Edit.Other";
 // advanced edit menu groups
 
 const char * const G_EDIT_FORMAT         = "QtCreator.Group.Edit.Format";
+const char * const G_EDIT_REFORMAT       = "QtCreator.Group.Edit.Reformat";
 const char * const G_EDIT_COLLAPSING     = "QtCreator.Group.Edit.Collapsing";
 const char * const G_EDIT_FONT           = "QtCreator.Group.Edit.Font";
 const char * const G_EDIT_EDITOR         = "QtCreator.Group.Edit.Editor";
diff --git a/src/plugins/duieditor/duicodeformatter.cpp b/src/plugins/duieditor/duicodeformatter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..feb88982f8f21f4db8f0487e26bd25786700a8c9
--- /dev/null
+++ b/src/plugins/duieditor/duicodeformatter.cpp
@@ -0,0 +1,92 @@
+#include "duicodeformatter.h"
+#include "qmljsast_p.h"
+
+using namespace DuiEditor::Internal;
+using namespace QmlJS;
+using namespace QmlJS::AST;
+
+DuiCodeFormatter::DuiCodeFormatter()
+{
+}
+
+DuiCodeFormatter::~DuiCodeFormatter()
+{
+}
+
+bool DuiCodeFormatter::visit(QmlJS::AST::UiProgram *ast)
+{
+    Node::accept(ast->imports, this);
+
+    if (ast->imports && ast->members)
+        newline();
+
+    Node::accept(ast->members, this);
+
+    return false;
+}
+
+QString DuiCodeFormatter::operator()(QmlJS::AST::UiProgram *ast, const QString &originalSource, const QList<QmlJS::AST::SourceLocation> &comments, int start, int end)
+{
+    m_result.clear();
+    m_result.reserve(originalSource.length() * 2);
+    m_originalSource = originalSource;
+    m_start = start;
+    m_end = end;
+
+    Node::acceptChild(ast, this);
+
+    return m_result;
+}
+
+bool DuiCodeFormatter::visit(UiImport *ast)
+{
+    append("import ");
+    append(ast->fileNameToken);
+
+    if (ast->versionToken.isValid()) {
+        append(' ');
+        append(ast->versionToken);
+    }
+
+    if (ast->asToken.isValid()) {
+        append(" as ");
+        append(ast->importIdToken);
+    }
+
+    if (ast->semicolonToken.isValid())
+        append(';');
+
+    newline();
+
+    return false;
+}
+
+bool DuiCodeFormatter::visit(UiObjectDefinition *ast)
+{
+    indent();
+    Node::accept(ast->qualifiedTypeNameId, this);
+    append(' ');
+    Node::accept(ast->initializer, this);
+    newline();
+
+    return false;
+}
+
+bool DuiCodeFormatter::visit(QmlJS::AST::UiQualifiedId *ast)
+{
+    for (UiQualifiedId *it = ast; it; it = it->next) {
+        append(it->name->asString());
+
+        if (it->next)
+            append('.');
+    }
+
+    return false;
+}
+
+bool DuiCodeFormatter::visit(QmlJS::AST::UiObjectInitializer *ast)
+{
+    append(ast->lbraceToken.offset, ast->rbraceToken.end() - ast->lbraceToken.offset);
+
+    return false;
+}
diff --git a/src/plugins/duieditor/duicodeformatter.h b/src/plugins/duieditor/duicodeformatter.h
new file mode 100644
index 0000000000000000000000000000000000000000..71077dfbef4fda730325aad89945d0516d2ec35f
--- /dev/null
+++ b/src/plugins/duieditor/duicodeformatter.h
@@ -0,0 +1,82 @@
+#ifndef DUICODEFORMATTER_H
+#define DUICODEFORMATTER_H
+
+#include <QString>
+
+#include "qmljsastfwd_p.h"
+#include "qmljsastvisitor_p.h"
+#include "qmljsengine_p.h"
+
+namespace DuiEditor {
+namespace Internal {
+
+class DuiCodeFormatter: protected QmlJS::AST::Visitor
+{
+public:
+    DuiCodeFormatter();
+    ~DuiCodeFormatter();
+
+    QString operator()(QmlJS::AST::UiProgram *ast, const QString &originalSource, const QList<QmlJS::AST::SourceLocation> &comments, int start = -1, int end = -1);
+
+protected:
+    virtual bool visit(QmlJS::AST::UiProgram *ast);
+//    virtual bool visit(UiImportList *ast);
+    virtual bool visit(QmlJS::AST::UiImport *ast);
+//    virtual bool visit(UiPublicMember *ast);
+//    virtual bool visit(UiSourceElement *ast);
+    virtual bool visit(QmlJS::AST::UiObjectDefinition *ast);
+    virtual bool visit(QmlJS::AST::UiObjectInitializer *ast);
+//    virtual bool visit(UiObjectBinding *ast);
+//    virtual bool visit(UiScriptBinding *ast);
+//    virtual bool visit(UiArrayBinding *ast);
+//    virtual bool visit(UiObjectMemberList *ast);
+//    virtual bool visit(UiArrayMemberList *ast);
+    virtual bool visit(QmlJS::AST::UiQualifiedId *ast);
+//    virtual bool visit(UiSignature *ast);
+//    virtual bool visit(UiFormalList *ast);
+//    virtual bool visit(UiFormal *ast);
+//
+//    virtual void endVisit(UiProgram *ast);
+//    virtual void endVisit(UiImport *ast);
+//    virtual void endVisit(UiPublicMember *ast);
+//    virtual void endVisit(UiSourceElement *ast);
+//    virtual void endVisit(UiObjectDefinition *ast);
+//    virtual void endVisit(UiObjectInitializer *ast);
+//    virtual void endVisit(UiObjectBinding *ast);
+//    virtual void endVisit(UiScriptBinding *ast);
+//    virtual void endVisit(UiArrayBinding *ast);
+//    virtual void endVisit(UiObjectMemberList *ast);
+//    virtual void endVisit(UiArrayMemberList *ast);
+//    virtual void endVisit(UiQualifiedId *ast);
+//    virtual void endVisit(UiSignature *ast);
+//    virtual void endVisit(UiFormalList *ast);
+//    virtual void endVisit(UiFormal *ast);
+
+private:
+    void append(char c) { m_result += c; }
+    void append(char *s) { m_result += s; }
+    void append(const QString &s) { m_result += s; }
+    void append(const QmlJS::AST::SourceLocation &loc) { m_result += textAt(loc); }
+    void append(int pos, int len) { append(textAt(pos, len)); }
+
+    QString textAt(const QmlJS::AST::SourceLocation &loc) const
+    { return textAt(loc.offset, loc.length); }
+
+    QString textAt(int pos, int len) const
+    { return m_originalSource.mid(pos, len); }
+
+    void indent() { if (m_indentDepth) append(QString(' ', m_indentDepth)); }
+    void newline() { append('\n'); }
+
+private:
+    QString m_result;
+    QString m_originalSource;
+    int m_start;
+    int m_end;
+    unsigned m_indentDepth;
+};
+
+} // namespace Internal
+} // namespace DuiEditor
+
+#endif // DUICODEFORMATTER_H
diff --git a/src/plugins/duieditor/duieditor.cpp b/src/plugins/duieditor/duieditor.cpp
index 97bd6940d42bc441a9c2411eb6a1a8a5cc40f12e..7e29259abb60a4155be4a34932fa0700b56fb0c4 100644
--- a/src/plugins/duieditor/duieditor.cpp
+++ b/src/plugins/duieditor/duieditor.cpp
@@ -34,12 +34,14 @@
 #include "duidocument.h"
 #include "duimodelmanager.h"
 
-#include "rewriter_p.h"
-
 #include "qmljsastvisitor_p.h"
 #include "qmljsast_p.h"
 #include "qmljsengine_p.h"
 
+#include "rewriter_p.h"
+
+#include "navigationtokenfinder.h"
+
 #include <coreplugin/icore.h>
 #include <coreplugin/actionmanager/actionmanager.h>
 #include <extensionsystem/pluginmanager.h>
@@ -67,7 +69,6 @@ enum {
 using namespace QmlJS;
 using namespace QmlJS::AST;
 
-
 namespace DuiEditor {
 namespace Internal {
 
@@ -702,6 +703,35 @@ void ScriptEditor::createToolBar(ScriptEditorEditable *editable)
 	toolBar->insertWidget(actions.first(), m_methodCombo);
 }
 
+TextEditor::BaseTextEditor::Link ScriptEditor::findLinkAt(const QTextCursor &cursor, bool resolveTarget)
+{
+    Link link;
+
+    if (!m_modelManager)
+        return link;
+
+    const Snapshot snapshot = m_modelManager->snapshot();
+    DuiDocument::Ptr doc = snapshot.document(file()->fileName());
+    if (!doc)
+        return link;
+
+    NavigationTokenFinder finder;
+    if (finder(doc->program(), cursor.position(), resolveTarget)) {
+        link.fileName = file()->fileName();
+        link.pos = finder.linkPosition();
+        link.length = finder.linkLength();
+        link.line = finder.targetLine();
+        link.column = finder.targetColumn() - 1;
+    }
+
+    return link;
+}
+
+void ScriptEditor::reformat(QTextDocument *, QTextBlock block)
+{
+    // TODO (EV)
+}
+
 void ScriptEditor::contextMenuEvent(QContextMenuEvent *e)
 {
 	QMenu *menu = createStandardContextMenu();
diff --git a/src/plugins/duieditor/duieditor.h b/src/plugins/duieditor/duieditor.h
index 583153a12ed1a95044f796c1ed132ef2e2c20376..9e73fae908c5b7e79f0a14b009b77f748fc35b2b 100644
--- a/src/plugins/duieditor/duieditor.h
+++ b/src/plugins/duieditor/duieditor.h
@@ -131,6 +131,8 @@ protected:
 	void contextMenuEvent(QContextMenuEvent *e);
 	TextEditor::BaseTextEditorEditable *createEditableInterface();
 	void createToolBar(ScriptEditorEditable *editable);
+    TextEditor::BaseTextEditor::Link findLinkAt(const QTextCursor &cursor, bool resolveTarget = true);
+    virtual void reformat(QTextDocument *doc, QTextBlock block);
 
 private:
 	virtual bool isElectricCharacter(const QChar &ch) const;
diff --git a/src/plugins/duieditor/duieditor.pro b/src/plugins/duieditor/duieditor.pro
index 4d37e3fbf0f413454f61907774392326e4fd0a0c..6a400aa9480abf8b98db6a589fa756fbb03eaf4c 100644
--- a/src/plugins/duieditor/duieditor.pro
+++ b/src/plugins/duieditor/duieditor.pro
@@ -19,7 +19,9 @@ HEADERS += duieditor.h \
     duicompletionvisitor.h \
     duimodelmanagerinterface.h \
     duieditor_global.h \
-    duimodelmanager.h
+    duimodelmanager.h \
+    duicodeformatter.h \
+    navigationtokenfinder.h
 SOURCES += duieditor.cpp \
     duieditorfactory.cpp \
     duieditorplugin.cpp \
@@ -30,5 +32,7 @@ SOURCES += duieditor.cpp \
     duidocument.cpp \
     duicompletionvisitor.cpp \
     duimodelmanagerinterface.cpp \
-    duimodelmanager.cpp
+    duimodelmanager.cpp \
+    duicodeformatter.cpp \
+    navigationtokenfinder.cpp
 RESOURCES += duieditor.qrc
diff --git a/src/plugins/duieditor/duieditorplugin.cpp b/src/plugins/duieditor/duieditorplugin.cpp
index 774907c8a747a0140a3518ae461e620c01a1ad01..b4923418f2c007413f2533a35f7ddde89d62d366 100644
--- a/src/plugins/duieditor/duieditorplugin.cpp
+++ b/src/plugins/duieditor/duieditorplugin.cpp
@@ -113,8 +113,10 @@ bool DuiEditorPlugin::initialize(const QStringList & /*arguments*/, QString *err
 
     m_actionHandler = new TextEditor::TextEditorActionHandler(DuiEditor::Constants::C_DUIEDITOR,
           TextEditor::TextEditorActionHandler::Format
+        | TextEditor::TextEditorActionHandler::Reformat
         | TextEditor::TextEditorActionHandler::UnCommentSelection
         | TextEditor::TextEditorActionHandler::UnCollapseAll);
+    m_actionHandler->initializeActions();
 
     m_completion = new DuiCodeCompletion();
     addAutoReleasedObject(m_completion);
diff --git a/src/plugins/duieditor/navigationtokenfinder.cpp b/src/plugins/duieditor/navigationtokenfinder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b52178f2396f3c2b8d5b93848a190f77d6b84214
--- /dev/null
+++ b/src/plugins/duieditor/navigationtokenfinder.cpp
@@ -0,0 +1,281 @@
+#include <QDebug>
+
+#include "qmljsast_p.h"
+#include "qmljsengine_p.h"
+
+#include "navigationtokenfinder.h"
+
+using namespace QmlJS;
+using namespace QmlJS::AST;
+using namespace DuiEditor::Internal;
+
+bool NavigationTokenFinder::operator()(QmlJS::AST::UiProgram *ast, int position, bool resolveTarget)
+{
+    _resolveTarget = resolveTarget;
+    _scopes.clear();
+    _pos = position;
+    _linkPosition = -1;
+    _targetLine = -1;
+
+    Node::accept(ast, this);
+
+    if (resolveTarget)
+        return targetFound();
+    else
+        return linkFound();
+}
+
+bool NavigationTokenFinder::visit(QmlJS::AST::IdentifierExpression *ast)
+{
+    if (linkFound())
+        return false;
+
+    if (ast->identifierToken.offset <= _pos && _pos <= ast->identifierToken.end()) {
+        _linkPosition = ast->identifierToken.offset;
+        _linkLength = ast->identifierToken.length;
+
+        if (Node *node = findDeclarationInScopes(ast->name))
+            rememberStartPosition(node);
+    }
+
+    return false;
+}
+
+bool NavigationTokenFinder::visit(QmlJS::AST::UiArrayBinding *ast)
+{
+    if (linkFound())
+        return false;
+
+    Node::accept(ast->members, this);
+
+    return false;
+}
+
+bool NavigationTokenFinder::visit(QmlJS::AST::UiPublicMember *ast)
+{
+    if (linkFound())
+        return false;
+
+    Node::accept(ast->expression, this);
+
+    return false;
+}
+
+bool NavigationTokenFinder::visit(QmlJS::AST::Block *ast)
+{
+    _scopes.push(ast);
+
+    if (linkFound())
+        return false;
+
+    return true;
+}
+
+void NavigationTokenFinder::endVisit(QmlJS::AST::Block *)
+{
+    _scopes.pop();
+}
+
+bool NavigationTokenFinder::visit(QmlJS::AST::UiObjectBinding *ast)
+{
+    _scopes.push(ast);
+
+    if (linkFound())
+        return false;
+
+    Node::accept(ast->qualifiedTypeNameId, this);
+    Node::accept(ast->initializer, this);
+
+    return false;
+}
+
+void NavigationTokenFinder::endVisit(QmlJS::AST::UiObjectBinding *)
+{
+    _scopes.pop();
+}
+
+bool NavigationTokenFinder::visit(QmlJS::AST::UiObjectDefinition *ast)
+{
+    _scopes.push(ast);
+
+    if (linkFound())
+        return false;
+
+    return true;
+}
+
+void NavigationTokenFinder::endVisit(QmlJS::AST::UiObjectDefinition *)
+{
+    _scopes.pop();
+}
+
+bool NavigationTokenFinder::visit(QmlJS::AST::UiQualifiedId *ast)
+{
+    if (linkFound())
+        return false;
+
+    if (ast->identifierToken.offset <= _pos) {
+        for (UiQualifiedId *iter = ast; iter; iter = iter->next) {
+            if (_pos <= iter->identifierToken.end()) {
+                _linkPosition = ast->identifierToken.offset;
+
+                for (UiQualifiedId *iter2 = ast; iter2; iter2 = iter2->next)
+                    _linkLength = iter2->identifierToken.end() - _linkPosition;
+
+                if (Node *node = findDeclarationInScopes(ast))
+                    rememberStartPosition(node);
+
+                return false;
+            }
+        }
+    }
+
+    return false;
+}
+
+bool NavigationTokenFinder::visit(QmlJS::AST::UiScriptBinding *ast)
+{
+    if (linkFound())
+        return false;
+
+    Node::accept(ast->statement, this);
+
+    return false;
+}
+
+bool NavigationTokenFinder::visit(QmlJS::AST::UiSourceElement * /*ast*/)
+{
+    return false;
+}
+
+void NavigationTokenFinder::rememberStartPosition(QmlJS::AST::Node *node)
+{
+    if (UiObjectMember *om = dynamic_cast<UiObjectMember*>(node)) {
+        _targetLine = om->firstSourceLocation().startLine;
+        _targetColumn = om->firstSourceLocation().startColumn;
+    } else if (VariableDeclaration *vd = cast<VariableDeclaration*>(node)) {
+        _targetLine = vd->identifierToken.startLine;
+        _targetColumn = vd->identifierToken.startColumn;
+    } else {
+        qWarning() << "Found declaration of unknown type as a navigation target";
+    }
+}
+
+static inline bool isId(QmlJS::AST::UiQualifiedId *ast)
+{
+    return !(ast->next) && ast->name->asString() == "id";
+}
+
+static inline QString idToString(QmlJS::AST::Statement *stmt)
+{
+    if (ExpressionStatement *e = cast<ExpressionStatement*>(stmt))
+        if (IdentifierExpression *i = cast<IdentifierExpression*>(e->expression))
+            return i->name->asString();
+
+    return QString::null;
+}
+
+static QmlJS::AST::Node *findDeclaration(const QString &nameId, QmlJS::AST::UiObjectMember *m)
+{
+    if (UiPublicMember *p = cast<UiPublicMember*>(m)) {
+        if (p->name->asString() == nameId)
+            return p;
+    } else if (UiObjectBinding *o = cast<UiObjectBinding*>(m)) {
+        if (!(o->qualifiedId->next) && o->qualifiedId->name->asString() == nameId)
+            return o;
+    } else if (UiArrayBinding *a = cast<UiArrayBinding*>(m)) {
+        if (!(a->qualifiedId->next) && a->qualifiedId->name->asString() == nameId)
+            return a;
+    } else if (UiScriptBinding *s = cast<UiScriptBinding*>(m)) {
+        if (isId(s->qualifiedId) && nameId == idToString(s->statement))
+            return s;
+    }
+
+    return 0;
+}
+
+static QmlJS::AST::Node *findDeclaration(const QString &nameId, QmlJS::AST::UiObjectMemberList *l)
+{
+    for (UiObjectMemberList *iter = l; iter; iter = iter->next)
+        if (Node *n = findDeclaration(nameId, iter->member))
+            return n;
+
+    return 0;
+}
+
+static QmlJS::AST::Node *findDeclaration(const QString &nameId, QmlJS::AST::Statement *s)
+{
+    if (VariableStatement *v = cast<VariableStatement*>(s)) {
+        for (VariableDeclarationList *l = v->declarations; l; l = l->next) {
+            if (l->declaration->name->asString() == nameId)
+                return l->declaration;
+        }
+    }
+
+    return 0;
+}
+
+static QmlJS::AST::Node *findDeclaration(const QString &nameId, QmlJS::AST::StatementList *l)
+{
+    for (StatementList *iter = l; iter; iter = iter->next)
+        if (Node *n = findDeclaration(nameId, iter->statement))
+            return n;
+
+    return 0;
+}
+
+static QmlJS::AST::Node *findDeclarationAsDirectChild(const QString &nameId, QmlJS::AST::Node *node)
+{
+    if (UiObjectBinding *binding = cast<UiObjectBinding*>(node)) {
+        return findDeclaration(nameId, binding->initializer->members);
+    } else if (UiObjectDefinition *def = cast<UiObjectDefinition*>(node)) {
+        return findDeclaration(nameId, def->initializer->members);
+    } else if (Block *block = cast<Block *>(node)) {
+        return findDeclaration(nameId, block->statements);
+    } else {
+        return 0;
+    }
+}
+
+static QmlJS::AST::Node *findDeclarationInNode(QmlJS::AST::UiQualifiedId *qualifiedId, QmlJS::AST::Node *node)
+{
+    if (!qualifiedId || !node)
+        return node;
+    else
+        return findDeclarationInNode(qualifiedId->next, findDeclarationAsDirectChild(qualifiedId->name->asString(), node));
+}
+
+QmlJS::AST::Node *NavigationTokenFinder::findDeclarationInScopes(QmlJS::NameId *nameId)
+{
+    if (!_resolveTarget)
+        return 0;
+
+    const QString nameAsString = nameId->asString();
+
+    foreach (QmlJS::AST::Node *scope, _scopes) {
+        Node *result = findDeclarationAsDirectChild(nameAsString, scope);
+
+        if (result)
+            return result;
+    }
+
+    return 0;
+}
+
+QmlJS::AST::Node *NavigationTokenFinder::findDeclarationInScopes(QmlJS::AST::UiQualifiedId *qualifiedId)
+{
+    if (!_resolveTarget)
+        return 0;
+
+    const QString nameAsString = qualifiedId->name->asString();
+    qDebug() << "findDecl. for id part" << nameAsString;
+
+    foreach (QmlJS::AST::Node *scope, _scopes) {
+        Node *result = findDeclarationAsDirectChild(nameAsString, scope);
+
+        if (result)
+            return findDeclarationInNode(qualifiedId->next, result);
+    }
+
+    return 0;
+}
diff --git a/src/plugins/duieditor/navigationtokenfinder.h b/src/plugins/duieditor/navigationtokenfinder.h
new file mode 100644
index 0000000000000000000000000000000000000000..ab8c23c0d42eb810b7821e40b1a7a54aaf8fc7a6
--- /dev/null
+++ b/src/plugins/duieditor/navigationtokenfinder.h
@@ -0,0 +1,63 @@
+#ifndef NAVIGATIONTOKENFINDER_H
+#define NAVIGATIONTOKENFINDER_H
+
+#include <QStack>
+#include <QString>
+
+#include "qmljsastvisitor_p.h"
+
+namespace QmlJS {
+    class NameId;
+} // namespace QmlJS
+
+namespace DuiEditor {
+namespace Internal {
+
+class NavigationTokenFinder: protected QmlJS::AST::Visitor
+{
+public:
+    bool operator()(QmlJS::AST::UiProgram *ast, int position, bool resolveTarget);
+
+    bool targetFound() const { return _targetLine != -1; }
+    bool linkFound() const { return _linkPosition != -1; }
+
+    int linkPosition() const { return _linkPosition; }
+    int linkLength() const { return _linkLength; }
+    int targetLine() const { return _targetLine; }
+    int targetColumn() const { return _targetColumn; }
+
+protected:
+    virtual bool visit(QmlJS::AST::Block *ast);
+    virtual bool visit(QmlJS::AST::IdentifierExpression *ast);
+    virtual bool visit(QmlJS::AST::UiArrayBinding *ast);
+    virtual bool visit(QmlJS::AST::UiPublicMember *ast);
+    virtual bool visit(QmlJS::AST::UiObjectBinding *ast);
+    virtual bool visit(QmlJS::AST::UiObjectDefinition *ast);
+    virtual bool visit(QmlJS::AST::UiQualifiedId *ast);
+    virtual bool visit(QmlJS::AST::UiScriptBinding *ast);
+    virtual bool visit(QmlJS::AST::UiSourceElement *ast);
+
+    virtual void endVisit(QmlJS::AST::Block *);
+    virtual void endVisit(QmlJS::AST::UiObjectBinding *);
+    virtual void endVisit(QmlJS::AST::UiObjectDefinition *);
+
+private:
+    QmlJS::AST::Node *findDeclarationInScopes(QmlJS::AST::UiQualifiedId *ast);
+    QmlJS::AST::Node *findDeclarationInScopes(QmlJS::NameId *id);
+
+    void rememberStartPosition(QmlJS::AST::Node *node);
+
+private:
+    bool _resolveTarget;
+    quint32 _pos;
+    int _linkPosition;
+    int _linkLength;
+    int _targetLine;
+    int _targetColumn;
+    QStack<QmlJS::AST::Node*> _scopes;
+};
+
+} // namespace Internal
+} // namespace DuiEditor
+
+#endif // NAVIGATIONTOKENFINDER_H
diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp
index 59c55fcb2d4f056dcfff985b054cd980225f0fa0..511c4af88ef9f4b6bde691e3da6e5c5a60de1e7c 100644
--- a/src/plugins/texteditor/basetexteditor.cpp
+++ b/src/plugins/texteditor/basetexteditor.cpp
@@ -3242,6 +3242,10 @@ void BaseTextEditor::indentBlock(QTextDocument *, QTextBlock, QChar)
 {
 }
 
+void BaseTextEditor::reformatBlock(QTextDocument *, QTextBlock)
+{
+}
+
 void BaseTextEditor::indent(QTextDocument *doc, const QTextCursor &cursor, QChar typedChar)
 {
     if (cursor.hasSelection()) {
@@ -3256,6 +3260,20 @@ void BaseTextEditor::indent(QTextDocument *doc, const QTextCursor &cursor, QChar
     }
 }
 
+void BaseTextEditor::reformat(QTextDocument *doc, const QTextCursor &cursor)
+{
+    if (cursor.hasSelection()) {
+        QTextBlock block = doc->findBlock(qMin(cursor.selectionStart(), cursor.selectionEnd()));
+        const QTextBlock end = doc->findBlock(qMax(cursor.selectionStart(), cursor.selectionEnd())).next();
+        do {
+            reformatBlock(doc, block);
+            block = block.next();
+        } while (block.isValid() && block != end);
+    } else {
+        reformatBlock(doc, cursor.block());
+    }
+}
+
 BaseTextEditor::Link BaseTextEditor::findLinkAt(const QTextCursor &, bool)
 {
     return Link();
@@ -3987,6 +4005,14 @@ void BaseTextEditor::format()
     cursor.endEditBlock();
 }
 
+void BaseTextEditor::reformat()
+{
+    QTextCursor cursor = textCursor();
+    cursor.beginEditBlock();
+    reformat(document(), cursor);
+    cursor.endEditBlock();
+}
+
 void BaseTextEditor::rewrapParagraph()
 {
     const int paragraphWidth = displaySettings().m_wrapColumn;
diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h
index 17a67d3b0a9bd4bde8cdc329cad1db02f32ee01d..556df22488dfebc618124c9177eafe40e8149256 100644
--- a/src/plugins/texteditor/basetexteditor.h
+++ b/src/plugins/texteditor/basetexteditor.h
@@ -482,6 +482,7 @@ public:
 
 public slots:
     virtual void format();
+    virtual void reformat();
     virtual void rewrapParagraph();
     virtual void unCommentSelection();
     virtual void setFontSettings(const TextEditor::FontSettings &);
@@ -509,6 +510,11 @@ protected:
     // Indent at cursor. Calls indentBlock for selection or current line.
     virtual void indent(QTextDocument *doc, const QTextCursor &cursor, QChar typedChar);
 
+    // Reformats/prettyprints a text block based on previous line. Default does nothing
+    virtual void reformatBlock(QTextDocument *doc, QTextBlock block);
+    // Reformat/prettyprint the current document.
+    virtual void reformat(QTextDocument *doc, const QTextCursor &cursor);
+
     struct Link
     {
         Link(const QString &fileName = QString(),
diff --git a/src/plugins/texteditor/texteditoractionhandler.cpp b/src/plugins/texteditor/texteditoractionhandler.cpp
index 2cabc7caa32473732a55caeda2b17d3920e81e53..bf80d2987b772e4d9932c11ed9470dcd5183d786 100644
--- a/src/plugins/texteditor/texteditoractionhandler.cpp
+++ b/src/plugins/texteditor/texteditoractionhandler.cpp
@@ -65,6 +65,7 @@ TextEditorActionHandler::TextEditorActionHandler(const QString &context,
     m_cleanWhitespaceAction(0),
     m_textWrappingAction(0),
     m_unCommentSelectionAction(0),
+    m_reformatAction(0),
     m_unCollapseAllAction(0),
     m_collapseAction(0),
     m_expandAction(0),
@@ -183,6 +184,12 @@ void TextEditorActionHandler::createActions()
     connect(m_unCommentSelectionAction, SIGNAL(triggered()), this, SLOT(unCommentSelection()));
     advancedMenu->addAction(command, Core::Constants::G_EDIT_FORMAT);
 
+    m_reformatAction = new QAction(tr("&Reformat"), this);
+    command = am->registerAction(m_reformatAction, Constants::REFORMAT, m_contextId);
+    command->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+F")));
+    connect(m_reformatAction, SIGNAL(triggered()), this, SLOT(reformatAction()));
+    advancedMenu->addAction(command, Core::Constants::G_EDIT_REFORMAT);
+
     m_cutLineAction = new QAction(tr("Cut &Line"), this);
     command = am->registerAction(m_cutLineAction, Constants::CUT_LINE, m_contextId);
     command->setDefaultKeySequence(QKeySequence(tr("Shift+Del")));
@@ -318,11 +325,11 @@ void TextEditorActionHandler::updateActions(UpdateMode um)
     m_pasteAction->setEnabled(um != ReadOnlyMode);
     m_formatAction->setEnabled((m_optionalActions & Format) && um != ReadOnlyMode);
     m_unCommentSelectionAction->setEnabled((m_optionalActions & UnCommentSelection) && um != ReadOnlyMode);
+    m_reformatAction->setEnabled((m_optionalActions & Reformat) && um != ReadOnlyMode);
     m_moveLineUpAction->setEnabled(um != ReadOnlyMode);
     m_moveLineDownAction->setEnabled(um != ReadOnlyMode);
 
     m_formatAction->setEnabled((m_optionalActions & Format));
-    m_unCommentSelectionAction->setEnabled((m_optionalActions & UnCommentSelection));
     m_unCollapseAllAction->setEnabled((m_optionalActions & UnCollapseAll));
     m_visualizeWhitespaceAction->setChecked(m_currentEditor->displaySettings().m_visualizeWhitespace);
     if (m_textWrappingAction) {
@@ -407,6 +414,7 @@ FUNCTION2(copyAction, copy)
 FUNCTION2(cutAction, cut)
 FUNCTION2(pasteAction, paste)
 FUNCTION2(formatAction, format)
+FUNCTION2(reformatAction, reformat)
 FUNCTION2(rewrapParagraphAction, rewrapParagraph)
 FUNCTION2(selectAllAction, selectAll)
 FUNCTION(cleanWhitespace)
diff --git a/src/plugins/texteditor/texteditoractionhandler.h b/src/plugins/texteditor/texteditoractionhandler.h
index ca9a878ca1e544646f3228cb1d1454aaabb0b871..b64c7e868e539c10d178749e9f6f35006a9e5169 100644
--- a/src/plugins/texteditor/texteditoractionhandler.h
+++ b/src/plugins/texteditor/texteditoractionhandler.h
@@ -54,7 +54,8 @@ public:
         None = 0,
         Format = 1,
         UnCommentSelection = 2,
-        UnCollapseAll = 4
+        UnCollapseAll = 4,
+        Reformat = 8
     };
 
     TextEditorActionHandler(const QString &context, uint optionalActions = None);
@@ -91,6 +92,7 @@ private slots:
     void gotoAction();
     void printAction();
     void formatAction();
+    void reformatAction();
     void rewrapParagraphAction();
     void setVisualizeWhitespace(bool);
     void cleanWhitespace();
@@ -131,6 +133,7 @@ private:
     QAction *m_cleanWhitespaceAction;
     QAction *m_textWrappingAction;
     QAction *m_unCommentSelectionAction;
+    QAction *m_reformatAction;
     QAction *m_unCollapseAllAction;
     QAction *m_collapseAction;
     QAction *m_expandAction;
diff --git a/src/plugins/texteditor/texteditorconstants.h b/src/plugins/texteditor/texteditorconstants.h
index f0f5d43f6b24152ee5f148d3df66b747283df85a..6f9aec0bb1a5da28a3769fc45db1f4dc1e3255ec 100644
--- a/src/plugins/texteditor/texteditorconstants.h
+++ b/src/plugins/texteditor/texteditorconstants.h
@@ -40,6 +40,7 @@ const char * const VISUALIZE_WHITESPACE  = "TextEditor.VisualizeWhitespace";
 const char * const CLEAN_WHITESPACE      = "TextEditor.CleanWhitespace";
 const char * const TEXT_WRAPPING         = "TextEditor.TextWrapping";
 const char * const UN_COMMENT_SELECTION  = "TextEditor.UnCommentSelection";
+const char * const REFORMAT              = "TextEditor.Reformat";
 const char * const COLLAPSE              = "TextEditor.Collapse";
 const char * const EXPAND                = "TextEditor.Expand";
 const char * const UN_COLLAPSE_ALL       = "TextEditor.UnCollapseAll";