diff --git a/src/libs/qmljs/qmljs-lib.pri b/src/libs/qmljs/qmljs-lib.pri
index 0c4cb8e17a97bc778373cc6803c65099a8ff8f98..fa9484182bfa58284b83236869c36ab0076db98f 100644
--- a/src/libs/qmljs/qmljs-lib.pri
+++ b/src/libs/qmljs/qmljs-lib.pri
@@ -56,6 +56,11 @@ OTHER_FILES += \
     $$PWD/parser/qmljs.g
 
 contains(QT, gui) {
-    SOURCES += $$PWD/qmljsindenter.cpp
-    HEADERS += $$PWD/qmljsindenter.h
+    SOURCES += \
+        $$PWD/qmljsindenter.cpp \
+        $$PWD/qmljscodeformatter.cpp
+
+    HEADERS += \
+        $$PWD/qmljsindenter.h \
+        $$PWD/qmljscodeformatter.h
 }
diff --git a/src/libs/qmljs/qmljscodeformatter.cpp b/src/libs/qmljs/qmljscodeformatter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..468d112cbcbfe4bacb5e6bb85e8132bc5a9f55b6
--- /dev/null
+++ b/src/libs/qmljs/qmljscodeformatter.cpp
@@ -0,0 +1,910 @@
+/**************************************************************************
+**
+** 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 "qmljscodeformatter.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QMetaEnum>
+#include <QtGui/QTextDocument>
+#include <QtGui/QTextCursor>
+#include <QtGui/QTextBlock>
+
+using namespace QmlJS;
+
+CodeFormatter::BlockData::BlockData()
+    : m_blockRevision(-1)
+{
+}
+
+CodeFormatter::CodeFormatter()
+    : m_indentDepth(0)
+    , m_tabSize(4)
+{
+}
+
+CodeFormatter::~CodeFormatter()
+{
+}
+
+void CodeFormatter::setTabSize(int tabSize)
+{
+    m_tabSize = tabSize;
+}
+
+void CodeFormatter::recalculateStateAfter(const QTextBlock &block)
+{
+    restoreCurrentState(block.previous());
+
+    const int lexerState = tokenizeBlock(block);
+    m_tokenIndex = 0;
+    m_newStates.clear();
+
+    //qDebug() << "Starting to look at " << block.text() << block.blockNumber() + 1;
+
+    for (; m_tokenIndex < m_tokens.size(); ) {
+        m_currentToken = tokenAt(m_tokenIndex);
+        const int kind = extendedTokenKind(m_currentToken);
+        //dump();
+        //qDebug() << "Token" << m_currentLine.mid(m_currentToken.begin(), m_currentToken.length) << m_tokenIndex << "in line" << block.blockNumber() + 1;
+
+        if (kind == Comment
+                && state().type != multiline_comment_cont
+                && state().type != multiline_comment_start) {
+            m_tokenIndex += 1;
+            continue;
+        }
+
+        switch (m_currentState.top().type) {
+        case topmost_intro:
+            switch (kind) {
+            case Identifier:    enter(objectdefinition_or_js); continue;
+            case Import:        enter(top_qml); continue;
+            default:            enter(top_js); continue;
+            } break;
+
+        case top_qml:
+            switch (kind) {
+            case Import:        enter(import_start); break;
+            case Identifier:    enter(binding_or_objectdefinition); break;
+            } break;
+
+        case top_js:
+            tryStatement();
+            break;
+
+        case objectdefinition_or_js:
+            switch (kind) {
+            case Dot:           break;
+            case Identifier:
+                if (!m_currentLine.at(m_currentToken.begin()).isUpper()) {
+                    turnInto(top_js);
+                    continue;
+                }
+                break;
+            case LeftBrace:     turnInto(binding_or_objectdefinition); continue;
+            default:            turnInto(top_js); continue;
+            } break;
+
+        case import_start:
+            enter(import_maybe_dot_or_version_or_as);
+            break;
+
+        case import_maybe_dot_or_version_or_as:
+            switch (kind) {
+            case Dot:           turnInto(import_dot); break;
+            case As:            turnInto(import_as); break;
+            case Number:        turnInto(import_maybe_as); break;
+            default:            leave(); leave(); continue;
+            } break;
+
+        case import_maybe_as:
+            switch (kind) {
+            case As:            turnInto(import_as); break;
+            default:            leave(); leave(); continue;
+            } break;
+
+        case import_dot:
+            switch (kind) {
+            case Identifier:    turnInto(import_maybe_dot_or_version_or_as); break;
+            default:            leave(); leave(); continue;
+            } break;
+
+        case import_as:
+            switch (kind) {
+            case Identifier:    leave(); leave(); break;
+            } break;
+
+        case binding_or_objectdefinition:
+            switch (kind) {
+            case Colon:         enter(binding_assignment); break;
+            case LeftBrace:     enter(objectdefinition_open); break;
+            } break;
+
+        case binding_assignment:
+            switch (kind) {
+            case Semicolon:     leave(true); break;
+            case If:            enter(if_statement); break;
+            case LeftBrace:     enter(jsblock_open); break;
+            case On:
+            case As:
+            case List:
+            case Import:
+            case Signal:
+            case Property:
+            case Identifier:    enter(expression_or_objectdefinition); break;
+            default:            enter(expression); continue;
+            } break;
+
+        case objectdefinition_open:
+            switch (kind) {
+            case RightBrace:    leave(true); break;
+            case Default:       enter(default_property_start); break;
+            case Property:      enter(property_start); break;
+            case Function:      enter(function_start); break;
+            case Signal:        enter(signal_start); break;
+            case On:
+            case As:
+            case List:
+            case Import:
+            case Identifier:    enter(binding_or_objectdefinition); break;
+            } break;
+
+        case default_property_start:
+            if (kind != Property)
+                leave(true);
+            else
+                turnInto(property_start);
+            break;
+
+        case property_start:
+            switch (kind) {
+            case Colon:         enter(binding_assignment); break; // oops, was a binding
+            case Var:
+            case Identifier:    enter(property_type); break;
+            case List:          enter(property_list_open); break;
+            default:            leave(true); continue;
+            } break;
+
+        case property_type:
+            turnInto(property_maybe_initializer);
+            break;
+
+        case property_list_open:
+            if (m_currentLine.midRef(m_currentToken.begin(), m_currentToken.length) == QLatin1String(">"))
+                turnInto(property_maybe_initializer);
+            break;
+
+        case property_maybe_initializer:
+            switch (kind) {
+            case Colon:         enter(binding_assignment); break;
+            default:            leave(true); continue;
+            } break;
+
+        case signal_start:
+            switch (kind) {
+            case Colon:         enter(binding_assignment); break; // oops, was a binding
+            default:            enter(signal_maybe_arglist); break;
+            } break;
+
+        case signal_maybe_arglist:
+            switch (kind) {
+            case LeftParenthesis:   turnInto(signal_arglist_open); break;
+            default:                leave(true); continue;
+            } break;
+
+        case signal_arglist_open:
+            switch (kind) {
+            case RightParenthesis:  leave(true); break;
+            } break;
+
+        case function_start:
+            switch (kind) {
+            case LeftParenthesis:   enter(function_arglist_open); break;
+            } break;
+
+        case function_arglist_open:
+            switch (kind) {
+            case RightParenthesis:  turnInto(function_arglist_closed); break;
+            } break;
+
+        case function_arglist_closed:
+            switch (kind) {
+            case LeftBrace:         turnInto(jsblock_open); break;
+            default:                leave(true); continue; // error recovery
+            } break;
+
+        case expression_or_objectdefinition:
+            switch (kind) {
+            case LeftBrace:     turnInto(objectdefinition_open); break;
+            default:            enter(expression); continue; // really? first token already gone!
+            } break;
+
+        case expression:
+            if (tryInsideExpression())
+                break;
+            switch (kind) {
+            case Comma:
+            case Delimiter:         enter(expression_continuation); break;
+            case RightBracket:
+            case RightParenthesis:  leave(); continue;
+            case RightBrace:        leave(true); continue;
+            case Semicolon:         leave(true); break;
+            } break;
+
+        case expression_continuation:
+            leave();
+            continue;
+
+        case expression_maybe_continuation:
+            switch (kind) {
+            case Question:
+            case Delimiter:
+            case LeftBracket:
+            case LeftParenthesis:  leave(); continue;
+            default:               leave(true); continue;
+            } break;
+
+        case paren_open:
+            if (tryInsideExpression())
+                break;
+            switch (kind) {
+            case RightParenthesis:  leave(); break;
+            } break;
+
+        case bracket_open:
+            if (tryInsideExpression())
+                break;
+            switch (kind) {
+            case Comma:             enter(bracket_element_start); break;
+            case RightBracket:      leave(); break;
+            } break;
+
+        case bracket_element_start:
+            switch (kind) {
+            case Identifier:        turnInto(bracket_element_maybe_objectdefinition); break;
+            default:                leave(); continue;
+            } break;
+
+        case bracket_element_maybe_objectdefinition:
+            switch (kind) {
+            case LeftBrace:         turnInto(objectdefinition_open); break;
+            default:                leave(); continue;
+            } break;
+
+        case ternary_op:
+            if (tryInsideExpression())
+                break;
+            switch (kind) {
+            case RightParenthesis:
+            case RightBracket:
+            case RightBrace:
+            case Comma:
+            case Semicolon:         leave(); continue;
+            case Colon:             enter(expression); break; // entering expression makes maybe_continuation work
+            } break;
+
+        case jsblock_open:
+        case substatement_open:
+            if (tryStatement())
+                break;
+            switch (kind) {
+            case RightBrace:        leave(true); break;
+            } break;
+
+        case substatement:
+            // prefer substatement_open over block_open
+            if (kind != LeftBrace) {
+                if (tryStatement())
+                    break;
+            }
+            switch (kind) {
+            case LeftBrace:         turnInto(substatement_open); break;
+            } break;
+
+        case if_statement:
+            switch (kind) {
+            case LeftParenthesis:   enter(condition_open); break;
+            default:                leave(true); break; // error recovery
+            } break;
+
+        case maybe_else:
+            if (kind == Else) {
+                turnInto(else_clause);
+                enter(substatement);
+                break;
+            } else {
+                leave(true);
+                continue;
+            }
+
+        case else_clause:
+            // ### shouldn't happen
+            dump();
+            Q_ASSERT(false);
+            leave(true);
+            break;
+
+        case condition_open:
+            switch (kind) {
+            case RightParenthesis:  turnInto(substatement); break;
+            case LeftParenthesis:   enter(condition_paren_open); break;
+            } break;
+
+        // paren nesting
+        case condition_paren_open:
+            switch (kind) {
+            case RightParenthesis:  leave(); break;
+            case LeftParenthesis:   enter(condition_paren_open); break;
+            } break;
+
+        case switch_statement:
+        case statement_with_condition:
+            switch (kind) {
+            case LeftParenthesis:   enter(statement_with_condition_paren_open); break;
+            default:                leave(true);
+            } break;
+
+        case statement_with_condition_paren_open:
+            if (tryInsideExpression())
+                break;
+            switch (kind) {
+            case RightParenthesis:  turnInto(substatement); break;
+            } break;
+
+        case statement_with_block:
+            switch (kind) {
+            case LeftBrace:         enter(jsblock_open); break;
+            default:                leave(true); break;
+            } break;
+
+        case do_statement:
+            switch (kind) {
+            case While:             break;
+            case LeftParenthesis:   enter(do_statement_while_paren_open); break;
+            default:                leave(true); break;
+            } break;
+
+        case do_statement_while_paren_open:
+            if (tryInsideExpression())
+                break;
+            switch (kind) {
+            case RightParenthesis:  leave(); leave(true); break;
+            } break;
+
+            break;
+
+        case case_start:
+            switch (kind) {
+            case Colon:             turnInto(case_cont); break;
+            } break;
+
+        case case_cont:
+            if (kind != Case && kind != Default && tryStatement())
+                break;
+            switch (kind) {
+            case RightBrace:        leave(); continue;
+            case Default:
+            case Case:              leave(); continue;
+            } break;
+
+        case multiline_comment_start:
+        case multiline_comment_cont:
+            if (kind != Comment) {
+                leave();
+                continue;
+            } else if (m_tokenIndex == m_tokens.size() - 1
+                       && lexerState == Scanner::Normal) {
+                leave();
+            } else if (m_tokenIndex == 0) {
+                // to allow enter/leave to update the indentDepth
+                turnInto(multiline_comment_cont);
+            }
+            break;
+
+        default:
+            qWarning() << "Unhandled state" << m_currentState.top().type;
+            break;
+        } // end of state switch
+
+        ++m_tokenIndex;
+    }
+
+    int topState = m_currentState.top().type;
+
+    if (topState == expression
+            || topState == expression_or_objectdefinition) {
+        enter(expression_maybe_continuation);
+    }
+    if (topState != multiline_comment_start
+            && topState != multiline_comment_cont
+            && lexerState == Scanner::MultiLineComment) {
+        enter(multiline_comment_start);
+    }
+
+    saveCurrentState(block);
+}
+
+int CodeFormatter::indentFor(const QTextBlock &block)
+{
+//    qDebug() << "indenting for" << block.blockNumber() + 1;
+
+    restoreCurrentState(block.previous());
+    correctIndentation(block);
+    return m_indentDepth;
+}
+
+void CodeFormatter::updateStateUntil(const QTextBlock &endBlock)
+{
+    QStack<State> previousState = initialState();
+    QTextBlock it = endBlock.document()->firstBlock();
+
+    // find the first block that needs recalculation
+    for (; it.isValid() && it != endBlock; it = it.next()) {
+        BlockData blockData;
+        if (!loadBlockData(it, &blockData))
+            break;
+        if (blockData.m_blockRevision != it.revision())
+            break;
+        if (previousState != blockData.m_beginState)
+            break;
+        if (loadLexerState(it) == -1)
+            break;
+
+        previousState = blockData.m_endState;
+    }
+
+    if (it == endBlock)
+        return;
+
+    // update everthing until endBlock
+    for (; it.isValid() && it != endBlock; it = it.next()) {
+        recalculateStateAfter(it);
+    }
+
+    // invalidate everything below by marking the state in endBlock as invalid
+    if (it.isValid()) {
+        BlockData invalidBlockData;
+        saveBlockData(&it, invalidBlockData);
+    }
+}
+
+void CodeFormatter::updateLineStateChange(const QTextBlock &block)
+{
+    if (!block.isValid())
+        return;
+
+    BlockData blockData;
+    if (loadBlockData(block, &blockData) && blockData.m_blockRevision == block.revision())
+        return;
+
+    recalculateStateAfter(block);
+
+    // invalidate everything below by marking the next block's state as invalid
+    QTextBlock next = block.next();
+    if (!next.isValid())
+        return;
+
+    saveBlockData(&next, BlockData());
+}
+
+CodeFormatter::State CodeFormatter::state(int belowTop) const
+{
+    if (belowTop < m_currentState.size())
+        return m_currentState.at(m_currentState.size() - 1 - belowTop);
+    else
+        return State();
+}
+
+const QVector<CodeFormatter::State> &CodeFormatter::newStatesThisLine() const
+{
+    return m_newStates;
+}
+
+int CodeFormatter::tokenIndex() const
+{
+    return m_tokenIndex;
+}
+
+int CodeFormatter::tokenCount() const
+{
+    return m_tokens.size();
+}
+
+const Token &CodeFormatter::currentToken() const
+{
+    return m_currentToken;
+}
+
+void CodeFormatter::invalidateCache(QTextDocument *document)
+{
+    if (!document)
+        return;
+
+    BlockData invalidBlockData;
+    QTextBlock it = document->firstBlock();
+    for (; it.isValid(); it = it.next()) {
+        saveBlockData(&it, invalidBlockData);
+    }
+}
+
+void CodeFormatter::enter(int newState)
+{
+    int savedIndentDepth = m_indentDepth;
+    onEnter(newState, &m_indentDepth, &savedIndentDepth);
+    State s(newState, savedIndentDepth);
+    m_currentState.push(s);
+    m_newStates.push(s);
+
+    if (newState == bracket_open)
+        enter(bracket_element_start);
+}
+
+void CodeFormatter::leave(bool statementDone)
+{
+    Q_ASSERT(m_currentState.size() > 1);
+    if (m_currentState.top().type == topmost_intro)
+        return;
+
+    if (m_newStates.size() > 0)
+        m_newStates.pop();
+
+    // restore indent depth
+    State poppedState = m_currentState.pop();
+    m_indentDepth = poppedState.savedIndentDepth;
+
+    int topState = m_currentState.top().type;
+
+    // if statement is done, may need to leave recursively
+    if (statementDone) {
+        if (!isExpressionEndState(topState))
+            leave(true);
+        if (topState == if_statement) {
+            if (poppedState.type != maybe_else)
+                enter(maybe_else);
+            else
+                leave(true);
+        } else if (topState == else_clause) {
+            // leave the else *and* the surrounding if, to prevent another else
+            leave();
+            leave(true);
+        }
+    }
+}
+
+void CodeFormatter::correctIndentation(const QTextBlock &block)
+{
+    const int lexerState = tokenizeBlock(block);
+    Q_ASSERT(m_currentState.size() >= 1);
+
+    adjustIndent(m_tokens, lexerState, &m_indentDepth);
+}
+
+bool CodeFormatter::tryInsideExpression(bool alsoExpression)
+{
+    int newState = -1;
+    const int kind = extendedTokenKind(m_currentToken);
+    switch (kind) {
+    case LeftParenthesis:   newState = paren_open; break;
+    case LeftBracket:       newState = bracket_open; break;
+    case Function:          newState = function_start; break;
+    case Question:          newState = ternary_op; break;
+    }
+
+    if (newState != -1) {
+        if (alsoExpression)
+            enter(expression);
+        enter(newState);
+        return true;
+    }
+
+    return false;
+}
+
+bool CodeFormatter::tryStatement()
+{
+    const int kind = extendedTokenKind(m_currentToken);
+    switch (kind) {
+    case Semicolon:
+        enter(empty_statement);
+        leave(true);
+        return true;
+    case Return:
+        enter(return_statement);
+        enter(expression);
+        return true;
+    case While:
+    case For:
+    case Catch:
+        enter(statement_with_condition);
+        return true;
+    case Switch:
+        enter(switch_statement);
+        return true;
+    case If:
+        enter(if_statement);
+        return true;
+    case Do:
+        enter(do_statement);
+        enter(substatement);
+        return true;
+    case Case:
+    case Default:
+        enter(case_start);
+        return true;
+    case Try:
+    case Finally:
+        enter(statement_with_block);
+        return true;
+    case LeftBrace:
+        enter(jsblock_open);
+        return true;
+    case Identifier:
+    case Delimiter:
+    case PlusPlus:
+    case MinusMinus:
+    case Import:
+    case Signal:
+    case On:
+    case As:
+    case List:
+    case Property:
+    case Function:
+        enter(expression);
+        // look at the token again
+        m_tokenIndex -= 1;
+        return true;
+    }
+    return false;
+}
+
+bool CodeFormatter::isBracelessState(int type) const
+{
+    return
+            type == if_statement ||
+            type == else_clause ||
+            type == substatement ||
+            type == binding_assignment ||
+            type == binding_or_objectdefinition;
+}
+
+bool CodeFormatter::isExpressionEndState(int type) const
+{
+    return
+            type == topmost_intro ||
+            type == top_js ||
+            type == objectdefinition_open ||
+            type == if_statement ||
+            type == else_clause ||
+            type == do_statement ||
+            type == jsblock_open ||
+            type == substatement_open ||
+            type == bracket_open ||
+            type == paren_open ||
+            type == case_cont;
+}
+
+const Token &CodeFormatter::tokenAt(int idx) const
+{
+    static const Token empty;
+    if (idx < 0 || idx >= m_tokens.size())
+        return empty;
+    else
+        return m_tokens.at(idx);
+}
+
+int CodeFormatter::column(int index) const
+{
+    int col = 0;
+    if (index > m_currentLine.length())
+        index = m_currentLine.length();
+
+    const QChar tab = QLatin1Char('\t');
+
+    for (int i = 0; i < index; i++) {
+        if (m_currentLine[i] == tab) {
+            col = ((col / m_tabSize) + 1) * m_tabSize;
+        } else {
+            col++;
+        }
+    }
+    return col;
+}
+
+QStringRef CodeFormatter::currentTokenText() const
+{
+    return m_currentLine.midRef(m_currentToken.begin(), m_currentToken.length);
+}
+
+void CodeFormatter::turnInto(int newState)
+{
+    leave(false);
+    enter(newState);
+}
+
+void CodeFormatter::saveCurrentState(const QTextBlock &block)
+{
+    if (!block.isValid())
+        return;
+
+    BlockData blockData;
+    blockData.m_blockRevision = block.revision();
+    blockData.m_beginState = m_beginState;
+    blockData.m_endState = m_currentState;
+    blockData.m_indentDepth = m_indentDepth;
+
+    QTextBlock saveableBlock(block);
+    saveBlockData(&saveableBlock, blockData);
+}
+
+void CodeFormatter::restoreCurrentState(const QTextBlock &block)
+{
+    if (block.isValid()) {
+        BlockData blockData;
+        if (loadBlockData(block, &blockData)) {
+            m_indentDepth = blockData.m_indentDepth;
+            m_currentState = blockData.m_endState;
+            m_beginState = m_currentState;
+            return;
+        }
+    }
+
+    m_currentState = initialState();
+    m_beginState = m_currentState;
+    m_indentDepth = 0;
+}
+
+QStack<CodeFormatter::State> CodeFormatter::initialState()
+{
+    static QStack<CodeFormatter::State> initialState;
+    if (initialState.isEmpty())
+        initialState.push(State(topmost_intro, 0));
+    return initialState;
+}
+
+int CodeFormatter::tokenizeBlock(const QTextBlock &block)
+{
+    int startState = loadLexerState(block.previous());
+    if (block.blockNumber() == 0)
+        startState = 0;
+    Q_ASSERT(startState != -1);
+
+    Scanner tokenize;
+    tokenize.setScanComments(true);
+
+    m_currentLine = block.text();
+    // to determine whether a line was joined, Tokenizer needs a
+    // newline character at the end
+    m_currentLine.append(QLatin1Char('\n'));
+    m_tokens = tokenize(m_currentLine, startState);
+
+    const int lexerState = tokenize.state();
+    QTextBlock saveableBlock(block);
+    saveLexerState(&saveableBlock, lexerState);
+    return lexerState;
+}
+
+CodeFormatter::TokenKind CodeFormatter::extendedTokenKind(const QmlJS::Token &token) const
+{
+    const int kind = token.kind;
+    QStringRef text = m_currentLine.midRef(token.begin(), token.length);
+
+    if (kind == Identifier) {
+        if (text == "as")
+            return As;
+        if (text == "import")
+            return Import;
+        if (text == "signal")
+            return Signal;
+        if (text == "property")
+            return Property;
+        if (text == "on")
+            return On;
+        if (text == "list")
+            return On;
+    } else if (kind == Keyword) {
+        const QChar char1 = text.at(0);
+        const QChar char2 = text.at(1);
+        const QChar char3 = (text.size() > 2 ? text.at(2) : QChar());
+        switch (char1.toLatin1()) {
+        case 'v':
+            return Var;
+        case 'i':
+            if (char2 == 'f')
+                return If;
+            else if (char3 == 's')
+                return Instanceof;
+            else
+                return In;
+        case 'f':
+            if (char2 == 'o')
+                return For;
+            else if (char2 == 'u')
+                return Function;
+            else
+                return Finally;
+        case 'e':
+            return Else;
+        case 'n':
+            return New;
+        case 'r':
+            return Return;
+        case 's':
+            return Switch;
+        case 'w':
+            if (char2 == 'h')
+                return While;
+            return With;
+        case 'c':
+            if (char3 == 's')
+                return Case;
+            if (char3 == 't')
+                return Catch;
+            return Continue;
+        case 'd':
+            if (char3 == 'l')
+                return Delete;
+            if (char3 == 'f')
+                return Default;
+            if (char3 == 'b')
+                return Debugger;
+            return Do;
+        case 't':
+            if (char3 == 'i')
+                return This;
+            if (char3 == 'y')
+                return Try;
+            if (char3 == 'r')
+                return Throw;
+            return Typeof;
+        case 'b':
+            return Break;
+        }
+    } else if (kind == Delimiter) {
+        if (text == "?")
+            return Question;
+        else if (text == "++")
+            return PlusPlus;
+        else if (text == "--")
+            return MinusMinus;
+    }
+
+    return static_cast<TokenKind>(kind);
+}
+
+void CodeFormatter::dump() const
+{
+    QMetaEnum metaEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("StateType"));
+
+    qDebug() << "Current token index" << m_tokenIndex;
+    qDebug() << "Current state:";
+    foreach (State s, m_currentState) {
+        qDebug() << metaEnum.valueToKey(s.type) << s.savedIndentDepth;
+    }
+    qDebug() << "Current indent depth:" << m_indentDepth;
+}
diff --git a/src/libs/qmljs/qmljscodeformatter.h b/src/libs/qmljs/qmljscodeformatter.h
new file mode 100644
index 0000000000000000000000000000000000000000..40954647f5134183ff182ac018f7c2fa36a0b77f
--- /dev/null
+++ b/src/libs/qmljs/qmljscodeformatter.h
@@ -0,0 +1,309 @@
+/**************************************************************************
+**
+** 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 QMLJSCODEFORMATTER_H
+#define QMLJSCODEFORMATTER_H
+
+#include "qmljs_global.h"
+
+#include "qmljsscanner.h"
+
+#include <QtCore/QChar>
+#include <QtCore/QStack>
+#include <QtCore/QList>
+#include <QtCore/QVector>
+#include <QtCore/QPointer>
+
+QT_BEGIN_NAMESPACE
+class QTextDocument;
+class QTextBlock;
+QT_END_NAMESPACE
+
+namespace QmlJS {
+
+class QMLJS_EXPORT CodeFormatter
+{
+    Q_GADGET
+public:
+    CodeFormatter();
+    virtual ~CodeFormatter();
+
+    // updates all states up until block if necessary
+    // it is safe to call indentFor on block afterwards
+    void updateStateUntil(const QTextBlock &block);
+
+    // calculates the state change introduced by changing a single line
+    void updateLineStateChange(const QTextBlock &block);
+
+    int indentFor(const QTextBlock &block);
+
+    void setTabSize(int tabSize);
+
+    void invalidateCache(QTextDocument *document);
+
+protected:
+    virtual void onEnter(int newState, int *indentDepth, int *savedIndentDepth) const = 0;
+    virtual void adjustIndent(const QList<Token> &tokens, int lexerState, int *indentDepth) const = 0;
+
+    class State;
+    class BlockData
+    {
+    public:
+        BlockData();
+
+        QStack<State> m_beginState;
+        QStack<State> m_endState;
+        int m_indentDepth;
+        int m_blockRevision;
+    };
+
+    virtual void saveBlockData(QTextBlock *block, const BlockData &data) const = 0;
+    virtual bool loadBlockData(const QTextBlock &block, BlockData *data) const = 0;
+
+    virtual void saveLexerState(QTextBlock *block, int state) const = 0;
+    virtual int loadLexerState(const QTextBlock &block) const = 0;
+
+public: // must be public to make Q_GADGET introspection work
+    enum StateType {
+        invalid = 0,
+
+        topmost_intro, // The first line in a "topmost" definition.
+
+        top_qml, // root state for qml
+        top_js, // root for js
+        objectdefinition_or_js, // file starts with identifier
+
+        multiline_comment_start,
+        multiline_comment_cont,
+
+        import_start, // after 'import'
+        import_maybe_dot_or_version_or_as, // after string or identifier
+        import_dot, // after .
+        import_maybe_as, // after version
+        import_as,
+
+        property_start, // after 'property'
+        default_property_start, // after 'default'
+        property_type, // after first identifier
+        property_list_open, // after 'list' as a type
+        property_maybe_initializer, // after
+
+        signal_start, // after 'signal'
+        signal_maybe_arglist, // after identifier
+        signal_arglist_open, // after '('
+
+        function_start, // after 'function'
+        function_arglist_open, // after '(' starting function argument list
+        function_arglist_closed, // after ')' in argument list, expecting '{'
+
+        binding_or_objectdefinition, // after an identifier
+
+        binding_assignment, // after :
+        objectdefinition_open, // after {
+
+        expression,
+        expression_continuation, // at the end of the line, when the next line definitely is a continuation
+        expression_maybe_continuation, // at the end of the line, when the next line may be an expression
+        expression_or_objectdefinition, // after a binding starting with an identifier ("x: foo")
+
+        paren_open, // opening ( in expression
+        bracket_open, // opening [ in expression
+
+        bracket_element_start, // after starting bracket_open or after ',' in bracket_open
+        bracket_element_maybe_objectdefinition, // after an identifier in bracket_element_start
+
+        ternary_op, // The ? : operator
+
+        jsblock_open,
+
+        empty_statement, // for a ';', will never linger
+
+        if_statement, // After 'if'
+        maybe_else, // after the first substatement in an if
+        else_clause, // The else line of an if-else construct.
+
+        condition_open, // Start of a condition in 'if', 'while', entered after opening paren
+        condition_paren_open, // After an lparen in a condition
+
+        substatement, // The first line after a conditional or loop construct.
+        substatement_open, // The brace that opens a substatement block.
+
+        return_statement, // After 'return'
+
+        statement_with_condition, // After the 'for', 'while', 'catch', ... token
+        statement_with_condition_paren_open, // While inside the (...)
+
+        statement_with_block, // try, finally
+
+        do_statement, // after 'do'
+        do_statement_while_paren_open, // after '(' in while clause
+
+        switch_statement, // After 'switch' token
+        case_start, // after a 'case' or 'default' token
+        case_cont, // after the colon in a case/default
+    };
+    Q_ENUMS(StateType)
+
+protected:
+    // extends Token::Kind from qmljsscanner.h
+    // the entries until EndOfExistingTokenKinds must match
+    enum TokenKind {
+        EndOfFile,
+        Keyword,
+        Identifier,
+        String,
+        Comment,
+        Number,
+        LeftParenthesis,
+        RightParenthesis,
+        LeftBrace,
+        RightBrace,
+        LeftBracket,
+        RightBracket,
+        Semicolon,
+        Colon,
+        Comma,
+        Dot,
+        Delimiter,
+
+        EndOfExistingTokenKinds,
+
+        Break,
+        Case,
+        Catch,
+        Continue,
+        Debugger,
+        Default,
+        Delete,
+        Do,
+        Else,
+        Finally,
+        For,
+        Function,
+        If,
+        In,
+        Instanceof,
+        New,
+        Return,
+        Switch,
+        This,
+        Throw,
+        Try,
+        Typeof,
+        Var,
+        Void,
+        While,
+        With,
+
+        Import,
+        Signal,
+        On,
+        As,
+        List,
+        Property,
+
+        Question,
+        PlusPlus,
+        MinusMinus,
+    };
+
+    TokenKind extendedTokenKind(const QmlJS::Token &token) const;
+
+    struct State {
+        State()
+            : savedIndentDepth(0)
+            , type(0)
+        {}
+
+        State(quint8 ty, quint16 savedDepth)
+            : savedIndentDepth(savedDepth)
+            , type(ty)
+        {}
+
+        quint16 savedIndentDepth;
+        quint8 type;
+
+        bool operator==(const State &other) const {
+            return type == other.type
+                && savedIndentDepth == other.savedIndentDepth;
+        }
+    };
+
+    State state(int belowTop = 0) const;
+    const QVector<State> &newStatesThisLine() const;
+    int tokenIndex() const;
+    int tokenCount() const;
+    const Token &currentToken() const;
+    const Token &tokenAt(int idx) const;
+    int column(int position) const;
+
+    bool isBracelessState(int type) const;
+    bool isExpressionEndState(int type) const;
+
+    void dump() const;
+
+private:
+    void recalculateStateAfter(const QTextBlock &block);
+    void saveCurrentState(const QTextBlock &block);
+    void restoreCurrentState(const QTextBlock &block);
+
+    QStringRef currentTokenText() const;
+
+    int tokenizeBlock(const QTextBlock &block);
+
+    void turnInto(int newState);
+
+    bool tryInsideExpression(bool alsoExpression = false);
+    bool tryStatement();
+
+    void enter(int newState);
+    void leave(bool statementDone = false);
+    void correctIndentation(const QTextBlock &block);
+
+private:
+    static QStack<State> initialState();
+
+    QStack<State> m_beginState;
+    QStack<State> m_currentState;
+    QStack<State> m_newStates;
+
+    QList<Token> m_tokens;
+    QString m_currentLine;
+    Token m_currentToken;
+    int m_tokenIndex;
+
+    // should store indent level and padding instead
+    int m_indentDepth;
+
+    int m_tabSize;
+};
+
+} // namespace QmlJS
+
+#endif // QMLJSCODEFORMATTER_H
diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp
index bf01cd0381222c8808ecae394bbea61e264e1b11..6119e11999f3190d3e1160ed25107c274a0a802a 100644
--- a/src/plugins/qmljseditor/qmljseditor.cpp
+++ b/src/plugins/qmljseditor/qmljseditor.cpp
@@ -33,8 +33,8 @@
 #include "qmljseditorplugin.h"
 #include "qmljsmodelmanager.h"
 #include "qmloutlinemodel.h"
+#include "qmljseditorcodeformatter.h"
 
-#include <qmljs/qmljsindenter.h>
 #include <qmljs/qmljsbind.h>
 #include <qmljs/qmljscheck.h>
 #include <qmljs/qmljsdocument.h>
@@ -1276,15 +1276,25 @@ bool QmlJSTextEditor::isClosingBrace(const QList<Token> &tokens) const
     return false;
 }
 
+static QmlJSEditor::QtStyleCodeFormatter setupCodeFormatter(const TextEditor::TabSettings &ts)
+{
+    QmlJSEditor::QtStyleCodeFormatter codeFormatter;
+    codeFormatter.setIndentSize(ts.m_indentSize);
+    codeFormatter.setTabSize(ts.m_tabSize);
+    return codeFormatter;
+}
+
 void QmlJSTextEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar)
 {
-    TextEditor::TabSettings ts = tabSettings();
-    QmlJSIndenter indenter;
-    indenter.setTabSize(ts.m_tabSize);
-    indenter.setIndentSize(ts.m_indentSize);
+    Q_UNUSED(doc)
+    Q_UNUSED(typedChar)
+
+    const TextEditor::TabSettings &ts = tabSettings();
+    QmlJSEditor::QtStyleCodeFormatter codeFormatter = setupCodeFormatter(ts);
 
-    const int indent = indenter.indentForBottomLine(doc->begin(), block.next(), typedChar);
-    ts.indentLine(block, indent);
+    codeFormatter.updateStateUntil(block);
+    const int depth = codeFormatter.indentFor(block);
+    ts.indentLine(block, depth);
 }
 
 TextEditor::BaseTextEditorEditable *QmlJSTextEditor::createEditableInterface()
diff --git a/src/plugins/qmljseditor/qmljseditor.pro b/src/plugins/qmljseditor/qmljseditor.pro
index 6bcd71a22b57e3728c687eac2ad53ba7f0214570..72fa4657623b6940c53792e41a1aff17e64fa925 100644
--- a/src/plugins/qmljseditor/qmljseditor.pro
+++ b/src/plugins/qmljseditor/qmljseditor.pro
@@ -26,7 +26,8 @@ HEADERS += \
     qmljscomponentfromobjectdef.h \
     qmljsoutline.h \
     qmloutlinemodel.h \
-    qmltaskmanager.h
+    qmltaskmanager.h \
+    qmljseditorcodeformatter.h
 
 SOURCES += \
     qmljscodecompletion.cpp \
@@ -46,7 +47,8 @@ SOURCES += \
     qmljsoutline.cpp \
     qmloutlinemodel.cpp \
     qmltaskmanager.cpp \
-    qmljsquickfixes.cpp
+    qmljsquickfixes.cpp \
+    qmljseditorcodeformatter.cpp
 
 RESOURCES += qmljseditor.qrc
 OTHER_FILES += QmlJSEditor.pluginspec QmlJSEditor.mimetypes.xml
diff --git a/src/plugins/qmljseditor/qmljseditorcodeformatter.cpp b/src/plugins/qmljseditor/qmljseditorcodeformatter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..175e384a5964e7f819b5f28fe5a542e43f2fa5e6
--- /dev/null
+++ b/src/plugins/qmljseditor/qmljseditorcodeformatter.cpp
@@ -0,0 +1,358 @@
+/**************************************************************************
+**
+** 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 "qmljseditorcodeformatter.h"
+
+#include <QtCore/QDebug>
+
+using namespace QmlJS;
+using namespace QmlJSEditor;
+using namespace TextEditor;
+
+QtStyleCodeFormatter::QtStyleCodeFormatter()
+    : m_indentSize(4)
+{
+}
+
+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;
+
+        bool followedByData = (!lastToken && !tokenAt(tokenIndex() + 1).kind == Token::Comment);
+        if (firstToken || followedByData)
+            *savedIndentDepth = tokenPosition;
+
+        *indentDepth = *savedIndentDepth;
+
+        if (followedByData) {
+            *indentDepth = column(tokenAt(tokenIndex() + 1).begin());
+        } else {
+            *indentDepth += 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;
+    }
+}
diff --git a/src/plugins/qmljseditor/qmljseditorcodeformatter.h b/src/plugins/qmljseditor/qmljseditorcodeformatter.h
new file mode 100644
index 0000000000000000000000000000000000000000..a9aed6d05db743b5eda378738b046946ffaf1fc2
--- /dev/null
+++ b/src/plugins/qmljseditor/qmljseditorcodeformatter.h
@@ -0,0 +1,69 @@
+/**************************************************************************
+**
+** 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 QMLJSEDITORCODEFORMATTER_H
+#define QMLJSEDITORCODEFORMATTER_H
+
+#include "qmljseditor_global.h"
+
+#include <texteditor/basetextdocumentlayout.h>
+#include <qmljs/qmljscodeformatter.h>
+
+namespace QmlJSEditor {
+
+class QMLJSEDITOR_EXPORT QtStyleCodeFormatter : public QmlJS::CodeFormatter
+{
+public:
+    QtStyleCodeFormatter();
+
+    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 QmlJSEditor
+
+#endif // QMLJSEDITORCODEFORMATTER_H
diff --git a/tests/auto/qml/qmleditor/codeformatter/codeformatter.pro b/tests/auto/qml/qmleditor/codeformatter/codeformatter.pro
new file mode 100644
index 0000000000000000000000000000000000000000..ee9545690806bf20b97068565b4c8e4acf9dbfed
--- /dev/null
+++ b/tests/auto/qml/qmleditor/codeformatter/codeformatter.pro
@@ -0,0 +1,24 @@
+TEMPLATE = app
+CONFIG += qt warn_on console depend_includepath
+QT += testlib network
+
+SRCDIR = ../../../../../src
+
+#DEFINES += QML_BUILD_STATIC_LIB
+#include($$SRCDIR/../qtcreator.pri)
+include($$SRCDIR/libs/qmljs/qmljs-lib.pri)
+include($$SRCDIR/libs/utils/utils-lib.pri)
+#LIBS += -L$$IDE_LIBRARY_PATH
+
+SOURCES += \
+    tst_codeformatter.cpp \
+    $$SRCDIR/plugins/qmljseditor/qmljseditorcodeformatter.cpp \
+    $$SRCDIR/plugins/texteditor/basetextdocumentlayout.cpp
+
+HEADERS += \
+    $$SRCDIR/plugins/qmljseditor/qmljseditorcodeformatter.h \
+    $$SRCDIR/plugins/texteditor/basetextdocumentlayout.h \
+
+INCLUDEPATH += $$SRCDIR/plugins $$SRCDIR/libs
+
+TARGET=tst_$$TARGET
diff --git a/tests/auto/qml/qmleditor/codeformatter/tst_codeformatter.cpp b/tests/auto/qml/qmleditor/codeformatter/tst_codeformatter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..336e642eaf8613e6771e4b7590e69511b72adf99
--- /dev/null
+++ b/tests/auto/qml/qmleditor/codeformatter/tst_codeformatter.cpp
@@ -0,0 +1,888 @@
+#include <QtTest>
+#include <QObject>
+#include <QList>
+#include <QTextDocument>
+#include <QTextBlock>
+
+#include <qmljseditor/qmljseditorcodeformatter.h>
+
+using namespace QmlJSEditor;
+
+class tst_CodeFormatter: public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void objectDefinitions1();
+    void objectDefinitions2();
+    void expressionEndSimple();
+    void expressionEnd();
+    void expressionEndBracket();
+    void expressionEndParen();
+    void objectBinding();
+    void arrayBinding();
+    void functionDeclaration();
+    void functionExpression();
+    void propertyDeclarations();
+    void signalDeclarations();
+    void ifBinding1();
+    void ifBinding2();
+    void ifStatementWithoutBraces1();
+    void ifStatementWithoutBraces2();
+    void ifStatementWithBraces1();
+    void ifStatementWithBraces2();
+    void ifStatementMixed();
+    void ifStatementAndComments();
+    void ifStatementLongCondition();
+    void moreIfThenElse();
+    void strayElse();
+    void oneLineIf();
+    void forStatement();
+    void whileStatement();
+    void tryStatement();
+    void doWhile();
+    void cStyleComments();
+    void cppStyleComments();
+    void qmlKeywords();
+    void ternary();
+    void switch1();
+//    void gnuStyle();
+//    void whitesmithsStyle();
+    void expressionContinuation();
+};
+
+struct Line {
+    Line(QString l)
+        : line(l)
+    {
+        for (int i = 0; i < l.size(); ++i) {
+            if (!l.at(i).isSpace()) {
+                expectedIndent = i;
+                return;
+            }
+        }
+        expectedIndent = l.size();
+    }
+
+    Line(QString l, int expect)
+        : line(l), expectedIndent(expect)
+    {}
+
+    QString line;
+    int expectedIndent;
+};
+
+QString concatLines(QList<Line> lines)
+{
+    QString result;
+    foreach (const Line &l, lines) {
+        result += l.line;
+        result += "\n";
+    }
+    return result;
+}
+
+void checkIndent(QList<Line> data, int style = 0)
+{
+    Q_UNUSED(style)
+
+    QString text = concatLines(data);
+    QTextDocument document(text);
+    QtStyleCodeFormatter formatter;
+
+    int i = 0;
+    foreach (const Line &l, data) {
+        QTextBlock b = document.findBlockByLineNumber(i);
+        if (l.expectedIndent != -1) {
+            int actualIndent = formatter.indentFor(b);
+            if (actualIndent != l.expectedIndent) {
+                QFAIL(QString("Wrong indent in line %1 with text '%2', expected indent %3, got %4").arg(
+                        QString::number(i+1), l.line, QString::number(l.expectedIndent), QString::number(actualIndent)).toLatin1().constData());
+            }
+        }
+        formatter.updateLineStateChange(b);
+        ++i;
+    }
+}
+
+void tst_CodeFormatter::objectDefinitions1()
+{
+    QList<Line> data;
+    data << Line("import Qt 4.7")
+         << Line("")
+         << Line("Rectangle {")
+         << Line("    foo: bar;")
+         << Line("    Item {")
+         << Line("        x: 42;")
+         << Line("        y: x;")
+         << Line("    }")
+         << Line("    Component.onCompleted: foo;")
+         << Line("    ")
+         << Line("    Foo.Bar {")
+         << Line("        width: 12 + 54;")
+         << Line("        anchors.fill: parent;")
+         << Line("    }")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::objectDefinitions2()
+{
+    QList<Line> data;
+    data << Line("import Qt 4.7")
+         << Line("")
+         << Line("Rectangle {")
+         << Line("    foo: bar;")
+         << Line("    Image { source: \"a+b+c\"; x: 42; y: 12 }")
+         << Line("    Component.onCompleted: foo;")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::expressionEndSimple()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("    foo: bar +")
+         << Line("         foo(4, 5) +")
+         << Line("         7")
+         << Line("    x: 42")
+         << Line("    y: 43")
+         << Line("    width: 10")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::expressionEnd()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("    foo: bar +")
+         << Line("         foo(4")
+         << Line("             + 5)")
+         << Line("         + 7")
+         << Line("    x: 42")
+         << Line("       + 43")
+         << Line("       + 10")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::expressionEndParen()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("    foo: bar")
+         << Line("         (foo(4")
+         << Line("              + 5)")
+         << Line("          + 7,")
+         << Line("          abc)")
+         << Line("    x: a + b(fpp, ba + 12) + foo(")
+         << Line("           bar,")
+         << Line("           10)")
+         << Line("       + 10")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::expressionEndBracket()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("    foo: bar")
+         << Line("         [foo[4")
+         << Line("              + 5]")
+         << Line("          + 7,")
+         << Line("          abc]")
+         << Line("    x: a + b[fpp, ba + 12] + foo[")
+         << Line("           bar,")
+         << Line("           10]")
+         << Line("       + 10")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::objectBinding()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("    foo: bar")
+         << Line("    x: 3")
+         << Line("    foo: Gradient {")
+         << Line("        x: 12")
+         << Line("        y: x")
+         << Line("    }")
+         << Line("    Item {")
+         << Line("        states: State {}")
+         << Line("    }")
+         << Line("    x: 1")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::arrayBinding()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("    foo: bar")
+         << Line("    x: 3")
+         << Line("    foo: [")
+         << Line("        State {")
+         << Line("            y: x")
+         << Line("        },")
+         << Line("        State")
+         << Line("        {")
+         << Line("        }")
+         << Line("    ]")
+         << Line("    foo: [")
+         << Line("        1 +")
+         << Line("        2")
+         << Line("        + 345 * foo(")
+         << Line("            bar, car,")
+         << Line("            dar),")
+         << Line("        x, y,")
+         << Line("        z,")
+         << Line("    ]")
+         << Line("    x: 1")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+
+
+void tst_CodeFormatter::moreIfThenElse()
+{
+    QList<Line> data;
+    data << Line("Image {")
+         << Line("    source: {")
+         << Line("        if(type == 1) {")
+         << Line("            \"pics/blueStone.png\";")
+         << Line("        } else if (type == 2) {")
+         << Line("            \"pics/head.png\";")
+         << Line("        } else {")
+         << Line("            \"pics/redStone.png\";")
+         << Line("        }")
+         << Line("    }")
+         << Line("}");
+    checkIndent(data);
+}
+
+
+void tst_CodeFormatter::functionDeclaration()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("    foo: bar")
+         << Line("    function foo(a, b, c) {")
+         << Line("        if (a)")
+         << Line("            b;")
+         << Line("    }")
+         << Line("    property alias boo :")
+         << Line("        foo")
+         << Line("    Item {")
+         << Line("        property variant g : Gradient {")
+         << Line("            v: 12")
+         << Line("        }")
+         << Line("        function bar(")
+         << Line("            a, b,")
+         << Line("            c)")
+         << Line("        {")
+         << Line("            var b")
+         << Line("        }")
+         << Line("        function bar(a,")
+         << Line("                     a, b,")
+         << Line("                     c)")
+         << Line("        {")
+         << Line("            var b")
+         << Line("        }")
+         << Line("    }")
+         << Line("    x: 1")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::functionExpression()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("onFoo: {", 4)
+         << Line("    function foo(a, b, c) {")
+         << Line("        if (a)")
+         << Line("            b;")
+         << Line("    }")
+         << Line("    return function(a, b) { return a + b; }")
+         << Line("    return function foo(a, b) {")
+         << Line("        return a")
+         << Line("    }")
+         << Line("}")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::propertyDeclarations()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("    foo: bar")
+         << Line("    property int foo : 2 +")
+         << Line("                       x")
+         << Line("    property list<Foo> bar")
+         << Line("    property alias boo :")
+         << Line("        foo")
+         << Line("    Item {")
+         << Line("        property variant g : Gradient {")
+         << Line("            v: 12")
+         << Line("        }")
+         << Line("        default property Item g")
+         << Line("        default property Item g : parent.foo")
+         << Line("    }")
+         << Line("    x: 1")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::signalDeclarations()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("    foo: bar")
+         << Line("    signal foo")
+         << Line("    x: bar")
+         << Line("    signal bar(a, int b)")
+         << Line("    signal bar2()")
+         << Line("    Item {")
+         << Line("        signal property")
+         << Line("        signal import(a, b);")
+         << Line("    }")
+         << Line("    x: 1")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::ifBinding1()
+{
+    QList<Line> data;
+    data << Line("A.Rectangle {")
+         << Line("    foo: bar")
+         << Line("    x: if (a) b")
+         << Line("    x: if (a)")
+         << Line("           b")
+         << Line("    x: if (a) b;")
+         << Line("    x: if (a)")
+         << Line("           b;")
+         << Line("    x: if (a) b; else c")
+         << Line("    x: if (a) b")
+         << Line("       else c")
+         << Line("    x: if (a) b;")
+         << Line("       else c")
+         << Line("    x: if (a) b;")
+         << Line("       else")
+         << Line("           c")
+         << Line("    x: if (a)")
+         << Line("           b")
+         << Line("       else")
+         << Line("           c")
+         << Line("    x: if (a) b; else c;")
+         << Line("    x: 1")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::ifBinding2()
+{
+    QList<Line> data;
+    data << Line("A.Rectangle {")
+         << Line("    foo: bar")
+         << Line("    x: if (a) b +")
+         << Line("              5 +")
+         << Line("              5 * foo(")
+         << Line("                  1, 2)")
+         << Line("       else a =")
+         << Line("            foo(15,")
+         << Line("                bar(")
+         << Line("                    1),")
+         << Line("                bar)")
+         << Line("    x: if (a) b")
+         << Line("              + 5")
+         << Line("              + 5")
+         << Line("    x: if (a)")
+         << Line("           b")
+         << Line("               + 5")
+         << Line("               + 5")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::ifStatementWithoutBraces1()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("    x: if (a)")
+         << Line("           if (b)")
+         << Line("               foo")
+         << Line("           else if (c)")
+         << Line("               foo")
+         << Line("           else")
+         << Line("               if (d)")
+         << Line("                   foo;")
+         << Line("               else")
+         << Line("                   a + b + ")
+         << Line("                       c")
+         << Line("       else")
+         << Line("           foo;")
+         << Line("    y: 2")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::ifStatementWithoutBraces2()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("    x: {")
+         << Line("        if (a)")
+         << Line("            if (b)")
+         << Line("                foo;")
+         << Line("        if (a) b();")
+         << Line("        if (a) b(); else")
+         << Line("            foo;")
+         << Line("        if (a)")
+         << Line("            if (b)")
+         << Line("                foo;")
+         << Line("            else if (c)")
+         << Line("                foo;")
+         << Line("            else")
+         << Line("                if (d)")
+         << Line("                    foo;")
+         << Line("                else")
+         << Line("                    e")
+         << Line("        else")
+         << Line("            foo;")
+         << Line("    }")
+         << Line("    foo: bar")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::ifStatementWithBraces1()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("onClicked: {", 4)
+         << Line("    if (a) {")
+         << Line("        if (b) {")
+         << Line("            foo;")
+         << Line("        } else if (c) {")
+         << Line("            foo")
+         << Line("        } else {")
+         << Line("            if (d) {")
+         << Line("                foo")
+         << Line("            } else {")
+         << Line("                foo;")
+         << Line("            }")
+         << Line("        }")
+         << Line("    } else {")
+         << Line("        foo;")
+         << Line("    }")
+         << Line("}")
+         << Line("}");
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::ifStatementWithBraces2()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("onClicked:", 4)
+         << Line("    if (a)")
+         << Line("    {")
+         << Line("        if (b)")
+         << Line("        {")
+         << Line("            foo")
+         << Line("        }")
+         << Line("        else if (c)")
+         << Line("        {")
+         << Line("            foo;")
+         << Line("        }")
+         << Line("        else")
+         << Line("        {")
+         << Line("            if (d)")
+         << Line("            {")
+         << Line("                foo;")
+         << Line("            }")
+         << Line("            else")
+         << Line("            {")
+         << Line("                foo")
+         << Line("            }")
+         << Line("        }")
+         << Line("    }")
+         << Line("    else")
+         << Line("    {")
+         << Line("        foo")
+         << Line("    }")
+         << Line("}");
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::ifStatementMixed()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("onClicked:", 4)
+         << Line("    if (foo)")
+         << Line("        if (bar)")
+         << Line("        {")
+         << Line("            foo;")
+         << Line("        }")
+         << Line("        else")
+         << Line("            if (car)")
+         << Line("            {}")
+         << Line("            else doo")
+         << Line("    else abc")
+         << Line("}");
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::ifStatementAndComments()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("onClicked: {", 4)
+         << Line("    if (foo)")
+         << Line("        ; // bla")
+         << Line("    else if (bar)")
+         << Line("        ;")
+         << Line("    if (foo)")
+         << Line("        ; /*bla")
+         << Line("        bla */")
+         << Line("    else if (bar)")
+         << Line("        // foobar")
+         << Line("        ;")
+         << Line("    else if (bar)")
+         << Line("        /* bla")
+         << Line("  bla */")
+         << Line("        ;")
+         << Line("}")
+         << Line("}");
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::ifStatementLongCondition()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("onClicked: {", 4)
+         << Line("    if (foo &&")
+         << Line("            bar")
+         << Line("            || (a + b > 4")
+         << Line("                && foo(bar)")
+         << Line("                )")
+         << Line("            ) {")
+         << Line("        foo;")
+         << Line("    }")
+         << Line("}");
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::strayElse()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("onClicked: {", 4)
+         << Line("    while( true ) {}")
+         << Line("    else", -1)
+         << Line("    else {", -1)
+         << Line("    }", -1)
+         << Line("}");
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::oneLineIf()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("    onClicked: { if (showIt) show(); }")
+         << Line("    x: 2")
+         << Line("};")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::forStatement()
+{
+    QList<Line> data;
+    data << Line("for (var i = 0; i < 20; ++i) {")
+         << Line("    print(i);")
+         << Line("}")
+         << Line("for (var x in [a, b, c, d])")
+         << Line("    x += 5")
+         << Line("var z")
+         << Line("for (var x in [a, b, c, d])")
+         << Line("    for (;;)")
+         << Line("    {")
+         << Line("        for (a(); b(); c())")
+         << Line("            for (a();")
+         << Line("                 b(); c())")
+         << Line("                for (a(); b(); c())")
+         << Line("                    print(3*d)")
+         << Line("    }")
+         << Line("z = 2")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::whileStatement()
+{
+    QList<Line> data;
+    data << Line("while (i < 20) {")
+         << Line("    print(i);")
+         << Line("}")
+         << Line("while (x in [a, b, c, d])")
+         << Line("    x += 5")
+         << Line("var z")
+         << Line("while (a + b > 0")
+         << Line("       && b + c > 0)")
+         << Line("    for (;;)")
+         << Line("    {")
+         << Line("        for (a(); b(); c())")
+         << Line("            while (a())")
+         << Line("                for (a(); b(); c())")
+         << Line("                    print(3*d)")
+         << Line("    }")
+         << Line("z = 2")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::tryStatement()
+{
+    QList<Line> data;
+    data << Line("try {")
+         << Line("    print(i);")
+         << Line("} catch (foo) {")
+         << Line("    print(foo)")
+         << Line("} finally {")
+         << Line("    var z")
+         << Line("    while (a + b > 0")
+         << Line("           && b + c > 0)")
+         << Line("        ;")
+         << Line("}")
+         << Line("z = 2")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::doWhile()
+{
+    QList<Line> data;
+    data << Line("function foo() {")
+         << Line("    do { if (c) foo; } while(a);")
+         << Line("    do {")
+         << Line("        if(a);")
+         << Line("    } while(a);")
+         << Line("    do")
+         << Line("        foo;")
+         << Line("    while(a);")
+         << Line("    do foo; while(a);")
+         << Line("};")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::cStyleComments()
+{
+    QList<Line> data;
+    data << Line("/*")
+         << Line("  ")
+         << Line("      foo")
+         << Line("      ")
+         << Line("   foo")
+         << Line("   ")
+         << Line("*/")
+         << Line("Rectangle {")
+         << Line("    /*")
+         << Line("      ")
+         << Line("   foo")
+         << Line("   ")
+         << Line("    */")
+         << Line("    /* bar */")
+         << Line("}")
+         << Line("Item {")
+         << Line("    /* foo */")
+         << Line("    /*")
+         << Line("      ")
+         << Line("   foo")
+         << Line("   ")
+         << Line("    */")
+         << Line("    /* bar */")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::cppStyleComments()
+{
+    QList<Line> data;
+    data << Line("// abc")
+         << Line("Item {  ")
+         << Line("    // ghij")
+         << Line("    // def")
+         << Line("    // ghij")
+         << Line("    x: 4 // hik")
+         << Line("    // doo")
+         << Line("} // ba")
+         << Line("// ba")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::ternary()
+{
+    QList<Line> data;
+    data << Line("function foo() {")
+         << Line("    var i = a ? b : c;")
+         << Line("    foo += a_bigger_condition ?")
+         << Line("                b")
+         << Line("              : c;")
+         << Line("    foo += a_bigger_condition")
+         << Line("            ? b")
+         << Line("            : c;")
+         << Line("    var i = a ?")
+         << Line("            b : c;")
+         << Line("    var i = aooo ? b")
+         << Line("                 : c +")
+         << Line("                   2;")
+         << Line("    var i = (a ? b : c) + (foo")
+         << Line("                           bar);")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::switch1()
+{
+    QList<Line> data;
+    data << Line("function foo() {")
+         << Line("    switch (a) {")
+         << Line("    case 1:")
+         << Line("        foo;")
+         << Line("        if (a);")
+         << Line("    case 2:")
+         << Line("    case 3: {")
+         << Line("        foo")
+         << Line("    }")
+         << Line("    case 4:")
+         << Line("    {")
+         << Line("        foo;")
+         << Line("    }")
+         << Line("    case bar:")
+         << Line("        break")
+         << Line("    }")
+         << Line("    case 4:")
+         << Line("    {")
+         << Line("        if (a) {")
+         << Line("        }")
+         << Line("    }")
+         << Line("}")
+         ;
+    checkIndent(data);
+}
+
+//void tst_CodeFormatter::gnuStyle()
+//{
+//    QList<Line> data;
+//    data << Line("struct S")
+//         << Line("{")
+//         << Line("    void foo()")
+//         << Line("    {")
+//         << Line("        if (a)")
+//         << Line("            {")
+//         << Line("                fpp;")
+//         << Line("            }")
+//         << Line("        else if (b)")
+//         << Line("            {")
+//         << Line("                fpp;")
+//         << Line("            }")
+//         << Line("        else")
+//         << Line("            {")
+//         << Line("            }")
+//         << Line("        if (b) {")
+//         << Line("            fpp;")
+//         << Line("        }")
+//         << Line("    }")
+//         << Line("};")
+//         ;
+//    checkIndent(data, 1);
+//}
+
+//void tst_CodeFormatter::whitesmithsStyle()
+//{
+//    QList<Line> data;
+//    data << Line("struct S")
+//         << Line("    {")
+//         << Line("    void foo()")
+//         << Line("        {")
+//         << Line("        if (a)")
+//         << Line("            {")
+//         << Line("            fpp;")
+//         << Line("            }")
+//         << Line("        if (b) {")
+//         << Line("            fpp;")
+//         << Line("            }")
+//         << Line("        }")
+//         << Line("    };")
+//         ;
+//    checkIndent(data, 2);
+//}
+
+void tst_CodeFormatter::qmlKeywords()
+{
+    QList<Line> data;
+    data << Line("Rectangle {")
+         << Line("    on: 2")
+         << Line("    property: 2")
+         << Line("    signal: 2")
+         << Line("    list: 2")
+         << Line("    as: 2")
+         << Line("    import: 2")
+         << Line("    Item {")
+         << Line("    }")
+         << Line("    x: 2")
+         << Line("};")
+         ;
+    checkIndent(data);
+}
+
+void tst_CodeFormatter::expressionContinuation()
+{
+    QList<Line> data;
+    data << Line("var x = 1 ? 2")
+         << Line("            + 3 : 4")
+         << Line("++x")
+         << Line("++y--")
+         << Line("x +=")
+         << Line("        y++")
+         << Line("var z")
+         ;
+    checkIndent(data);
+}
+
+QTEST_APPLESS_MAIN(tst_CodeFormatter)
+#include "tst_codeformatter.moc"
+
+
diff --git a/tests/auto/qml/qmleditor/qmleditor.pro b/tests/auto/qml/qmleditor/qmleditor.pro
index 089574dbe77e62d3f0b91846dd39d1e2f75a6619..7c5fddb9a781c009102ca7bf2fb3071413a9da3f 100644
--- a/tests/auto/qml/qmleditor/qmleditor.pro
+++ b/tests/auto/qml/qmleditor/qmleditor.pro
@@ -1,3 +1,3 @@
 TEMPLATE = subdirs
 
-SUBDIRS += lookup
+SUBDIRS += lookup codeformatter