forked from qt-creator/qt-creator
refactor rename selections
the new approach makes it possible to use more edit features inside the rename selection like cut/copy/paste. Furthermore it compresses rename operations better on the undo stack.
This commit is contained in:
@@ -562,6 +562,8 @@ CPPEditor::CPPEditor(QWidget *parent)
|
|||||||
: TextEditor::BaseTextEditor(parent)
|
: TextEditor::BaseTextEditor(parent)
|
||||||
, m_currentRenameSelection(-1)
|
, m_currentRenameSelection(-1)
|
||||||
, m_inRename(false)
|
, m_inRename(false)
|
||||||
|
, m_inRenameChanged(false)
|
||||||
|
, m_firstRenameChange(false)
|
||||||
, m_allowSkippingOfBlockEnd(false)
|
, m_allowSkippingOfBlockEnd(false)
|
||||||
{
|
{
|
||||||
m_initialized = false;
|
m_initialized = false;
|
||||||
@@ -669,7 +671,6 @@ void CPPEditor::inAllRenameSelections(EditOperation operation,
|
|||||||
QTextCursor cursor,
|
QTextCursor cursor,
|
||||||
const QString &text)
|
const QString &text)
|
||||||
{
|
{
|
||||||
m_inRename = true;
|
|
||||||
cursor.beginEditBlock();
|
cursor.beginEditBlock();
|
||||||
|
|
||||||
const int offset = cursor.position() - currentRenameSelection.cursor.anchor();
|
const int offset = cursor.position() - currentRenameSelection.cursor.anchor();
|
||||||
@@ -700,15 +701,78 @@ void CPPEditor::inAllRenameSelections(EditOperation operation,
|
|||||||
}
|
}
|
||||||
|
|
||||||
cursor.endEditBlock();
|
cursor.endEditBlock();
|
||||||
m_inRename = false;
|
|
||||||
|
|
||||||
setExtraSelections(CodeSemanticsSelection, m_renameSelections);
|
setExtraSelections(CodeSemanticsSelection, m_renameSelections);
|
||||||
setTextCursor(cursor);
|
setTextCursor(cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CPPEditor::paste()
|
||||||
|
{
|
||||||
|
if (m_currentRenameSelection == -1) {
|
||||||
|
BaseTextEditor::paste();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
startRename();
|
||||||
|
BaseTextEditor::paste();
|
||||||
|
finishRename();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPPEditor::cut()
|
||||||
|
{
|
||||||
|
if (m_currentRenameSelection == -1) {
|
||||||
|
BaseTextEditor::cut();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
startRename();
|
||||||
|
BaseTextEditor::cut();
|
||||||
|
finishRename();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPPEditor::startRename()
|
||||||
|
{
|
||||||
|
m_inRenameChanged = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPPEditor::finishRename()
|
||||||
|
{
|
||||||
|
if (!m_inRenameChanged)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_inRename = true;
|
||||||
|
|
||||||
|
QTextCursor cursor = textCursor();
|
||||||
|
cursor.joinPreviousEditBlock();
|
||||||
|
|
||||||
|
cursor.setPosition(m_currentRenameSelectionEnd.position());
|
||||||
|
cursor.setPosition(m_currentRenameSelectionBegin.position(), QTextCursor::KeepAnchor);
|
||||||
|
m_renameSelections[m_currentRenameSelection].cursor = cursor;
|
||||||
|
QString text = cursor.selectedText();
|
||||||
|
|
||||||
|
for (int i = 0; i < m_renameSelections.size(); ++i) {
|
||||||
|
if (i == m_currentRenameSelection)
|
||||||
|
continue;
|
||||||
|
QTextEdit::ExtraSelection &s = m_renameSelections[i];
|
||||||
|
int pos = s.cursor.selectionStart();
|
||||||
|
s.cursor.removeSelectedText();
|
||||||
|
s.cursor.insertText(text);
|
||||||
|
s.cursor.setPosition(pos, QTextCursor::KeepAnchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
setExtraSelections(CodeSemanticsSelection, m_renameSelections);
|
||||||
|
cursor.endEditBlock();
|
||||||
|
|
||||||
|
m_inRename = false;
|
||||||
|
}
|
||||||
|
|
||||||
void CPPEditor::abortRename()
|
void CPPEditor::abortRename()
|
||||||
{
|
{
|
||||||
|
if (m_currentRenameSelection < 0)
|
||||||
|
return;
|
||||||
m_currentRenameSelection = -1;
|
m_currentRenameSelection = -1;
|
||||||
|
m_currentRenameSelectionBegin = QTextCursor();
|
||||||
|
m_currentRenameSelectionEnd = QTextCursor();
|
||||||
m_renameSelections.clear();
|
m_renameSelections.clear();
|
||||||
setExtraSelections(CodeSemanticsSelection, m_renameSelections);
|
setExtraSelections(CodeSemanticsSelection, m_renameSelections);
|
||||||
}
|
}
|
||||||
@@ -830,7 +894,7 @@ Symbol *CPPEditor::markSymbols()
|
|||||||
{
|
{
|
||||||
updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource()));
|
updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource()));
|
||||||
|
|
||||||
m_currentRenameSelection = -1;
|
abortRename();
|
||||||
|
|
||||||
QList<QTextEdit::ExtraSelection> selections;
|
QList<QTextEdit::ExtraSelection> selections;
|
||||||
|
|
||||||
@@ -868,15 +932,20 @@ Symbol *CPPEditor::markSymbols()
|
|||||||
void CPPEditor::renameSymbolUnderCursor()
|
void CPPEditor::renameSymbolUnderCursor()
|
||||||
{
|
{
|
||||||
updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource()));
|
updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource()));
|
||||||
|
abortRename();
|
||||||
|
|
||||||
QTextCursor c = textCursor();
|
QTextCursor c = textCursor();
|
||||||
m_currentRenameSelection = -1;
|
|
||||||
|
|
||||||
for (int i = 0; i < m_renameSelections.size(); ++i) {
|
for (int i = 0; i < m_renameSelections.size(); ++i) {
|
||||||
QTextEdit::ExtraSelection s = m_renameSelections.at(i);
|
QTextEdit::ExtraSelection s = m_renameSelections.at(i);
|
||||||
if (c.position() >= s.cursor.anchor()
|
if (c.position() >= s.cursor.anchor()
|
||||||
&& c.position() <= s.cursor.position()) {
|
&& c.position() <= s.cursor.position()) {
|
||||||
m_currentRenameSelection = i;
|
m_currentRenameSelection = i;
|
||||||
|
m_firstRenameChange = true;
|
||||||
|
m_currentRenameSelectionBegin = QTextCursor(c.document()->docHandle(),
|
||||||
|
m_renameSelections[i].cursor.selectionStart());
|
||||||
|
m_currentRenameSelectionEnd = QTextCursor(c.document()->docHandle(),
|
||||||
|
m_renameSelections[i].cursor.selectionEnd());
|
||||||
m_renameSelections[i].format = m_occurrenceRenameFormat;
|
m_renameSelections[i].format = m_occurrenceRenameFormat;
|
||||||
setExtraSelections(CodeSemanticsSelection, m_renameSelections);
|
setExtraSelections(CodeSemanticsSelection, m_renameSelections);
|
||||||
break;
|
break;
|
||||||
@@ -890,12 +959,21 @@ void CPPEditor::renameSymbolUnderCursor()
|
|||||||
void CPPEditor::onContentsChanged(int position, int charsRemoved, int charsAdded)
|
void CPPEditor::onContentsChanged(int position, int charsRemoved, int charsAdded)
|
||||||
{
|
{
|
||||||
Q_UNUSED(position)
|
Q_UNUSED(position)
|
||||||
Q_UNUSED(charsAdded)
|
|
||||||
|
|
||||||
if (m_currentRenameSelection == -1)
|
if (m_currentRenameSelection == -1 || m_inRename)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!m_inRename)
|
if (position + charsAdded == m_currentRenameSelectionBegin.position()) {
|
||||||
|
// we are inserting at the beginning of the rename selection => expand
|
||||||
|
m_currentRenameSelectionBegin.setPosition(position);
|
||||||
|
m_renameSelections[m_currentRenameSelection].cursor.setPosition(position, QTextCursor::KeepAnchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the condition looks odd, but keep in mind that the begin and end cursors do move automatically
|
||||||
|
m_inRenameChanged = (position >= m_currentRenameSelectionBegin.position()
|
||||||
|
&& position + charsAdded <= m_currentRenameSelectionEnd.position());
|
||||||
|
|
||||||
|
if (!m_inRenameChanged)
|
||||||
abortRename();
|
abortRename();
|
||||||
|
|
||||||
if (charsRemoved > 0)
|
if (charsRemoved > 0)
|
||||||
@@ -936,7 +1014,7 @@ bool CPPEditor::sortedMethodOverview() const
|
|||||||
|
|
||||||
void CPPEditor::updateMethodBoxIndex()
|
void CPPEditor::updateMethodBoxIndex()
|
||||||
{
|
{
|
||||||
m_updateMethodBoxTimer->start(UPDATE_METHOD_BOX_INTERVAL);
|
m_updateMethodBoxTimer->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPPEditor::highlightUses(const QList<SemanticInfo::Use> &uses,
|
void CPPEditor::highlightUses(const QList<SemanticInfo::Use> &uses,
|
||||||
@@ -977,8 +1055,6 @@ void CPPEditor::highlightUses(const QList<SemanticInfo::Use> &uses,
|
|||||||
|
|
||||||
void CPPEditor::updateMethodBoxIndexNow()
|
void CPPEditor::updateMethodBoxIndexNow()
|
||||||
{
|
{
|
||||||
m_updateMethodBoxTimer->stop();
|
|
||||||
|
|
||||||
int line = 0, column = 0;
|
int line = 0, column = 0;
|
||||||
convertPosition(position(), &line, &column);
|
convertPosition(position(), &line, &column);
|
||||||
|
|
||||||
@@ -1008,13 +1084,11 @@ void CPPEditor::updateMethodBoxToolTip()
|
|||||||
|
|
||||||
void CPPEditor::updateUses()
|
void CPPEditor::updateUses()
|
||||||
{
|
{
|
||||||
m_updateUsesTimer->start(UPDATE_USES_INTERVAL);
|
m_updateUsesTimer->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPPEditor::updateUsesNow()
|
void CPPEditor::updateUsesNow()
|
||||||
{
|
{
|
||||||
m_updateUsesTimer->stop();
|
|
||||||
|
|
||||||
if (m_currentRenameSelection != -1)
|
if (m_currentRenameSelection != -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -1757,7 +1831,6 @@ void CPPEditor::keyPressEvent(QKeyEvent *e)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QTextEdit::ExtraSelection ¤tRenameSelection = m_renameSelections.at(m_currentRenameSelection);
|
|
||||||
QTextCursor cursor = textCursor();
|
QTextCursor cursor = textCursor();
|
||||||
const QTextCursor::MoveMode moveMode =
|
const QTextCursor::MoveMode moveMode =
|
||||||
(e->modifiers() & Qt::ShiftModifier) ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor;
|
(e->modifiers() & Qt::ShiftModifier) ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor;
|
||||||
@@ -1771,9 +1844,9 @@ void CPPEditor::keyPressEvent(QKeyEvent *e)
|
|||||||
return;
|
return;
|
||||||
case Qt::Key_Home: {
|
case Qt::Key_Home: {
|
||||||
// Send home to start of name when within the name and not at the start
|
// Send home to start of name when within the name and not at the start
|
||||||
if (cursor.position() > currentRenameSelection.cursor.anchor()
|
if (cursor.position() > m_currentRenameSelectionBegin.position()
|
||||||
&& cursor.position() <= currentRenameSelection.cursor.position()) {
|
&& cursor.position() <= m_currentRenameSelectionEnd.position()) {
|
||||||
cursor.setPosition(currentRenameSelection.cursor.anchor(), moveMode);
|
cursor.setPosition(m_currentRenameSelectionBegin.position(), moveMode);
|
||||||
setTextCursor(cursor);
|
setTextCursor(cursor);
|
||||||
e->accept();
|
e->accept();
|
||||||
return;
|
return;
|
||||||
@@ -1782,9 +1855,9 @@ void CPPEditor::keyPressEvent(QKeyEvent *e)
|
|||||||
}
|
}
|
||||||
case Qt::Key_End: {
|
case Qt::Key_End: {
|
||||||
// Send end to end of name when within the name and not at the end
|
// Send end to end of name when within the name and not at the end
|
||||||
if (cursor.position() >= currentRenameSelection.cursor.anchor()
|
if (cursor.position() >= m_currentRenameSelectionBegin.position()
|
||||||
&& cursor.position() < currentRenameSelection.cursor.position()) {
|
&& cursor.position() < m_currentRenameSelectionEnd.position()) {
|
||||||
cursor.setPosition(currentRenameSelection.cursor.position(), moveMode);
|
cursor.setPosition(m_currentRenameSelectionEnd.position(), moveMode);
|
||||||
setTextCursor(cursor);
|
setTextCursor(cursor);
|
||||||
e->accept();
|
e->accept();
|
||||||
return;
|
return;
|
||||||
@@ -1792,49 +1865,43 @@ void CPPEditor::keyPressEvent(QKeyEvent *e)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Qt::Key_Backspace: {
|
case Qt::Key_Backspace: {
|
||||||
if (cursor.position() == currentRenameSelection.cursor.anchor()) {
|
if (cursor.position() == m_currentRenameSelectionBegin.position()) {
|
||||||
// Eat backspace at start of name
|
// Eat backspace at start of name
|
||||||
e->accept();
|
e->accept();
|
||||||
return;
|
return;
|
||||||
} else if (cursor.position() > currentRenameSelection.cursor.anchor()
|
}
|
||||||
&& cursor.position() <= currentRenameSelection.cursor.position()) {
|
|
||||||
|
|
||||||
inAllRenameSelections(DeletePreviousChar, currentRenameSelection, cursor);
|
|
||||||
e->accept();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Qt::Key_Delete: {
|
case Qt::Key_Delete: {
|
||||||
if (cursor.position() == currentRenameSelection.cursor.position()) {
|
if (cursor.position() == m_currentRenameSelectionEnd.position()) {
|
||||||
// Eat delete at end of name
|
// Eat delete at end of name
|
||||||
e->accept();
|
e->accept();
|
||||||
return;
|
return;
|
||||||
} else if (cursor.position() >= currentRenameSelection.cursor.anchor()
|
|
||||||
&& cursor.position() < currentRenameSelection.cursor.position()) {
|
|
||||||
|
|
||||||
inAllRenameSelections(DeleteChar, currentRenameSelection, cursor);
|
|
||||||
e->accept();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
QString text = e->text();
|
|
||||||
if (! text.isEmpty() && text.at(0).isPrint()) {
|
|
||||||
if (cursor.position() >= currentRenameSelection.cursor.anchor()
|
|
||||||
&& cursor.position() <= currentRenameSelection.cursor.position()) {
|
|
||||||
|
|
||||||
inAllRenameSelections(InsertText, currentRenameSelection, cursor, text);
|
|
||||||
e->accept();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} // switch
|
||||||
|
|
||||||
|
startRename();
|
||||||
|
|
||||||
|
bool wantEditBlock = (cursor.position() >= m_currentRenameSelectionBegin.position()
|
||||||
|
&& cursor.position() <= m_currentRenameSelectionEnd.position());
|
||||||
|
|
||||||
|
if (wantEditBlock) {
|
||||||
|
// possible change inside rename selection
|
||||||
|
if (m_firstRenameChange)
|
||||||
|
cursor.beginEditBlock();
|
||||||
|
else
|
||||||
|
cursor.joinPreviousEditBlock();
|
||||||
|
m_firstRenameChange = false;
|
||||||
|
}
|
||||||
TextEditor::BaseTextEditor::keyPressEvent(e);
|
TextEditor::BaseTextEditor::keyPressEvent(e);
|
||||||
|
if (wantEditBlock)
|
||||||
|
cursor.endEditBlock();
|
||||||
|
finishRename();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<int> CPPEditorEditable::context() const
|
QList<int> CPPEditorEditable::context() const
|
||||||
|
@@ -191,6 +191,9 @@ public:
|
|||||||
bool isOutdated() const;
|
bool isOutdated() const;
|
||||||
SemanticInfo semanticInfo() const;
|
SemanticInfo semanticInfo() const;
|
||||||
|
|
||||||
|
virtual void paste(); // reimplemented from BaseTextEditor
|
||||||
|
virtual void cut(); // reimplemented from BaseTextEditor
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
virtual void setFontSettings(const TextEditor::FontSettings &);
|
virtual void setFontSettings(const TextEditor::FontSettings &);
|
||||||
void setSortedMethodOverview(bool sort);
|
void setSortedMethodOverview(bool sort);
|
||||||
@@ -269,6 +272,8 @@ private:
|
|||||||
const QTextEdit::ExtraSelection ¤tRenameSelection,
|
const QTextEdit::ExtraSelection ¤tRenameSelection,
|
||||||
QTextCursor cursor,
|
QTextCursor cursor,
|
||||||
const QString &text = QString());
|
const QString &text = QString());
|
||||||
|
void startRename();
|
||||||
|
void finishRename();
|
||||||
void abortRename();
|
void abortRename();
|
||||||
|
|
||||||
Link findLinkAt(const QTextCursor &, bool resolveTarget = true);
|
Link findLinkAt(const QTextCursor &, bool resolveTarget = true);
|
||||||
@@ -292,7 +297,9 @@ private:
|
|||||||
|
|
||||||
QList<QTextEdit::ExtraSelection> m_renameSelections;
|
QList<QTextEdit::ExtraSelection> m_renameSelections;
|
||||||
int m_currentRenameSelection;
|
int m_currentRenameSelection;
|
||||||
bool m_inRename;
|
bool m_inRename, m_inRenameChanged, m_firstRenameChange;
|
||||||
|
QTextCursor m_currentRenameSelectionBegin;
|
||||||
|
QTextCursor m_currentRenameSelectionEnd;
|
||||||
|
|
||||||
mutable bool m_allowSkippingOfBlockEnd;
|
mutable bool m_allowSkippingOfBlockEnd;
|
||||||
|
|
||||||
|
@@ -4349,7 +4349,10 @@ void BaseTextEditor::setExtraSelections(ExtraSelectionKind kind, const QList<QTe
|
|||||||
if (kind == CodeSemanticsSelection) {
|
if (kind == CodeSemanticsSelection) {
|
||||||
d->m_overlay->clear();
|
d->m_overlay->clear();
|
||||||
foreach (const QTextEdit::ExtraSelection &selection, d->m_extraSelections[kind]) {
|
foreach (const QTextEdit::ExtraSelection &selection, d->m_extraSelections[kind]) {
|
||||||
d->m_overlay->addOverlaySelection(selection.cursor, selection.format.background().color(), true);
|
d->m_overlay->addOverlaySelection(selection.cursor,
|
||||||
|
selection.format.background().color(),
|
||||||
|
selection.format.background().color(),
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
d->m_overlay->setVisible(!d->m_overlay->isEmpty());
|
d->m_overlay->setVisible(!d->m_overlay->isEmpty());
|
||||||
|
|
||||||
|
@@ -377,8 +377,8 @@ public:
|
|||||||
public slots:
|
public slots:
|
||||||
void setDisplayName(const QString &title);
|
void setDisplayName(const QString &title);
|
||||||
|
|
||||||
void paste();
|
virtual void paste();
|
||||||
void cut();
|
virtual void cut();
|
||||||
|
|
||||||
void zoomIn(int range = 1);
|
void zoomIn(int range = 1);
|
||||||
void zoomOut(int range = 1);
|
void zoomOut(int range = 1);
|
||||||
|
@@ -83,11 +83,8 @@ void TextEditorOverlay::addOverlaySelection(int begin, int end,
|
|||||||
selection.m_fg = fg;
|
selection.m_fg = fg;
|
||||||
selection.m_bg = bg;
|
selection.m_bg = bg;
|
||||||
|
|
||||||
selection.m_cursor_begin = QTextCursor(document);
|
selection.m_cursor_begin = QTextCursor(document->docHandle(), begin);
|
||||||
selection.m_cursor_begin.setPosition(begin);
|
selection.m_cursor_end = QTextCursor(document->docHandle(), end);
|
||||||
|
|
||||||
selection.m_cursor_end = QTextCursor(document);
|
|
||||||
selection.m_cursor_end.setPosition(end);
|
|
||||||
|
|
||||||
if (lockSize)
|
if (lockSize)
|
||||||
selection.m_fixedLength = (end - begin);
|
selection.m_fixedLength = (end - begin);
|
||||||
|
Reference in New Issue
Block a user