1 | /* |
2 | This file is part of KDE. |
3 | |
4 | Copyright (c) 2009 Thomas McGuire <mcguire@kde.org> |
5 | Copyright (c) 2010 Stephen Kelly <steveire@gmail.com> |
6 | |
7 | This library is free software; you can redistribute it and/or modify it |
8 | under the terms of the GNU Library General Public License as published by |
9 | the Free Software Foundation; either version 2 of the License, or (at your |
10 | option) any later version. |
11 | |
12 | This library is distributed in the hope that it will be useful, but WITHOUT |
13 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public |
15 | License for more details. |
16 | |
17 | You should have received a copy of the GNU Library General Public License |
18 | along with this library; see the file COPYING.LIB. If not, write to the |
19 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
20 | 02110-1301, USA. |
21 | */ |
22 | |
23 | #include "textutils.h" |
24 | |
25 | #include <QTextBlock> |
26 | #include <QTextCharFormat> |
27 | #include <QTextDocument> |
28 | #include <KDE/KDebug> |
29 | |
30 | using namespace KPIMTextEdit; |
31 | |
32 | static bool isCharFormatFormatted( const QTextCharFormat &format, const QFont &defaultFont, |
33 | const QTextCharFormat &defaultBlockFormat ) |
34 | { |
35 | if ( !format.anchorHref().isEmpty() || |
36 | format.font() != defaultFont || |
37 | format.isAnchor() || |
38 | format.verticalAlignment() != defaultBlockFormat.verticalAlignment() || |
39 | format.layoutDirection() != defaultBlockFormat.layoutDirection() || |
40 | format.underlineStyle() != defaultBlockFormat.underlineStyle() || |
41 | format.foreground().color() != defaultBlockFormat.foreground().color() || |
42 | format.background().color() != defaultBlockFormat.background().color() ) { |
43 | return true; |
44 | } |
45 | |
46 | return false; |
47 | } |
48 | |
49 | static bool isBlockFormatFormatted( const QTextBlockFormat &format, |
50 | const QTextBlockFormat &defaultFormat ) |
51 | { |
52 | if ( format.alignment() != defaultFormat.alignment() || |
53 | format.layoutDirection() != defaultFormat.layoutDirection() || |
54 | format.indent() != defaultFormat.indent() || |
55 | format.textIndent() != defaultFormat.textIndent() ) { |
56 | return true; |
57 | } |
58 | |
59 | return false; |
60 | } |
61 | |
62 | /// @return true if the format represents a list, table, image or something like that. |
63 | static bool isSpecial( const QTextFormat &charFormat ) |
64 | { |
65 | return charFormat.isFrameFormat() || charFormat.isImageFormat() || |
66 | charFormat.isListFormat() || charFormat.isTableFormat() || charFormat.isTableCellFormat(); |
67 | } |
68 | |
69 | bool TextUtils::containsFormatting( const QTextDocument *document ) |
70 | { |
71 | if ( !document ) { |
72 | return false; |
73 | } |
74 | |
75 | QTextDocument defaultTextDocument; |
76 | const QTextCharFormat defaultCharFormat = defaultTextDocument.begin().charFormat(); |
77 | const QTextBlockFormat defaultBlockFormat = defaultTextDocument.begin().blockFormat(); |
78 | const QFont defaultFont = defaultTextDocument.defaultFont(); |
79 | |
80 | QTextBlock block = document->firstBlock(); |
81 | while ( block.isValid() ) { |
82 | |
83 | if ( isBlockFormatFormatted( block.blockFormat(), defaultBlockFormat ) ) { |
84 | return true; |
85 | } |
86 | |
87 | if ( isSpecial( block.charFormat() ) || isSpecial( block.blockFormat() ) || |
88 | block.textList() ) { |
89 | return true; |
90 | } |
91 | |
92 | QTextBlock::iterator it = block.begin(); |
93 | while ( !it.atEnd() ) { |
94 | const QTextFragment fragment = it.fragment(); |
95 | const QTextCharFormat charFormat = fragment.charFormat(); |
96 | if ( isSpecial( charFormat ) ) { |
97 | return true; |
98 | } |
99 | if ( isCharFormatFormatted( fragment.charFormat(), defaultFont, defaultCharFormat ) ) { |
100 | return true; |
101 | } |
102 | |
103 | it++; |
104 | } |
105 | |
106 | block = block.next(); |
107 | } |
108 | |
109 | if ( document->toHtml().contains( QLatin1String( "<hr />" ) ) ) { |
110 | return true; |
111 | } |
112 | |
113 | return false; |
114 | } |
115 | |
116 | QString TextUtils::flowText( QString &wrappedText, const QString &indent, int maxLength ) |
117 | { |
118 | if ( wrappedText.isEmpty() ) { |
119 | return indent; |
120 | } |
121 | |
122 | if ( maxLength <= indent.length() ) { |
123 | kWarning() << "indent was set to a string that is longer or the same length " |
124 | << "as maxLength, setting maxLength to indent.length() + 1" ; |
125 | maxLength = indent.length() + 1; |
126 | } |
127 | |
128 | maxLength -= indent.length(); // take into account indent |
129 | QString result; |
130 | while ( !wrappedText.isEmpty() ) { |
131 | // first check for the next newline. if it's before maxLength, break there, and continue |
132 | int newLine = wrappedText.indexOf( QLatin1Char( '\n' ) ); |
133 | if ( newLine > 0 && newLine <= maxLength ) { |
134 | result += indent + wrappedText.left( newLine + 1 ); |
135 | wrappedText = wrappedText.mid( newLine + 1 ); |
136 | continue; |
137 | } |
138 | // Find the next point in the wrappedText where we have to do a line break. |
139 | // Start searching at maxLength position and then walk backwards looking |
140 | // for a space. |
141 | int breakPosition; |
142 | if ( wrappedText.length() > maxLength ) { |
143 | breakPosition = maxLength; |
144 | while ( ( breakPosition >= 0 ) && ( wrappedText[breakPosition] != QLatin1Char( ' ' ) ) ) { |
145 | breakPosition--; |
146 | } |
147 | if ( breakPosition <= 0 ) { |
148 | // Couldn't break before maxLength. |
149 | breakPosition = maxLength; |
150 | } |
151 | } else { |
152 | breakPosition = wrappedText.length(); |
153 | } |
154 | |
155 | QString line = wrappedText.left( breakPosition ); |
156 | if ( breakPosition < wrappedText.length() ) { |
157 | wrappedText = wrappedText.mid( breakPosition ); |
158 | } else { |
159 | wrappedText.clear(); |
160 | } |
161 | |
162 | // Strip leading whitespace of new lines, since that looks strange |
163 | if ( !result.isEmpty() && line.startsWith( QLatin1Char( ' ' ) ) ) { |
164 | line = line.mid( 1 ); |
165 | } |
166 | |
167 | result += indent + line + QLatin1Char( '\n' ); |
168 | } |
169 | |
170 | return result.left( result.length() - 1 ); |
171 | } |
172 | |