00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "katerenderer.h"
00024
00025 #include "katedocument.h"
00026 #include "kateconfig.h"
00027 #include "katehighlight.h"
00028 #include "kateview.h"
00029 #include "katerenderrange.h"
00030 #include "katetextlayout.h"
00031
00032 #include <limits.h>
00033
00034 #include <kdebug.h>
00035
00036 #include <QtGui/QPainter>
00037 #include <QtGui/QTextLine>
00038 #include <QtCore/QStack>
00039 #include <QtGui/QBrush>
00040
00041 static const QChar tabChar('\t');
00042 static const QChar spaceChar(' ');
00043
00044 KateRenderer::KateRenderer(KateDocument* doc, KateView *view)
00045 : m_doc(doc), m_view (view), m_caretStyle(KateRenderer::Line)
00046 , m_drawCaret(true)
00047 , m_showSelections(true)
00048 , m_showTabs(true)
00049 , m_showSpaces(true)
00050 , m_printerFriendly(false)
00051 , m_dynamicRegion(doc)
00052 {
00053 m_config = new KateRendererConfig (this);
00054
00055 m_tabWidth = m_doc->config()->tabWidth();
00056 m_indentWidth = m_doc->config()->indentationWidth();
00057
00058 updateAttributes ();
00059 }
00060
00061 KateRenderer::~KateRenderer()
00062 {
00063 delete m_config;
00064 }
00065
00066 void KateRenderer::updateAttributes ()
00067 {
00068 m_attributes = m_doc->highlight()->attributes (config()->schema ());
00069 }
00070
00071 KTextEditor::Attribute::Ptr KateRenderer::attribute(uint pos) const
00072 {
00073 if (pos < (uint)m_attributes.count())
00074 return m_attributes[pos];
00075
00076 return m_attributes[0];
00077 }
00078
00079 KTextEditor::Attribute::Ptr KateRenderer::specificAttribute( int context ) const
00080 {
00081 if (context >= 0 && context < m_attributes.count())
00082 return m_attributes[context];
00083
00084 return m_attributes[0];
00085 }
00086
00087 void KateRenderer::setDrawCaret(bool drawCaret)
00088 {
00089 m_drawCaret = drawCaret;
00090 }
00091
00092 void KateRenderer::setCaretStyle(KateRenderer::caretStyles style)
00093 {
00094 m_caretStyle = style;
00095 }
00096
00097 void KateRenderer::setShowTabs(bool showTabs)
00098 {
00099 m_showTabs = showTabs;
00100 }
00101
00102 void KateRenderer::setShowTrailingSpaces(bool showSpaces)
00103 {
00104 m_showSpaces = showSpaces;
00105 }
00106
00107 void KateRenderer::setTabWidth(int tabWidth)
00108 {
00109 m_tabWidth = tabWidth;
00110 }
00111
00112 bool KateRenderer::showIndentLines() const
00113 {
00114 return m_config->showIndentationLines();
00115 }
00116
00117 void KateRenderer::setShowIndentLines(bool showIndentLines)
00118 {
00119 m_config->setShowIndentationLines(showIndentLines);
00120 }
00121
00122 void KateRenderer::setIndentWidth(int indentWidth)
00123 {
00124 m_indentWidth = indentWidth;
00125 }
00126
00127 void KateRenderer::setShowSelections(bool showSelections)
00128 {
00129 m_showSelections = showSelections;
00130 }
00131
00132 void KateRenderer::increaseFontSizes()
00133 {
00134 QFont f ( config()->font () );
00135 f.setPointSize (f.pointSize ()+1);
00136
00137 config()->setFont (f);
00138 }
00139
00140 void KateRenderer::decreaseFontSizes()
00141 {
00142 QFont f ( config()->font () );
00143
00144 if ((f.pointSize ()-1) > 0)
00145 f.setPointSize (f.pointSize ()-1);
00146
00147 config()->setFont (f);
00148 }
00149
00150 bool KateRenderer::isPrinterFriendly() const
00151 {
00152 return m_printerFriendly;
00153 }
00154
00155 void KateRenderer::setPrinterFriendly(bool printerFriendly)
00156 {
00157 m_printerFriendly = printerFriendly;
00158 setShowTabs(false);
00159 setShowTrailingSpaces(false);
00160 setShowSelections(false);
00161 setDrawCaret(false);
00162 }
00163
00164 void KateRenderer::paintTextLineBackground(QPainter& paint, KateLineLayoutPtr layout, int currentViewLine, int xStart, int xEnd)
00165 {
00166 if (isPrinterFriendly())
00167 return;
00168
00169
00170 QColor backgroundColor( config()->backgroundColor() );
00171
00172
00173 QColor currentLineColor = config()->highlightedLineColor();
00174
00175
00176 int markRed = 0, markGreen = 0, markBlue = 0, markCount = 0;
00177
00178
00179 uint mrk = m_doc->mark( layout->line() );
00180 if (mrk)
00181 {
00182 for (uint bit = 0; bit < 32; bit++)
00183 {
00184 KTextEditor::MarkInterface::MarkTypes markType = (KTextEditor::MarkInterface::MarkTypes)(1<<bit);
00185 if (mrk & markType)
00186 {
00187 QColor markColor = config()->lineMarkerColor(markType);
00188
00189 if (markColor.isValid()) {
00190 markCount++;
00191 markRed += markColor.red();
00192 markGreen += markColor.green();
00193 markBlue += markColor.blue();
00194 }
00195 }
00196 }
00197 }
00198
00199 if (markCount) {
00200 markRed /= markCount;
00201 markGreen /= markCount;
00202 markBlue /= markCount;
00203 backgroundColor.setRgb(
00204 int((backgroundColor.red() * 0.9) + (markRed * 0.1)),
00205 int((backgroundColor.green() * 0.9) + (markGreen * 0.1)),
00206 int((backgroundColor.blue() * 0.9) + (markBlue * 0.1))
00207 );
00208 }
00209
00210
00211 paint.fillRect(0, 0, xEnd - xStart, config()->fontMetrics().height() * layout->viewLineCount(), backgroundColor);
00212
00213
00214 if (currentViewLine != -1) {
00215 if (markCount) {
00216 markRed /= markCount;
00217 markGreen /= markCount;
00218 markBlue /= markCount;
00219 currentLineColor.setRgb(
00220 int((currentLineColor.red() * 0.9) + (markRed * 0.1)),
00221 int((currentLineColor.green() * 0.9) + (markGreen * 0.1)),
00222 int((currentLineColor.blue() * 0.9) + (markBlue * 0.1))
00223 );
00224 }
00225
00226 paint.fillRect(0, config()->fontMetrics().height() * currentViewLine, xEnd - xStart, config()->fontMetrics().height(), currentLineColor);
00227 }
00228 }
00229
00230 void KateRenderer::paintTabstop(QPainter &paint, qreal x, qreal y)
00231 {
00232 QPen penBackup( paint.pen() );
00233 QPen pen( config()->tabMarkerColor() );
00234 pen.setWidthF(qMax(0.5, spaceWidth() * .1));
00235 pen.setCapStyle(Qt::RoundCap);
00236 paint.setPen( pen );
00237
00238
00239 qreal dist = spaceWidth() * 0.3;
00240 QPointF points[8];
00241 points[0] = QPointF(x - dist, y - dist);
00242 points[1] = QPointF(x, y);
00243 points[2] = QPointF(x, y);
00244 points[3] = QPointF(x - dist, y + dist);
00245 x += spaceWidth() / 3.0;
00246 points[4] = QPointF(x - dist, y - dist);
00247 points[5] = QPointF(x, y);
00248 points[6] = QPointF(x, y);
00249 points[7] = QPointF(x - dist, y + dist);
00250 paint.drawLines(points, 4);
00251 paint.setPen( penBackup );
00252 }
00253
00254 void KateRenderer::paintTrailingSpace(QPainter &paint, qreal x, qreal y)
00255 {
00256 QPen penBackup( paint.pen() );
00257 QPen pen( config()->tabMarkerColor() );
00258 pen.setWidthF(spaceWidth() / 3.5);
00259 pen.setCapStyle(Qt::RoundCap);
00260 paint.setPen( pen );
00261
00262 paint.drawPoint( QPointF(x, y) );
00263 paint.setPen( penBackup );
00264 }
00265
00266 void KateRenderer::paintIndentMarker(QPainter &paint, uint x, uint row)
00267 {
00268 QPen penBackup( paint.pen() );
00269 paint.setPen( config()->tabMarkerColor() );
00270
00271 const int height = config()->fontMetrics().height();
00272 const int top = 0;
00273 const int bottom = height-1;
00274 const int h = bottom - top + 1;
00275
00276
00277 int pad = 0;
00278 if(row & 1 && h & 1) pad = 1;
00279
00280 for(int i = top; i <= bottom; i++)
00281 {
00282 if((i + pad) & 1)
00283 {
00284 paint.drawPoint(x + 2, i);
00285 }
00286 }
00287
00288 paint.setPen( penBackup );
00289 }
00290
00291 QList<QTextLayout::FormatRange> KateRenderer::decorationsForLine( const KateTextLine::Ptr& textLine, int line, bool selectionsOnly, KateRenderRange* completionHighlight, bool completionSelected ) const
00292 {
00293 QList<QTextLayout::FormatRange> newHighlight;
00294
00295
00296 if (selectionsOnly || textLine->attributesList().count() || m_view->externalHighlights().count() || m_view->internalHighlights().count() || m_doc->documentHighlights().count()) {
00297 RenderRangeList renderRanges;
00298
00299
00300 NormalRenderRange* inbuiltHighlight = new NormalRenderRange();
00301 const QVector<int> &al = textLine->attributesList();
00302 for (int i = 0; i+2 < al.count(); i += 3) {
00303 inbuiltHighlight->addRange(new KTextEditor::Range(KTextEditor::Cursor(line, al[i]), al[i+1]), specificAttribute(al[i+2]));
00304 }
00305 renderRanges.append(inbuiltHighlight);
00306
00307 if (!completionHighlight) {
00308
00309 renderRanges.appendRanges(m_view->internalHighlights(), selectionsOnly, view());
00310 renderRanges.appendRanges(m_view->externalHighlights(), selectionsOnly, view());
00311 renderRanges.appendRanges(m_doc->documentHighlights(), selectionsOnly, view());
00312
00313 } else {
00314
00315 renderRanges.append(completionHighlight);
00316 }
00317
00318
00319 if ((selectionsOnly && showSelections() && m_view->selection()) || (completionHighlight && completionSelected) || m_view->blockSelection()) {
00320 NormalRenderRange* selectionHighlight = new NormalRenderRange();
00321
00322
00323 static KTextEditor::Attribute::Ptr backgroundAttribute;
00324 if (!backgroundAttribute)
00325 backgroundAttribute = KTextEditor::Attribute::Ptr(new KTextEditor::Attribute());
00326
00327 backgroundAttribute->setBackground(config()->selectionColor());
00328
00329
00330 if (completionHighlight && completionSelected)
00331 selectionHighlight->addRange(new KTextEditor::Range(line, 0, line + 1, 0), backgroundAttribute);
00332 else
00333 if(m_view->blockSelection() && m_view->selectionRange().overlapsLine(line))
00334 selectionHighlight->addRange(new KTextEditor::Range(line, m_view->selectionRange().start().column(), line, m_view->selectionRange().end().column()), backgroundAttribute);
00335 else
00336 selectionHighlight->addRange(new KTextEditor::Range(m_view->selectionRange()), backgroundAttribute);
00337
00338 renderRanges.append(selectionHighlight);
00339 }
00340
00341 KTextEditor::Cursor currentPosition, endPosition;
00342
00343
00344 if (selectionsOnly) {
00345 if(m_view->blockSelection()) {
00346 int startColumn = m_view->selectionRange().start().column();
00347 int endColumn = m_view->selectionRange().end().column();
00348 currentPosition = KTextEditor::Cursor(line, qMin(startColumn, endColumn));
00349 endPosition = KTextEditor::Cursor(line, qMax(startColumn, endColumn));
00350 } else {
00351 KTextEditor::Range rangeNeeded = m_view->selectionRange().encompass(m_dynamicRegion.boundingRange());
00352 rangeNeeded &= KTextEditor::Range(line, 0, line + 1, 0);
00353
00354 currentPosition = qMax(KTextEditor::Cursor(line, 0), rangeNeeded.start());
00355 endPosition = qMin(KTextEditor::Cursor(line + 1, 0), rangeNeeded.end());
00356 }
00357 } else {
00358 currentPosition = KTextEditor::Cursor(line, 0);
00359 endPosition = KTextEditor::Cursor(line + 1, 0);
00360 }
00361
00362
00363
00364 while (currentPosition < endPosition) {
00365 renderRanges.advanceTo(currentPosition);
00366
00367 if (!renderRanges.hasAttribute()) {
00368
00369 currentPosition = renderRanges.nextBoundary();
00370 continue;
00371 }
00372
00373 KTextEditor::Cursor nextPosition = renderRanges.nextBoundary();
00374
00375
00376 QTextLayout::FormatRange fr;
00377 fr.start = currentPosition.column();
00378
00379 if (nextPosition < endPosition || endPosition.line() <= line) {
00380 fr.length = nextPosition.column() - currentPosition.column();
00381
00382 } else {
00383
00384 fr.length = textLine->length() - currentPosition.column() + 1;
00385 }
00386
00387 KTextEditor::Attribute a = renderRanges.generateAttribute();
00388 fr.format = a;
00389
00390 if(selectionsOnly) {
00391 if(m_view->blockSelection()) {
00392 int minSelectionColumn = qMin(m_view->selectionRange().start().column(), m_view->selectionRange().end().column());
00393 int maxSelectionColumn = qMax(m_view->selectionRange().start().column(), m_view->selectionRange().end().column());
00394
00395 if(currentPosition.column() >= minSelectionColumn && currentPosition.column() < maxSelectionColumn)
00396 assignSelectionBrushesFromAttribute(fr, a);
00397
00398 } else if (m_view->selection() && m_view->selectionRange().contains(currentPosition)) {
00399 assignSelectionBrushesFromAttribute(fr, a);
00400 }
00401 }
00402
00403 newHighlight.append(fr);
00404
00405 currentPosition = nextPosition;
00406 }
00407
00408 if (completionHighlight)
00409
00410 renderRanges.removeAll(completionHighlight);
00411
00412 qDeleteAll(renderRanges);
00413 }
00414
00415 return newHighlight;
00416 }
00417
00418 void KateRenderer::assignSelectionBrushesFromAttribute(QTextLayout::FormatRange& target, const KTextEditor::Attribute& attribute) const
00419 {
00420 if(attribute.hasProperty(KTextEditor::Attribute::SelectedForeground)) {
00421 target.format.setForeground(attribute.selectedForeground());
00422 }
00423 if(attribute.hasProperty(KTextEditor::Attribute::SelectedBackground)) {
00424 target.format.setBackground(attribute.selectedBackground());
00425 }
00426 }
00427
00428
00429
00430
00431
00432
00433 void KateRenderer::paintTextLine(QPainter& paint, KateLineLayoutPtr range, int xStart, int xEnd, const KTextEditor::Cursor* cursor)
00434 {
00435 Q_ASSERT(range->isValid());
00436
00437
00438
00439
00440 const QFontMetrics& fm = config()->fontMetrics();
00441
00442 int currentViewLine = -1;
00443 if (cursor && cursor->line() == range->line())
00444 currentViewLine = range->viewLineForColumn(cursor->column());
00445
00446 paintTextLineBackground(paint, range, currentViewLine, xStart, xEnd);
00447
00448
00449 if (range->startsInvisibleBlock()) {
00450 paint.setPen(QPen(config()->wordWrapMarkerColor(), 1, Qt::DashLine));
00451 paint.drawLine(0, (fm.height() * range->viewLineCount()) - 1, xEnd - xStart, (fm.height() * range->viewLineCount()) - 1);
00452 }
00453
00454 if (range->layout()) {
00455 QVector<QTextLayout::FormatRange> additionalFormats;
00456 if (range->length() > 0) {
00457
00458
00459
00460 paint.setPen(attribute(KateExtendedAttribute::dsNormal)->foreground().color());
00461
00462 if (m_dynamicRegion.boundingRange().isValid() || (m_view->selection() && showSelections() && m_view->selectionRange().overlapsLine(range->line()))) {
00463
00464 additionalFormats = decorationsForLine(range->textLine(), range->line(), true).toVector();
00465 range->layout()->draw(&paint, QPoint(-xStart,0), additionalFormats);
00466
00467 } else {
00468 range->layout()->draw(&paint, QPoint(-xStart,0));
00469 }
00470 }
00471
00472 QBrush backgroundBrush;
00473 bool backgroundBrushSet = false;
00474
00475
00476 QListIterator<QTextLayout::FormatRange> it = range->layout()->additionalFormats();
00477 QVectorIterator<QTextLayout::FormatRange> it2 = additionalFormats;
00478 for (int i = 0; i < range->viewLineCount(); ++i) {
00479 KateTextLayout line = range->viewLine(i);
00480
00481
00482 backgroundBrushSet = false;
00483 while (it2.hasNext()) {
00484 const QTextLayout::FormatRange& fr = it2.peekNext();
00485 if (fr.start > line.endCol())
00486 goto backgroundDetermined;
00487
00488 if (fr.start + fr.length > line.endCol()) {
00489 if (fr.format.hasProperty(QTextFormat::BackgroundBrush)) {
00490 backgroundBrushSet = true;
00491 backgroundBrush = fr.format.background();
00492 }
00493
00494 goto backgroundDetermined;
00495 }
00496
00497 it2.next();
00498 }
00499
00500 while (it.hasNext()) {
00501 const QTextLayout::FormatRange& fr = it.peekNext();
00502 if (fr.start > line.endCol())
00503 break;
00504
00505 if (fr.start + fr.length > line.endCol()) {
00506 if (fr.format.hasProperty(QTextFormat::BackgroundBrush)) {
00507 backgroundBrushSet = true;
00508 backgroundBrush = fr.format.background();
00509 }
00510
00511 break;
00512 }
00513
00514 it.next();
00515 }
00516
00517 backgroundDetermined:
00518
00519
00520 if (!m_printerFriendly ) {
00521 bool draw = false;
00522 QBrush drawBrush;
00523 if (m_view->selection() && !m_view->blockSelection() && m_view->lineEndSelected(line.end(true))) {
00524 draw = true;
00525 drawBrush = config()->selectionColor();
00526 } else if (backgroundBrushSet && !m_view->blockSelection()) {
00527 draw = true;
00528 drawBrush = backgroundBrush;
00529 }
00530
00531 if (draw) {
00532 int fillStartX = line.endX() - line.startX() + line.xOffset() - xStart;
00533 int fillStartY = fm.height() * i;
00534 int width= xEnd - xStart - fillStartX;
00535 int height= fm.height();
00536
00537
00538 if (range->layout()->textOption().alignment() == Qt::AlignRight)
00539 fillStartX = 0;
00540
00541 QRect area(fillStartX, fillStartY, width, height);
00542 paint.fillRect(area, drawBrush);
00543 }
00544 }
00545
00546 if (showIndentLines() && i == 0)
00547 {
00548 const int w = spaceWidth();
00549 const int lastIndentColumn = range->textLine()->indentDepth(m_tabWidth);
00550
00551 for (int x = m_indentWidth; x < lastIndentColumn; x += m_indentWidth)
00552 {
00553 paintIndentMarker(paint, x * w + 1 - xStart, range->line());
00554 }
00555 }
00556
00557
00558 if (showTabs() || showTrailingSpaces()) {
00559 const QString& text = range->textLine()->string();
00560 int y = fm.height() * i + fm.ascent() - fm.strikeOutPos();
00561
00562 if (showTabs()) {
00563 int tabIndex = text.indexOf(tabChar, line.startCol());
00564 while (tabIndex != -1 && tabIndex < line.endCol()) {
00565 paintTabstop(paint, line.lineLayout().cursorToX(tabIndex) - xStart + spaceWidth()/2.0, y);
00566 tabIndex = text.indexOf(tabChar, tabIndex + 1);
00567 }
00568 }
00569
00570 if (showTrailingSpaces()) {
00571 int spaceIndex = line.endCol() - 1;
00572 int trailingPos = range->textLine()->lastChar();
00573 if (trailingPos < 0)
00574 trailingPos = 0;
00575 if (spaceIndex >= trailingPos) {
00576 while (spaceIndex >= line.startCol() && text.at(spaceIndex).isSpace()) {
00577 if (text.at(spaceIndex) != '\t' || !showTabs())
00578 paintTrailingSpace(paint, line.lineLayout().cursorToX(spaceIndex) - xStart + spaceWidth()/2.0, y);
00579 --spaceIndex;
00580 }
00581 }
00582 }
00583 }
00584 }
00585
00586
00587 if ( (range->viewLineCount() > 1) && range->shiftX() && (range->shiftX() > xStart) )
00588 {
00589 if (backgroundBrushSet)
00590 paint.fillRect(0, fm.height(), range->shiftX() - xStart, fm.height() * (range->viewLineCount() - 1),
00591 backgroundBrush);
00592 paint.fillRect(0, fm.height(), range->shiftX() - xStart, fm.height() * (range->viewLineCount() - 1),
00593 QBrush(config()->wordWrapMarkerColor(), Qt::Dense4Pattern));
00594 }
00595
00596
00597 if (drawCaret() && cursor && range->includesCursor(*cursor)) {
00598
00599 int caretWidth = 2;
00600 QTextLine line = range->layout()->lineForTextPosition(cursor->column());
00601 if (caretStyle() == Block) {
00602 if (line.isValid() && cursor->column() < range->length()) {
00603 caretWidth = int(line.cursorToX(cursor->column() + 1) - line.cursorToX(cursor->column()));
00604 if (caretWidth < 0)
00605 caretWidth = -caretWidth;
00606
00607 } else {
00608 caretWidth = spaceWidth();
00609 }
00610 }
00611
00612 QColor c;
00613
00614 if (m_caretOverrideColor.isValid()) {
00615 c = m_caretOverrideColor;
00616
00617 } else {
00618 foreach (const QTextLayout::FormatRange &r, range->layout()->additionalFormats())
00619 if ( (r.start <= cursor->column() ) && ( (r.start + r.length) > cursor->column()) ) {
00620 c = r.format.foreground().color();
00621 break;
00622 }
00623 if (!c.isValid())
00624 if (range->layout()->additionalFormats().count())
00625 c = range->layout()->additionalFormats().last().format.foreground().color();
00626 else
00627 c = attribute(KateExtendedAttribute::dsNormal)->foreground().color();
00628 }
00629
00630 if (cursor->column() <= range->length()) {
00631 paint.save();
00632 paint.setPen(QPen(c, caretWidth));
00633
00634
00635 paint.setClipRect(0, line.lineNumber() * fm.height(), xEnd - xStart, fm.height());
00636
00637 range->layout()->drawCursor(&paint, QPoint(-xStart,0), cursor->column(), caretWidth);
00638
00639 paint.restore();
00640
00641 } else {
00642
00643 const KateTextLayout& lastLine = range->viewLine(range->viewLineCount() - 1);
00644 int x = range->widthOfLastLine() + spaceWidth() * (cursor->column() - range->length());
00645 if ( (x >= xStart) && (x <= xEnd))
00646 paint.fillRect(x, (int)lastLine.lineLayout().y(), caretWidth, fm.height(), c);
00647 }
00648 }
00649 }
00650
00651
00652 if ((!isPrinterFriendly()) && config()->wordWrapMarker() && QFontInfo(config()->font()).fixedPitch())
00653 {
00654 paint.setPen( config()->wordWrapMarkerColor() );
00655 int _x = m_doc->config()->wordWrapAt() * fm.width('x') - xStart;
00656 paint.drawLine( _x,0,_x,fm.height() );
00657 }
00658 }
00659
00660 const QFont& KateRenderer::currentFont() const
00661 {
00662 return config()->font();
00663 }
00664
00665 const QFontMetrics& KateRenderer::currentFontMetrics() const
00666 {
00667 return config()->fontMetrics();
00668 }
00669
00670 uint KateRenderer::fontHeight()
00671 {
00672 return config()->fontMetrics().height();
00673 }
00674
00675 uint KateRenderer::documentHeight()
00676 {
00677 return m_doc->lines() * fontHeight();
00678 }
00679
00680 bool KateRenderer::getSelectionBounds(int line, int lineLength, int &start, int &end) const
00681 {
00682 bool hasSel = false;
00683
00684 if (m_view->selection() && !m_view->blockSelectionMode())
00685 {
00686 if (m_view->lineIsSelection(line))
00687 {
00688 start = m_view->selectionRange().start().column();
00689 end = m_view->selectionRange().end().column();
00690 hasSel = true;
00691 }
00692 else if (line == m_view->selectionRange().start().line())
00693 {
00694 start = m_view->selectionRange().start().column();
00695 end = lineLength;
00696 hasSel = true;
00697 }
00698 else if (m_view->selectionRange().containsLine(line))
00699 {
00700 start = 0;
00701 end = lineLength;
00702 hasSel = true;
00703 }
00704 else if (line == m_view->selectionRange().end().line())
00705 {
00706 start = 0;
00707 end = m_view->selectionRange().end().column();
00708 hasSel = true;
00709 }
00710 }
00711 else if (m_view->lineHasSelected(line))
00712 {
00713 start = m_view->selectionRange().start().column();
00714 end = m_view->selectionRange().end().column();
00715 hasSel = true;
00716 }
00717
00718 if (start > end) {
00719 int temp = end;
00720 end = start;
00721 start = temp;
00722 }
00723
00724 return hasSel;
00725 }
00726
00727 void KateRenderer::updateConfig ()
00728 {
00729
00730 updateAttributes ();
00731
00732 if (m_view)
00733 m_view->updateRendererConfig();
00734 }
00735
00736 uint KateRenderer::spaceWidth() const
00737 {
00738 return config()->fontMetrics().width(spaceChar);
00739 }
00740
00741 void KateRenderer::layoutLine(KateLineLayoutPtr lineLayout, int maxwidth, bool cacheLayout) const
00742 {
00743
00744
00745 Q_ASSERT(lineLayout->textLine());
00746
00747 QTextLayout* l = lineLayout->layout();
00748 if (!l) {
00749 l = new QTextLayout(lineLayout->textLine()->string(), config()->font());
00750 } else {
00751 l->setText(lineLayout->textLine()->string());
00752 l->setFont(config()->font());
00753 }
00754
00755 l->setCacheEnabled(cacheLayout);
00756
00757
00758
00759
00760 QTextOption opt;
00761 opt.setFlags(QTextOption::IncludeTrailingSpaces);
00762 opt.setTabStop(m_tabWidth * config()->fontMetrics().width(spaceChar));
00763 opt.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
00764
00765
00766
00767
00768
00769
00770
00771
00772 if (isLineRightToLeft(lineLayout)) {
00773 opt.setAlignment( Qt::AlignRight );
00774 opt.setTextDirection( Qt::RightToLeft );
00775 }
00776 else {
00777 opt.setAlignment( Qt::AlignLeft );
00778 opt.setTextDirection( Qt::LeftToRight );
00779 }
00780
00781 l->setTextOption(opt);
00782
00783
00784 l->setAdditionalFormats(decorationsForLine(lineLayout->textLine(), lineLayout->line()));
00785
00786
00787 l->beginLayout();
00788
00789 int height = 0;
00790 int shiftX = 0;
00791
00792 bool needShiftX = (maxwidth != -1)
00793 && (m_view->config()->dynWordWrapAlignIndent() > 0);
00794
00795 forever {
00796 QTextLine line = l->createLine();
00797 if (!line.isValid())
00798 break;
00799
00800 if (maxwidth > 0)
00801 line.setLineWidth(maxwidth);
00802
00803 line.setPosition(QPoint(line.lineNumber() ? shiftX : 0, height));
00804
00805 if (needShiftX) {
00806 needShiftX = false;
00807
00808 int pos = lineLayout->textLine()->nextNonSpaceChar(0);
00809
00810 if (pos > 0) {
00811 shiftX = (int)line.cursorToX(pos);
00812 }
00813
00814
00815 if (shiftX > ((double)maxwidth / 100 * m_view->config()->dynWordWrapAlignIndent()))
00816 shiftX = 0;
00817
00818
00819 maxwidth -= shiftX;
00820
00821 lineLayout->setShiftX(shiftX);
00822 }
00823
00824 height += config()->fontMetrics().height();
00825 }
00826
00827 l->endLayout();
00828
00829 lineLayout->setLayout(l);
00830 }
00831
00832
00833
00834
00835
00836
00837
00838 bool KateRenderer::isLineRightToLeft( KateLineLayoutPtr lineLayout ) const
00839 {
00840 QString s = lineLayout->textLine()->string();
00841 int i = s.length();
00842 int RTLchars = 0;
00843 int LTRchars = 0;
00844
00845
00846 while( i != 0 )
00847 {
00848 QChar c = s.at(i-1);
00849
00850 switch(c.direction()) {
00851 case QChar::DirL:
00852 case QChar::DirLRO:
00853 case QChar::DirLRE:
00854 LTRchars ++;
00855 break;
00856
00857 case QChar::DirR:
00858 case QChar::DirAL:
00859 case QChar::DirRLO:
00860 case QChar::DirRLE:
00861 RTLchars ++;
00862 break;
00863
00864 default:
00865 break;
00866 }
00867 i --;
00868 }
00869
00870 return (RTLchars > LTRchars);
00871 }
00872
00873 int KateRenderer::cursorToX(const KateTextLayout& range, int col) const
00874 {
00875 return cursorToX(range, KTextEditor::Cursor(range.line(), col));
00876 }
00877
00878 int KateRenderer::cursorToX(const KateTextLayout& range, const KTextEditor::Cursor & pos) const
00879 {
00880 Q_ASSERT(range.isValid());
00881
00882 return (int)range.lineLayout().cursorToX(pos.column());
00883 }
00884
00885 KTextEditor::Cursor KateRenderer::xToCursor(const KateTextLayout & range, int x, bool returnPastLine ) const
00886 {
00887 Q_ASSERT(range.isValid());
00888
00889 int adjustedX = x;
00890
00891 if (adjustedX < range.xOffset())
00892 adjustedX = range.xOffset();
00893 else if (adjustedX > range.width() + range.xOffset())
00894 adjustedX = range.width() + range.xOffset();
00895
00896 Q_ASSERT(range.isValid());
00897 KTextEditor::Cursor ret(range.line(), range.lineLayout().xToCursor(adjustedX));
00898
00899 if (returnPastLine && x > range.width() + range.xOffset())
00900 ret.setColumn(ret.column() + ((x - (range.width() + range.xOffset())) / spaceWidth()));
00901
00902 return ret;
00903 }
00904
00905 void KateRenderer::setCaretOverrideColor(const QColor& color)
00906 {
00907 m_caretOverrideColor = color;
00908 }
00909
00910