forked from qt-creator/qt-creator
TextEditor: Duplicate selection (Duplicate selection and comment)
New TextEditor action for duplicating current selection. Extended version of this feature creates commented duplications. Possible use cases: 1. No selection, cursor anywhere in text - Duplicity line 2. Simple selection - Duplicity selection 3. Block selection, without columns - Duplicity lines 4. Block selection, with columns - Duplicity selection Cursor position and selection stays unchanged. Works well with Undo action. First use case with no selection looks similar as copyLineDown, but difference is that copyLineDown moves current cursor position and select created line. This feature don't change cursor position. Because of this difference it is not possible to integrate this additions with copyLineDown. Quick intro: https://youtu.be/Fv6WdCnCLpo Change-Id: I7c36fca6e17de030cbd22cfa103c2ed672deabbc Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -256,6 +256,8 @@ public:
|
||||
void print(QPrinter *printer);
|
||||
|
||||
void maybeSelectLine();
|
||||
void duplicateSelection(bool comment);
|
||||
void duplicateBlockSelection(bool comment);
|
||||
void updateCannotDecodeInfo();
|
||||
void collectToCircularClipboard();
|
||||
|
||||
@@ -6165,6 +6167,128 @@ void TextEditorWidget::copyLine()
|
||||
copy();
|
||||
}
|
||||
|
||||
void TextEditorWidgetPrivate::duplicateSelection(bool comment)
|
||||
{
|
||||
if (m_inBlockSelectionMode) {
|
||||
duplicateBlockSelection(comment);
|
||||
return;
|
||||
}
|
||||
|
||||
QTextCursor cursor = q->textCursor();
|
||||
|
||||
if (cursor.hasSelection()) {
|
||||
|
||||
// Cannot "duplicate and comment" files without multi-line comment
|
||||
if (comment && !m_commentDefinition.hasMultiLineStyle())
|
||||
return;
|
||||
|
||||
QString dupText = cursor.selectedText().replace(QChar::ParagraphSeparator, QLatin1Char('\n'));
|
||||
if (comment)
|
||||
dupText = (m_commentDefinition.multiLineStart + dupText + m_commentDefinition.multiLineEnd);
|
||||
const int selStart = cursor.selectionStart();
|
||||
const int selEnd = cursor.selectionEnd();
|
||||
const bool cursorAtStart = (cursor.position() == selStart);
|
||||
cursor.setPosition(selEnd);
|
||||
cursor.insertText(dupText);
|
||||
cursor.setPosition(cursorAtStart ? selEnd : selStart);
|
||||
cursor.setPosition(cursorAtStart ? selStart : selEnd, QTextCursor::KeepAnchor);
|
||||
} else {
|
||||
const int curPos = cursor.position();
|
||||
const QTextBlock &block = cursor.block();
|
||||
QString dupText = block.text() + QLatin1Char('\n');
|
||||
if (comment && m_commentDefinition.hasSingleLineStyle())
|
||||
dupText.append(m_commentDefinition.singleLine);
|
||||
cursor.setPosition(block.position());
|
||||
cursor.insertText(dupText);
|
||||
cursor.setPosition(curPos);
|
||||
}
|
||||
q->setTextCursor(cursor);
|
||||
}
|
||||
|
||||
void TextEditorWidgetPrivate::duplicateBlockSelection(bool comment)
|
||||
{
|
||||
QTextCursor cursor = q->textCursor();
|
||||
|
||||
const TextBlockSelection curSel = m_blockSelection;
|
||||
|
||||
if (curSel.positionColumn == curSel.anchorColumn) {
|
||||
// No columns selected, duplicating multiple lines
|
||||
|
||||
const bool isUp = curSel.positionBlock > curSel.anchorBlock;
|
||||
const QString commentText =
|
||||
(comment && m_commentDefinition.hasSingleLineStyle()) ?
|
||||
m_commentDefinition.singleLine : QString();
|
||||
|
||||
QTextBlock block = cursor.block();
|
||||
QString dupText = commentText + block.text() + QLatin1Char('\n');
|
||||
|
||||
for (int b = curSel.firstBlockNumber(); b < curSel.lastBlockNumber(); ++b) {
|
||||
if (isUp) {
|
||||
block = block.previous();
|
||||
dupText.prepend(commentText + block.text() + QLatin1Char('\n'));
|
||||
} else {
|
||||
block = block.next();
|
||||
dupText.append(commentText + block.text() + QLatin1Char('\n'));
|
||||
}
|
||||
}
|
||||
|
||||
if (isUp)
|
||||
block = cursor.block();
|
||||
|
||||
cursor.setPosition(block.position() + block.length());
|
||||
cursor.insertText(dupText);
|
||||
|
||||
} else {
|
||||
// Duplicating full block selection with columns
|
||||
|
||||
// Cannot "duplicate and comment" files without multi-line comment
|
||||
if (comment && !m_commentDefinition.hasMultiLineStyle())
|
||||
return;
|
||||
|
||||
const int fc = curSel.firstVisualColumn();
|
||||
const int lc = curSel.lastVisualColumn();
|
||||
const int l = lc - fc;
|
||||
|
||||
cursor.beginEditBlock();
|
||||
for (int b = curSel.firstBlockNumber(); b <= curSel.lastBlockNumber(); ++b) {
|
||||
const QTextBlock &block = m_document->document()->findBlockByNumber(b);
|
||||
QString dupText = block.text();
|
||||
const int dupTextLength = dupText.length();
|
||||
|
||||
if (dupTextLength < lc) {
|
||||
const QString addSpace(lc - dupTextLength, ' ');
|
||||
cursor.setPosition(block.position() + dupTextLength);
|
||||
cursor.insertText(addSpace);
|
||||
dupText.append(addSpace);
|
||||
}
|
||||
|
||||
cursor.setPosition(block.position() + lc);
|
||||
dupText = dupText.mid(fc, l);
|
||||
|
||||
if (comment)
|
||||
dupText = (m_commentDefinition.multiLineStart + dupText + m_commentDefinition.multiLineEnd);
|
||||
cursor.insertText(dupText);
|
||||
}
|
||||
cursor.endEditBlock();
|
||||
}
|
||||
|
||||
enableBlockSelection(curSel.positionBlock, curSel.positionColumn,
|
||||
curSel.anchorBlock, curSel.anchorColumn);
|
||||
|
||||
cursor = m_blockSelection.cursor(m_document.data());
|
||||
q->doSetTextCursor(cursor, m_blockSelection.hasSelection());
|
||||
}
|
||||
|
||||
void TextEditorWidget::duplicateSelection()
|
||||
{
|
||||
d->duplicateSelection(false);
|
||||
}
|
||||
|
||||
void TextEditorWidget::duplicateSelectionAndComment()
|
||||
{
|
||||
d->duplicateSelection(true);
|
||||
}
|
||||
|
||||
void TextEditorWidget::deleteLine()
|
||||
{
|
||||
d->maybeSelectLine();
|
||||
|
||||
@@ -357,6 +357,8 @@ public:
|
||||
|
||||
void cutLine();
|
||||
void copyLine();
|
||||
void duplicateSelection();
|
||||
void duplicateSelectionAndComment();
|
||||
void deleteLine();
|
||||
void deleteEndOfWord();
|
||||
void deleteEndOfWordCamelCase();
|
||||
|
||||
@@ -142,6 +142,8 @@ public:
|
||||
QAction *m_unfoldAction;
|
||||
QAction *m_cutLineAction;
|
||||
QAction *m_copyLineAction;
|
||||
QAction *m_duplicateSelectionAction;
|
||||
QAction *m_duplicateSelectionAndCommentAction;
|
||||
QAction *m_deleteLineAction;
|
||||
QAction *m_deleteEndOfWordAction;
|
||||
QAction *m_deleteEndOfWordCamelCaseAction;
|
||||
@@ -206,6 +208,8 @@ TextEditorActionHandlerPrivate::TextEditorActionHandlerPrivate
|
||||
m_unfoldAction(0),
|
||||
m_cutLineAction(0),
|
||||
m_copyLineAction(0),
|
||||
m_duplicateSelectionAction(0),
|
||||
m_duplicateSelectionAndCommentAction(0),
|
||||
m_deleteLineAction(0),
|
||||
m_deleteEndOfWordAction(0),
|
||||
m_deleteEndOfWordCamelCaseAction(0),
|
||||
@@ -403,6 +407,14 @@ void TextEditorActionHandlerPrivate::createActions()
|
||||
[this] (TextEditorWidget *w) { w->copyLine(); }, false, tr("Copy &Line"),
|
||||
QKeySequence(tr("Ctrl+Ins")),
|
||||
G_EDIT_TEXT, advancedEditMenu);
|
||||
m_duplicateSelectionAction = registerAction(DUPLICATE_SELECTION,
|
||||
[this] (TextEditorWidget *w) { w->duplicateSelection(); }, false, tr("&Duplicate Selection"),
|
||||
QKeySequence(),
|
||||
G_EDIT_TEXT, advancedEditMenu);
|
||||
m_duplicateSelectionAndCommentAction = registerAction(DUPLICATE_SELECTION_AND_COMMENT,
|
||||
[this] (TextEditorWidget *w) { w->duplicateSelectionAndComment(); }, false, tr("&Duplicate Selection and Comment"),
|
||||
QKeySequence(),
|
||||
G_EDIT_TEXT, advancedEditMenu);
|
||||
m_upperCaseSelectionAction = registerAction(UPPERCASE_SELECTION,
|
||||
[this] (TextEditorWidget *w) { w->uppercaseSelection(); }, true, tr("Uppercase Selection"),
|
||||
QKeySequence(Core::UseMacShortcuts ? tr("Meta+Shift+U") : tr("Alt+Shift+U")),
|
||||
|
||||
@@ -144,6 +144,8 @@ const char UPPERCASE_SELECTION[] = "TextEditor.UppercaseSelection";
|
||||
const char LOWERCASE_SELECTION[] = "TextEditor.LowercaseSelection";
|
||||
const char CUT_LINE[] = "TextEditor.CutLine";
|
||||
const char COPY_LINE[] = "TextEditor.CopyLine";
|
||||
const char DUPLICATE_SELECTION[] = "TextEditor.DuplicateSelection";
|
||||
const char DUPLICATE_SELECTION_AND_COMMENT[] = "TextEditor.DuplicateSelectionAndComment";
|
||||
const char DELETE_LINE[] = "TextEditor.DeleteLine";
|
||||
const char DELETE_END_OF_WORD[] = "TextEditor.DeleteEndOfWord";
|
||||
const char DELETE_END_OF_WORD_CAMEL_CASE[] = "TextEditor.DeleteEndOfWordCamelCase";
|
||||
|
||||
Reference in New Issue
Block a user