diff options
author | David Schulz <david.schulz@digia.com> | 2014-02-26 11:16:38 +0100 |
---|---|---|
committer | David Schulz <david.schulz@digia.com> | 2014-02-27 06:49:07 +0100 |
commit | b4394dabdbae87bd749a902ceb688ee737f3c591 (patch) | |
tree | cff3cac6676de1d5c3f8e4a9cecfa6b1736bc9c6 | |
parent | 6cac6f0ef6d440e9f1090f3a0a682c2daf838812 (diff) |
Editor: fix upper and lower case on blockselection.
Task-number: QTCREATORBUG-11546
Change-Id: I2e8b5b05ff0044e5ab159119f24dff873be949d7
Reviewed-by: Christian Stenger <christian.stenger@digia.com>
-rw-r--r-- | src/plugins/texteditor/basetexteditor.cpp | 79 | ||||
-rw-r--r-- | src/plugins/texteditor/basetexteditor_p.h | 1 | ||||
-rw-r--r-- | src/plugins/texteditor/basetexteditor_test.cpp | 136 | ||||
-rw-r--r-- | src/plugins/texteditor/texteditor.pro | 5 | ||||
-rw-r--r-- | src/plugins/texteditor/texteditor.qbs | 8 | ||||
-rw-r--r-- | src/plugins/texteditor/texteditorplugin.h | 3 |
6 files changed, 194 insertions, 38 deletions
diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index d8e3e9f937..95bfc56881 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -6166,6 +6166,13 @@ void BaseTextBlockSelection::moveAnchor(int blockNumber, int visualColumn) lastBlock.movePosition(QTextCursor::EndOfBlock); } +int BaseTextBlockSelection::position(const TabSettings &ts) const +{ + const QTextBlock &block = anchor <= TopRight ? lastBlock.block() : firstBlock.block(); + const int column = anchor % 2 ? firstVisualColumn : lastVisualColumn; + return block.position() + ts.positionAtColumn(block.text(), column); +} + QTextCursor BaseTextBlockSelection::selection(const TabSettings &ts) const { QTextCursor cursor = firstBlock; @@ -6334,50 +6341,46 @@ void BaseTextEditorWidget::transformSelection(TransformationMethod method) void BaseTextEditorWidget::transformBlockSelection(TransformationMethod method) { QTextCursor cursor = textCursor(); - int minPos = cursor.anchor(); - int maxPos = cursor.position(); - if (minPos > maxPos) - qSwap(minPos, maxPos); - int leftBound = verticalBlockSelectionFirstColumn(); - int rightBound = verticalBlockSelectionLastColumn(); - BaseTextBlockSelection::Anchor anchorPosition = d->m_blockSelection.anchor; - QString text = cursor.selectedText(); - QString transformedText = text; - QTextBlock currentLine = document()->findBlock(minPos); - int lineStart = currentLine.position(); - do { - if (currentLine.contains(lineStart + leftBound)) { - int currentBlockWidth = qBound(0, currentLine.text().length() - leftBound, - rightBound - leftBound); - cursor.setPosition(lineStart + leftBound); - cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, currentBlockWidth); - transformedText.replace(lineStart + leftBound - minPos, currentBlockWidth, - (cursor.selectedText().*method)()); + const TabSettings &ts = d->m_document->tabSettings(); + + // saved to restore the blockselection + const int selectionPosition = d->m_blockSelection.position(ts); + const int anchorColumn = d->m_blockSelection.anchorColumnNumber(); + const int anchorBlock = d->m_blockSelection.anchorBlockNumber(); + const BaseTextBlockSelection::Anchor anchor = d->m_blockSelection.anchor; + + QTextBlock block = d->m_blockSelection.firstBlock.block(); + const QTextBlock &lastBlock = d->m_blockSelection.lastBlock.block(); + + cursor.beginEditBlock(); + for (;;) { + // get position of the selection + const QString &blockText = block.text(); + const int startPos = block.position() + + ts.positionAtColumn(blockText, d->m_blockSelection.firstVisualColumn); + const int endPos = block.position() + + ts.positionAtColumn(blockText, d->m_blockSelection.lastVisualColumn); + + // check if the selection is inside the text block + if (startPos < endPos) { + cursor.setPosition(startPos); + cursor.setPosition(endPos, QTextCursor::KeepAnchor); + const QString &transformedText = (d->m_document->textAt(startPos, endPos - startPos).*method)(); + if (transformedText != cursor.selectedText()) + cursor.insertText(transformedText); } - currentLine = currentLine.next(); - if (!currentLine.isValid()) + if (block == lastBlock) break; - lineStart = currentLine.position(); - } while (lineStart < maxPos); - - if (transformedText == text) { - // if the transformation does not do anything to the selection, do no create an undo step - return; + block = block.next(); } + cursor.endEditBlock(); - cursor.setPosition(minPos); - cursor.setPosition(maxPos, QTextCursor::KeepAnchor); - cursor.insertText(transformedText); // restore former block selection - if (anchorPosition <= BaseTextBlockSelection::TopRight) - qSwap(minPos, maxPos); - cursor.setPosition(minPos); - cursor.setPosition(maxPos, QTextCursor::KeepAnchor); - d->m_blockSelection.fromSelection(d->m_document->tabSettings(), cursor); - d->m_blockSelection.anchor = anchorPosition; + cursor.setPosition(selectionPosition, QTextCursor::MoveAnchor); d->m_inBlockSelectionMode = true; - d->m_blockSelection.firstVisualColumn = leftBound; - d->m_blockSelection.lastVisualColumn = rightBound; + d->m_blockSelection.fromSelection(ts, cursor); + d->m_blockSelection.anchor = anchor; + d->m_blockSelection.moveAnchor(anchorBlock, anchorColumn); setTextCursor(d->m_blockSelection.selection(d->m_document->tabSettings())); viewport()->update(); } diff --git a/src/plugins/texteditor/basetexteditor_p.h b/src/plugins/texteditor/basetexteditor_p.h index 69b25eeac8..87f9682912 100644 --- a/src/plugins/texteditor/basetexteditor_p.h +++ b/src/plugins/texteditor/basetexteditor_p.h @@ -70,6 +70,7 @@ public: enum Anchor {TopLeft = 0, TopRight, BottomLeft, BottomRight} anchor; BaseTextBlockSelection():firstVisualColumn(0), lastVisualColumn(0), anchor(BottomRight){} void moveAnchor(int blockNumber, int visualColumn); + int position(const TabSettings &ts) const; inline int anchorColumnNumber() const { return (anchor % 2) ? lastVisualColumn : firstVisualColumn; } inline int anchorBlockNumber() const { return (anchor <= TopRight ? firstBlock.blockNumber() : lastBlock.blockNumber()); } diff --git a/src/plugins/texteditor/basetexteditor_test.cpp b/src/plugins/texteditor/basetexteditor_test.cpp new file mode 100644 index 0000000000..de296bab66 --- /dev/null +++ b/src/plugins/texteditor/basetexteditor_test.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifdef WITH_TESTS + +#include <QString> +#include <QtTest/QtTest> + +#include <coreplugin/editormanager/editormanager.h> +#include <coreplugin/coreconstants.h> + +#include "basetexteditor.h" +#include "texteditorplugin.h" + +using namespace TextEditor; + +enum TransFormationType { Uppercase, Lowercase }; + +Q_DECLARE_METATYPE(TransFormationType) + +void Internal::TextEditorPlugin::testBlockSelectionTransformation_data() +{ + QTest::addColumn<QByteArray>("input"); + QTest::addColumn<QByteArray>("transformedText"); + QTest::addColumn<int>("position"); + QTest::addColumn<int>("anchor"); + QTest::addColumn<TransFormationType>("type"); + + QTest::newRow("uppercase") + << QByteArray("aaa\nbbb\nccc\n") + << QByteArray("aAa\nbBb\ncCc\n") + << 10 << 1 << Uppercase; + QTest::newRow("lowercase") + << QByteArray("AAA\nBBB\nCCC\n") + << QByteArray("AaA\nBbB\nCcC\n") + << 10 << 1 << Lowercase; + QTest::newRow("uppercase_leading_tabs") + << QByteArray("\taaa\n\tbbb\n\tccc\n") + << QByteArray("\taAa\n\tbBb\n\tcCc\n") + << 13 << 2 << Uppercase; + QTest::newRow("lowercase_leading_tabs") + << QByteArray("\tAAA\n\tBBB\n\tCCC\n") + << QByteArray("\tAaA\n\tBbB\n\tCcC\n") + << 13 << 2 << Lowercase; + QTest::newRow("uppercase_mixed_leading_whitespace") + << QByteArray("\taaa\n bbbbb\n ccccc\n") + << QByteArray("\tAaa\n bbbbB\n ccccC\n") + << 24 << 1 << Uppercase; + QTest::newRow("lowercase_mixed_leading_whitespace") + << QByteArray("\tAAA\n BBBBB\n CCCCC\n") + << QByteArray("\taAA\n BBBBb\n CCCCc\n") + << 24 << 1 << Lowercase; + QTest::newRow("uppercase_mid_tabs1") + << QByteArray("a\ta\nbbbbbbbbb\nccccccccc\n") + << QByteArray("a\ta\nbBBBBBbbb\ncCCCCCccc\n") + << 20 << 1 << Uppercase; + QTest::newRow("lowercase_mid_tabs2") + << QByteArray("AA\taa\n\t\t\nccccCCCCCC\n") + << QByteArray("Aa\taa\n\t\t\ncccccccccC\n") + << 18 << 1 << Lowercase; + QTest::newRow("uppercase_over_line_ending") + << QByteArray("aaaaa\nbbb\nccccc\n") + << QByteArray("aAAAa\nbBB\ncCCCc\n") + << 14 << 1 << Uppercase; + QTest::newRow("lowercase_over_line_ending") + << QByteArray("AAAAA\nBBB\nCCCCC\n") + << QByteArray("AaaaA\nBbb\nCcccC\n") + << 14 << 1 << Lowercase; +} + +void Internal::TextEditorPlugin::testBlockSelectionTransformation() +{ + // fetch test data + QFETCH(QByteArray, input); + QFETCH(QByteArray, transformedText); + QFETCH(int, position); + QFETCH(int, anchor); + QFETCH(TransFormationType, type); + + // open editor + Core::IEditor *editor = Core::EditorManager::openEditorWithContents( + Core::Constants::K_DEFAULT_TEXT_EDITOR_ID, 0, input); + QVERIFY(editor); + if (BaseTextEditor *textEditor = qobject_cast<BaseTextEditor*>(editor)) { + + // place cursor and enable block selection + BaseTextEditorWidget *editorWidget = textEditor->editorWidget(); + QTextCursor cursor = editorWidget->textCursor(); + cursor.setPosition(anchor); + cursor.setPosition(position, QTextCursor::KeepAnchor); + editorWidget->setTextCursor(cursor); + editorWidget->setBlockSelection(true); + + // transform blockselection + switch (type) { + case Uppercase: + editorWidget->uppercaseSelection(); + break; + case Lowercase: + editorWidget->lowercaseSelection(); + break; + } + QCOMPARE(textEditor->baseTextDocument()->plainText().toLatin1(), transformedText); + } else { + + } + Core::EditorManager::closeEditor(editor, false); +} + +#endif // ifdef WITH_TESTS diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro index 7bc37d6d3f..a580e286bb 100644 --- a/src/plugins/texteditor/texteditor.pro +++ b/src/plugins/texteditor/texteditor.pro @@ -240,3 +240,8 @@ FORMS += \ tabsettingswidget.ui \ codestyleselectorwidget.ui RESOURCES += texteditor.qrc + +equals(TEST, 1) { +SOURCES += basetexteditor_test.cpp +} + diff --git a/src/plugins/texteditor/texteditor.qbs b/src/plugins/texteditor/texteditor.qbs index 5d44e8fb76..8d1703c169 100644 --- a/src/plugins/texteditor/texteditor.qbs +++ b/src/plugins/texteditor/texteditor.qbs @@ -268,4 +268,12 @@ QtcPlugin { "snippetssettingspage.ui", ] } + + Group { + name: "Tests" + condition: project.testsEnabled + files: [ + "basetexteditor_test.cpp", + ] + } } diff --git a/src/plugins/texteditor/texteditorplugin.h b/src/plugins/texteditor/texteditorplugin.h index 24930a17ee..895a08c628 100644 --- a/src/plugins/texteditor/texteditorplugin.h +++ b/src/plugins/texteditor/texteditorplugin.h @@ -76,6 +76,9 @@ private slots: #ifdef WITH_TESTS void testSnippetParsing_data(); void testSnippetParsing(); + + void testBlockSelectionTransformation_data(); + void testBlockSelectionTransformation(); #endif private: |