Newer
Older
selectedText.remove(0, commonPrefix.length());
commonPrefix.prepend(QChar::ParagraphSeparator);
selectedText.replace(commonPrefix, QLatin1String("\n"));
// remove any repeated spaces, trim lines to PARAGRAPH_WIDTH width and
// keep the same indentation level as first line in paragraph.
QString currentWord;
for (int i = 0; i < selectedText.length(); ++i) {
QChar ch = selectedText.at(i);
if (ch.isSpace()) {
if (!currentWord.isEmpty()) {
currentLength += currentWord.length() + 1;
if (currentLength > paragraphWidth) {
currentLength = currentWord.length() + 1 + indentLevel;
result.chop(1); // remove trailing space
result.append(QChar::ParagraphSeparator);
result.append(spacing);
}
result.append(currentWord);
result.append(QLatin1Char(' '));
currentWord.clear();
}
continue;
}
currentWord.append(ch);
}
result.chop(1);
result.append(QChar::ParagraphSeparator);
cursor.insertText(result);
cursor.endEditBlock();
}
void BaseTextEditor::unCommentSelection()
void BaseTextEditor::showEvent(QShowEvent* e)
{
if (!d->m_fontSettings.isEmpty()) {
setFontSettings(d->m_fontSettings);
d->m_fontSettings.clear();
}
QPlainTextEdit::showEvent(e);
}
void BaseTextEditor::setFontSettingsIfVisible(const TextEditor::FontSettings &fs)
{
if (!isVisible()) {
d->m_fontSettings = fs;
return;
void BaseTextEditor::setFontSettings(const TextEditor::FontSettings &fs)
{
const QTextCharFormat textFormat = fs.toTextCharFormat(QLatin1String(Constants::C_TEXT));
const QTextCharFormat selectionFormat = fs.toTextCharFormat(QLatin1String(Constants::C_SELECTION));
const QTextCharFormat lineNumberFormat = fs.toTextCharFormat(QLatin1String(Constants::C_LINE_NUMBER));
const QTextCharFormat searchResultFormat = fs.toTextCharFormat(QLatin1String(Constants::C_SEARCH_RESULT));
d->m_searchScopeFormat = fs.toTextCharFormat(QLatin1String(Constants::C_SEARCH_SCOPE));
const QTextCharFormat parenthesesFormat = fs.toTextCharFormat(QLatin1String(Constants::C_PARENTHESES));
d->m_currentLineFormat = fs.toTextCharFormat(QLatin1String(Constants::C_CURRENT_LINE));
d->m_currentLineNumberFormat = fs.toTextCharFormat(QLatin1String(Constants::C_CURRENT_LINE_NUMBER));
d->m_linkFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_LINK));
d->m_ifdefedOutFormat = fs.toTextCharFormat(QLatin1String(Constants::C_DISABLED_CODE));
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
QFont font(textFormat.font());
const QColor foreground = textFormat.foreground().color();
const QColor background = textFormat.background().color();
QPalette p = palette();
p.setColor(QPalette::Text, foreground);
p.setColor(QPalette::Foreground, foreground);
p.setColor(QPalette::Base, background);
p.setColor(QPalette::Highlight, (selectionFormat.background().style() != Qt::NoBrush) ?
selectionFormat.background().color() :
QApplication::palette().color(QPalette::Highlight));
p.setColor(QPalette::HighlightedText, selectionFormat.foreground().color());
p.setBrush(QPalette::Inactive, QPalette::Highlight, p.highlight());
p.setBrush(QPalette::Inactive, QPalette::HighlightedText, p.highlightedText());
setPalette(p);
setFont(font);
setTabSettings(d->m_document->tabSettings()); // update tabs, they depend on the font
// Line numbers
QPalette ep = d->m_extraArea->palette();
ep.setColor(QPalette::Dark, lineNumberFormat.foreground().color());
ep.setColor(QPalette::Background, lineNumberFormat.background().style() != Qt::NoBrush ?
lineNumberFormat.background().color() : background);
d->m_extraArea->setPalette(ep);
// Search results
d->m_searchResultFormat.setBackground(searchResultFormat.background());
// Matching braces
d->m_matchFormat.setForeground(parenthesesFormat.foreground());
d->m_rangeFormat.setBackground(parenthesesFormat.background());
slotUpdateExtraAreaWidth(); // Adjust to new font width
updateCurrentLineHighlight(); // Make sure it takes the new color
}
void BaseTextEditor::setTabSettings(const TabSettings &ts)
{
d->m_document->setTabSettings(ts);
int charWidth = QFontMetrics(font()).width(QChar(' '));
setTabStopWidth(charWidth * ts.m_tabSize);
}
void BaseTextEditor::setDisplaySettings(const DisplaySettings &ds)
{
setLineWrapMode(ds.m_textWrapping ? QPlainTextEdit::WidgetWidth : QPlainTextEdit::NoWrap);
setLineNumbersVisible(ds.m_displayLineNumbers);
setVisibleWrapColumn(ds.m_showWrapColumn ? ds.m_wrapColumn : 0);
setCodeFoldingVisible(ds.m_displayFoldingMarkers);
setHighlightCurrentLine(ds.m_highlightCurrentLine);
setRevisionsVisible(ds.m_markTextChanges);
if (d->m_displaySettings.m_visualizeWhitespace != ds.m_visualizeWhitespace) {
if (QSyntaxHighlighter *highlighter = baseTextDocument()->syntaxHighlighter())
highlighter->rehighlight();
QTextOption option = document()->defaultTextOption();
if (ds.m_visualizeWhitespace)
option.setFlags(option.flags() | QTextOption::ShowTabsAndSpaces);
else
option.setFlags(option.flags() & ~QTextOption::ShowTabsAndSpaces);
option.setFlags(option.flags() | QTextOption::AddSpaceForLineAndParagraphSeparators);
document()->setDefaultTextOption(option);
d->m_displaySettings = ds;
if (!ds.m_highlightBlocks) {
d->extraAreaHighlightCollapseBlockNumber = d->extraAreaHighlightCollapseColumn = -1;
d->m_highlightBlocksInfo = BaseTextEditorPrivateHighlightBlocks();
}
slotCursorPositionChanged();
void BaseTextEditor::setBehaviorSettings(const TextEditor::BehaviorSettings &bs)
{
setMouseNavigationEnabled(bs.m_mouseNavigation);
setScrollWheelZoomingEnabled(bs.m_scrollWheelZooming);
}
void BaseTextEditor::setStorageSettings(const StorageSettings &storageSettings)
{
d->m_document->setStorageSettings(storageSettings);
}
void BaseTextEditor::collapse()
{
QTextDocument *doc = document();
TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
QTextBlock curBlock = block;
if (TextBlockUserData::canCollapse(block) && block.next().isVisible()) {
break;
if ((block.next().userState()) >> 8 <= (curBlock.previous().userState() >> 8))
break;
}
block = block.previous();
}
if (block.isValid()) {
TextBlockUserData::doCollapse(block, false);
d->moveCursorVisible();
documentLayout->requestUpdate();
documentLayout->emitDocumentSizeChanged();
}
}
void BaseTextEditor::expand()
{
QTextDocument *doc = document();
TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
QTextBlock block = textCursor().block();
while (block.isValid() && !block.isVisible())
block = block.previous();
TextBlockUserData::doCollapse(block, true);
d->moveCursorVisible();
documentLayout->requestUpdate();
documentLayout->emitDocumentSizeChanged();
}
void BaseTextEditor::unCollapseAll()
{
QTextDocument *doc = document();
TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
QTextBlock block = doc->firstBlock();
bool makeVisible = true;
while (block.isValid()) {
if (block.isVisible() && TextBlockUserData::canCollapse(block) && block.next().isVisible()) {
makeVisible = false;
break;
}
block = block.next();
}
block = doc->firstBlock();
while (block.isValid()) {
if (TextBlockUserData::canCollapse(block))
TextBlockUserData::doCollapse(block, makeVisible);
block = block.next();
}
d->moveCursorVisible();
documentLayout->requestUpdate();
documentLayout->emitDocumentSizeChanged();
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
}
void BaseTextEditor::setTextCodec(QTextCodec *codec)
{
baseTextDocument()->setCodec(codec);
}
QTextCodec *BaseTextEditor::textCodec() const
{
return baseTextDocument()->codec();
}
void BaseTextEditor::setReadOnly(bool b)
{
QPlainTextEdit::setReadOnly(b);
if (b)
setTextInteractionFlags(textInteractionFlags() | Qt::TextSelectableByKeyboard);
}
void BaseTextEditor::cut()
{
if (d->m_inBlockSelectionMode) {
copy();
d->removeBlockSelection();
return;
}
QPlainTextEdit::cut();
}
void BaseTextEditor::paste()
{
if (d->m_inBlockSelectionMode) {
d->removeBlockSelection();
}
QPlainTextEdit::paste();
}
QMimeData *BaseTextEditor::createMimeDataFromSelection() const
{
if (d->m_inBlockSelectionMode) {
QMimeData *mimeData = new QMimeData;
QString text = d->copyBlockSelection();
mimeData->setData(QLatin1String("application/vnd.nokia.qtcreator.vblocktext"), text.toUtf8());
mimeData->setText(text); // for exchangeability
return mimeData;
} else if (textCursor().hasSelection()){
QTextCursor cursor = textCursor();
QMimeData *mimeData = new QMimeData;
QString text = cursor.selectedText();
convertToPlainText(text);
mimeData->setText(text);
/*
Try to figure out whether we are copying an entire block, and store the complete block
including indentation in the qtcreator.blocktext mimetype.
*/
QTextCursor selstart = cursor;
selstart.setPosition(cursor.selectionStart());
QTextCursor selend = cursor;
selend.setPosition(cursor.selectionEnd());
const TabSettings &ts = d->m_document->tabSettings();
bool startOk = ts.cursorIsAtBeginningOfLine(selstart);
bool multipleBlocks = (selend.block() != selstart.block());
selstart.movePosition(QTextCursor::StartOfBlock);
if (ts.cursorIsAtBeginningOfLine(selend))
selend.movePosition(QTextCursor::StartOfBlock);
cursor.setPosition(selstart.position());
cursor.setPosition(selend.position(), QTextCursor::KeepAnchor);
text = cursor.selectedText();
mimeData->setData(QLatin1String("application/vnd.nokia.qtcreator.blocktext"), text.toUtf8());
}
return mimeData;
}
bool BaseTextEditor::canInsertFromMimeData(const QMimeData *source) const
{
return QPlainTextEdit::canInsertFromMimeData(source);
}
void BaseTextEditor::insertFromMimeData(const QMimeData *source)
{
if (isReadOnly())
return;
if (source->hasFormat(QLatin1String("application/vnd.nokia.qtcreator.vblocktext"))) {
QString text = QString::fromUtf8(source->data(QLatin1String("application/vnd.nokia.qtcreator.vblocktext")));
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
if (text.isEmpty())
return;
QStringList lines = text.split(QLatin1Char('\n'));
QTextCursor cursor = textCursor();
cursor.beginEditBlock();
int initialCursorPosition = cursor.position();
int column = cursor.position() - cursor.block().position();
cursor.insertText(lines.first());
for (int i = 1; i < lines.count(); ++i) {
QTextBlock next = cursor.block().next();
if (next.isValid()) {
cursor.setPosition(next.position() + qMin(column, next.length()-1));
} else {
cursor.movePosition(QTextCursor::EndOfBlock);
cursor.insertBlock();
}
int actualColumn = cursor.position() - cursor.block().position();
if (actualColumn < column)
cursor.insertText(QString(column - actualColumn, QLatin1Char(' ')));
cursor.insertText(lines.at(i));
}
cursor.setPosition(initialCursorPosition);
cursor.endEditBlock();
setTextCursor(cursor);
ensureCursorVisible();
return;
}
QString text = source->text();
if (text.isEmpty())
return;
const TabSettings &ts = d->m_document->tabSettings();
QTextCursor cursor = textCursor();
cursor.beginEditBlock();
cursor.insertText(text);
cursor.endEditBlock();
setTextCursor(cursor);
return;
}
cursor.beginEditBlock();
bool insertAtBeginningOfLine = ts.cursorIsAtBeginningOfLine(cursor);
if (insertAtBeginningOfLine
&& source->hasFormat(QLatin1String("application/vnd.nokia.qtcreator.blocktext"))) {
text = QString::fromUtf8(source->data(QLatin1String("application/vnd.nokia.qtcreator.blocktext")));
if (text.isEmpty())
return;
int reindentBlockStart = cursor.blockNumber() + (insertAtBeginningOfLine?0:1);
bool hasFinalNewline = (text.endsWith(QLatin1Char('\n'))
|| text.endsWith(QChar::ParagraphSeparator)
|| text.endsWith(QLatin1Char('\r')));
if (insertAtBeginningOfLine
&& hasFinalNewline) // since we'll add a final newline, preserve current line's indentation
cursor.setPosition(cursor.block().position());
int cursorPosition = cursor.position();
cursor.insertText(text);
int reindentBlockEnd = cursor.blockNumber() - (hasFinalNewline?1:0);
if (reindentBlockStart < reindentBlockEnd
|| (reindentBlockStart == reindentBlockEnd
&& (!insertAtBeginningOfLine || hasFinalNewline))) {
if (insertAtBeginningOfLine && !hasFinalNewline) {
QTextCursor unnecessaryWhitespace = cursor;
unnecessaryWhitespace.setPosition(cursorPosition);
unnecessaryWhitespace.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
unnecessaryWhitespace.removeSelectedText();
QTextCursor c = cursor;
c.setPosition(cursor.document()->findBlockByNumber(reindentBlockStart).position());
c.setPosition(cursor.document()->findBlockByNumber(reindentBlockEnd).position(),
QTextCursor::KeepAnchor);
reindent(document(), c);
}
cursor.endEditBlock();
setTextCursor(cursor);
}
BaseTextEditorEditable::BaseTextEditorEditable(BaseTextEditor *editor)
: e(editor)
{
#ifndef TEXTEDITOR_STANDALONE
using namespace Find;
Aggregation::Aggregate *aggregate = new Aggregation::Aggregate;
BaseTextFind *baseTextFind = new BaseTextFind(editor);
connect(baseTextFind, SIGNAL(highlightAll(QString, Find::IFindSupport::FindFlags)),
editor, SLOT(highlightSearchResults(QString, Find::IFindSupport::FindFlags)));
connect(baseTextFind, SIGNAL(findScopeChanged(QTextCursor)), editor, SLOT(setFindScope(QTextCursor)));
aggregate->add(baseTextFind);
aggregate->add(editor);
#endif
m_cursorPositionLabel = new Utils::LineColumnLabel;
QHBoxLayout *l = new QHBoxLayout;
QWidget *w = new QWidget;
l->setMargin(0);
l->setContentsMargins(5, 0, 5, 0);
l->addStretch(0);
l->addWidget(m_cursorPositionLabel);
w->setLayout(l);
m_toolBar = new QToolBar;
m_toolBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
m_toolBar->addWidget(w);
connect(editor, SIGNAL(cursorPositionChanged()), this, SLOT(updateCursorPosition()));
}
void BaseTextEditor::appendStandardContextMenuActions(QMenu *menu)
{
menu->addSeparator();
Core::ActionManager *am = Core::ICore::instance()->actionManager();
QAction *a = am->command(Core::Constants::CUT)->action();
if (a && a->isEnabled())
menu->addAction(a);
a = am->command(Core::Constants::COPY)->action();
if (a && a->isEnabled())
menu->addAction(a);
a = am->command(Core::Constants::PASTE)->action();
if (a && a->isEnabled())
menu->addAction(a);
}
BaseTextEditorEditable::~BaseTextEditorEditable()
{
delete m_toolBar;
delete e;
}
5464
5465
5466
5467
5468
5469
5470
5471
5472
5473
5474
5475
5476
5477
5478
5479
5480
5481
5482
5483
5484
5485
5486
5487
5488
5489
5490
5491
5492
5493
5494
5495
5496
5497
5498
5499
5500
5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
{
return m_toolBar;
}
int BaseTextEditorEditable::find(const QString &) const
{
return 0;
}
int BaseTextEditorEditable::currentLine() const
{
return e->textCursor().blockNumber() + 1;
}
int BaseTextEditorEditable::currentColumn() const
{
QTextCursor cursor = e->textCursor();
return cursor.position() - cursor.block().position() + 1;
}
QRect BaseTextEditorEditable::cursorRect(int pos) const
{
QTextCursor tc = e->textCursor();
if (pos >= 0)
tc.setPosition(pos);
QRect result = e->cursorRect(tc);
result.moveTo(e->viewport()->mapToGlobal(result.topLeft()));
return result;
}
QString BaseTextEditorEditable::contents() const
{
return e->toPlainText();
}
QString BaseTextEditorEditable::selectedText() const
{
if (e->textCursor().hasSelection())
return e->textCursor().selectedText();
return QString();
}
QString BaseTextEditorEditable::textAt(int pos, int length) const
{
QTextCursor c = e->textCursor();
if (pos < 0)
pos = 0;
c.movePosition(QTextCursor::End);
if (pos + length > c.position())
length = c.position() - pos;
c.setPosition(pos);
c.setPosition(pos + length, QTextCursor::KeepAnchor);
return c.selectedText();
}
void BaseTextEditorEditable::remove(int length)
{
QTextCursor tc = e->textCursor();
tc.setPosition(tc.position() + length, QTextCursor::KeepAnchor);
tc.removeSelectedText();
}
void BaseTextEditorEditable::insert(const QString &string)
{
QTextCursor tc = e->textCursor();
tc.insertText(string);
}
void BaseTextEditorEditable::replace(int length, const QString &string)
{
QTextCursor tc = e->textCursor();
tc.setPosition(tc.position() + length, QTextCursor::KeepAnchor);
tc.insertText(string);
}
void BaseTextEditorEditable::setCurPos(int pos)
{
QTextCursor tc = e->textCursor();
tc.setPosition(pos);
e->setTextCursor(tc);
}
void BaseTextEditorEditable::select(int toPos)
{
QTextCursor tc = e->textCursor();
tc.setPosition(toPos, QTextCursor::KeepAnchor);
e->setTextCursor(tc);
}
void BaseTextEditorEditable::updateCursorPosition()
{
const QTextCursor cursor = e->textCursor();
const QTextBlock block = cursor.block();
const int line = block.blockNumber() + 1;
const int column = cursor.position() - block.position();
m_cursorPositionLabel->setText(tr("Line: %1, Col: %2").arg(line).arg(e->tabSettings().columnAt(block.text(), column)+1),
tr("Line: %1, Col: 999").arg(e->blockCount()));
5564
5565
5566
5567
5568
5569
5570
5571
5572
5573
5574
5575
5576
5577
5578
5579
5580
5581
5582
5583
5584
5585
5586
5587
5588
m_contextHelpId.clear();
if (!block.isVisible())
e->ensureCursorVisible();
}
QString BaseTextEditorEditable::contextHelpId() const
{
if (m_contextHelpId.isEmpty())
emit const_cast<BaseTextEditorEditable*>(this)->contextHelpIdRequested(e->editableInterface(),
e->textCursor().position());
return m_contextHelpId;
}
TextBlockUserData::~TextBlockUserData()
{
TextMarks marks = m_marks;
m_marks.clear();
foreach (ITextMark *mrk, marks) {
mrk->removedFromEditor();
}
}