summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Schulz <david.schulz@digia.com>2014-06-16 14:20:36 +0200
committerhjk <hjk121@nokiamail.com>2014-06-20 13:16:54 +0200
commit6e9b7240066e3ec9f5798136bee0dce3a472716e (patch)
treeda76d2994163fd6f768c168008ad375f3e94ecc2
parentce324b8d28c51188672dc48d70d6e21a0adc8610 (diff)
downloadqt-creator-6e9b7240066e3ec9f5798136bee0dce3a472716e.tar.gz
Editor: Blockselection rewrite.
Also adding the possibility to insert text into the blockselection. Task-number: QTCREATORBUG-7773 Change-Id: I7a47a1d630f769a8253ee1a2f21057820ea170d5 Reviewed-by: Lukas Holecek <hluk@email.cz> Reviewed-by: Christian Stenger <christian.stenger@digia.com> Reviewed-by: hjk <hjk121@nokiamail.com>
-rw-r--r--src/plugins/fakevim/fakevimhandler.cpp29
-rw-r--r--src/plugins/fakevim/fakevimhandler.h4
-rw-r--r--src/plugins/fakevim/fakevimplugin.cpp35
-rw-r--r--src/plugins/texteditor/basetexteditor.cpp835
-rw-r--r--src/plugins/texteditor/basetexteditor.h13
-rw-r--r--src/plugins/texteditor/basetexteditor_p.h56
-rw-r--r--src/plugins/texteditor/basetexteditor_test.cpp462
-rw-r--r--src/plugins/texteditor/codeassist/codeassistant.cpp3
-rw-r--r--src/plugins/texteditor/tabsettings.cpp12
-rw-r--r--src/plugins/texteditor/tabsettings.h1
-rw-r--r--src/plugins/texteditor/texteditorplugin.h25
11 files changed, 1063 insertions, 412 deletions
diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp
index 650564da4c..628c29fd37 100644
--- a/src/plugins/fakevim/fakevimhandler.cpp
+++ b/src/plugins/fakevim/fakevimhandler.cpp
@@ -1800,12 +1800,19 @@ public:
}
// Set cursor in text editor widget.
void commitCursor() {
- if (editor())
- EDITOR(setTextCursor(m_cursor));
+ if (isVisualBlockMode()) {
+ emit q->requestSetBlockSelection(m_cursor);
+ } else {
+ emit q->requestDisableBlockSelection();
+ if (editor())
+ EDITOR(setTextCursor(m_cursor));
+ }
}
// Restore cursor from editor widget.
void pullCursor() {
- if (editor())
+ if (isVisualBlockMode())
+ q->requestBlockSelection(&m_cursor);
+ else if (editor())
m_cursor = EDITOR(textCursor());
}
@@ -2500,14 +2507,12 @@ void FakeVimHandler::Private::exportSelection()
const int col2 = pos - document()->findBlock(pos).position();
if (col1 > col2)
++anc;
- else if (!atEndOfLine())
+ else if (!atBlockEnd())
++pos;
// FIXME: After '$' command (i.e. m_visualTargetColumn == -1), end of selected lines
// should be selected.
setAnchorAndPosition(anc, pos);
commitCursor();
- emit q->requestSetBlockSelection(false);
- emit q->requestSetBlockSelection(true);
} else if (g.visualMode == VisualLineMode) {
const int posLine = lineForPosition(pos);
const int ancLine = lineForPosition(anc);
@@ -2642,9 +2647,6 @@ void FakeVimHandler::Private::ensureCursorVisible()
void FakeVimHandler::Private::importSelection()
{
- bool hasBlock = false;
- emit q->requestHasBlockSelection(&hasBlock);
-
if (position() == m_oldExternalPosition
&& anchor() == m_oldExternalAnchor) {
// Undo drawing correction.
@@ -6867,8 +6869,6 @@ void FakeVimHandler::Private::scrollToLine(int line)
EDITOR(ensureCursorVisible());
EDITOR(setTextCursor(tc));
- if (isVisualBlockMode())
- emit q->requestSetBlockSelection(true);
m_firstVisibleLine = line;
}
@@ -7388,15 +7388,11 @@ bool FakeVimHandler::Private::passEventToEditor(QEvent &event)
{
removeEventFilter();
- commitCursor();
-
EDITOR(setOverwriteMode(false));
- emit q->requestSetBlockSelection(false);
+ commitCursor();
bool accepted = QApplication::sendEvent(editor(), &event);
if (!m_textedit && !m_plaintextedit)
return false;
- if (isVisualBlockMode())
- emit q->requestSetBlockSelection(true);
updateCursorShape();
if (accepted)
@@ -7567,7 +7563,6 @@ void FakeVimHandler::Private::toggleVisualMode(VisualMode visualMode)
if (visualMode == g.visualMode) {
leaveVisualMode();
} else {
- emit q->requestSetBlockSelection(false);
m_positionPastEnd = false;
m_anchorPastEnd = false;
g.visualMode = visualMode;
diff --git a/src/plugins/fakevim/fakevimhandler.h b/src/plugins/fakevim/fakevimhandler.h
index 408b1c3cc3..e2631778ea 100644
--- a/src/plugins/fakevim/fakevimhandler.h
+++ b/src/plugins/fakevim/fakevimhandler.h
@@ -148,7 +148,9 @@ signals:
void findRequested(bool reverse);
void findNextRequested(bool reverse);
void handleExCommandRequested(bool *handled, const ExCommand &cmd);
- void requestSetBlockSelection(bool on);
+ void requestDisableBlockSelection();
+ void requestSetBlockSelection(const QTextCursor&);
+ void requestBlockSelection(QTextCursor*);
void requestHasBlockSelection(bool *on);
void foldToggle(int depth);
void foldAll(bool fold);
diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp
index 851a8eabbf..1440f17fc5 100644
--- a/src/plugins/fakevim/fakevimplugin.cpp
+++ b/src/plugins/fakevim/fakevimplugin.cpp
@@ -1018,7 +1018,9 @@ private slots:
void jumpToGlobalMark(QChar mark, bool backTickMode, const QString &fileName);
void showSettingsDialog();
void maybeReadVimRc();
- void setBlockSelection(bool);
+ void disableBlockSelection();
+ void setBlockSelection(const QTextCursor&);
+ void blockSelection(QTextCursor *);
void hasBlockSelection(bool*);
void setShowRelativeLineNumbers(const QVariant &value);
@@ -1767,8 +1769,12 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor)
SLOT(indentRegion(int,int,QChar)));
connect(handler, SIGNAL(checkForElectricCharacter(bool*,QChar)),
SLOT(checkForElectricCharacter(bool*,QChar)), Qt::DirectConnection);
- connect(handler, SIGNAL(requestSetBlockSelection(bool)),
- SLOT(setBlockSelection(bool)));
+ connect(handler, SIGNAL(requestDisableBlockSelection()),
+ SLOT(disableBlockSelection()));
+ connect(handler, SIGNAL(requestSetBlockSelection(QTextCursor)),
+ SLOT(setBlockSelection(QTextCursor)));
+ connect(handler, SIGNAL(requestBlockSelection(QTextCursor*)),
+ SLOT(blockSelection(QTextCursor*)), Qt::DirectConnection);
connect(handler, SIGNAL(requestHasBlockSelection(bool*)),
SLOT(hasBlockSelection(bool*)), Qt::DirectConnection);
connect(handler, SIGNAL(completionRequested()),
@@ -1864,13 +1870,32 @@ void FakeVimPluginPrivate::triggerSimpleCompletions(const QString &needle, bool
m_wordProvider->setActive(needle, forward, qobject_cast<FakeVimHandler *>(sender()));
}
-void FakeVimPluginPrivate::setBlockSelection(bool on)
+void FakeVimPluginPrivate::disableBlockSelection()
{
FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
if (!handler)
return;
if (BaseTextEditorWidget *bt = qobject_cast<BaseTextEditorWidget *>(handler->widget()))
- bt->setBlockSelection(on);
+ bt->setBlockSelection(false);
+}
+
+void FakeVimPluginPrivate::setBlockSelection(const QTextCursor &cursor)
+{
+ FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
+ if (!handler)
+ return;
+ if (BaseTextEditorWidget *bt = qobject_cast<BaseTextEditorWidget *>(handler->widget()))
+ bt->setBlockSelection(cursor);
+}
+
+void FakeVimPluginPrivate::blockSelection(QTextCursor *cursor)
+{
+ FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
+ if (!handler)
+ return;
+ if (BaseTextEditorWidget *bt = qobject_cast<BaseTextEditorWidget *>(handler->widget()))
+ if (cursor)
+ *cursor = bt->blockSelection();
}
void FakeVimPluginPrivate::hasBlockSelection(bool *on)
diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp
index 37b90868e2..6c6b70b972 100644
--- a/src/plugins/texteditor/basetexteditor.cpp
+++ b/src/plugins/texteditor/basetexteditor.cpp
@@ -69,6 +69,7 @@
#include <QCoreApplication>
#include <QTextCodec>
#include <QDebug>
+#include <QTime>
#include <QTimer>
#include <QTimeLine>
#include <QMimeData>
@@ -195,7 +196,6 @@ QString BaseTextEditorWidget::convertToPlainText(const QString &txt)
}
static const char kTextBlockMimeType[] = "application/vnd.qtcreator.blocktext";
-static const char kVerticalTextBlockMimeType[] = "application/vnd.qtcreator.vblocktext";
BaseTextEditorWidget::BaseTextEditorWidget(QWidget *parent)
: QPlainTextEdit(parent)
@@ -540,6 +540,22 @@ QString BaseTextEditorWidget::msgTextTooLarge(quint64 size)
arg(size >> 20);
}
+void BaseTextEditorWidget::insertPlainText(const QString &text)
+{
+ if (d->m_inBlockSelectionMode)
+ d->insertIntoBlockSelection(text);
+ else
+ QPlainTextEdit::insertPlainText(text);
+}
+
+QString BaseTextEditorWidget::selectedText() const
+{
+ if (d->m_inBlockSelectionMode)
+ return d->copyBlockSelection();
+ else
+ return textCursor().selectedText();
+}
+
void BaseTextEditorWidget::updateCannotDecodeInfo()
{
setReadOnly(d->m_document->hasDecodingError());
@@ -651,15 +667,8 @@ void BaseTextEditorWidget::editorContentsChange(int position, int charsRemoved,
void BaseTextEditorWidget::slotSelectionChanged()
{
- if (d->m_inBlockSelectionMode && !textCursor().hasSelection()) {
- d->m_inBlockSelectionMode = false;
- d->m_blockSelection.clear();
- viewport()->update();
- }
-
- if (!d->m_selectBlockAnchor.isNull() && !textCursor().hasSelection())
+ if (!textCursor().hasSelection() && !d->m_selectBlockAnchor.isNull())
d->m_selectBlockAnchor = QTextCursor();
-
// Clear any link which might be showing when the selection changes
clearLink();
}
@@ -976,6 +985,8 @@ void BaseTextEditorWidget::insertLineAbove()
void BaseTextEditorWidget::insertLineBelow()
{
+ if (d->m_inBlockSelectionMode)
+ d->disableBlockSelection(false);
QTextCursor cursor = textCursor();
cursor.beginEditBlock();
cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::MoveAnchor);
@@ -1015,6 +1026,20 @@ void BaseTextEditorWidget::unindent()
setTextCursor(baseTextDocument()->unindent(textCursor()));
}
+void BaseTextEditorWidget::undo()
+{
+ if (d->m_inBlockSelectionMode)
+ d->disableBlockSelection(false);
+ QPlainTextEdit::undo();
+}
+
+void BaseTextEditorWidget::redo()
+{
+ if (d->m_inBlockSelectionMode)
+ d->disableBlockSelection(false);
+ QPlainTextEdit::redo();
+}
+
void BaseTextEditorWidget::openLinkUnderCursor()
{
const bool openInNextSplit = alwaysOpenLinksInNextSplit();
@@ -1049,6 +1074,8 @@ void BaseTextEditorWidget::moveLineUpDown(bool up)
bool hasSelection = cursor.hasSelection();
if (hasSelection) {
+ if (d->m_inBlockSelectionMode)
+ d->disableBlockSelection(true);
move.setPosition(cursor.selectionStart());
move.movePosition(QTextCursor::StartOfBlock);
move.setPosition(cursor.selectionEnd(), QTextCursor::KeepAnchor);
@@ -1565,24 +1592,24 @@ void BaseTextEditorWidget::keyPressEvent(QKeyEvent *e)
bool ro = isReadOnly();
const bool inOverwriteMode = overwriteMode();
- if (d->m_inBlockSelectionMode) {
+ if (!ro && d->m_inBlockSelectionMode) {
if (e == QKeySequence::Cut) {
- if (!ro) {
- cut();
- e->accept();
- return;
- }
+ cut();
+ e->accept();
+ return;
} else if (e == QKeySequence::Delete || e->key() == Qt::Key_Backspace) {
- if (!ro) {
- d->removeBlockSelection();
- e->accept();
- return;
+ if (d->m_blockSelection.positionColumn == d->m_blockSelection.anchorColumn) {
+ if (e == QKeySequence::Delete)
+ ++d->m_blockSelection.positionColumn;
+ else if (d->m_blockSelection.positionColumn > 0)
+ --d->m_blockSelection.positionColumn;
}
+ d->removeBlockSelection();
+ e->accept();
+ return;
} else if (e == QKeySequence::Paste) {
- if (!ro) {
- d->removeBlockSelection();
- // continue
- }
+ d->removeBlockSelection();
+ // continue
}
}
@@ -1590,6 +1617,11 @@ void BaseTextEditorWidget::keyPressEvent(QKeyEvent *e)
if (!ro
&& (e == QKeySequence::InsertParagraphSeparator
|| (!d->m_lineSeparatorsAllowed && e == QKeySequence::InsertLineSeparator))) {
+ if (d->m_inBlockSelectionMode) {
+ d->disableBlockSelection(false);
+ e->accept();
+ return;
+ }
if (d->m_snippetOverlay->isVisible()) {
e->accept();
d->m_snippetOverlay->hide();
@@ -1602,8 +1634,6 @@ void BaseTextEditorWidget::keyPressEvent(QKeyEvent *e)
}
QTextCursor cursor = textCursor();
- if (d->m_inBlockSelectionMode)
- cursor.clearSelection();
const TabSettings &ts = d->m_document->tabSettings();
const TypingSettings &tps = d->m_document->typingSettings();
cursor.beginEditBlock();
@@ -1706,6 +1736,19 @@ void BaseTextEditorWidget::keyPressEvent(QKeyEvent *e)
c.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
c.removeSelectedText();
return;
+ } else if (!ro && (e == QKeySequence::MoveToNextPage || e == QKeySequence::MoveToPreviousPage)
+ && d->m_inBlockSelectionMode) {
+ d->disableBlockSelection(false);
+ QPlainTextEdit::keyPressEvent(e);
+ return;
+ } else if (!ro && (e == QKeySequence::SelectNextPage || e == QKeySequence::SelectPreviousPage)
+ && d->m_inBlockSelectionMode) {
+ QPlainTextEdit::keyPressEvent(e);
+ d->m_blockSelection.positionBlock = QPlainTextEdit::textCursor().blockNumber();
+ setTextCursor(d->m_blockSelection.selection(d->m_document.data()), true);
+ viewport()->update();
+ e->accept();
+ return;
} else switch (e->key()) {
@@ -1763,26 +1806,34 @@ void BaseTextEditorWidget::keyPressEvent(QKeyEvent *e)
break;
if ((e->modifiers()
& (Qt::AltModifier | Qt::ShiftModifier)) == (Qt::AltModifier | Qt::ShiftModifier)) {
- int diff_row = 0;
- int diff_col = 0;
- if (e->key() == Qt::Key_Up)
- diff_row = -1;
- else if (e->key() == Qt::Key_Down)
- diff_row = 1;
- else if (e->key() == Qt::Key_Left)
- diff_col = -1;
- else if (e->key() == Qt::Key_Right)
- diff_col = 1;
- handleBlockSelection(diff_row, diff_col);
+ if (!d->m_inBlockSelectionMode)
+ d->enableBlockSelection(textCursor());
+ switch (e->key()) {
+ case Qt::Key_Up:
+ if (d->m_blockSelection.positionBlock > 0)
+ --d->m_blockSelection.positionBlock;
+ break;
+ case Qt::Key_Down:
+ if (d->m_blockSelection.positionBlock < document()->blockCount() - 1)
+ ++d->m_blockSelection.positionBlock;
+ break;
+ case Qt::Key_Left:
+ if (d->m_blockSelection.positionColumn > 0)
+ --d->m_blockSelection.positionColumn;
+ break;
+ case Qt::Key_Right:
+ ++d->m_blockSelection.positionColumn;
+ break;
+ default:
+ break;
+ }
+ d->resetCursorFlashTimer();
+ setTextCursor(d->m_blockSelection.selection(d->m_document.data()), true);
+ viewport()->update();
e->accept();
return;
- } else {
- // leave block selection mode
- if (d->m_inBlockSelectionMode) {
- d->m_inBlockSelectionMode = false;
- d->m_blockSelection.clear();
- viewport()->update();
- }
+ } else if (d->m_inBlockSelectionMode) { // leave block selection mode
+ d->disableBlockSelection();
}
break;
case Qt::Key_Insert:
@@ -1811,8 +1862,8 @@ void BaseTextEditorWidget::keyPressEvent(QKeyEvent *e)
const QString eventText = e->text();
if (!ro && d->m_inBlockSelectionMode) {
- if (!isPrintableText(eventText)) {
- d->removeBlockSelection(eventText);
+ if (isPrintableText(eventText)) {
+ d->insertIntoBlockSelection(eventText);
goto skip_event;
}
}
@@ -1964,10 +2015,12 @@ void BaseTextEditorWidget::universalHelper()
// give it proper scrutiny before pushing it onto others.
}
-void BaseTextEditorWidget::setTextCursor(const QTextCursor &cursor)
+void BaseTextEditorWidget::setTextCursor(const QTextCursor &cursor, bool keepBlockSelection)
{
// workaround for QTextControl bug
bool selectionChange = cursor.hasSelection() || textCursor().hasSelection();
+ if (!keepBlockSelection && d->m_inBlockSelectionMode)
+ d->disableBlockSelection(false);
QTextCursor c = cursor;
c.setVisualNavigation(true);
QPlainTextEdit::setTextCursor(c);
@@ -1975,6 +2028,11 @@ void BaseTextEditorWidget::setTextCursor(const QTextCursor &cursor)
slotSelectionChanged();
}
+void BaseTextEditorWidget::setTextCursor(const QTextCursor &cursor)
+{
+ setTextCursor(cursor, false);
+}
+
void BaseTextEditorWidget::gotoLine(int line, int column, bool centerLine)
{
d->m_lastCursorChangeWasInteresting = false; // avoid adding the previous position to history
@@ -2062,6 +2120,16 @@ bool BaseTextEditorWidget::event(QEvent *e)
return QPlainTextEdit::event(e);
}
+void BaseTextEditorWidget::inputMethodEvent(QInputMethodEvent *e)
+{
+ if (d->m_inBlockSelectionMode) {
+ if (!e->commitString().isEmpty())
+ d->insertIntoBlockSelection(e->commitString());
+ return;
+ }
+ QPlainTextEdit::inputMethodEvent(e);
+}
+
void BaseTextEditorWidget::documentAboutToBeReloaded()
{
//memorize cursor position
@@ -2660,26 +2728,16 @@ void BaseTextEditorWidgetPrivate::highlightSearchResults(const QTextBlock &block
}
}
-void BaseTextEditorWidgetPrivate::clearBlockSelection()
-{
- if (m_inBlockSelectionMode) {
- m_inBlockSelectionMode = false;
- m_blockSelection.clear();
- QTextCursor cursor = q->textCursor();
- cursor.clearSelection();
- q->setTextCursor(cursor);
- }
-}
-
QString BaseTextEditorWidgetPrivate::copyBlockSelection()
{
- QString selection;
- QTextCursor cursor = q->textCursor();
if (!m_inBlockSelectionMode)
- return selection;
+ return QString();
+ QString selection;
const TabSettings &ts = m_document->tabSettings();
- QTextBlock block = m_blockSelection.firstBlock.block();
- QTextBlock lastBlock = m_blockSelection.lastBlock.block();
+ QTextBlock block =
+ m_document->document()->findBlockByNumber(m_blockSelection.firstBlockNumber());
+ const QTextBlock &lastBlock =
+ m_document->document()->findBlockByNumber(m_blockSelection.lastBlockNumber());
bool textInserted = false;
for (;;) {
if (q->selectionVisible(block.blockNumber())) {
@@ -2689,9 +2747,9 @@ QString BaseTextEditorWidgetPrivate::copyBlockSelection()
QString text = block.text();
int startOffset = 0;
- int startPos = ts.positionAtColumn(text, m_blockSelection.firstVisualColumn, &startOffset);
+ int startPos = ts.positionAtColumn(text, m_blockSelection.firstVisualColumn(), &startOffset);
int endOffset = 0;
- int endPos = ts.positionAtColumn(text, m_blockSelection.lastVisualColumn, &endOffset);
+ int endPos = ts.positionAtColumn(text, m_blockSelection.lastVisualColumn(), &endOffset);
if (startPos == endPos) {
selection += QString(endOffset - startOffset, QLatin1Char(' '));
@@ -2715,45 +2773,202 @@ QString BaseTextEditorWidgetPrivate::copyBlockSelection()
return selection;
}
-void BaseTextEditorWidgetPrivate::removeBlockSelection(const QString &text)
+void BaseTextEditorWidgetPrivate::setCursorToColumn(QTextCursor &cursor, int column, QTextCursor::MoveMode moveMode)
+{
+ const TabSettings &ts = m_document->tabSettings();
+ int offset = 0;
+ const int cursorPosition = cursor.position();
+ const int pos = ts.positionAtColumn(cursor.block().text(), column, &offset);
+ cursor.setPosition(cursor.block().position() + pos, offset == 0 ? moveMode : QTextCursor::MoveAnchor);
+ if (offset == 0)
+ return;
+ if (offset < 0) {
+ // the column is inside a tab so it is replaced with spaces
+ cursor.setPosition(cursor.block().position() + pos - 1, QTextCursor::KeepAnchor);
+ cursor.insertText(ts.indentationString(
+ ts.columnAt(cursor.block().text(), pos - 1),
+ ts.columnAt(cursor.block().text(), pos), cursor.block()));
+ } else {
+ // column is behind the last position
+ cursor.insertText(ts.indentationString(ts.columnAt(cursor.block().text(), pos),
+ column, cursor.block()));
+ }
+ if (moveMode == QTextCursor::KeepAnchor)
+ cursor.setPosition(cursorPosition);
+ cursor.setPosition(cursor.block().position() + ts.positionAtColumn(
+ cursor.block().text(), column), moveMode);
+}
+
+void BaseTextEditorWidgetPrivate::insertIntoBlockSelection(const QString &text)
+{
+ // TODO: add autocompleter support
+ QTextCursor cursor = q->textCursor();
+ cursor.beginEditBlock();
+
+ if (q->overwriteMode() && m_blockSelection.lastVisualColumn() == m_blockSelection.positionColumn)
+ ++m_blockSelection.positionColumn;
+
+ if (m_blockSelection.positionColumn != m_blockSelection.anchorColumn) {
+ removeBlockSelection();
+ if (!m_inBlockSelectionMode) {
+ q->insertPlainText(text);
+ cursor.endEditBlock();
+ return;
+ }
+ }
+
+ if (text.isEmpty()) {
+ cursor.endEditBlock();
+ return;
+ }
+
+ int positionBlock = m_blockSelection.positionBlock;
+ int anchorBlock = m_blockSelection.anchorBlock;
+ int column = m_blockSelection.positionColumn;
+
+ const QTextBlock &firstBlock =
+ m_document->document()->findBlockByNumber(m_blockSelection.firstBlockNumber());
+ QTextBlock block =
+ m_document->document()->findBlockByNumber(m_blockSelection.lastBlockNumber());
+
+ // unify the length of all lines in a multiline text
+ const int selectionLineCount = m_blockSelection.lastBlockNumber()
+ - m_blockSelection.firstBlockNumber();
+ const int textNewLineCount = text.count(QLatin1Char('\n')) ;
+ QStringList textLines = text.split(QLatin1Char('\n'));
+ const TabSettings &ts = m_document->tabSettings();
+ int textLength = 0;
+ const QStringList::const_iterator endLine = textLines.constEnd();
+ for (QStringList::const_iterator textLine = textLines.constBegin(); textLine != endLine; ++textLine)
+ textLength += qMax(0, ts.columnCountForText(*textLine, column) - textLength);
+ for (QStringList::iterator textLine = textLines.begin(); textLine != endLine; ++textLine)
+ textLine->append(QString(qMax(0, textLength - ts.columnCountForText(*textLine, column)), QLatin1Char(' ')));
+
+ // insert Text
+ for (;;) {
+ // If the number of lines to be inserted equals the number of the selected lines the
+ // lines of the copy paste buffer are inserted in the corresponding lines of the selection.
+ // Otherwise the complete buffer is inserted in each of the selected lines.
+ cursor.setPosition(block.position());
+ if (selectionLineCount == textNewLineCount) {
+ setCursorToColumn(cursor, column);
+ cursor.insertText(textLines.at(block.blockNumber()
+ - m_blockSelection.firstBlockNumber()));
+ } else {
+ QStringList::const_iterator textLine = textLines.constBegin();
+ while (true) {
+ setCursorToColumn(cursor, column);
+ cursor.insertText(*textLine);
+ ++textLine;
+ if (textLine == endLine)
+ break;
+ cursor.movePosition(QTextCursor::EndOfBlock);
+ cursor.insertText(QLatin1String("\n"));
+ if (qMax(anchorBlock, positionBlock) == anchorBlock)
+ ++anchorBlock;
+ else
+ ++positionBlock;
+ }
+ }
+ if (block == firstBlock)
+ break;
+ block = block.previous();
+ }
+ cursor.endEditBlock();
+
+ column += textLength;
+ m_blockSelection.fromPostition(positionBlock, column, anchorBlock, column);
+ q->setTextCursor(m_blockSelection.selection(m_document.data()), true);
+}
+
+void BaseTextEditorWidgetPrivate::removeBlockSelection()
{
QTextCursor cursor = q->textCursor();
if (!cursor.hasSelection() || !m_inBlockSelectionMode)
return;
+ const int firstColumn = m_blockSelection.firstVisualColumn();
+ const int lastColumn = m_blockSelection.lastVisualColumn();
+ if (firstColumn == lastColumn)
+ return;
+ const int positionBlock = m_blockSelection.positionBlock;
+ const int anchorBlock = m_blockSelection.anchorBlock;
+
int cursorPosition = cursor.selectionStart();
cursor.clearSelection();
cursor.beginEditBlock();
const TabSettings &ts = m_document->tabSettings();
- QTextBlock block = m_blockSelection.firstBlock.block();
- QTextBlock lastBlock = m_blockSelection.lastBlock.block();
+ QTextBlock block = m_document->document()->findBlockByNumber(m_blockSelection.firstBlockNumber());
+ const QTextBlock &lastBlock = m_document->document()->findBlockByNumber(m_blockSelection.lastBlockNumber());
for (;;) {
- QString text = block.text();
int startOffset = 0;
- int startPos = ts.positionAtColumn(text, m_blockSelection.firstVisualColumn, &startOffset);
- int endOffset = 0;
- int endPos = ts.positionAtColumn(text, m_blockSelection.lastVisualColumn, &endOffset);
-
- cursor.setPosition(block.position() + startPos);
- cursor.setPosition(block.position() + endPos, QTextCursor::KeepAnchor);
- cursor.removeSelectedText();
-
- if (startOffset < 0)
- cursor.insertText(QString(ts.m_tabSize + startOffset, QLatin1Char(' ')));
- if (endOffset < 0)
- cursor.insertText(QString(-endOffset, QLatin1Char(' ')));
-
+ const int startPos = ts.positionAtColumn(block.text(), firstColumn, &startOffset);
+ // removing stuff doesn't make sense if the cursor is behind the code
+ if (startPos < block.length() - 1 || startOffset < 0) {
+ cursor.setPosition(block.position());
+ setCursorToColumn(cursor, firstColumn);
+ setCursorToColumn(cursor, lastColumn, QTextCursor::KeepAnchor);
+ cursor.removeSelectedText();
+ }
if (block == lastBlock)
break;
block = block.next();
}
cursor.setPosition(cursorPosition);
- if (!text.isEmpty())
- cursor.insertText(text);
cursor.endEditBlock();
+ m_blockSelection.fromPostition(positionBlock, firstColumn, anchorBlock, firstColumn);
+ cursor = m_blockSelection.selection(m_document.data());
+ q->setTextCursor(cursor, m_blockSelection.hasSelection());
+}
+
+void BaseTextEditorWidgetPrivate::enableBlockSelection(const QTextCursor &cursor)
+{
+ const TabSettings &ts = m_document->tabSettings();
+ const QTextBlock &positionTextBlock = cursor.block();
+ int positionBlock = positionTextBlock.blockNumber();
+ int positionColumn = ts.columnAt(positionTextBlock.text(),
+ cursor.position() - positionTextBlock.position());
+
+ const QTextDocument *document = cursor.document();
+ const QTextBlock &anchorTextBlock = document->findBlock(cursor.anchor());
+ int anchorBlock = anchorTextBlock.blockNumber();
+ int anchorColumn = ts.columnAt(anchorTextBlock.text(),
+ cursor.anchor() - anchorTextBlock.position());
+ enableBlockSelection(positionBlock, anchorColumn, anchorBlock, positionColumn);
+}
+
+void BaseTextEditorWidgetPrivate::enableBlockSelection(int positionBlock, int positionColumn,
+ int anchorBlock, int anchorColumn)
+{
+ m_blockSelection.fromPostition(positionBlock, anchorColumn, anchorBlock, positionColumn);
+ resetCursorFlashTimer();
+ m_inBlockSelectionMode = true;
+ q->setTextCursor(m_blockSelection.selection(m_document.data()), true);
+ q->viewport()->update();
+}
+
+void BaseTextEditorWidgetPrivate::disableBlockSelection(bool keepSelection)
+{
+ m_inBlockSelectionMode = false;
+ m_cursorFlashTimer.stop();
+ QTextCursor cursor = m_blockSelection.selection(m_document.data());
+ m_blockSelection.clear();
+ if (!keepSelection)
+ cursor.clearSelection();
q->setTextCursor(cursor);
+ q->viewport()->update();
+}
+
+void BaseTextEditorWidgetPrivate::resetCursorFlashTimer()
+{
+ m_cursorVisible = true;
+ const int flashTime = qApp->cursorFlashTime();
+ if (flashTime > 0) {
+ m_cursorFlashTimer.stop();
+ m_cursorFlashTimer.start(flashTime / 2, q);
+ }
}
void BaseTextEditorWidgetPrivate::moveCursorVisible(bool ensureVisible)
@@ -2812,6 +3027,16 @@ static QColor calcBlendColor(const QColor &baseColor, int level, int count)
return blendColors(color80, color90, blendFactor);
}
+static QTextLayout::FormatRange createBlockCursorCharFormatRange(int pos, const QPalette &palette)
+{
+ QTextLayout::FormatRange o;
+ o.start = pos;
+ o.length = 1;
+ o.format.setForeground(palette.base());
+ o.format.setBackground(palette.text());
+ return o;
+}
+
void BaseTextEditorWidget::paintEvent(QPaintEvent *e)
{
/*
@@ -2929,8 +3154,8 @@ void BaseTextEditorWidget::paintEvent(QPaintEvent *e)
int blockSelectionIndex = -1;
- if (d->m_inBlockSelectionMode
- && context.selections.count() && context.selections.last().cursor == textCursor()) {
+ if (d->m_inBlockSelectionMode && context.selections.count()
+ && context.selections.last().cursor == textCursor()) {
blockSelectionIndex = context.selections.size()-1;
context.selections[blockSelectionIndex].format.clearBackground();
}
@@ -3123,8 +3348,8 @@ void BaseTextEditorWidget::paintEvent(QPaintEvent *e)
if (i == blockSelectionIndex) {
QString text = block.text();
const TabSettings &ts = d->m_document->tabSettings();
- o.start = ts.positionAtColumn(text, d->m_blockSelection.firstVisualColumn);
- o.length = ts.positionAtColumn(text, d->m_blockSelection.lastVisualColumn) - o.start;
+ o.start = ts.positionAtColumn(text, d->m_blockSelection.firstVisualColumn());
+ o.length = ts.positionAtColumn(text, d->m_blockSelection.lastVisualColumn()) - o.start;
}
if ((hasMainSelection && i == context.selections.size()-1)
|| (o.format.foreground().style() == Qt::NoBrush
@@ -3171,21 +3396,25 @@ void BaseTextEditorWidget::paintEvent(QPaintEvent *e)
QRectF blockSelectionCursorRect;
if (d->m_inBlockSelectionMode
- && block.position() >= d->m_blockSelection.firstBlock.block().position()
- && block.position() <= d->m_blockSelection.lastBlock.block().position()) {
+ && block.blockNumber() >= d->m_blockSelection.firstBlockNumber()
+ && block.blockNumber() <= d->m_blockSelection.lastBlockNumber()) {
QString text = block.text();
const TabSettings &ts = d->m_document->tabSettings();
- qreal spacew = QFontMetricsF(font()).width(QLatin1Char(' '));
+ const qreal spacew = QFontMetricsF(font()).width(QLatin1Char(' '));
+ const int cursorw = overwriteMode() ? QFontMetrics(font()).width(QLatin1Char(' '))
+ : cursorWidth();
int offset = 0;
- int relativePos = ts.positionAtColumn(text, d->m_blockSelection.firstVisualColumn, &offset);
- QTextLine line = layout->lineForTextPosition(relativePos);
- qreal x = line.cursorToX(relativePos) + offset * spacew;
+ int relativePos = ts.positionAtColumn(text, d->m_blockSelection.firstVisualColumn(),
+ &offset);
+ const QTextLine line = layout->lineForTextPosition(relativePos);
+ const qreal x = line.cursorToX(relativePos) + offset * spacew;
int eoffset = 0;
- int erelativePos = ts.positionAtColumn(text, d->m_blockSelection.lastVisualColumn, &eoffset);
- QTextLine eline = layout->lineForTextPosition(erelativePos);
- qreal ex = eline.cursorToX(erelativePos) + eoffset * spacew;
+ int erelativePos = ts.positionAtColumn(text, d->m_blockSelection.lastVisualColumn(),
+ &eoffset);
+ const QTextLine eline = layout->lineForTextPosition(erelativePos);
+ const qreal ex = eline.cursorToX(erelativePos) + eoffset * spacew;
QRectF rr = line.naturalTextRect();
rr.moveTop(rr.top() + r.top());
@@ -3193,13 +3422,18 @@ void BaseTextEditorWidget::paintEvent(QPaintEvent *e)
if (line.lineNumber() == eline.lineNumber())
rr.setRight(r.left() + ex);
painter.fillRect(rr, palette().highlight());
- if ((d->m_blockSelection.anchor == BaseTextBlockSelection::TopLeft
- && block == d->m_blockSelection.firstBlock.block())
- || (d->m_blockSelection.anchor == BaseTextBlockSelection::BottomLeft
- && block == d->m_blockSelection.lastBlock.block())
- ) {
- rr.setRight(rr.left()+2);
- blockSelectionCursorRect = rr;
+ if (d->m_cursorVisible
+ && d->m_blockSelection.firstVisualColumn()
+ == d->m_blockSelection.positionColumn) {
+ if (overwriteMode() && offset == 0
+ && relativePos < text.length()
+ && text.at(relativePos) != QLatin1Char('\t')
+ && text.at(relativePos) != QLatin1Char('\n')) {
+ selections.append(createBlockCursorCharFormatRange(relativePos, palette()));
+ } else {
+ blockSelectionCursorRect = rr;
+ blockSelectionCursorRect.setRight(rr.left() + cursorw);
+ }
}
for (int i = line.lineNumber() + 1; i < eline.lineNumber(); ++i) {
rr = layout->lineAt(i).naturalTextRect();
@@ -3213,12 +3447,19 @@ void BaseTextEditorWidget::paintEvent(QPaintEvent *e)
rr.setRight(r.left() + ex);
if (line.lineNumber() != eline.lineNumber())
painter.fillRect(rr, palette().highlight());
- if ((d->m_blockSelection.anchor == BaseTextBlockSelection::TopRight
- && block == d->m_blockSelection.firstBlock.block())
- || (d->m_blockSelection.anchor == BaseTextBlockSelection::BottomRight
- && block == d->m_blockSelection.lastBlock.block())) {
- rr.setLeft(rr.right()-2);
- blockSelectionCursorRect = rr;
+ if (d->m_cursorVisible
+ && d->m_blockSelection.lastVisualColumn()
+ == d->m_blockSelection.positionColumn) {
+ if (overwriteMode() && eoffset == 0
+ && erelativePos < text.length()
+ && text.at(erelativePos) != QLatin1Char('\t')
+ && text.at(erelativePos) != QLatin1Char('\n')) {
+ selections.append(createBlockCursorCharFormatRange(erelativePos, palette()));
+ } else {
+ blockSelectionCursorRect = rr;
+ blockSelectionCursorRect.setLeft(rr.right());
+ blockSelectionCursorRect.setRight(rr.right() + cursorw);
+ }
}
}
@@ -3227,7 +3468,7 @@ void BaseTextEditorWidget::paintEvent(QPaintEvent *e)
&& context.cursorPosition >= blpos
&& context.cursorPosition < blpos + bllen);
- bool drawCursorAsBlock = drawCursor && overwriteMode() ;
+ bool drawCursorAsBlock = drawCursor && overwriteMode() && !d->m_inBlockSelectionMode;
if (drawCursorAsBlock) {
int relativePos = context.cursorPosition - blpos;
@@ -3253,14 +3494,8 @@ void BaseTextEditorWidget::paintEvent(QPaintEvent *e)
rr.moveLeft(r.left() + x);
rr.setWidth(w);
painter.fillRect(rr, palette().text());
- if (doSelection) {
- QTextLayout::FormatRange o;
- o.start = relativePos;
- o.length = 1;
- o.format.setForeground(palette().base());
- o.format.setBackground(palette().text());
- selections.append(o);
- }
+ if (doSelection)
+ selections.append(createBlockCursorCharFormatRange(relativePos, palette()));
}
@@ -3268,8 +3503,7 @@ void BaseTextEditorWidget::paintEvent(QPaintEvent *e)
layout->draw(&painter, offset, selections, er);
if ((drawCursor && !drawCursorAsBlock)
- || (editable && context.cursorPosition < -1
- && !layout->preeditAreaText().isEmpty())) {
+ || (editable && context.cursorPosition < -1 && !layout->preeditAreaText().isEmpty())) {
int cpos = context.cursorPosition;
if (cpos < -1)
cpos = layout->preeditAreaPosition() - (cpos + 2);
@@ -3281,7 +3515,9 @@ void BaseTextEditorWidget::paintEvent(QPaintEvent *e)
cursor_pen = painter.pen();
}
- if (!HostOsInfo::isMacHost() && blockSelectionCursorRect.isValid())
+ if ((!HostOsInfo::isMacHost()
+ || d->m_blockSelection.positionColumn == d->m_blockSelection.anchorColumn)
+ && blockSelectionCursorRect.isValid())
painter.fillRect(blockSelectionCursorRect, palette().text());
}
@@ -4021,6 +4257,9 @@ void BaseTextEditorWidget::timerEvent(QTimerEvent *e)
d->suggestedVisibleFoldedBlockNumber = -1;
d->foldedBlockTimer.stop();
viewport()->update();
+ } else if (e->timerId() == d->m_cursorFlashTimer.timerId()) {
+ d->m_cursorVisible = !d->m_cursorVisible;
+ viewport()->update();
}
QPlainTextEdit::timerEvent(e);
}
@@ -4067,20 +4306,36 @@ void BaseTextEditorWidget::mouseMoveEvent(QMouseEvent *e)
if (e->modifiers() & Qt::AltModifier) {
if (!d->m_inBlockSelectionMode) {
- d->m_blockSelection.fromSelection(d->m_document->tabSettings(), textCursor());
- d->m_inBlockSelectionMode = true;
+ if (textCursor().hasSelection()) {
+ d->enableBlockSelection(textCursor());
+ } else {
+ const QTextCursor &cursor = cursorForPosition(e->pos());
+ int column = d->m_document->tabSettings().columnAt(
+ cursor.block().text(), cursor.positionInBlock());
+ if (cursor.positionInBlock() == cursor.block().length()-1)
+ column += (e->pos().x() - cursorRect().center().x()) / QFontMetricsF(font()).width(QLatin1Char(' '));
+ int block = cursor.blockNumber();
+ if (block == blockCount() - 1)
+ block += (e->pos().y() - cursorRect().center().y()) / QFontMetricsF(font()).lineSpacing();
+ d->enableBlockSelection(block, column, block, column);
+ }
} else {
- QTextCursor cursor = textCursor();
+ const QTextCursor &cursor = textCursor();
// get visual column
int column = d->m_document->tabSettings().columnAt(
cursor.block().text(), cursor.positionInBlock());
if (cursor.positionInBlock() == cursor.block().length()-1)
- column += (e->pos().x() - cursorRect().center().x())/QFontMetricsF(font()).width(QLatin1Char(' '));
- d->m_blockSelection.moveAnchor(cursor.blockNumber(), column);
- setTextCursor(d->m_blockSelection.selection(d->m_document->tabSettings()));
+ column += (e->pos().x() - cursorRect().center().x()) / QFontMetricsF(font()).width(QLatin1Char(' '));
+
+ d->m_blockSelection.positionBlock = cursor.blockNumber();
+ d->m_blockSelection.positionColumn = column;
+
+ setTextCursor(d->m_blockSelection.selection(d->m_document.data()), true);
viewport()->update();
}
+ } else if (d->m_inBlockSelectionMode) {
+ d->disableBlockSelection();
}
}
if (viewport()->cursor().shape() == Qt::BlankCursor)
@@ -4104,22 +4359,43 @@ static bool handleForwardBackwardMouseButtons(QMouseEvent *e)
void BaseTextEditorWidget::mousePressEvent(QMouseEvent *e)
{
if (e->button() == Qt::LeftButton) {
- d->clearBlockSelection(); // just in case, otherwise we might get strange drag and drop
-
- QTextBlock foldedBlock = foldedBlockAt(e->pos());
- if (foldedBlock.isValid()) {
- toggleBlockVisible(foldedBlock);
- viewport()->setCursor(Qt::IBeamCursor);
- }
+ if (e->modifiers() == Qt::AltModifier) {
+ const QTextCursor &cursor = cursorForPosition(e->pos());
+ int column = d->m_document->tabSettings().columnAt(
+ cursor.block().text(), cursor.positionInBlock());
+ if (cursor.positionInBlock() == cursor.block().length()-1)
+ column += (e->pos().x() - cursorRect(cursor).center().x()) / QFontMetricsF(font()).width(QLatin1Char(' '));
+ int block = cursor.blockNumber();
+ if (block == blockCount() - 1)
+ block += (e->pos().y() - cursorRect(cursor).center().y()) / QFontMetricsF(font()).lineSpacing();
+ if (d->m_inBlockSelectionMode) {
+ d->m_blockSelection.positionBlock = block;
+ d->m_blockSelection.positionColumn = column;
- RefactorMarker refactorMarker = d->m_refactorOverlay->markerAt(e->pos());
- if (refactorMarker.isValid()) {
- emit refactorMarkerClicked(refactorMarker);
+ setTextCursor(d->m_blockSelection.selection(d->m_document.data()), true);
+ viewport()->update();
+ } else {
+ d->enableBlockSelection(block, column, block, column);
+ }
} else {
- updateLink(e);
+ if (d->m_inBlockSelectionMode)
+ d->disableBlockSelection(false); // just in case, otherwise we might get strange drag and drop
+
+ QTextBlock foldedBlock = foldedBlockAt(e->pos());
+ if (foldedBlock.isValid()) {
+ toggleBlockVisible(foldedBlock);
+ viewport()->setCursor(Qt::IBeamCursor);
+ }
+
+ RefactorMarker refactorMarker = d->m_refactorOverlay->markerAt(e->pos());
+ if (refactorMarker.isValid()) {
+ emit refactorMarkerClicked(refactorMarker);
+ } else {
+ updateLink(e);
- if (d->m_currentLink.hasValidLinkText())
- d->m_linkPressed = true;
+ if (d->m_currentLink.hasValidLinkText())
+ d->m_linkPressed = true;
+ }
}
} else if (e->button() == Qt::RightButton) {
int eventCursorPosition = cursorForPosition(e->pos()).position();
@@ -4738,16 +5014,12 @@ void BaseTextEditorWidget::highlightSearchResults(const QString &txt, Core::Find
int BaseTextEditorWidget::verticalBlockSelectionFirstColumn() const
{
- if (d->m_inBlockSelectionMode)
- return d->m_blockSelection.firstVisualColumn;
- return -1;
+ return d->m_inBlockSelectionMode ? d->m_blockSelection.firstVisualColumn() : -1;
}
int BaseTextEditorWidget::verticalBlockSelectionLastColumn() const
{
- if (d->m_inBlockSelectionMode)
- return d->m_blockSelection.lastVisualColumn;
- return -1;
+ return d->m_inBlockSelectionMode ? d->m_blockSelection.lastVisualColumn() : -1;
}
QRegion BaseTextEditorWidget::translatedLineRegion(int lineStart, int lineEnd) const
@@ -5081,7 +5353,7 @@ void BaseTextEditorWidget::copyLine()
copy();
if (!prevCursor.hasSelection())
prevCursor.movePosition(QTextCursor::StartOfBlock);
- setTextCursor(prevCursor);
+ setTextCursor(prevCursor, d->m_inBlockSelectionMode);
}
void BaseTextEditorWidget::deleteLine()
@@ -5579,19 +5851,26 @@ void BaseTextEditorWidget::cut()
void BaseTextEditorWidget::selectAll()
{
- d->clearBlockSelection();
+ d->disableBlockSelection();
QPlainTextEdit::selectAll();
}
void BaseTextEditorWidget::copy()
{
- if (!textCursor().hasSelection())
+ if (!textCursor().hasSelection() || (d->m_inBlockSelectionMode
+ && d->m_blockSelection.anchorColumn == d->m_blockSelection.positionColumn)) {
return;
+ }
QPlainTextEdit::copy();
collectToCircularClipboard();
}
+void BaseTextEditorWidget::paste()
+{
+ QPlainTextEdit::paste();
+}
+
void BaseTextEditorWidget::collectToCircularClipboard()
{
const QMimeData *mimeData = QApplication::clipboard()->mimeData();
@@ -5603,13 +5882,6 @@ void BaseTextEditorWidget::collectToCircularClipboard()
circularClipBoard->toLastCollect();
}
-void BaseTextEditorWidget::paste()
-{
- if (d->m_inBlockSelectionMode)
- d->removeBlockSelection();
- QPlainTextEdit::paste();
-}
-
void BaseTextEditorWidget::circularPaste()
{
CircularClipboard *circularClipBoard = CircularClipboard::instance();
@@ -5636,9 +5908,7 @@ QMimeData *BaseTextEditorWidget::createMimeDataFromSelection() const
{
if (d->m_inBlockSelectionMode) {
QMimeData *mimeData = new QMimeData;
- QString text = d->copyBlockSelection();
- mimeData->setData(QLatin1String(kVerticalTextBlockMimeType), text.toUtf8());
- mimeData->setText(text); // for exchangeability
+ mimeData->setText(d->copyBlockSelection());
return mimeData;
} else if (textCursor().hasSelection()) {
QTextCursor cursor = textCursor();
@@ -5737,54 +6007,6 @@ void BaseTextEditorWidget::insertFromMimeData(const QMimeData *source)
if (isReadOnly())
return;
- if (source->hasFormat(QLatin1String(kVerticalTextBlockMimeType))) {
- QString text = QString::fromUtf8(source->data(QLatin1String(kVerticalTextBlockMimeType)));
- if (text.isEmpty())
- return;
-
- if (d->m_codeAssistant->hasContext())
- d->m_codeAssistant->destroyContext();
-
- QStringList lines = text.split(QLatin1Char('\n'));
- QTextCursor cursor = textCursor();
- cursor.beginEditBlock();
- const TabSettings &ts = d->m_document->tabSettings();
- int initialCursorPosition = cursor.position();
- int column = ts.columnAt(cursor.block().text(), cursor.positionInBlock());
- cursor.insertText(lines.first());
- for (int i = 1; i < lines.count(); ++i) {
- QTextBlock next = cursor.block().next();
- if (next.isValid()) {
- cursor.setPosition(next.position());
- } else {
- cursor.movePosition(QTextCursor::EndOfBlock);
- cursor.insertBlock();
- }
- int offset = 0;
- int position = ts.positionAtColumn(cursor.block().text(), column, &offset);
- cursor.setPosition(cursor.block().position() + position);
- if (offset < 0) {
- cursor.deleteChar();
- cursor.insertText(QString(-offset, QLatin1Char(' ')));
- } else {
- cursor.insertText(QString(offset, QLatin1Char(' ')));
- }
- cursor.insertText(lines.at(i));
- }
- cursor.setPosition(initialCursorPosition);
- cursor.endEditBlock();
- setTextCursor(cursor);
- ensureCursorVisible();
-
- if (d->m_snippetOverlay->isVisible() && lines.count() > 1) {
- d->m_snippetOverlay->hide();
- d->m_snippetOverlay->mangle();
- d->m_snippetOverlay->clear();
- }
-
- return;
- }
-
QString text = source->text();
if (text.isEmpty())
return;
@@ -5792,6 +6014,11 @@ void BaseTextEditorWidget::insertFromMimeData(const QMimeData *source)
if (d->m_codeAssistant->hasContext())
d->m_codeAssistant->destroyContext();
+ if (d->m_inBlockSelectionMode) {
+ d->insertIntoBlockSelection(text);
+ return;
+ }
+
if (d->m_snippetOverlay->isVisible() && (text.contains(QLatin1Char('\n'))
|| text.contains(QLatin1Char('\t')))) {
d->m_snippetOverlay->hide();
@@ -5863,10 +6090,7 @@ QMimeData *BaseTextEditorWidget::duplicateMimeData(const QMimeData *source)
QMimeData *mimeData = new QMimeData;
mimeData->setText(source->text());
mimeData->setHtml(source->html());
- if (source->hasFormat(QLatin1String(kVerticalTextBlockMimeType))) {
- mimeData->setData(QLatin1String(kVerticalTextBlockMimeType),
- source->data(QLatin1String(kVerticalTextBlockMimeType)));
- } else if (source->hasFormat(QLatin1String(kTextBlockMimeType))) {
+ if (source->hasFormat(QLatin1String(kTextBlockMimeType))) {
mimeData->setData(QLatin1String(kTextBlockMimeType),
source->data(QLatin1String(kTextBlockMimeType)));
}
@@ -6031,9 +6255,7 @@ QRect BaseTextEditor::cursorRect(int pos) const
QString BaseTextEditor::selectedText() const
{
- if (m_editorWidget->textCursor().hasSelection())
- return m_editorWidget->textCursor().selectedText();
- return QString();
+ return m_editorWidget->selectedText();
}
void BaseTextEditor::remove(int length)
@@ -6045,8 +6267,7 @@ void BaseTextEditor::remove(int length)
void BaseTextEditor::insert(const QString &string)
{
- QTextCursor tc = m_editorWidget->textCursor();
- tc.insertText(string);
+ m_editorWidget->insertPlainText(string);
}
void BaseTextEditor::replace(int length, const QString &string)
@@ -6058,6 +6279,7 @@ void BaseTextEditor::replace(int length, const QString &string)
void BaseTextEditor::setCursorPosition(int pos)
{
+ m_editorWidget->setBlockSelection(false);
QTextCursor tc = m_editorWidget->textCursor();
tc.setPosition(pos);
m_editorWidget->setTextCursor(tc);
@@ -6065,6 +6287,7 @@ void BaseTextEditor::setCursorPosition(int pos)
void BaseTextEditor::select(int toPos)
{
+ m_editorWidget->setBlockSelection(false);
QTextCursor tc = m_editorWidget->textCursor();
tc.setPosition(toPos, QTextCursor::KeepAnchor);
m_editorWidget->setTextCursor(tc);
@@ -6150,81 +6373,76 @@ void BaseTextEditorWidget::doFoo() {
#endif
}
-void BaseTextBlockSelection::moveAnchor(int blockNumber, int visualColumn)
+BaseTextBlockSelection::BaseTextBlockSelection(const BaseTextBlockSelection &other)
{
- if (visualColumn >= 0) {
- if (anchor % 2) {
- lastVisualColumn = visualColumn;
- if (lastVisualColumn < firstVisualColumn) {
- qSwap(firstVisualColumn, lastVisualColumn);
- anchor = (Anchor) (anchor - 1);
- }
- } else {
- firstVisualColumn = visualColumn;
- if (firstVisualColumn > lastVisualColumn) {
- qSwap(firstVisualColumn, lastVisualColumn);
- anchor = (Anchor) (anchor + 1);
- }
- }
- }
+ positionBlock = other.positionBlock;
+ positionColumn = other.positionColumn;
+ anchorBlock = other.anchorBlock;
+ anchorColumn = other.anchorColumn;
+}
- if (blockNumber >= 0 && blockNumber < firstBlock.document()->blockCount()) {
- if (anchor <= TopRight) {
- firstBlock.setPosition(firstBlock.document()->findBlockByNumber(blockNumber).position());
- if (firstBlock.blockNumber() > lastBlock.blockNumber()) {
- qSwap(firstBlock, lastBlock);
- anchor = (Anchor) (anchor + 2);
- }
- } else {
- lastBlock.setPosition(firstBlock.document()->findBlockByNumber(blockNumber).position());
- if (lastBlock.blockNumber() < firstBlock.blockNumber()) {
- qSwap(firstBlock, lastBlock);
- anchor = (Anchor) (anchor - 2);
- }
- }
- }
- firstBlock.movePosition(QTextCursor::StartOfBlock);
- lastBlock.movePosition(QTextCursor::EndOfBlock);
+void BaseTextBlockSelection::clear()
+{
+ positionColumn = positionBlock = anchorColumn = anchorBlock = 0;
}
-int BaseTextBlockSelection::position(const TabSettings &ts) const
+// returns a cursor which always has the complete selection
+QTextCursor BaseTextBlockSelection::selection(const BaseTextDocument *baseTextDocument) 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);
+ return cursor(baseTextDocument, true);
}
-QTextCursor BaseTextBlockSelection::selection(const TabSettings &ts) const
+// returns a cursor which always has the correct position and anchor
+QTextCursor BaseTextBlockSelection::cursor(const BaseTextDocument *baseTextDocument) const
{
- QTextCursor cursor = firstBlock;
- if (anchor <= TopRight) {
- cursor.setPosition(lastBlock.block().position() + ts.positionAtColumn(lastBlock.block().text(), lastVisualColumn));
- cursor.setPosition(firstBlock.block().position() + ts.positionAtColumn(firstBlock.block().text(), firstVisualColumn),
- QTextCursor::KeepAnchor);
+ return cursor(baseTextDocument, false);
+}
+
+QTextCursor BaseTextBlockSelection::cursor(const BaseTextDocument *baseTextDocument,
+ bool fullSelection) const
+{
+ if (!baseTextDocument)
+ return QTextCursor();
+ QTextDocument *document = baseTextDocument->document();
+ const TabSettings &ts = baseTextDocument->tabSettings();
+
+ int selectionAnchorColumn;
+ int selectionPositionColumn;
+ if (anchorBlock == positionBlock || !fullSelection) {
+ selectionAnchorColumn = anchorColumn;
+ selectionPositionColumn = positionColumn;
+ } else if (anchorBlock == firstBlockNumber()){
+ selectionAnchorColumn = firstVisualColumn();
+ selectionPositionColumn = lastVisualColumn();
} else {
- cursor.setPosition(firstBlock.block().position() + ts.positionAtColumn(firstBlock.block().text(), firstVisualColumn));
- cursor.setPosition(lastBlock.block().position() + ts.positionAtColumn(lastBlock.block().text(), lastVisualColumn),
- QTextCursor::KeepAnchor);
+ selectionAnchorColumn = lastVisualColumn();
+ selectionPositionColumn = firstVisualColumn();
}
+
+ QTextCursor cursor(document);
+
+ const QTextBlock &anchorTextBlock = document->findBlockByNumber(anchorBlock);
+ const int anchorPosition = anchorTextBlock.position()
+ + ts.positionAtColumn(anchorTextBlock.text(), selectionAnchorColumn);
+
+ const QTextBlock &positionTextBlock = document->findBlockByNumber(positionBlock);
+ const int cursorPosition = positionTextBlock.position()
+ + ts.positionAtColumn(positionTextBlock.text(), selectionPositionColumn);
+
+ cursor.setPosition(anchorPosition);
+ cursor.setPosition(cursorPosition, QTextCursor::KeepAnchor);
return cursor;
}
-void BaseTextBlockSelection::fromSelection(const TabSettings &ts, const QTextCursor &selection)
+void BaseTextBlockSelection::fromPostition(int positionBlock, int positionColumn,
+ int anchorBlock, int anchorColumn)
{
- firstBlock = selection;
- firstBlock.setPosition(selection.selectionStart());
- firstVisualColumn = ts.columnAt(firstBlock.block().text(), firstBlock.positionInBlock());
- lastBlock = selection;
- lastBlock.setPosition(selection.selectionEnd());
- lastVisualColumn = ts.columnAt(lastBlock.block().text(), lastBlock.positionInBlock());
- if (selection.anchor() > selection.position())
- anchor = TopLeft;
- else
- anchor = BottomRight;
-
- firstBlock.movePosition(QTextCursor::StartOfBlock);
- lastBlock.movePosition(QTextCursor::EndOfBlock);
+ this->positionBlock = positionBlock;
+ this->positionColumn = positionColumn;
+ this->anchorBlock = anchorBlock;
+ this->anchorColumn = anchorColumn;
}
+
bool BaseTextEditorWidget::inFindScope(const QTextCursor &cursor)
{
if (cursor.isNull())
@@ -6261,38 +6479,31 @@ void BaseTextEditorWidget::setBlockSelection(bool on)
if (d->m_inBlockSelectionMode == on)
return;
- d->m_inBlockSelectionMode = on;
if (on)
- d->m_blockSelection.fromSelection(d->m_document->tabSettings(), textCursor());
- viewport()->update();
+ d->enableBlockSelection(textCursor());
+ else
+ d->disableBlockSelection(false);
}
-bool BaseTextEditorWidget::hasBlockSelection() const
+void BaseTextEditorWidget::setBlockSelection(int positionBlock, int positionColumn,
+ int anchhorBlock, int anchorColumn)
{
- return d->m_inBlockSelectionMode;
+ d->enableBlockSelection(positionBlock, positionColumn, anchhorBlock, anchorColumn);
}
-void BaseTextEditorWidget::handleBlockSelection(int diff_row, int diff_col)
+void BaseTextEditorWidget::setBlockSelection(const QTextCursor &cursor)
{
+ d->enableBlockSelection(cursor);
+}
- if (!d->m_inBlockSelectionMode) {
- d->m_blockSelection.fromSelection(d->m_document->tabSettings(), textCursor());
- d->m_inBlockSelectionMode = true;
- }
-
- d->m_blockSelection.moveAnchor(d->m_blockSelection.anchorBlockNumber() + diff_row,
- d->m_blockSelection.anchorColumnNumber() + diff_col);
- setTextCursor(d->m_blockSelection.selection(d->m_document->tabSettings()));
-
- viewport()->update();
-
-// ### TODO ensure horizontal visibility
-// const bool rtl = q->isRightToLeft();
-// if (cr.left() < visible.left() || cr.right() > visible.right()) {
-// int x = cr.center().x() + horizontalOffset() - visible.width()/2;
-// hbar->setValue(rtl ? hbar->maximum() - x : x);
-// }
+QTextCursor BaseTextEditorWidget::blockSelection() const
+{
+ return d->m_blockSelection.cursor(d->m_document.data());
+}
+bool BaseTextEditorWidget::hasBlockSelection() const
+{
+ return d->m_inBlockSelectionMode;
}
void BaseTextEditorWidget::updateTabStops()
@@ -6365,22 +6576,24 @@ void BaseTextEditorWidget::transformBlockSelection(TransformationMethod 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;
+ const int positionColumn = d->m_blockSelection.positionColumn;
+ const int positionBlock = d->m_blockSelection.positionBlock;
+ const int anchorColumn = d->m_blockSelection.anchorColumn;
+ const int anchorBlock = d->m_blockSelection.anchorBlock;
- QTextBlock block = d->m_blockSelection.firstBlock.block();
- const QTextBlock &lastBlock = d->m_blockSelection.lastBlock.block();
+ QTextBlock block = d->m_document->document()->findBlockByNumber(
+ d->m_blockSelection.firstBlockNumber());
+ const QTextBlock &lastBlock = d->m_document->document()->findBlockByNumber(
+ d->m_blockSelection.lastBlockNumber());
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);
+ + ts.positionAtColumn(blockText, d->m_blockSelection.firstVisualColumn());
const int endPos = block.position()
- + ts.positionAtColumn(blockText, d->m_blockSelection.lastVisualColumn);
+ + ts.positionAtColumn(blockText, d->m_blockSelection.lastVisualColumn());
// check if the selection is inside the text block
if (startPos < endPos) {
@@ -6397,13 +6610,7 @@ void BaseTextEditorWidget::transformBlockSelection(TransformationMethod method)
cursor.endEditBlock();
// restore former block selection
- cursor.setPosition(selectionPosition, QTextCursor::MoveAnchor);
- d->m_inBlockSelectionMode = true;
- 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();
+ d->enableBlockSelection(positionBlock, anchorColumn, anchorBlock, positionColumn);
}
void BaseTextEditorWidget::inSnippetMode(bool *active)
diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h
index 5d37e0c3b8..18b8bfb250 100644
--- a/src/plugins/texteditor/basetexteditor.h
+++ b/src/plugins/texteditor/basetexteditor.h
@@ -206,11 +206,16 @@ public:
void setReadOnly(bool b);
+ void setTextCursor(const QTextCursor &cursor, bool keepBlockSelection);
void setTextCursor(const QTextCursor &cursor);
void insertCodeSnippet(const QTextCursor &cursor, const QString &snippet);
void setBlockSelection(bool on);
+ void setBlockSelection(int positionBlock, int positionColumn, int anchhorBlock,
+ int anchorColumn);
+ void setBlockSelection(const QTextCursor &cursor);
+ QTextCursor blockSelection() const;
bool hasBlockSelection() const;
int verticalBlockSelectionFirstColumn() const;
@@ -231,6 +236,9 @@ public:
static QString msgTextTooLarge(quint64 size);
+ void insertPlainText(const QString &text);
+ QString selectedText() const;
+
public slots:
virtual void copy();
virtual void paste();
@@ -310,6 +318,9 @@ public slots:
void indent();
void unindent();
+ void undo();
+ void redo();
+
void openLinkUnderCursor();
void openLinkUnderCursorInNextSplit();
@@ -322,6 +333,7 @@ signals:
protected:
bool event(QEvent *e);
+ void inputMethodEvent(QInputMethodEvent *e);
void keyPressEvent(QKeyEvent *e);
void wheelEvent(QWheelEvent *e);
void changeEvent(QEvent *e);
@@ -549,7 +561,6 @@ private:
void transformBlockSelection(Internal::TransformationMethod method);
private slots:
- void handleBlockSelection(int diff_row, int diff_col);
void updateTabStops();
void applyFontSettingsDelayed();
diff --git a/src/plugins/texteditor/basetexteditor_p.h b/src/plugins/texteditor/basetexteditor_p.h
index 0748e0141d..1e69b3525e 100644
--- a/src/plugins/texteditor/basetexteditor_p.h
+++ b/src/plugins/texteditor/basetexteditor_p.h
@@ -59,23 +59,34 @@ class ClipboardAssistProvider;
class TEXTEDITOR_EXPORT BaseTextBlockSelection
{
public:
+ BaseTextBlockSelection()
+ : positionBlock(0), positionColumn(0)
+ , anchorBlock(0) , anchorColumn(0){}
+ BaseTextBlockSelection(const BaseTextBlockSelection &other);
+
+ void clear();
+ QTextCursor selection(const BaseTextDocument *baseTextDocument) const;
+ QTextCursor cursor(const BaseTextDocument *baseTextDocument) const;
+ void fromPostition(int positionBlock, int positionColumn, int anchorBlock, int anchorColumn);
+ bool hasSelection() { return !(positionBlock == anchorBlock && positionColumn == anchorColumn); }
+
+ // defines the first block
+ inline int firstBlockNumber() const { return qMin(positionBlock, anchorBlock); }
+ // defines the last block
+ inline int lastBlockNumber() const { return qMax(positionBlock, anchorBlock); }
+ // defines the first visual column of the selection
+ inline int firstVisualColumn() const { return qMin(positionColumn, anchorColumn); }
+ // defines the last visual column of the selection
+ inline int lastVisualColumn() const { return qMax(positionColumn, anchorColumn); }
- bool isValid() const{ return !firstBlock.isNull() && !lastBlock.isNull(); }
- void clear() { firstBlock = lastBlock = QTextCursor(); }
-
- QTextCursor firstBlock; // defines the first block
- QTextCursor lastBlock; // defines the last block
- int firstVisualColumn; // defines the first visual column of the selection
- int lastVisualColumn; // defines the last visual column of the selection
- 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()); }
- QTextCursor selection(const TabSettings &ts) const;
- void fromSelection(const TabSettings &ts, const QTextCursor &selection);
+public:
+ int positionBlock;
+ int positionColumn;
+ int anchorBlock;
+ int anchorColumn;
+
+private:
+ QTextCursor cursor(const BaseTextDocument *baseTextDocument, bool fullSelection) const;
};
//================BaseTextEditorPrivate==============
@@ -180,9 +191,18 @@ public:
// block selection mode
bool m_inBlockSelectionMode;
- void clearBlockSelection();
QString copyBlockSelection();
- void removeBlockSelection(const QString &text = QString());
+ void insertIntoBlockSelection(const QString &text = QString());
+ void setCursorToColumn(QTextCursor &cursor, int column,
+ QTextCursor::MoveMode moveMode = QTextCursor::MoveAnchor);
+ void removeBlockSelection();
+ void enableBlockSelection(const QTextCursor &cursor);
+ void enableBlockSelection(int positionBlock, int positionColumn,
+ int anchorBlock, int anchorColumn);
+ void disableBlockSelection(bool keepSelection = true);
+ void resetCursorFlashTimer();
+ QBasicTimer m_cursorFlashTimer;
+ bool m_cursorVisible;
bool m_moveLineUndoHack;
QTextCursor m_findScopeStart;
diff --git a/src/plugins/texteditor/basetexteditor_test.cpp b/src/plugins/texteditor/basetexteditor_test.cpp
index de296bab66..077a97d095 100644
--- a/src/plugins/texteditor/basetexteditor_test.cpp
+++ b/src/plugins/texteditor/basetexteditor_test.cpp
@@ -29,6 +29,7 @@
#ifdef WITH_TESTS
+#include <QClipboard>
#include <QString>
#include <QtTest/QtTest>
@@ -42,80 +43,99 @@ using namespace TextEditor;
enum TransFormationType { Uppercase, Lowercase };
+struct TestBlockSelection
+{
+ int positionBlock;
+ int positionColumn;
+ int anchorBlock;
+ int anchorColumn;
+ TestBlockSelection(int positionBlock, int positionColumn, int anchorBlock, int anchorColumn)
+ : positionBlock(positionBlock), positionColumn(positionColumn)
+ , anchorBlock(anchorBlock), anchorColumn(anchorColumn) {}
+ TestBlockSelection() {}
+};
+
Q_DECLARE_METATYPE(TransFormationType)
+Q_DECLARE_METATYPE(TestBlockSelection)
void Internal::TextEditorPlugin::testBlockSelectionTransformation_data()
{
- QTest::addColumn<QByteArray>("input");
- QTest::addColumn<QByteArray>("transformedText");
- QTest::addColumn<int>("position");
- QTest::addColumn<int>("anchor");
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<QString>("transformedText");
+ QTest::addColumn<TestBlockSelection>("selection");
QTest::addColumn<TransFormationType>("type");
QTest::newRow("uppercase")
- << QByteArray("aaa\nbbb\nccc\n")
- << QByteArray("aAa\nbBb\ncCc\n")
- << 10 << 1 << Uppercase;
+ << QString::fromLatin1("aaa\nbbb\nccc\n")
+ << QString::fromLatin1("aAa\nbBb\ncCc\n")
+ << TestBlockSelection(0, 1, 2, 2)
+ << Uppercase;
QTest::newRow("lowercase")
- << QByteArray("AAA\nBBB\nCCC\n")
- << QByteArray("AaA\nBbB\nCcC\n")
- << 10 << 1 << Lowercase;
+ << QString::fromLatin1("AAA\nBBB\nCCC\n")
+ << QString::fromLatin1("AaA\nBbB\nCcC\n")
+ << TestBlockSelection(0, 1, 2, 2)
+ << Lowercase;
QTest::newRow("uppercase_leading_tabs")
- << QByteArray("\taaa\n\tbbb\n\tccc\n")
- << QByteArray("\taAa\n\tbBb\n\tcCc\n")
- << 13 << 2 << Uppercase;
+ << QString::fromLatin1("\taaa\n" "\tbbb\n" "\tccc\n")
+ << QString::fromLatin1("\taAa\n" "\tbBb\n" "\tcCc\n")
+ << TestBlockSelection(0, 9, 2, 10)
+ << Uppercase;
QTest::newRow("lowercase_leading_tabs")
- << QByteArray("\tAAA\n\tBBB\n\tCCC\n")
- << QByteArray("\tAaA\n\tBbB\n\tCcC\n")
- << 13 << 2 << Lowercase;
+ << QString::fromLatin1("\tAAA\n\tBBB\n\tCCC\n")
+ << QString::fromLatin1("\tAaA\n\tBbB\n\tCcC\n")
+ << TestBlockSelection(0, 9, 2, 10)
+ << Lowercase;
QTest::newRow("uppercase_mixed_leading_whitespace")
- << QByteArray("\taaa\n bbbbb\n ccccc\n")
- << QByteArray("\tAaa\n bbbbB\n ccccC\n")
- << 24 << 1 << Uppercase;
+ << QString::fromLatin1("\taaa\n bbbbb\n ccccc\n")
+ << QString::fromLatin1("\tAaa\n bbbbB\n ccccC\n")
+ << TestBlockSelection(0, 8, 2, 9)
+ << Uppercase;
QTest::newRow("lowercase_mixed_leading_whitespace")
- << QByteArray("\tAAA\n BBBBB\n CCCCC\n")
- << QByteArray("\taAA\n BBBBb\n CCCCc\n")
- << 24 << 1 << Lowercase;
+ << QString::fromLatin1("\tAAA\n BBBBB\n CCCCC\n")
+ << QString::fromLatin1("\taAA\n BBBBb\n CCCCc\n")
+ << TestBlockSelection(0, 8, 2, 9)
+ << Lowercase;
QTest::newRow("uppercase_mid_tabs1")
- << QByteArray("a\ta\nbbbbbbbbb\nccccccccc\n")
- << QByteArray("a\ta\nbBBBBBbbb\ncCCCCCccc\n")
- << 20 << 1 << Uppercase;
+ << QString::fromLatin1("a\ta\nbbbbbbbbb\nccccccccc\n")
+ << QString::fromLatin1("a\ta\nbBBBBBbbb\ncCCCCCccc\n")
+ << TestBlockSelection(0, 1, 2, 6)
+ << 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;
+ << QString::fromLatin1("AA\taa\n\t\t\nccccCCCCCC\n")
+ << QString::fromLatin1("Aa\taa\n\t\t\ncccccccccC\n")
+ << TestBlockSelection(0, 1, 2, 9)
+ << Lowercase;
QTest::newRow("uppercase_over_line_ending")
- << QByteArray("aaaaa\nbbb\nccccc\n")
- << QByteArray("aAAAa\nbBB\ncCCCc\n")
- << 14 << 1 << Uppercase;
+ << QString::fromLatin1("aaaaa\nbbb\nccccc\n")
+ << QString::fromLatin1("aAAAa\nbBB\ncCCCc\n")
+ << TestBlockSelection(0, 1, 2, 4)
+ << Uppercase;
QTest::newRow("lowercase_over_line_ending")
- << QByteArray("AAAAA\nBBB\nCCCCC\n")
- << QByteArray("AaaaA\nBbb\nCcccC\n")
- << 14 << 1 << Lowercase;
+ << QString::fromLatin1("AAAAA\nBBB\nCCCCC\n")
+ << QString::fromLatin1("AaaaA\nBbb\nCcccC\n")
+ << TestBlockSelection(0, 1, 2, 4)
+ << Lowercase;
}
void Internal::TextEditorPlugin::testBlockSelectionTransformation()
{
// fetch test data
- QFETCH(QByteArray, input);
- QFETCH(QByteArray, transformedText);
- QFETCH(int, position);
- QFETCH(int, anchor);
+ QFETCH(QString, input);
+ QFETCH(QString, transformedText);
+ QFETCH(TestBlockSelection, selection);
QFETCH(TransFormationType, type);
// open editor
Core::IEditor *editor = Core::EditorManager::openEditorWithContents(
- Core::Constants::K_DEFAULT_TEXT_EDITOR_ID, 0, input);
+ Core::Constants::K_DEFAULT_TEXT_EDITOR_ID, 0, input.toLatin1());
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);
+ editorWidget->setBlockSelection(selection.positionBlock,
+ selection.positionColumn,
+ selection.anchorBlock,
+ selection.anchorColumn);
+ editorWidget->update();
// transform blockselection
switch (type) {
@@ -126,9 +146,355 @@ void Internal::TextEditorPlugin::testBlockSelectionTransformation()
editorWidget->lowercaseSelection();
break;
}
- QCOMPARE(textEditor->baseTextDocument()->plainText().toLatin1(), transformedText);
- } else {
+ QCOMPARE(textEditor->baseTextDocument()->plainText(), transformedText);
+ }
+ Core::EditorManager::closeEditor(editor, false);
+}
+
+static const char text[] =
+ "first line\n"
+ "second line\n"
+ "third line\n"
+ "\n"
+ "longest line in this text\n"
+ " leading space\n"
+ "" "\tleading tab\n"
+ "mid\t" "tab\n"
+ "endtab\t\n";
+
+void Internal::TextEditorPlugin::testBlockSelectionInsert_data()
+{
+ QTest::addColumn<QString>("transformedText");
+ QTest::addColumn<TestBlockSelection>("selection");
+ QTest::addColumn<QString>("insertText");
+
+ QTest::newRow("insert")
+ << QString::fromLatin1(".first line\n"
+ ".second line\n"
+ ".third line\n"
+ "\n"
+ "longest line in this text\n"
+ " leading space\n"
+ "" "\tleading tab\n"
+ "mid\t" "tab\n"
+ "endtab\t\n")
+ << TestBlockSelection(0, 0, 2, 0)
+ << QString::fromLatin1(".");
+ QTest::newRow("insert after line end 1")
+ << QString::fromLatin1("first line\n"
+ "second line\n"
+ "third. line\n"
+ " .\n"
+ "longe.st line in this text\n"
+ " leading space\n"
+ "" "\tleading tab\n"
+ "mid\t" "tab\n"
+ "endtab\t\n")
+ << TestBlockSelection(2, 5, 4, 5)
+ << QString::fromLatin1(".");
+ QTest::newRow("insert after line end 2")
+ << QString::fromLatin1("first line .\n"
+ "second line .\n"
+ "third line .\n"
+ " .\n"
+ "longest line in this text .\n"
+ " leading space .\n"
+ "" "\tleading tab .\n"
+ "mid\t" "tab .\n"
+ "endtab\t .\n")
+ << TestBlockSelection(0, 32, 8, 32)
+ << QString::fromLatin1(".");
+ QTest::newRow("insert in leading tab")
+ << QString::fromLatin1("first line\n"
+ "second line\n"
+ "third line\n"
+ "\n"
+ "lo.ngest line in this text\n"
+ " . leading space\n"
+ " . leading tab\n"
+ "mid\t" "tab\n"
+ "endtab\t\n")
+ << TestBlockSelection(4, 2, 6, 2)
+ << QString::fromLatin1(".");
+ QTest::newRow("insert in middle tab")
+ << QString::fromLatin1("first line\n"
+ "second line\n"
+ "third line\n"
+ "\n"
+ "longest line in this text\n"
+ " leading space\n"
+ " . leading tab\n"
+ "mid . tab\n"
+ "endta.b\t\n")
+
+ << TestBlockSelection(6, 5, 8, 5)
+ << QString::fromLatin1(".");
+ QTest::newRow("insert same block count with all blocks same length")
+ << QString::fromLatin1(".first line\n"
+ ".second line\n"
+ ".third line\n"
+ "\n"
+ "longest line in this text\n"
+ " leading space\n"
+ "" "\tleading tab\n"
+ "mid\t" "tab\n"
+ "endtab\t\n")
+ << TestBlockSelection(0, 0, 2, 0)
+ << QString::fromLatin1(".\n.\n.");
+ QTest::newRow("insert same block count with all blocks different length")
+ << QString::fromLatin1(". first line\n"
+ ".. second line\n"
+ "...third line\n"
+ "\n"
+ "longest line in this text\n"
+ " leading space\n"
+ "" "\tleading tab\n"
+ "mid\t" "tab\n"
+ "endtab\t\n")
+ << TestBlockSelection(0, 0, 2, 0)
+ << QString::fromLatin1(".\n..\n...");
+ QTest::newRow("insert same block count with some blocks containing tabs")
+ << QString::fromLatin1(". first line\n"
+ ".\t second line\n"
+ ".\t.third line\n"
+ "\n"
+ "longest line in this text\n"
+ " leading space\n"
+ "" "\tleading tab\n"
+ "mid\t" "tab\n"
+ "endtab\t\n")
+ << TestBlockSelection(0, 0, 2, 0)
+ << QString::fromLatin1(".\n.\t\n.\t.");
+ QTest::newRow("insert same block count with some blocks containing tabs in mid line")
+ << QString::fromLatin1("fi. rst line\n"
+ "se.\t cond line\n"
+ "th.\t.ird line\n"
+ "\n"
+ "longest line in this text\n"
+ " leading space\n"
+ "" "\tleading tab\n"
+ "mid\t" "tab\n"
+ "endtab\t\n")
+ << TestBlockSelection(0, 2, 2, 2)
+ << QString::fromLatin1(".\n.\t\n.\t.");
+ QTest::newRow("insert different block count with all blocks same length")
+ << QString::fromLatin1(".first line\n"
+ ".\n"
+ ".second line\n"
+ ".\n"
+ ".third line\n"
+ ".\n"
+ "\n"
+ "longest line in this text\n"
+ " leading space\n"
+ "" "\tleading tab\n"
+ "mid\t" "tab\n"
+ "endtab\t\n")
+ << TestBlockSelection(0, 0, 2, 0)
+ << QString::fromLatin1(".\n.");
+ QTest::newRow("insert different block count with all blocks different length")
+ << QString::fromLatin1(". first line\n"
+ "..\n"
+ ". second line\n"
+ "..\n"
+ ". third line\n"
+ "..\n"
+ "\n"
+ "longest line in this text\n"
+ " leading space\n"
+ "" "\tleading tab\n"
+ "mid\t" "tab\n"
+ "endtab\t\n")
+ << TestBlockSelection(0, 0, 2, 0)
+ << QString::fromLatin1(".\n..");
+ QTest::newRow("insert different block count with some blocks containing tabs")
+ << QString::fromLatin1(". first line\n"
+ ".\t \n"
+ ".\t.\n"
+ ". second line\n"
+ ".\t \n"
+ ".\t.\n"
+ "third line\n"
+ "\n"
+ "longest line in this text\n"
+ " leading space\n"
+ "" "\tleading tab\n"
+ "mid\t" "tab\n"
+ "endtab\t\n")
+ << TestBlockSelection(0, 0, 1, 0)
+ << QString::fromLatin1(".\n.\t\n.\t.");
+ QTest::newRow("insert different block count with some blocks containing tabs in mid line")
+ << QString::fromLatin1("fi. rst line\n"
+ " .\t \n"
+ " .\t.\n"
+ "se. cond line\n"
+ " .\t \n"
+ " .\t.\n"
+ "third line\n"
+ "\n"
+ "longest line in this text\n"
+ " leading space\n"
+ "" "\tleading tab\n"
+ "mid\t" "tab\n"
+ "endtab\t\n")
+ << TestBlockSelection(0, 2, 1, 2)
+ << QString::fromLatin1(".\n.\t\n.\t.");
+}
+
+void Internal::TextEditorPlugin::testBlockSelectionInsert()
+{
+ // fetch test data
+ QFETCH(QString, transformedText);
+ QFETCH(TestBlockSelection, selection);
+ QFETCH(QString, insertText);
+
+ // open editor
+ Core::IEditor *editor = Core::EditorManager::openEditorWithContents(
+ Core::Constants::K_DEFAULT_TEXT_EDITOR_ID, 0, text);
+ QVERIFY(editor);
+ if (BaseTextEditor *textEditor = qobject_cast<BaseTextEditor*>(editor)) {
+ BaseTextEditorWidget *editorWidget = textEditor->editorWidget();
+ editorWidget->setBlockSelection(selection.positionBlock,
+ selection.positionColumn,
+ selection.anchorBlock,
+ selection.anchorColumn);
+ editorWidget->update();
+ editorWidget->insertPlainText(insertText);
+
+ QCOMPARE(textEditor->baseTextDocument()->plainText(), transformedText);
+ }
+ Core::EditorManager::closeEditor(editor, false);
+}
+
+
+void Internal::TextEditorPlugin::testBlockSelectionRemove_data()
+{
+ QTest::addColumn<QString>("transformedText");
+ QTest::addColumn<TestBlockSelection>("selection");
+ QTest::newRow("Delete")
+ << QString::fromLatin1("first ine\n"
+ "second ine\n"
+ "third ine\n"
+ "\n"
+ "longest line in this text\n"
+ " leading space\n"
+ "" "\tleading tab\n"
+ "mid\t" "tab\n"
+ "endtab\t\n")
+ << TestBlockSelection(0, 7, 2, 8);
+ QTest::newRow("Delete All")
+ << QString::fromLatin1("\n\n\n\n\n\n\n\n\n")
+ << TestBlockSelection(0, 0, 8, 30);
+ QTest::newRow("Delete Inside Tab")
+ << QString::fromLatin1("first line\n"
+ "second line\n"
+ "third line\n"
+ "\n"
+ "longest line in this text\n"
+ " leading space\n"
+ " leading tab\n"
+ "mi\t" "tab\n"
+ "endtab\t\n")
+ << TestBlockSelection(5, 2, 7, 3);
+ QTest::newRow("Delete around Tab")
+ << QString::fromLatin1("first line\n"
+ "second line\n"
+ "third line\n"
+ "\n"
+ "longest line in this text\n"
+ " ng space\n"
+ " eading tab\n"
+ "miab\n"
+ "endtab\t\n")
+ << TestBlockSelection(5, 2, 7, 9);
+ QTest::newRow("Delete behind text")
+ << QString::fromLatin1("first line\n"
+ "second line\n"
+ "third line\n"
+ "\n"
+ "longest line in this text\n"
+ " leading space\n"
+ "" "\tleading tab\n"
+ "mid\t" "tab\n"
+ "endtab\t\n")
+ << TestBlockSelection(0, 30, 8, 35);
+}
+
+void Internal::TextEditorPlugin::testBlockSelectionRemove()
+{
+ // fetch test data
+ QFETCH(QString, transformedText);
+ QFETCH(TestBlockSelection, selection);
+
+ // open editor
+ Core::IEditor *editor = Core::EditorManager::openEditorWithContents(
+ Core::Constants::K_DEFAULT_TEXT_EDITOR_ID, 0, text);
+ QVERIFY(editor);
+ if (BaseTextEditor *textEditor = qobject_cast<BaseTextEditor*>(editor)) {
+ BaseTextEditorWidget *editorWidget = textEditor->editorWidget();
+ editorWidget->setBlockSelection(selection.positionBlock,
+ selection.positionColumn,
+ selection.anchorBlock,
+ selection.anchorColumn);
+ editorWidget->update();
+ editorWidget->insertPlainText(QString());
+
+ QCOMPARE(textEditor->baseTextDocument()->plainText(), transformedText);
+ }
+ Core::EditorManager::closeEditor(editor, false);
+}
+
+void Internal::TextEditorPlugin::testBlockSelectionCopy_data()
+{
+ QTest::addColumn<QString>("copiedText");
+ QTest::addColumn<TestBlockSelection>("selection");
+ QTest::newRow("copy")
+ << QString::fromLatin1("lin\n"
+ "lin\n"
+ "lin")
+ << TestBlockSelection(0, 7, 2, 10);
+ QTest::newRow("copy over line end")
+ << QString::fromLatin1("ond line \n"
+ "rd line \n"
+ " ")
+ << TestBlockSelection(1, 3, 3, 15);
+ QTest::newRow("copy inside tab")
+ << QString::fromLatin1("ond line \n"
+ "rd line \n"
+ " ")
+ << TestBlockSelection(1, 3, 3, 15);
+ QTest::newRow("copy start in tab")
+ << QString::fromLatin1("gest lin\n"
+ " leading\n"
+ " lea")
+ << TestBlockSelection(4, 3, 6, 11);
+ QTest::newRow("copy around tab")
+ << QString::fromLatin1(" leadin\n"
+ " le\n"
+ "d\tta")
+ << TestBlockSelection(5, 2, 7, 10);
+}
+
+void Internal::TextEditorPlugin::testBlockSelectionCopy()
+{
+ // fetch test data
+ QFETCH(QString, copiedText);
+ QFETCH(TestBlockSelection, selection);
+
+ // open editor
+ Core::IEditor *editor = Core::EditorManager::openEditorWithContents(
+ Core::Constants::K_DEFAULT_TEXT_EDITOR_ID, 0, text);
+ QVERIFY(editor);
+ if (BaseTextEditor *textEditor = qobject_cast<BaseTextEditor*>(editor)) {
+ BaseTextEditorWidget *editorWidget = textEditor->editorWidget();
+ editorWidget->setBlockSelection(selection.positionBlock,
+ selection.positionColumn,
+ selection.anchorBlock,
+ selection.anchorColumn);
+ editorWidget->update();
+ editorWidget->copy();
+ QCOMPARE(qApp->clipboard()->text(), copiedText);
}
Core::EditorManager::closeEditor(editor, false);
}
diff --git a/src/plugins/texteditor/codeassist/codeassistant.cpp b/src/plugins/texteditor/codeassist/codeassistant.cpp
index 58caa1e4ab..c4b8ac0d07 100644
--- a/src/plugins/texteditor/codeassist/codeassistant.cpp
+++ b/src/plugins/texteditor/codeassist/codeassistant.cpp
@@ -248,6 +248,9 @@ void CodeAssistantPrivate::requestProposal(AssistReason reason,
{
QTC_ASSERT(!isWaitingForProposal(), return);
+ if (m_textEditor->editorWidget()->hasBlockSelection())
+ return; // TODO
+
if (!provider) {
if (kind == Completion)
provider = m_completionProvider;
diff --git a/src/plugins/texteditor/tabsettings.cpp b/src/plugins/texteditor/tabsettings.cpp
index be09d8cbde..bb3ce677b1 100644
--- a/src/plugins/texteditor/tabsettings.cpp
+++ b/src/plugins/texteditor/tabsettings.cpp
@@ -213,6 +213,18 @@ int TabSettings::positionAtColumn(const QString &text, int column, int *offset)
return i;
}
+int TabSettings::columnCountForText(const QString &text, int startColumn) const
+{
+ int column = startColumn;
+ for (int i = 0; i < text.size(); ++i) {
+ if (text.at(i) == QLatin1Char('\t'))
+ column = column - (column % m_tabSize) + m_tabSize;
+ else
+ ++column;
+ }
+ return column - startColumn;
+}
+
int TabSettings::spacesLeftFromPosition(const QString &text, int position)
{
int i = position;
diff --git a/src/plugins/texteditor/tabsettings.h b/src/plugins/texteditor/tabsettings.h
index c8836a25ef..0dfdb7cd26 100644
--- a/src/plugins/texteditor/tabsettings.h
+++ b/src/plugins/texteditor/tabsettings.h
@@ -70,6 +70,7 @@ public:
int lineIndentPosition(const QString &text) const;
int columnAt(const QString &text, int position) const;
int positionAtColumn(const QString &text, int column, int *offset = 0) const;
+ int columnCountForText(const QString &text, int startColumn = 0) const;
int indentedColumn(int column, bool doIndent = true) const;
QString indentationString(int startColumn, int targetColumn, const QTextBlock &currentBlock = QTextBlock()) const;
QString indentationString(const QString &text) const;
diff --git a/src/plugins/texteditor/texteditorplugin.h b/src/plugins/texteditor/texteditorplugin.h
index 895a08c628..db057c7c84 100644
--- a/src/plugins/texteditor/texteditorplugin.h
+++ b/src/plugins/texteditor/texteditorplugin.h
@@ -73,14 +73,6 @@ private slots:
void updateVariable(const QByteArray &variable);
void updateCurrentSelection(const QString &text);
-#ifdef WITH_TESTS
- void testSnippetParsing_data();
- void testSnippetParsing();
-
- void testBlockSelectionTransformation_data();
- void testBlockSelectionTransformation();
-#endif
-
private:
static TextEditorPlugin *m_instance;
TextEditorSettings *m_settings;
@@ -89,6 +81,23 @@ private:
Core::SearchResultWindow *m_searchResultWindow;
OutlineFactory *m_outlineFactory;
BaseTextMarkRegistry *m_baseTextMarkRegistry;
+
+
+#ifdef WITH_TESTS
+private slots:
+ void testSnippetParsing_data();
+ void testSnippetParsing();
+
+ void testBlockSelectionTransformation_data();
+ void testBlockSelectionTransformation();
+ void testBlockSelectionInsert_data();
+ void testBlockSelectionInsert();
+ void testBlockSelectionRemove_data();
+ void testBlockSelectionRemove();
+ void testBlockSelectionCopy_data();
+ void testBlockSelectionCopy();
+#endif
+
};
} // namespace Internal