1 | // Copyright (C) 2021 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qtextdocument_p.h" |
5 | #include "qtextblock_p.h" |
6 | |
7 | namespace Utils { |
8 | |
9 | TextDocument::TextDocument(const QString &text) |
10 | { |
11 | setPlainText(text); |
12 | } |
13 | |
14 | TextBlock TextDocument::findBlockByNumber(int blockNumber) const |
15 | { |
16 | return (blockNumber >= 0 && blockNumber < m_blocks.size()) |
17 | ? m_blocks.at(i: blockNumber).textBlock |
18 | : TextBlock(); |
19 | } |
20 | |
21 | TextBlock TextDocument::findBlockByLineNumber(int lineNumber) const |
22 | { |
23 | return findBlockByNumber(blockNumber: lineNumber); |
24 | } |
25 | |
26 | QChar TextDocument::characterAt(int pos) const |
27 | { |
28 | return m_content.at(i: pos); |
29 | } |
30 | |
31 | int TextDocument::characterCount() const |
32 | { |
33 | return m_content.size(); |
34 | } |
35 | |
36 | TextBlock TextDocument::begin() const |
37 | { |
38 | return m_blocks.isEmpty() ? TextBlock() : m_blocks.at(i: 0).textBlock; |
39 | } |
40 | |
41 | TextBlock TextDocument::firstBlock() const |
42 | { |
43 | return begin(); |
44 | } |
45 | |
46 | TextBlock TextDocument::lastBlock() const |
47 | { |
48 | return m_blocks.isEmpty() ? TextBlock() : m_blocks.last().textBlock; |
49 | } |
50 | |
51 | std::optional<int> TextDocument::version() const |
52 | { |
53 | return m_version; |
54 | } |
55 | |
56 | void TextDocument::setVersion(std::optional<int> v) |
57 | { |
58 | m_version = v; |
59 | } |
60 | |
61 | QString TextDocument::toPlainText() const |
62 | { |
63 | return m_content; |
64 | } |
65 | |
66 | void TextDocument::setPlainText(const QString &text) |
67 | { |
68 | m_content = text; |
69 | m_blocks.clear(); |
70 | |
71 | const auto appendToBlocks = [this](int blockNumber, int start, int length) { |
72 | Block block; |
73 | block.textBlock.setBlockNumber(blockNumber); |
74 | block.textBlock.setPosition(start); |
75 | block.textBlock.setDocument(this); |
76 | block.textBlock.setLength(length); |
77 | m_blocks.append(t: block); |
78 | }; |
79 | |
80 | int blockStart = 0; |
81 | int blockNumber = -1; |
82 | while (blockStart < text.size()) { |
83 | int blockEnd = text.indexOf(c: u'\n', from: blockStart) + 1; |
84 | if (blockEnd == 0) |
85 | blockEnd = text.size(); |
86 | appendToBlocks(++blockNumber, blockStart, blockEnd - blockStart); |
87 | blockStart = blockEnd; |
88 | } |
89 | // Add an empty block if the text ends with \n. This is required for retrieving |
90 | // the actual line of the text editor if requested, for example, in findBlockByNumber. |
91 | // Consider a case with text aa\nbb\n\n. You are on 4th line of the text editor and even |
92 | // if it is an empty line, we introduce a text block for it to maybe use later. |
93 | if (text.endsWith(c: u'\n')) |
94 | appendToBlocks(++blockNumber, blockStart, 0); |
95 | } |
96 | |
97 | bool TextDocument::isModified() const |
98 | { |
99 | return m_modified; |
100 | } |
101 | |
102 | void TextDocument::setModified(bool modified) |
103 | { |
104 | m_modified = modified; |
105 | } |
106 | |
107 | void TextDocument::setUserState(int blockNumber, int state) |
108 | { |
109 | if (blockNumber >= 0 && blockNumber < m_blocks.size()) |
110 | m_blocks[blockNumber].userState = state; |
111 | } |
112 | |
113 | int TextDocument::userState(int blockNumber) const |
114 | { |
115 | return (blockNumber >= 0 && blockNumber < m_blocks.size()) ? m_blocks[blockNumber].userState |
116 | : -1; |
117 | } |
118 | |
119 | QMutex *TextDocument::mutex() const |
120 | { |
121 | return &m_mutex; |
122 | } |
123 | |
124 | } // namespace Utils |
125 | |