Newer
Older
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
QString BaseTextEditor::insertParagraphSeparator(const QTextCursor &tc) const
{
Q_UNUSED(tc);
return QString();
}
QString BaseTextEditor::autoComplete(QTextCursor &cursor, const QString &textToInsert) const
{
const bool checkBlockEnd = d->m_allowSkippingOfBlockEnd;
d->m_allowSkippingOfBlockEnd = false; // consume blockEnd.
if (!contextAllowsAutoParentheses(cursor, textToInsert))
return QString();
const QString text = textToInsert;
const QChar lookAhead = characterAt(cursor.selectionEnd());
QChar character = textToInsert.at(0);
const QString parentheses = QLatin1String("()");
const QString brackets = QLatin1String("[]");
if (parentheses.contains(character) || brackets.contains(character)) {
QTextCursor tmp= cursor;
bool foundBlockStart = TextEditor::TextBlockUserData::findPreviousBlockOpenParenthesis(&tmp);
int blockStart = foundBlockStart ? tmp.position() : 0;
bool foundBlockEnd = TextEditor::TextBlockUserData::findNextBlockClosingParenthesis(&tmp);
int blockEnd = foundBlockEnd ? tmp.position() : (cursor.document()->characterCount() - 1);
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
const QChar openChar = parentheses.contains(character) ? QLatin1Char('(') : QLatin1Char('[');
const QChar closeChar = parentheses.contains(character) ? QLatin1Char(')') : QLatin1Char(']');
int errors = 0;
int stillopen = 0;
countBrackets(cursor, blockStart, blockEnd, openChar, closeChar, &errors, &stillopen);
int errorsBeforeInsertion = errors + stillopen;
errors = 0;
stillopen = 0;
countBrackets(cursor, blockStart, cursor.position(), openChar, closeChar, &errors, &stillopen);
countBracket(openChar, closeChar, character, &errors, &stillopen);
countBrackets(cursor, cursor.position(), blockEnd, openChar, closeChar, &errors, &stillopen);
int errorsAfterInsertion = errors + stillopen;
if (errorsAfterInsertion < errorsBeforeInsertion)
return QString(); // insertion fixes parentheses or bracket errors, do not auto complete
}
int skippedChars = 0;
const QString autoText = insertMatchingBrace(cursor, text, lookAhead, &skippedChars);
if (checkBlockEnd && textToInsert.at(0) == QLatin1Char('}')) {
if (textToInsert.length() > 1)
qWarning() << "*** handle event compression";
int startPos = cursor.selectionEnd(), pos = startPos;
while (characterAt(pos).isSpace())
++pos;
if (characterAt(pos) == QLatin1Char('}'))
skippedChars += (pos - startPos) + 1;
}
if (skippedChars) {
const int pos = cursor.position();
cursor.setPosition(pos + skippedChars);
cursor.setPosition(pos, QTextCursor::KeepAnchor);
}
return autoText;
}
bool BaseTextEditor::autoBackspace(QTextCursor &cursor)
{
d->m_allowSkippingOfBlockEnd = false;
int pos = cursor.position();
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
QTextCursor c = cursor;
c.setPosition(pos - 1);
QChar lookAhead = characterAt(pos);
QChar lookBehind = characterAt(pos-1);
QChar lookFurtherBehind = characterAt(pos-2);
QChar character = lookBehind;
if (character == QLatin1Char('(') || character == QLatin1Char('[')) {
QTextCursor tmp = cursor;
TextEditor::TextBlockUserData::findPreviousBlockOpenParenthesis(&tmp);
int blockStart = tmp.isNull() ? 0 : tmp.position();
tmp = cursor;
TextEditor::TextBlockUserData::findNextBlockClosingParenthesis(&tmp);
int blockEnd = tmp.isNull() ? (cursor.document()->characterCount()-1) : tmp.position();
QChar openChar = character;
QChar closeChar = (character == QLatin1Char('(')) ? QLatin1Char(')') : QLatin1Char(']');
int errors = 0;
int stillopen = 0;
countBrackets(cursor, blockStart, blockEnd, openChar, closeChar, &errors, &stillopen);
int errorsBeforeDeletion = errors + stillopen;
errors = 0;
stillopen = 0;
countBrackets(cursor, blockStart, pos - 1, openChar, closeChar, &errors, &stillopen);
countBrackets(cursor, pos, blockEnd, openChar, closeChar, &errors, &stillopen);
int errorsAfterDeletion = errors + stillopen;
if (errorsAfterDeletion < errorsBeforeDeletion)
return false; // insertion fixes parentheses or bracket errors, do not auto complete
}
// ### this code needs to be generalized
if ((lookBehind == QLatin1Char('(') && lookAhead == QLatin1Char(')'))
|| (lookBehind == QLatin1Char('[') && lookAhead == QLatin1Char(']'))
|| (lookBehind == QLatin1Char('"') && lookAhead == QLatin1Char('"')
&& lookFurtherBehind != QLatin1Char('\\'))
|| (lookBehind == QLatin1Char('\'') && lookAhead == QLatin1Char('\'')
&& lookFurtherBehind != QLatin1Char('\\'))) {
if (! isInComment(c)) {
cursor.beginEditBlock();
cursor.deleteChar();
cursor.deletePreviousChar();
cursor.endEditBlock();
return true;
}
}
int BaseTextEditor::paragraphSeparatorAboutToBeInserted(QTextCursor &cursor)
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
if (characterAt(cursor.position()-1) != QLatin1Char('{'))
return 0;
if (!contextAllowsAutoParentheses(cursor))
return 0;
// verify that we indeed do have an extra opening brace in the document
int braceDepth = document()->lastBlock().userState();
if (braceDepth >= 0)
braceDepth >>= 8;
else
braceDepth= 0;
if (braceDepth <= 0)
return 0; // braces are all balanced or worse, no need to do anything
// we have an extra brace , let's see if we should close it
/* verify that the next block is not further intended compared to the current block.
This covers the following case:
if (condition) {|
statement;
*/
const TabSettings &ts = tabSettings();
QTextBlock block = cursor.block();
int indentation = ts.indentationColumn(block.text());
if (block.next().isValid()
&& ts.indentationColumn(block.next().text()) > indentation)
return 0;
int pos = cursor.position();
const QString textToInsert = insertParagraphSeparator(cursor);
cursor.insertText(textToInsert);
cursor.setPosition(pos);
if (ts.m_autoIndent) {
cursor.insertBlock();
indent(document(), cursor, QChar::Null);
} else {
QString previousBlockText = cursor.block().text();
cursor.insertBlock();
cursor.insertText(ts.indentationString(previousBlockText));
}
cursor.setPosition(pos);
d->m_allowSkippingOfBlockEnd = true;
return 1;
}
void BaseTextEditor::indentBlock(QTextDocument *, QTextBlock, QChar)
{
}
void BaseTextEditor::indent(QTextDocument *doc, const QTextCursor &cursor, QChar typedChar)
{
if (cursor.hasSelection()) {
QTextBlock block = doc->findBlock(cursor.selectionStart());
const QTextBlock end = doc->findBlock(cursor.selectionEnd()).next();
do {
indentBlock(doc, block, typedChar);
block = block.next();
} while (block.isValid() && block != end);
} else {
indentBlock(doc, cursor.block(), typedChar);
}
}
void BaseTextEditor::reindent(QTextDocument *doc, const QTextCursor &cursor)
{
if (cursor.hasSelection()) {
QTextBlock block = doc->findBlock(cursor.selectionStart());
const QTextBlock end = doc->findBlock(cursor.selectionEnd()).next();
const TabSettings &ts = d->m_document->tabSettings();
// skip empty blocks
while (block.isValid() && block != end) {
QString bt = block.text();
if (ts.firstNonSpace(bt) < bt.size())
break;
indentBlock(doc, block, QChar::Null);
block = block.next();
}
int previousIndentation = ts.indentationColumn(block.text());
indentBlock(doc, block, QChar::Null);
int currentIndentation = ts.indentationColumn(block.text());
int delta = currentIndentation - previousIndentation;
block = block.next();
while (block.isValid() && block != end) {
ts.reindentLine(block, delta);
block = block.next();
}
} else {
indentBlock(doc, cursor.block(), QChar::Null);
}
}
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
BaseTextEditor::Link BaseTextEditor::findLinkAt(const QTextCursor &, bool)
{
return Link();
}
bool BaseTextEditor::openLink(const Link &link)
{
if (link.fileName.isEmpty())
return false;
if (baseTextDocument()->fileName() == link.fileName) {
Core::EditorManager *editorManager = Core::EditorManager::instance();
editorManager->addCurrentPositionToNavigationHistory();
gotoLine(link.line, link.column);
setFocus();
return true;
}
return openEditorAt(link.fileName, link.line, link.column);
}
void BaseTextEditor::updateLink(QMouseEvent *e)
{
bool linkFound = false;
if (mouseNavigationEnabled() && e->modifiers() & Qt::ControlModifier) {
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
// Link emulation behaviour for 'go to definition'
const QTextCursor cursor = cursorForPosition(e->pos());
// Check that the mouse was actually on the text somewhere
bool onText = cursorRect(cursor).right() >= e->x();
if (!onText) {
QTextCursor nextPos = cursor;
nextPos.movePosition(QTextCursor::Right);
onText = cursorRect(nextPos).right() >= e->x();
}
const Link link = findLinkAt(cursor, false);
if (onText && link.isValid()) {
showLink(link);
linkFound = true;
}
}
if (!linkFound)
clearLink();
}
void BaseTextEditor::showLink(const Link &link)
{
if (d->m_currentLink == link)
return;
QTextEdit::ExtraSelection sel;
sel.cursor = textCursor();

Roberto Raggi
committed
sel.cursor.setPosition(link.begin);
sel.cursor.setPosition(link.end, QTextCursor::KeepAnchor);
sel.format = d->m_linkFormat;
sel.format.setFontUnderline(true);
setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>() << sel);
viewport()->setCursor(Qt::PointingHandCursor);
d->m_currentLink = link;
d->m_linkPressed = false;
}
void BaseTextEditor::clearLink()
{
if (!d->m_currentLink.isValid())
return;
setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>());
viewport()->setCursor(Qt::IBeamCursor);
d->m_currentLink = Link();
d->m_linkPressed = false;
}
void BaseTextEditorPrivate::updateMarksBlock(const QTextBlock &block)
{
if (const TextBlockUserData *userData = TextEditDocumentLayout::testUserData(block))
foreach (ITextMark *mrk, userData->marks())
mrk->updateBlock(block);
}
void BaseTextEditorPrivate::updateMarksLineNumber()
{
QTextDocument *doc = q->document();
QTextBlock block = doc->begin();
int blockNumber = 0;
while (block.isValid()) {
if (const TextBlockUserData *userData = TextEditDocumentLayout::testUserData(block))
foreach (ITextMark *mrk, userData->marks()) {
mrk->updateLineNumber(blockNumber + 1);
}
block = block.next();
++blockNumber;
}
}
void BaseTextEditor::markBlocksAsChanged(QList<int> blockNumbers)
{
QTextBlock block = document()->begin();
while (block.isValid()) {
if (block.revision() < 0)
block.setRevision(-block.revision() - 1);
block = block.next();
}
foreach (const int blockNumber, blockNumbers) {
QTextBlock block = document()->findBlockByNumber(blockNumber);
if (block.isValid())
block.setRevision(-block.revision() - 1);
}
}
TextBlockUserData::MatchType TextBlockUserData::checkOpenParenthesis(QTextCursor *cursor, QChar c)
{
QTextBlock block = cursor->block();
if (!TextEditDocumentLayout::hasParentheses(block) || TextEditDocumentLayout::ifdefedOut(block))
Parentheses parenList = TextEditDocumentLayout::parentheses(block);
QTextBlock closedParenParag = block;
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
const int cursorPos = cursor->position() - closedParenParag.position();
int i = 0;
int ignore = 0;
bool foundOpen = false;
for (;;) {
if (!foundOpen) {
if (i >= parenList.count())
return NoMatch;
openParen = parenList.at(i);
if (openParen.pos != cursorPos) {
++i;
continue;
} else {
foundOpen = true;
++i;
}
}
if (i >= parenList.count()) {
for (;;) {
closedParenParag = closedParenParag.next();
if (!closedParenParag.isValid())
return NoMatch;
if (TextEditDocumentLayout::hasParentheses(closedParenParag)
&& !TextEditDocumentLayout::ifdefedOut(closedParenParag)) {
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
parenList = TextEditDocumentLayout::parentheses(closedParenParag);
break;
}
}
i = 0;
}
closedParen = parenList.at(i);
if (closedParen.type == Parenthesis::Opened) {
ignore++;
++i;
continue;
} else {
if (ignore > 0) {
ignore--;
++i;
continue;
}
cursor->clearSelection();
cursor->setPosition(closedParenParag.position() + closedParen.pos + 1, QTextCursor::KeepAnchor);
if ((c == QLatin1Char('{') && closedParen.chr != QLatin1Char('}'))
|| (c == QLatin1Char('(') && closedParen.chr != QLatin1Char(')'))
|| (c == QLatin1Char('[') && closedParen.chr != QLatin1Char(']'))
|| (c == QLatin1Char('+') && closedParen.chr != QLatin1Char('-'))
)
return Mismatch;
return Match;
}
}
}
TextBlockUserData::MatchType TextBlockUserData::checkClosedParenthesis(QTextCursor *cursor, QChar c)
{
QTextBlock block = cursor->block();
if (!TextEditDocumentLayout::hasParentheses(block) || TextEditDocumentLayout::ifdefedOut(block))
Parentheses parenList = TextEditDocumentLayout::parentheses(block);
QTextBlock openParenParag = block;
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
const int cursorPos = cursor->position() - openParenParag.position();
int i = parenList.count() - 1;
int ignore = 0;
bool foundClosed = false;
for (;;) {
if (!foundClosed) {
if (i < 0)
return NoMatch;
closedParen = parenList.at(i);
if (closedParen.pos != cursorPos - 1) {
--i;
continue;
} else {
foundClosed = true;
--i;
}
}
if (i < 0) {
for (;;) {
openParenParag = openParenParag.previous();
if (!openParenParag.isValid())
return NoMatch;
if (TextEditDocumentLayout::hasParentheses(openParenParag)
&& !TextEditDocumentLayout::ifdefedOut(openParenParag)) {
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
parenList = TextEditDocumentLayout::parentheses(openParenParag);
break;
}
}
i = parenList.count() - 1;
}
openParen = parenList.at(i);
if (openParen.type == Parenthesis::Closed) {
ignore++;
--i;
continue;
} else {
if (ignore > 0) {
ignore--;
--i;
continue;
}
cursor->clearSelection();
cursor->setPosition(openParenParag.position() + openParen.pos, QTextCursor::KeepAnchor);
if ((c == '}' && openParen.chr != '{') ||
(c == ')' && openParen.chr != '(') ||
(c == ']' && openParen.chr != '[') ||
(c == '-' && openParen.chr != '+'))
return Mismatch;
return Match;
}
}
}
bool TextBlockUserData::findPreviousOpenParenthesis(QTextCursor *cursor, bool select)
{
QTextBlock block = cursor->block();
int position = cursor->position();
int ignore = 0;
while (block.isValid()) {
Parentheses parenList = TextEditDocumentLayout::parentheses(block);
if (!parenList.isEmpty() && !TextEditDocumentLayout::ifdefedOut(block)) {
for (int i = parenList.count()-1; i >= 0; --i) {
Parenthesis paren = parenList.at(i);
if (block == cursor->block() &&
(position - block.position() <= paren.pos + (paren.type == Parenthesis::Closed ? 1 : 0)))
continue;
if (paren.type == Parenthesis::Closed) {
++ignore;
} else if (ignore > 0) {
--ignore;
} else {
cursor->setPosition(block.position() + paren.pos, select ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor);
return true;
}
}
}
block = block.previous();
}
return false;
}
bool TextBlockUserData::findPreviousBlockOpenParenthesis(QTextCursor *cursor, bool checkStartPosition)
{
QTextBlock block = cursor->block();
int position = cursor->position();
int ignore = 0;
while (block.isValid()) {
Parentheses parenList = TextEditDocumentLayout::parentheses(block);
if (!parenList.isEmpty() && !TextEditDocumentLayout::ifdefedOut(block)) {
for (int i = parenList.count()-1; i >= 0; --i) {
Parenthesis paren = parenList.at(i);
if (paren.chr != QLatin1Char('{') && paren.chr != QLatin1Char('}')
&& paren.chr != QLatin1Char('+') && paren.chr != QLatin1Char('-')
&& paren.chr != QLatin1Char('[') && paren.chr != QLatin1Char(']'))
if (block == cursor->block()) {
if (position - block.position() <= paren.pos + (paren.type == Parenthesis::Closed ? 1 : 0))
if (checkStartPosition && paren.type == Parenthesis::Opened && paren.pos== cursor->position()) {
if (paren.type == Parenthesis::Closed) {
++ignore;
} else if (ignore > 0) {
--ignore;
} else {
cursor->setPosition(block.position() + paren.pos);
return true;
}
}
}
}
return false;
}
bool TextBlockUserData::findNextClosingParenthesis(QTextCursor *cursor, bool select)
{
QTextBlock block = cursor->block();
int position = cursor->position();
int ignore = 0;
while (block.isValid()) {
Parentheses parenList = TextEditDocumentLayout::parentheses(block);
if (!parenList.isEmpty() && !TextEditDocumentLayout::ifdefedOut(block)) {
for (int i = 0; i < parenList.count(); ++i) {
Parenthesis paren = parenList.at(i);
if (block == cursor->block() &&
(position - block.position() > paren.pos - (paren.type == Parenthesis::Opened ? 1 : 0)))
continue;
if (paren.type == Parenthesis::Opened) {
++ignore;
} else if (ignore > 0) {
--ignore;
} else {
cursor->setPosition(block.position() + paren.pos+1, select ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor);
return true;
}
}
}
}
return false;
}
bool TextBlockUserData::findNextBlockClosingParenthesis(QTextCursor *cursor)
{
QTextBlock block = cursor->block();
int position = cursor->position();
int ignore = 0;
while (block.isValid()) {
Parentheses parenList = TextEditDocumentLayout::parentheses(block);
if (!parenList.isEmpty() && !TextEditDocumentLayout::ifdefedOut(block)) {
for (int i = 0; i < parenList.count(); ++i) {
Parenthesis paren = parenList.at(i);
if (paren.chr != QLatin1Char('{') && paren.chr != QLatin1Char('}')
&& paren.chr != QLatin1Char('+') && paren.chr != QLatin1Char('-')
&& paren.chr != QLatin1Char('[') && paren.chr != QLatin1Char(']'))
if (block == cursor->block() &&
(position - block.position() > paren.pos - (paren.type == Parenthesis::Opened ? 1 : 0)))
continue;
if (paren.type == Parenthesis::Opened) {
++ignore;
} else if (ignore > 0) {
--ignore;
} else {
cursor->setPosition(block.position() + paren.pos+1);
return true;
}
}
}
block = block.next();
}
return false;
}
TextBlockUserData::MatchType TextBlockUserData::matchCursorBackward(QTextCursor *cursor)
{
cursor->clearSelection();
const QTextBlock block = cursor->block();
if (!TextEditDocumentLayout::hasParentheses(block) || TextEditDocumentLayout::ifdefedOut(block))
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
return NoMatch;
const int relPos = cursor->position() - block.position();
Parentheses parentheses = TextEditDocumentLayout::parentheses(block);
const Parentheses::const_iterator cend = parentheses.constEnd();
for (Parentheses::const_iterator it = parentheses.constBegin();it != cend; ++it) {
const Parenthesis &paren = *it;
if (paren.pos == relPos - 1
&& paren.type == Parenthesis::Closed) {
return checkClosedParenthesis(cursor, paren.chr);
}
}
return NoMatch;
}
TextBlockUserData::MatchType TextBlockUserData::matchCursorForward(QTextCursor *cursor)
{
cursor->clearSelection();
const QTextBlock block = cursor->block();
if (!TextEditDocumentLayout::hasParentheses(block) || TextEditDocumentLayout::ifdefedOut(block))
return NoMatch;
const int relPos = cursor->position() - block.position();
Parentheses parentheses = TextEditDocumentLayout::parentheses(block);
const Parentheses::const_iterator cend = parentheses.constEnd();
for (Parentheses::const_iterator it = parentheses.constBegin();it != cend; ++it) {
const Parenthesis &paren = *it;
if (paren.pos == relPos
&& paren.type == Parenthesis::Opened) {
return checkOpenParenthesis(cursor, paren.chr);
}
}
return NoMatch;
}
void BaseTextEditor::highlightSearchResults(const QString &txt, Find::IFindSupport::FindFlags findFlags)
QString pattern = txt;
if (pattern.size() < 2)
pattern.clear(); // highlighting single characters is a bit pointless
if (d->m_searchExpr.pattern() == pattern)
d->m_searchExpr.setPattern(pattern);
d->m_searchExpr.setPatternSyntax((findFlags & Find::IFindSupport::FindRegularExpression) ?
QRegExp::RegExp : QRegExp::FixedString);
d->m_searchExpr.setCaseSensitivity((findFlags & Find::IFindSupport::FindCaseSensitively) ?
Qt::CaseSensitive : Qt::CaseInsensitive);
d->m_findFlags = findFlags;
d->m_delayedUpdateTimer->start(10);
}
void BaseTextEditor::setFindScope(const QTextCursor &scope)
{
if (scope.isNull() != d->m_findScope.isNull()) {
d->m_findScope = scope;
viewport()->update();
}
}
void BaseTextEditor::_q_animateUpdate(int position, QPointF lastPos, QRectF rect)

mae
committed
{
QTextCursor cursor(textCursor());
cursor.setPosition(position);
viewport()->update(QRectF(cursorRect(cursor).topLeft() + rect.topLeft(), rect.size()).toAlignedRect());
if (!lastPos.isNull())
viewport()->update(QRectF(lastPos + rect.topLeft(), rect.size()).toAlignedRect());

mae
committed
}
BaseTextEditorAnimator::BaseTextEditorAnimator(QObject *parent)
:QObject(parent)
{
m_value = 0;
m_timeline = new QTimeLine(256, this);

mae
committed
m_timeline->setCurveShape(QTimeLine::SineCurve);
connect(m_timeline, SIGNAL(valueChanged(qreal)), this, SLOT(step(qreal)));
connect(m_timeline, SIGNAL(finished()), this, SLOT(deleteLater()));
m_timeline->start();
}
void BaseTextEditorAnimator::setData(QFont f, QPalette pal, const QString &text)
{
m_font = f;
m_palette = pal;
m_text = text;
QFontMetrics fm(m_font);
m_size = QSizeF(fm.width(m_text), fm.height());
}

mae
committed
void BaseTextEditorAnimator::draw(QPainter *p, const QPointF &pos)
{
m_lastDrawPos = pos;

mae
committed
p->setPen(m_palette.text().color());
QFont f = m_font;
f.setPointSizeF(f.pointSizeF() * (1.0 + m_value/2));

mae
committed
QFontMetrics fm(f);
int width = fm.width(m_text);
QRectF r((m_size.width()-width)/2, (m_size.height() - fm.height())/2, width, fm.height());
r.translate(pos);
p->fillRect(r, m_palette.base());
p->setFont(f);
p->drawText(r, m_text);
}
bool BaseTextEditorAnimator::isRunning() const
{
return m_timeline->state() == QTimeLine::Running;
}

mae
committed
QRectF BaseTextEditorAnimator::rect() const
{
QFont f = m_font;
f.setPointSizeF(f.pointSizeF() * (1.0 + m_value/2));

mae
committed
QFontMetrics fm(f);
int width = fm.width(m_text);
return QRectF((m_size.width()-width)/2, (m_size.height() - fm.height())/2, width, fm.height());
}
void BaseTextEditorAnimator::step(qreal v)
{
QRectF before = rect();
m_value = v;
QRectF after = rect();
emit updateRequest(m_position, m_lastDrawPos, before.united(after));

mae
committed
}
void BaseTextEditorAnimator::finish()
{
m_timeline->stop();

mae
committed
step(0);
deleteLater();
}
void BaseTextEditor::_q_matchParentheses()
{
if (isReadOnly())
return;
QTextCursor backwardMatch = textCursor();
QTextCursor forwardMatch = textCursor();
const TextBlockUserData::MatchType backwardMatchType = TextBlockUserData::matchCursorBackward(&backwardMatch);
const TextBlockUserData::MatchType forwardMatchType = TextBlockUserData::matchCursorForward(&forwardMatch);
QList<QTextEdit::ExtraSelection> extraSelections;
if (backwardMatchType == TextBlockUserData::NoMatch && forwardMatchType == TextBlockUserData::NoMatch) {
setExtraSelections(ParenthesesMatchingSelection, extraSelections); // clear
return;
}

mae
committed
int animatePosition = -1;
if (backwardMatch.hasSelection()) {
QTextEdit::ExtraSelection sel;
if (backwardMatchType == TextBlockUserData::Mismatch) {
sel.cursor = backwardMatch;
sel.format = d->m_mismatchFormat;
} else {
if (d->m_displaySettings.m_animateMatchingParentheses) {
animatePosition = backwardMatch.selectionStart();
} else if (d->m_formatRange) {
sel.cursor = backwardMatch;
sel.format = d->m_rangeFormat;
extraSelections.append(sel);
}
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
sel.cursor = backwardMatch;
sel.format = d->m_matchFormat;
sel.cursor.setPosition(backwardMatch.selectionStart());
sel.cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
extraSelections.append(sel);
sel.cursor.setPosition(backwardMatch.selectionEnd());
sel.cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
}
extraSelections.append(sel);
}
if (forwardMatch.hasSelection()) {
QTextEdit::ExtraSelection sel;
if (forwardMatchType == TextBlockUserData::Mismatch) {
sel.cursor = forwardMatch;
sel.format = d->m_mismatchFormat;
} else {
if (d->m_displaySettings.m_animateMatchingParentheses) {
animatePosition = forwardMatch.selectionEnd()-1;
} else if (d->m_formatRange) {
sel.cursor = forwardMatch;
sel.format = d->m_rangeFormat;
extraSelections.append(sel);
}
sel.cursor = forwardMatch;
sel.format = d->m_matchFormat;
sel.cursor.setPosition(forwardMatch.selectionStart());
sel.cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
extraSelections.append(sel);
sel.cursor.setPosition(forwardMatch.selectionEnd());
sel.cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
}
extraSelections.append(sel);
}

mae
committed
if (animatePosition >= 0) {
foreach (const QTextEdit::ExtraSelection &sel, BaseTextEditor::extraSelections(ParenthesesMatchingSelection)) {
if (sel.cursor.selectionStart() == animatePosition
|| sel.cursor.selectionEnd() - 1 == animatePosition) {
animatePosition = -1;
break;
}
}
}

mae
committed
if (animatePosition >= 0) {
if (d->m_animator)
d->m_animator->finish(); // one animation is enough
d->m_animator = new BaseTextEditorAnimator(this);
d->m_animator->setPosition(animatePosition);
QPalette pal;
pal.setBrush(QPalette::Text, d->m_matchFormat.foreground());
pal.setBrush(QPalette::Base, d->m_rangeFormat.background());
d->m_animator->setData(font(), pal, characterAt(d->m_animator->position()));
connect(d->m_animator, SIGNAL(updateRequest(int,QPointF,QRectF)),
this, SLOT(_q_animateUpdate(int,QPointF,QRectF)));

mae
committed
setExtraSelections(ParenthesesMatchingSelection, extraSelections);
void BaseTextEditor::_q_highlightBlocks()
{
BaseTextEditorPrivateHighlightBlocks highlightBlocksInfo;
if (d->extraAreaHighlightCollapseBlockNumber >= 0) {
QTextBlock block = document()->findBlockByNumber(d->extraAreaHighlightCollapseBlockNumber);
if (block.isValid()) {
QTextCursor cursor(block);
if (d->extraAreaHighlightCollapseColumn >= 0)
cursor.setPosition(cursor.position() + qMin(d->extraAreaHighlightCollapseColumn,
while (TextBlockUserData::findPreviousBlockOpenParenthesis(&cursor, firstRun)) {
highlightBlocksInfo.open.prepend(cursor.blockNumber());

mae
committed
int visualIndent = d->visualIndent(cursor.block());
if (closeCursor.isNull())
closeCursor = cursor;

mae
committed
if (TextBlockUserData::findNextBlockClosingParenthesis(&closeCursor)) {
highlightBlocksInfo.close.append(closeCursor.blockNumber());

mae
committed
visualIndent = qMin(visualIndent, d->visualIndent(closeCursor.block()));
}
highlightBlocksInfo.visualIndent.prepend(visualIndent);
if (d->m_highlightBlocksInfo != highlightBlocksInfo) {
d->m_highlightBlocksInfo = highlightBlocksInfo;
viewport()->update();
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
void BaseTextEditor::setActionHack(QObject *hack)
{
d->m_actionHack = hack;
}
QObject *BaseTextEditor::actionHack() const
{
return d->m_actionHack;
}
void BaseTextEditor::changeEvent(QEvent *e)
{
QPlainTextEdit::changeEvent(e);
if (e->type() == QEvent::ApplicationFontChange
|| e->type() == QEvent::FontChange) {
if (d->m_extraArea) {
QFont f = d->m_extraArea->font();
f.setPointSize(font().pointSize());
d->m_extraArea->setFont(f);
slotUpdateExtraAreaWidth();
d->m_extraArea->update();
}
}
}
void BaseTextEditor::focusInEvent(QFocusEvent *e)
{
QPlainTextEdit::focusInEvent(e);
void BaseTextEditor::focusOutEvent(QFocusEvent *e)
{
QPlainTextEdit::focusOutEvent(e);
if (viewport()->cursor().shape() == Qt::BlankCursor)
viewport()->setCursor(Qt::IBeamCursor);
}
void BaseTextEditor::maybeSelectLine()
{
QTextCursor cursor = textCursor();
if (!cursor.hasSelection()) {
const QTextBlock &block = cursor.block();
if (block.next().isValid()) {
cursor.setPosition(block.position());
cursor.setPosition(block.next().position(), QTextCursor::KeepAnchor);
} else {
cursor.movePosition(QTextCursor::EndOfBlock);
cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
}
setTextCursor(cursor);
}
}
// shift+del
void BaseTextEditor::cutLine()
{
maybeSelectLine();
void BaseTextEditor::deleteLine()
{
maybeSelectLine();
textCursor().removeSelectedText();
}
void BaseTextEditor::setExtraSelections(ExtraSelectionKind kind, const QList<QTextEdit::ExtraSelection> &selections)
if (selections.isEmpty() && d->m_extraSelections[kind].isEmpty())
return;
d->m_extraSelections[kind] = selections;
if (kind == CodeSemanticsSelection) {
d->m_overlay->clear();
foreach (const QTextEdit::ExtraSelection &selection, d->m_extraSelections[kind]) {
d->m_overlay->addOverlaySelection(selection.cursor,
selection.format.background().color(),
selection.format.background().color(),
}
d->m_overlay->setVisible(!d->m_overlay->isEmpty());
} else if (kind == SnippetPlaceholderSelection) {
d->m_snippetOverlay->clear();
foreach (const QTextEdit::ExtraSelection &selection, d->m_extraSelections[kind]) {
d->m_snippetOverlay->addOverlaySelection(selection.cursor,
selection.format.background().color(),
selection.format.background().color(),
TextEditorOverlay::ExpandBegin);
}
d->m_snippetOverlay->setVisible(!d->m_snippetOverlay->isEmpty());
} else {
QList<QTextEdit::ExtraSelection> all;
for (int i = 0; i < NExtraSelectionKinds; ++i) {
if (i == CodeSemanticsSelection || i == SnippetPlaceholderSelection)
continue;
all += d->m_extraSelections[i];
}
QPlainTextEdit::setExtraSelections(all);
}
QList<QTextEdit::ExtraSelection> BaseTextEditor::extraSelections(ExtraSelectionKind kind) const
return d->m_extraSelections[kind];