return;
}
- if (d->m_snippetOverlay->isVisible()
- && (e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace)) {
- d->snippetCheckCursor(textCursor());
- }
-
if (ro || e->text().isEmpty() || !e->text().at(0).isPrint()) {
if (cursorMoveKeyEvent(e))
;
- else
+ else {
+ QTextCursor cursor = textCursor();
+ bool cursorWithinSnippet = false;
+ if (d->m_snippetOverlay->isVisible()
+ && (e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace)) {
+ cursorWithinSnippet = d->snippetCheckCursor(cursor);
+ }
+ if (cursorWithinSnippet)
+ cursor.beginEditBlock();
+
QPlainTextEdit::keyPressEvent(e);
+
+ if (cursorWithinSnippet) {
+ cursor.endEditBlock();
+ d->m_snippetOverlay->updateEquivalentSelections(textCursor());
+ }
+ }
} else if ((e->modifiers() & (Qt::ControlModifier|Qt::AltModifier)) != Qt::ControlModifier){
QTextCursor cursor = textCursor();
QString text = e->text();
}
}
+ bool cursorWithinSnippet = false;
if (d->m_snippetOverlay->isVisible())
- d->snippetCheckCursor(cursor);
+ cursorWithinSnippet = d->snippetCheckCursor(cursor);
- bool doEditBlock = !(electricChar.isNull() && autoText.isEmpty());
+ bool doEditBlock = !electricChar.isNull() || !autoText.isEmpty() || cursorWithinSnippet;
if (doEditBlock)
cursor.beginEditBlock();
cursor.setPosition(autoText.length() == 1 ? cursor.position() : cursor.anchor());
}
- if (doEditBlock)
+ if (doEditBlock) {
cursor.endEditBlock();
+ if (cursorWithinSnippet)
+ d->m_snippetOverlay->updateEquivalentSelections(textCursor());
+ }
setTextCursor(cursor);
}
}
-void BaseTextEditorPrivate::snippetCheckCursor(const QTextCursor &cursor)
+bool BaseTextEditorPrivate::snippetCheckCursor(const QTextCursor &cursor)
{
if (!m_snippetOverlay->isVisible() || m_snippetOverlay->isEmpty())
- return;
+ return false;
QTextCursor start = cursor;
start.setPosition(cursor.selectionStart());
|| !m_snippetOverlay->hasCursorInSelection(end)) {
m_snippetOverlay->setVisible(false);
m_snippetOverlay->clear();
+ return false;
}
+ return true;
}
void BaseTextEditorPrivate::snippetTabOrBacktab(bool forward)
QTextCursor cursor = q->textCursor();
OverlaySelection final;
if (forward) {
- for (int i = 0; i < m_snippetOverlay->m_selections.count(); ++i){
- const OverlaySelection &selection = m_snippetOverlay->m_selections.at(i);
+ for (int i = 0; i < m_snippetOverlay->selections().count(); ++i){
+ const OverlaySelection &selection = m_snippetOverlay->selections().at(i);
if (selection.m_cursor_begin.position() >= cursor.position()
&& selection.m_cursor_end.position() > cursor.position()) {
final = selection;
}
}
} else {
- for (int i = m_snippetOverlay->m_selections.count()-1; i >= 0; --i){
- const OverlaySelection &selection = m_snippetOverlay->m_selections.at(i);
+ for (int i = m_snippetOverlay->selections().count()-1; i >= 0; --i){
+ const OverlaySelection &selection = m_snippetOverlay->selections().at(i);
if (selection.m_cursor_end.position() < cursor.position()) {
final = selection;
break;
}
if (final.m_cursor_begin.isNull())
- final = forward ? m_snippetOverlay->m_selections.first() : m_snippetOverlay->m_selections.last();
+ final = forward ? m_snippetOverlay->selections().first() : m_snippetOverlay->selections().last();
if (final.m_cursor_begin.position() == final.m_cursor_end.position()) { // empty tab stop
cursor.setPosition(final.m_cursor_end.position());
q->setTextCursor(cursor);
}
-
bool BaseTextEditor::viewportEvent(QEvent *event)
{
d->m_contentsChanged = false;
setTextCursor(cursor);
}
-
-#define SET_AND_RETURN(cursor) setTextCursor(cursor); return // make cursor visible and reset vertical x movement
void BaseTextEditor::handleBackspaceKey()
{
QTextCursor cursor = textCursor();
int pos = cursor.position();
QTC_ASSERT(!cursor.hasSelection(), return);
+ bool cursorWithinSnippet = false;
if (d->m_snippetOverlay->isVisible()) {
QTextCursor snippetCursor = cursor;
snippetCursor.movePosition(QTextCursor::Left);
- d->snippetCheckCursor(snippetCursor);
+ cursorWithinSnippet = d->snippetCheckCursor(snippetCursor);
}
const TextEditor::TabSettings &tabSettings = d->m_document->tabSettings();
if (tabSettings.m_autoIndent && d->m_autoCompleter->autoBackspace(cursor))
return;
+ bool handled = false;
if (!tabSettings.m_smartBackspace) {
+ if (cursorWithinSnippet)
+ cursor.beginEditBlock();
cursor.deletePreviousChar();
- SET_AND_RETURN(cursor);
+ handled = true;
+ } else {
+ QTextBlock currentBlock = cursor.block();
+ int positionInBlock = pos - currentBlock.position();
+ const QString blockText = currentBlock.text();
+ if (cursor.atBlockStart() || tabSettings.firstNonSpace(blockText) < positionInBlock) {
+ if (cursorWithinSnippet)
+ cursor.beginEditBlock();
+ cursor.deletePreviousChar();
+ handled = true;
+ } else {
+ int previousIndent = 0;
+ const int indent = tabSettings.columnAt(blockText, positionInBlock);
+
+ for (QTextBlock previousNonEmptyBlock = currentBlock.previous();
+ previousNonEmptyBlock.isValid();
+ previousNonEmptyBlock = previousNonEmptyBlock.previous()) {
+ QString previousNonEmptyBlockText = previousNonEmptyBlock.text();
+ if (previousNonEmptyBlockText.trimmed().isEmpty())
+ continue;
+ previousIndent =
+ tabSettings.columnAt(previousNonEmptyBlockText,
+ tabSettings.firstNonSpace(previousNonEmptyBlockText));
+ if (previousIndent < indent) {
+ cursor.beginEditBlock();
+ cursor.setPosition(currentBlock.position(), QTextCursor::KeepAnchor);
+ cursor.insertText(tabSettings.indentationString(previousNonEmptyBlockText));
+ cursor.endEditBlock();
+ handled = true;
+ break;
+ }
+ }
+ }
}
- QTextBlock currentBlock = cursor.block();
- int positionInBlock = pos - currentBlock.position();
- const QString blockText = currentBlock.text();
- if (cursor.atBlockStart() || tabSettings.firstNonSpace(blockText) < positionInBlock) {
+ if (!handled) {
+ if (cursorWithinSnippet)
+ cursor.beginEditBlock();
cursor.deletePreviousChar();
- SET_AND_RETURN(cursor);
}
- int previousIndent = 0;
- const int indent = tabSettings.columnAt(blockText, positionInBlock);
-
- for (QTextBlock previousNonEmptyBlock = currentBlock.previous();
- previousNonEmptyBlock.isValid();
- previousNonEmptyBlock = previousNonEmptyBlock.previous()) {
- QString previousNonEmptyBlockText = previousNonEmptyBlock.text();
- if (previousNonEmptyBlockText.trimmed().isEmpty())
- continue;
- previousIndent = tabSettings.columnAt(previousNonEmptyBlockText,
- tabSettings.firstNonSpace(previousNonEmptyBlockText));
- if (previousIndent < indent) {
- cursor.beginEditBlock();
- cursor.setPosition(currentBlock.position(), QTextCursor::KeepAnchor);
- cursor.insertText(tabSettings.indentationString(previousNonEmptyBlockText));
- cursor.endEditBlock();
- SET_AND_RETURN(cursor);
- }
+ if (cursorWithinSnippet) {
+ cursor.endEditBlock();
+ d->m_snippetOverlay->updateEquivalentSelections(cursor);
}
- cursor.deletePreviousChar();
- SET_AND_RETURN(cursor);
+
+ setTextCursor(cursor);
}
void BaseTextEditor::wheelEvent(QWheelEvent *e)
selection.format.background().color(),
TextEditorOverlay::ExpandBegin);
}
+ d->m_snippetOverlay->mapEquivalentSelections();
d->m_snippetOverlay->setVisible(!d->m_snippetOverlay->isEmpty());
} else {
QList<QTextEdit::ExtraSelection> all;
#include "texteditoroverlay.h"
#include "basetexteditor.h"
+#include <QtCore/QMap>
#include <QtGui/QPainter>
#include <QtGui/QTextBlock>
using namespace TextEditor;
using namespace TextEditor::Internal;
-TextEditorOverlay::TextEditorOverlay(BaseTextEditor *editor)
- :QObject(editor) {
- m_visible = false;
- m_borderWidth = 1;
- m_dropShadowWidth = 2;
- m_editor = editor;
- m_alpha = true;
- m_viewport = editor->viewport();
+TextEditorOverlay::TextEditorOverlay(BaseTextEditor *editor) :
+ QObject(editor),
+ m_visible(false),
+ m_borderWidth(1),
+ m_dropShadowWidth(2),
+ m_alpha(true),
+ m_editor(editor),
+ m_viewport(editor->viewport())
+{
}
void TextEditorOverlay::update()
*/
bool TextEditorOverlay::hasCursorInSelection(const QTextCursor &cursor) const
{
+ if (selectionIndexForCursor(cursor) != -1)
+ return true;
+ return false;
+}
+
+int TextEditorOverlay::selectionIndexForCursor(const QTextCursor &cursor) const
+{
for (int i = 0; i < m_selections.size(); ++i) {
const OverlaySelection &selection = m_selections.at(i);
if (cursor.position() >= selection.m_cursor_begin.position()
&& cursor.position() <= selection.m_cursor_end.position())
- return true;
+ return i;
+ }
+ return -1;
+}
+
+QString TextEditorOverlay::selectionText(int selectionIndex) const
+{
+ return assembleCursorForSelection(selectionIndex).selectedText();
+}
+
+QTextCursor TextEditorOverlay::assembleCursorForSelection(int selectionIndex) const
+{
+ const OverlaySelection &selection = m_selections.at(selectionIndex);
+ QTextCursor cursor(m_editor->document());
+ cursor.setPosition(selection.m_cursor_begin.position());
+ cursor.setPosition(selection.m_cursor_end.position(), QTextCursor::KeepAnchor);
+ return cursor;
+}
+
+void TextEditorOverlay::mapEquivalentSelections()
+{
+ m_equivalentSelections.clear();
+ m_equivalentSelections.resize(m_selections.size());
+
+ QMap<QString, int> all;
+ for (int i = 0; i < m_selections.size(); ++i)
+ all.insertMulti(selectionText(i), i);
+
+ const QList<QString> &uniqueKeys = all.uniqueKeys();
+ foreach (const QString &key, uniqueKeys) {
+ QList<int> indexes;
+ QMap<QString, int>::const_iterator lbit = all.lowerBound(key);
+ QMap<QString, int>::const_iterator ubit = all.upperBound(key);
+ while (lbit != ubit) {
+ indexes.append(lbit.value());
+ ++lbit;
+ }
+
+ foreach (int index, indexes)
+ m_equivalentSelections[index] = indexes;
+ }
+}
+
+void TextEditorOverlay::updateEquivalentSelections(const QTextCursor &cursor)
+{
+ int selectionIndex = selectionIndexForCursor(cursor);
+ if (selectionIndex == -1)
+ return;
+
+ const QString ¤tText = selectionText(selectionIndex);
+ const QList<int> &equivalents = m_equivalentSelections.at(selectionIndex);
+ foreach (int i, equivalents) {
+ if (i == selectionIndex)
+ continue;
+ const QString &equivalentText = selectionText(i);
+ if (currentText != equivalentText) {
+ QTextCursor selectionCursor = assembleCursorForSelection(i);
+ selectionCursor.joinPreviousEditBlock();
+ selectionCursor.removeSelectedText();
+ selectionCursor.insertText(currentText);
+ selectionCursor.endEditBlock();
+ }
}
- return false;
}
#define TEXTEDITOROVERLAY_H
#include <QtCore/QObject>
-
+#include <QtCore/QList>
+#include <QtCore/QVector>
#include <QtGui/QTextCursor>
#include <QtGui/QColor>
struct OverlaySelection
{
OverlaySelection():m_fixedLength(-1), m_dropShadow(false){}
+
QTextCursor m_cursor_begin;
QTextCursor m_cursor_end;
QColor m_fg;
class TextEditorOverlay : public QObject
{
Q_OBJECT
- BaseTextEditor *m_editor;
- QWidget *m_viewport;
-
-public:
- QList<OverlaySelection> m_selections;
-
-private:
- bool m_visible;
- int m_borderWidth;
- int m_dropShadowWidth;
- bool m_alpha;
-
public:
TextEditorOverlay(BaseTextEditor *editor);
void addOverlaySelection(int begin, int end, const QColor &fg, const QColor &bg,
uint overlaySelectionFlags = 0);
+ const QList<OverlaySelection> &selections() const { return m_selections; }
+
inline bool isEmpty() const { return m_selections.isEmpty(); }
inline int dropShadowWidth() const { return m_dropShadowWidth; }
bool hasCursorInSelection(const QTextCursor &cursor) const;
+ void mapEquivalentSelections();
+ void updateEquivalentSelections(const QTextCursor &cursor);
+
private:
QPainterPath createSelectionPath(const QTextCursor &begin, const QTextCursor &end, const QRect& clip);
void paintSelection(QPainter *painter, const OverlaySelection &selection);
void fillSelection(QPainter *painter, const OverlaySelection &selection, const QColor &color);
+ int selectionIndexForCursor(const QTextCursor &cursor) const;
+ QString selectionText(int selectionIndex) const;
+ QTextCursor assembleCursorForSelection(int selectionIndex) const;
+
+ bool m_visible;
+ int m_borderWidth;
+ int m_dropShadowWidth;
+ bool m_alpha;
+ BaseTextEditor *m_editor;
+ QWidget *m_viewport;
+ QList<OverlaySelection> m_selections;
+ QVector<QList<int> > m_equivalentSelections;
};
} // namespace Internal