File indexing completed on 2024-04-28 15:30:35

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_textLine()
0022     , m_line(-1)
0023     , m_virtualLine(-1)
0024     , m_shiftX(0)
0025     , m_layout(nullptr)
0026     , m_layoutDirty(true)
0027     , m_usePlainTextLine(false)
0028 {
0029 }
0030 
0031 void KateLineLayout::clear()
0032 {
0033     m_textLine = Kate::TextLine();
0034     m_line = -1;
0035     m_virtualLine = -1;
0036     m_shiftX = 0;
0037     // not touching dirty
0038     m_layout.reset();
0039     // not touching layout dirty
0040 }
0041 
0042 bool KateLineLayout::includesCursor(const KTextEditor::Cursor realCursor) const
0043 {
0044     return realCursor.line() == line();
0045 }
0046 
0047 const Kate::TextLine &KateLineLayout::textLine(bool reloadForce) const
0048 {
0049     if (reloadForce || !m_textLine) {
0050         m_textLine = usePlainTextLine() ? m_renderer.doc()->plainKateTextLine(line()) : m_renderer.doc()->kateTextLine(line());
0051     }
0052 
0053     Q_ASSERT(m_textLine);
0054 
0055     return m_textLine;
0056 }
0057 
0058 int KateLineLayout::line() const
0059 {
0060     return m_line;
0061 }
0062 
0063 void KateLineLayout::setLine(int line, int virtualLine)
0064 {
0065     m_line = line;
0066     m_virtualLine = (virtualLine == -1) ? m_renderer.folding().lineToVisibleLine(line) : virtualLine;
0067     m_textLine = Kate::TextLine();
0068 }
0069 
0070 int KateLineLayout::virtualLine() const
0071 {
0072     return m_virtualLine;
0073 }
0074 
0075 void KateLineLayout::setVirtualLine(int virtualLine)
0076 {
0077     m_virtualLine = virtualLine;
0078 }
0079 
0080 bool KateLineLayout::startsInvisibleBlock() const
0081 {
0082     if (!isValid()) {
0083         return false;
0084     }
0085 
0086     return (virtualLine() + 1) != m_renderer.folding().lineToVisibleLine(line() + 1);
0087 }
0088 
0089 int KateLineLayout::shiftX() const
0090 {
0091     return m_shiftX;
0092 }
0093 
0094 void KateLineLayout::setShiftX(int shiftX)
0095 {
0096     m_shiftX = shiftX;
0097 }
0098 
0099 KTextEditor::DocumentPrivate *KateLineLayout::doc() const
0100 {
0101     return m_renderer.doc();
0102 }
0103 
0104 bool KateLineLayout::isValid() const
0105 {
0106     return line() != -1 && layout() && textLine();
0107 }
0108 
0109 QTextLayout *KateLineLayout::layout() const
0110 {
0111     return m_layout.get();
0112 }
0113 
0114 void KateLineLayout::setLayout(QTextLayout *layout)
0115 {
0116     if (m_layout.get() != layout) {
0117         m_layout.reset(layout);
0118     }
0119 
0120     m_layoutDirty = !m_layout;
0121     m_dirtyList.clear();
0122     if (m_layout) {
0123         for (int i = 0; i < qMax(1, m_layout->lineCount()); ++i) {
0124             m_dirtyList.append(true);
0125         }
0126     }
0127 }
0128 
0129 void KateLineLayout::invalidateLayout()
0130 {
0131     setLayout(nullptr);
0132 }
0133 
0134 bool KateLineLayout::isDirty(int viewLine) const
0135 {
0136     Q_ASSERT(isValid() && viewLine >= 0 && viewLine < viewLineCount());
0137     return m_dirtyList[viewLine];
0138 }
0139 
0140 bool KateLineLayout::setDirty(int viewLine, bool dirty)
0141 {
0142     Q_ASSERT(isValid() && viewLine >= 0 && viewLine < viewLineCount());
0143     m_dirtyList[viewLine] = dirty;
0144     return dirty;
0145 }
0146 
0147 KTextEditor::Cursor KateLineLayout::start() const
0148 {
0149     return KTextEditor::Cursor(line(), 0);
0150 }
0151 
0152 int KateLineLayout::length() const
0153 {
0154     return textLine()->length();
0155 }
0156 
0157 int KateLineLayout::viewLineCount() const
0158 {
0159     return m_layout->lineCount();
0160 }
0161 
0162 KateTextLayout KateLineLayout::viewLine(int viewLine) const
0163 {
0164     if (viewLine < 0) {
0165         viewLine += viewLineCount();
0166     }
0167     Q_ASSERT(isValid());
0168     Q_ASSERT(viewLine >= 0 && viewLine < viewLineCount());
0169     return KateTextLayout(KateLineLayoutPtr(const_cast<KateLineLayout *>(this)), viewLine);
0170 }
0171 
0172 int KateLineLayout::width() const
0173 {
0174     int width = 0;
0175 
0176     for (int i = 0; i < m_layout->lineCount(); ++i) {
0177         width = qMax((int)m_layout->lineAt(i).naturalTextWidth(), width);
0178     }
0179 
0180     return width;
0181 }
0182 
0183 int KateLineLayout::widthOfLastLine() const
0184 {
0185     const KateTextLayout &lastLine = viewLine(viewLineCount() - 1);
0186     return lastLine.width() + lastLine.xOffset();
0187 }
0188 
0189 bool KateLineLayout::isOutsideDocument() const
0190 {
0191     return line() < 0 || line() >= m_renderer.doc()->lines();
0192 }
0193 
0194 void KateLineLayout::debugOutput() const
0195 {
0196     qCDebug(LOG_KTE) << "KateLineLayout: " << this << " valid " << isValid() << " line " << line() << " length " << length() << " width " << width()
0197                      << " viewLineCount " << viewLineCount();
0198 }
0199 
0200 int KateLineLayout::viewLineForColumn(int column) const
0201 {
0202     int len = 0;
0203     int i = 0;
0204     for (; i < m_layout->lineCount() - 1; ++i) {
0205         len += m_layout->lineAt(i).textLength();
0206         if (column < len) {
0207             return i;
0208         }
0209     }
0210     return i;
0211 }
0212 
0213 bool KateLineLayout::isLayoutDirty() const
0214 {
0215     return m_layoutDirty;
0216 }
0217 
0218 void KateLineLayout::setLayoutDirty(bool dirty)
0219 {
0220     m_layoutDirty = dirty;
0221 }
0222 
0223 bool KateLineLayout::usePlainTextLine() const
0224 {
0225     return m_usePlainTextLine;
0226 }
0227 
0228 void KateLineLayout::setUsePlainTextLine(bool plain)
0229 {
0230     m_usePlainTextLine = plain;
0231 }
0232 
0233 bool KateLineLayout::isRightToLeft() const
0234 {
0235     if (!m_layout) {
0236         return false;
0237     }
0238 
0239     return m_layout->textOption().textDirection() == Qt::RightToLeft;
0240 }