KPimTextEdit

textutils.cpp
1/*
2 This file is part of KDE.
3
4 SPDX-FileCopyrightText: 2009 Thomas McGuire <mcguire@kde.org>
5 SPDX-FileCopyrightText: 2010 Stephen Kelly <steveire@gmail.com>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#include "textutils.h"
11
12#include "kpimtextedit_debug.h"
13#include <QTextBlock>
14#include <QTextCharFormat>
15#include <QTextDocument>
16
17using namespace Qt::Literals::StringLiterals;
18using namespace KPIMTextEdit;
19
20static bool isCharFormatFormatted(const QTextCharFormat &format, const QFont &defaultFont, const QTextCharFormat &defaultBlockFormat)
21{
22 if (!format.anchorHref().isEmpty() || format.font() != defaultFont || format.isAnchor()
23 || format.verticalAlignment() != defaultBlockFormat.verticalAlignment() || format.layoutDirection() != defaultBlockFormat.layoutDirection()
24 || format.underlineStyle() != defaultBlockFormat.underlineStyle() || format.foreground().color() != defaultBlockFormat.foreground().color()
25 || format.background().color() != defaultBlockFormat.background().color()) {
26 return true;
27 }
28
29 return false;
30}
31
32static bool isBlockFormatFormatted(const QTextBlockFormat &format, const QTextBlockFormat &defaultFormat)
33{
34 if (format.alignment() != defaultFormat.alignment() || format.layoutDirection() != defaultFormat.layoutDirection()
35 || format.indent() != defaultFormat.indent() || format.textIndent() != defaultFormat.textIndent()) {
36 return true;
37 }
38
39 return false;
40}
41
42/// @return true if the format represents a list, table, image or something like that.
43static bool isSpecial(const QTextFormat &charFormat)
44{
45 return charFormat.isFrameFormat() || charFormat.isImageFormat() || charFormat.isListFormat() || charFormat.isTableFormat()
46 || charFormat.isTableCellFormat();
47}
48
50{
51 if (!document) {
52 return false;
53 }
54
55 QTextDocument defaultTextDocument;
56 const QTextCharFormat defaultCharFormat = defaultTextDocument.begin().charFormat();
57 const QTextBlockFormat defaultBlockFormat = defaultTextDocument.begin().blockFormat();
58 const QFont defaultFont = defaultTextDocument.defaultFont();
59
60 QTextBlock block = document->firstBlock();
61 while (block.isValid()) {
62 if (isBlockFormatFormatted(block.blockFormat(), defaultBlockFormat)) {
63 return true;
64 }
65
66 if (isSpecial(block.charFormat()) || isSpecial(block.blockFormat()) || block.textList()) {
67 return true;
68 }
69
70 QTextBlock::iterator it = block.begin();
71 while (!it.atEnd()) {
72 const QTextFragment fragment = it.fragment();
73 const QTextCharFormat charFormat = fragment.charFormat();
74 if (isSpecial(charFormat)) {
75 return true;
76 }
77 if (isCharFormatFormatted(fragment.charFormat(), defaultFont, defaultCharFormat)) {
78 return true;
79 }
80
81 ++it;
82 }
83
84 block = block.next();
85 }
86
87 if (document->toHtml().contains("<hr />"_L1)) {
88 return true;
89 }
90
91 return false;
92}
93
94QString TextUtils::flowText(QString &wrappedText, const QString &indent, int maxLength)
95{
96 if (wrappedText.isEmpty()) {
97 return indent;
98 }
99
100 if (maxLength <= indent.length()) {
101 qCWarning(KPIMTEXTEDIT_LOG) << "indent was set to a string that is longer or the same length "
102 << "as maxLength, setting maxLength to indent.length() + 1";
103 maxLength = indent.length() + 1;
104 }
105
106 maxLength -= indent.length(); // take into account indent
107 QString result;
108 while (!wrappedText.isEmpty()) {
109 // first check for the next newline. if it's before maxLength, break there, and continue
110 int newLine = wrappedText.indexOf(QLatin1Char('\n'));
111 if (newLine > 0 && newLine <= maxLength) {
112 result += indent + wrappedText.left(newLine + 1);
113 wrappedText = wrappedText.mid(newLine + 1);
114 continue;
115 }
116 // Find the next point in the wrappedText where we have to do a line break.
117 // Start searching at maxLength position and then walk backwards looking
118 // for a space.
119 int breakPosition;
120 if (wrappedText.length() > maxLength) {
121 breakPosition = maxLength;
122 while ((breakPosition >= 0) && (wrappedText[breakPosition] != QLatin1Char(' '))) {
123 breakPosition--;
124 }
125 if (breakPosition <= 0) {
126 // Couldn't break before maxLength.
127 breakPosition = maxLength;
128 }
129 } else {
130 breakPosition = wrappedText.length();
131 }
132
133 QString line = wrappedText.left(breakPosition);
134 if (breakPosition < wrappedText.length()) {
135 wrappedText = wrappedText.mid(breakPosition);
136 } else {
137 wrappedText.clear();
138 }
139
140 // Strip leading whitespace of new lines, since that looks strange
141 if (!result.isEmpty() && line.startsWith(QLatin1Char(' '))) {
142 line.remove(0, 1);
143 }
144
145 result += indent + line + QLatin1Char('\n');
146 }
147
148 return result.left(result.length() - 1);
149}
KPIMTEXTEDIT_EXPORT bool containsFormatting(const QTextDocument *document)
Returns whether the QTextDocument document contains rich text formatting.
Definition textutils.cpp:49
KPIMTEXTEDIT_EXPORT QString flowText(QString &text, const QString &indent, int maxLength)
Changes the given text so that each line of it fits into the given maximal length.
Definition textutils.cpp:94
const QColor & color() const const
void clear()
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString left(qsizetype n) const const
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
iterator begin() const const
QTextBlockFormat blockFormat() const const
QTextCharFormat charFormat() const const
bool isValid() const const
QTextBlock next() const const
QTextList * textList() const const
Qt::Alignment alignment() const const
int indent() const const
qreal textIndent() const const
QString anchorHref() const const
QFont font() const const
bool isAnchor() const const
UnderlineStyle underlineStyle() const const
VerticalAlignment verticalAlignment() const const
QTextBlock begin() const const
QTextBlock firstBlock() const const
QString toHtml() const const
QBrush background() const const
QBrush foreground() const const
bool isFrameFormat() const const
bool isImageFormat() const const
bool isListFormat() const const
bool isTableCellFormat() const const
bool isTableFormat() const const
Qt::LayoutDirection layoutDirection() const const
QTextCharFormat charFormat() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:18:49 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.