File indexing completed on 2024-04-21 03:57:33

0001 /*
0002     SPDX-FileCopyrightText: 2002-2005 Hamish Rodda <rodda@kde.org>
0003     SPDX-FileCopyrightText: 2003 Anakim Border <aborder@sources.sourceforge.net>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "katelinelayout.h"
0009 #include "katetextfolding.h"
0010 #include "katetextlayout.h"
0011 
0012 #include <QTextLine>
0013 
0014 #include "katepartdebug.h"
0015 
0016 #include "katedocument.h"
0017 #include "katerenderer.h"
0018 
0019 KateLineLayout::KateLineLayout(KateRenderer &renderer)
0020     : m_renderer(renderer)
0021     , m_line(-1)
0022     , m_virtualLine(-1)
0023     , m_layout(nullptr)
0024 {
0025 }
0026 
0027 void KateLineLayout::clear()
0028 {
0029     m_textLine.reset();
0030     m_line = -1;
0031     m_virtualLine = -1;
0032     shiftX = 0;
0033     // not touching dirty
0034     m_layout.reset();
0035     // not touching layout dirty
0036 }
0037 
0038 bool KateLineLayout::includesCursor(const KTextEditor::Cursor realCursor) const
0039 {
0040     return realCursor.line() == line();
0041 }
0042 
0043 const Kate::TextLine &KateLineLayout::textLine(bool reloadForce) const
0044 {
0045     if (reloadForce || !m_textLine) {
0046         m_textLine.reset();
0047         if (m_line >= 0 && m_line < m_renderer.doc()->lines()) {
0048             m_textLine = usePlainTextLine ? m_renderer.doc()->plainKateTextLine(m_line) : m_renderer.doc()->kateTextLine(m_line);
0049         }
0050     }
0051 
0052     Q_ASSERT(m_textLine);
0053 
0054     return *m_textLine;
0055 }
0056 
0057 int KateLineLayout::line() const
0058 {
0059     return m_line;
0060 }
0061 
0062 void KateLineLayout::setLine(int line, int virtualLine)
0063 {
0064     m_line = line;
0065     m_virtualLine = (virtualLine == -1) ? m_renderer.folding().lineToVisibleLine(line) : virtualLine;
0066     m_textLine.reset();
0067 }
0068 
0069 int KateLineLayout::virtualLine() const
0070 {
0071     return m_virtualLine;
0072 }
0073 
0074 void KateLineLayout::setVirtualLine(int virtualLine)
0075 {
0076     m_virtualLine = virtualLine;
0077 }
0078 
0079 bool KateLineLayout::startsInvisibleBlock() const
0080 {
0081     if (!isValid()) {
0082         return false;
0083     }
0084 
0085     return (virtualLine() + 1) != m_renderer.folding().lineToVisibleLine(line() + 1);
0086 }
0087 
0088 bool KateLineLayout::isValid() const
0089 {
0090     return line() != -1 && layout() && (textLine(), m_textLine);
0091 }
0092 
0093 QTextLayout *KateLineLayout::layout() const
0094 {
0095     return m_layout.get();
0096 }
0097 
0098 void KateLineLayout::setLayout(QTextLayout *layout)
0099 {
0100     if (m_layout.get() != layout) {
0101         m_layout.reset(layout);
0102     }
0103 
0104     layoutDirty = !m_layout;
0105     m_dirtyList.clear();
0106     if (m_layout) {
0107         for (int i = 0; i < qMax(1, m_layout->lineCount()); ++i) {
0108             m_dirtyList.append(true);
0109         }
0110     }
0111 }
0112 
0113 void KateLineLayout::invalidateLayout()
0114 {
0115     setLayout(nullptr);
0116 }
0117 
0118 bool KateLineLayout::isDirty(int viewLine) const
0119 {
0120     Q_ASSERT(isValid() && viewLine >= 0 && viewLine < viewLineCount());
0121     return m_dirtyList[viewLine];
0122 }
0123 
0124 bool KateLineLayout::setDirty(int viewLine, bool dirty)
0125 {
0126     Q_ASSERT(isValid() && viewLine >= 0 && viewLine < viewLineCount());
0127     m_dirtyList[viewLine] = dirty;
0128     return dirty;
0129 }
0130 
0131 KTextEditor::Cursor KateLineLayout::start() const
0132 {
0133     return KTextEditor::Cursor(line(), 0);
0134 }
0135 
0136 int KateLineLayout::length() const
0137 {
0138     return textLine().length();
0139 }
0140 
0141 int KateLineLayout::viewLineCount() const
0142 {
0143     return m_layout->lineCount();
0144 }
0145 
0146 KateTextLayout KateLineLayout::viewLine(int viewLine)
0147 {
0148     if (viewLine < 0) {
0149         viewLine += viewLineCount();
0150     }
0151     Q_ASSERT(isValid());
0152     Q_ASSERT(viewLine >= 0 && viewLine < viewLineCount());
0153     return KateTextLayout(this, viewLine);
0154 }
0155 
0156 int KateLineLayout::width() const
0157 {
0158     int width = 0;
0159 
0160     for (int i = 0; i < m_layout->lineCount(); ++i) {
0161         width = qMax((int)m_layout->lineAt(i).naturalTextWidth(), width);
0162     }
0163 
0164     return width;
0165 }
0166 
0167 int KateLineLayout::widthOfLastLine()
0168 {
0169     const KateTextLayout &lastLine = viewLine(viewLineCount() - 1);
0170     return lastLine.width() + lastLine.xOffset();
0171 }
0172 
0173 bool KateLineLayout::isOutsideDocument() const
0174 {
0175     return line() < 0 || line() >= m_renderer.doc()->lines();
0176 }
0177 
0178 void KateLineLayout::debugOutput() const
0179 {
0180     qCDebug(LOG_KTE) << "KateLineLayout: " << this << " valid " << isValid() << " line " << line() << " length " << length() << " width " << width()
0181                      << " viewLineCount " << viewLineCount();
0182 }
0183 
0184 int KateLineLayout::viewLineForColumn(int column) const
0185 {
0186     int len = 0;
0187     int i = 0;
0188     for (; i < m_layout->lineCount() - 1; ++i) {
0189         len += m_layout->lineAt(i).textLength();
0190         if (column < len) {
0191             return i;
0192         }
0193     }
0194     return i;
0195 }
0196 
0197 bool KateLineLayout::isRightToLeft() const
0198 {
0199     if (!m_layout) {
0200         return false;
0201     }
0202 
0203     return m_layout->textOption().textDirection() == Qt::RightToLeft;
0204 }