Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
PIM
PIM Messagelib
Commits
1c3bd593
Commit
1c3bd593
authored
May 25, 2016
by
Sandro Knauß
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move renderingparts to own subdir.
cleanup parsing and rendering from eachother.
parent
d8d23702
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
303 additions
and
462 deletions
+303
-462
mimetreeparser/src/CMakeLists.txt
mimetreeparser/src/CMakeLists.txt
+1
-1
mimetreeparser/src/themes/default/htmlblock.cpp
mimetreeparser/src/themes/default/htmlblock.cpp
+0
-48
mimetreeparser/src/themes/default/htmlblock.h
mimetreeparser/src/themes/default/htmlblock.h
+0
-16
mimetreeparser/src/themes/default/mailrenderer.cpp
mimetreeparser/src/themes/default/mailrenderer.cpp
+302
-2
mimetreeparser/src/viewer/messagepart.cpp
mimetreeparser/src/viewer/messagepart.cpp
+0
-381
mimetreeparser/src/viewer/messagepart.h
mimetreeparser/src/viewer/messagepart.h
+0
-14
No files found.
mimetreeparser/src/CMakeLists.txt
View file @
1c3bd593
...
...
@@ -29,7 +29,6 @@ set(libmimetreeparser_main_SRCS
viewer/bodypartformatterbasefactory.cpp
viewer/cryptohelper.cpp
viewer/csshelperbase.cpp
viewer/htmlblock.cpp
viewer/nodehelper.cpp
viewer/objecttreeparser.cpp
viewer/messagepart.cpp
...
...
@@ -49,6 +48,7 @@ set(libmimetreeparser_extra_SRCS
htmlwriter/filehtmlwriter.cpp
htmlwriter/queuehtmlwriter.cpp
themes/default/mailrenderer.cpp
themes/default/htmlblock.cpp
)
set
(
mimetreeparser_temporaryfile_SRCS
...
...
mimetreeparser/src/
viewer
/htmlblock.cpp
→
mimetreeparser/src/
themes/default
/htmlblock.cpp
View file @
1c3bd593
...
...
@@ -20,19 +20,10 @@
#include "htmlblock.h"
#include "mimetreeparser_debug.h"
#include "interfaces/objecttreesource.h"
#include "interfaces/htmlwriter.h"
#include "nodehelper.h"
#include <MessageCore/StringUtil>
#include <KMime/Content>
#include <gpgme.h>
#include <Libkleo/CryptoBackendFactory>
#include <KLocalizedString>
#include <KEmailAddress>
#include <QApplication>
using
namespace
MimeTreeParser
;
...
...
@@ -78,45 +69,6 @@ void AttachmentMarkBlock::internalExit()
entered
=
false
;
}
HTMLWarnBlock
::
HTMLWarnBlock
(
HtmlWriter
*
writer
,
const
QString
&
msg
)
:
mWriter
(
writer
)
,
mMsg
(
msg
)
{
internalEnter
();
}
HTMLWarnBlock
::~
HTMLWarnBlock
()
{
internalExit
();
}
void
HTMLWarnBlock
::
internalEnter
()
{
if
(
!
mWriter
||
entered
)
{
return
;
}
entered
=
true
;
if
(
!
mMsg
.
isEmpty
())
{
mWriter
->
queue
(
QStringLiteral
(
"<div class=
\"
htmlWarn
\"
>
\n
"
));
mWriter
->
queue
(
mMsg
);
mWriter
->
queue
(
QStringLiteral
(
"</div><br/><br/>"
));
}
mWriter
->
queue
(
QStringLiteral
(
"<div style=
\"
position: relative
\"
>
\n
"
));
}
void
HTMLWarnBlock
::
internalExit
()
{
if
(
!
entered
)
{
return
;
}
entered
=
false
;
mWriter
->
queue
(
QStringLiteral
(
"</div>
\n
"
));
}
RootBlock
::
RootBlock
(
HtmlWriter
*
writer
)
:
HTMLBlock
()
,
mWriter
(
writer
)
...
...
mimetreeparser/src/
viewer
/htmlblock.h
→
mimetreeparser/src/
themes/default
/htmlblock.h
View file @
1c3bd593
...
...
@@ -20,9 +20,6 @@
#ifndef __MIMETREEPARSER_HTMLBLOCK_H__
#define __MIMETREEPARSER_HTMLBLOCK_H__
#include "partmetadata.h"
#include <Libkleo/CryptoBackend>
#include <QString>
#include <QSharedPointer>
#include <QVector>
...
...
@@ -83,19 +80,6 @@ private:
HtmlWriter
*
mWriter
;
};
class
HTMLWarnBlock
:
public
HTMLBlock
{
public:
HTMLWarnBlock
(
MimeTreeParser
::
HtmlWriter
*
writer
,
const
QString
&
msg
);
virtual
~
HTMLWarnBlock
();
private:
void
internalEnter
();
void
internalExit
();
private:
HtmlWriter
*
mWriter
;
const
QString
&
mMsg
;
};
// Make sure the whole content is relative, so that nothing is painted over the header
// if a malicious message uses absolute positioning.
// Also force word wrapping, which is useful for printing, see https://issues.kolab.org/issue3992.
...
...
mimetreeparser/src/themes/default/mailrenderer.cpp
View file @
1c3bd593
...
...
@@ -19,10 +19,12 @@
#include "mailrenderer.h"
#include "htmlblock.h"
#include "interfaces/htmlwriter.h"
#include "utils/iconnamecache.h"
#include "viewer/csshelperbase.h"
#include "viewer/converthtmltoplaintext.h"
#include "viewer/htmlblock.h"
#include "viewer/messagepart.h"
#include "viewer/objecttreeparser.h"
...
...
@@ -33,9 +35,11 @@
#include <KEmailAddress>
#include <KLocalizedString>
#include <KTextToHTML>
#include <QApplication>
#include <QDebug>
#include <QFile>
#include <QTextCodec>
#include <QUrl>
...
...
@@ -88,6 +92,96 @@ Grantlee::Template getGrantleeTemplate(QObject *parent, const QString &name)
return
m_engine
->
loadByName
(
name
);
}
static
QString
iconToDataUrl
(
const
QString
&
iconPath
)
{
QFile
f
(
iconPath
);
if
(
!
f
.
open
(
QIODevice
::
ReadOnly
))
{
return
QString
();
}
const
QByteArray
ba
=
f
.
readAll
();
return
QStringLiteral
(
"data:image/png;base64,%1"
).
arg
(
QLatin1String
(
ba
.
toBase64
().
constData
()));
}
/** Check if the newline at position @p newLinePos in string @p s
seems to separate two paragraphs (important for correct BiDi
behavior, but is heuristic because paragraphs are not
well-defined) */
// Guesstimate if the newline at newLinePos actually separates paragraphs in the text s
// We use several heuristics:
// 1. If newLinePos points after or before (=at the very beginning of) text, it is not between paragraphs
// 2. If the previous line was longer than the wrap size, we want to consider it a paragraph on its own
// (some clients, notably Outlook, send each para as a line in the plain-text version).
// 3. Otherwise, we check if the newline could have been inserted for wrapping around; if this
// was the case, then the previous line will be shorter than the wrap size (which we already
// know because of item 2 above), but adding the first word from the next line will make it
// longer than the wrap size.
bool
looksLikeParaBreak
(
const
QString
&
s
,
unsigned
int
newLinePos
)
{
const
unsigned
int
WRAP_COL
=
78
;
unsigned
int
length
=
s
.
length
();
// 1. Is newLinePos at an end of the text?
if
(
newLinePos
>=
length
-
1
||
newLinePos
==
0
)
{
return
false
;
}
// 2. Is the previous line really a paragraph -- longer than the wrap size?
// First char of prev line -- works also for first line
unsigned
prevStart
=
s
.
lastIndexOf
(
QLatin1Char
(
'\n'
),
newLinePos
-
1
)
+
1
;
unsigned
prevLineLength
=
newLinePos
-
prevStart
;
if
(
prevLineLength
>
WRAP_COL
)
{
return
true
;
}
// find next line to delimit search for first word
unsigned
int
nextStart
=
newLinePos
+
1
;
int
nextEnd
=
s
.
indexOf
(
QLatin1Char
(
'\n'
),
nextStart
);
if
(
nextEnd
==
-
1
)
{
nextEnd
=
length
;
}
QString
nextLine
=
s
.
mid
(
nextStart
,
nextEnd
-
nextStart
);
length
=
nextLine
.
length
();
// search for first word in next line
unsigned
int
wordStart
;
bool
found
=
false
;
for
(
wordStart
=
0
;
!
found
&&
wordStart
<
length
;
wordStart
++
)
{
switch
(
nextLine
[
wordStart
].
toLatin1
())
{
case
'>'
:
case
'|'
:
case
' '
:
// spaces, tabs and quote markers don't count
case
'\t'
:
case
'\r'
:
break
;
default:
found
=
true
;
break
;
}
}
/* for() */
if
(
!
found
)
{
// next line is essentially empty, it seems -- empty lines are
// para separators
return
true
;
}
//Find end of first word.
//Note: flowText (in kmmessage.cpp) separates words for wrap by
//spaces only. This should be consistent, which calls for some
//refactoring.
int
wordEnd
=
nextLine
.
indexOf
(
QLatin1Char
(
' '
),
wordStart
);
if
(
wordEnd
==
(
-
1
))
{
wordEnd
=
length
;
}
int
wordLength
=
wordEnd
-
wordStart
;
// 3. If adding a space and the first word to the prev line don't
// make it reach the wrap column, then the break was probably
// meaningful
return
prevLineLength
+
wordLength
+
1
<
WRAP_COL
;
}
static
const
int
SIG_FRAME_COL_UNDEF
=
99
;
#define SIG_FRAME_COL_RED -1
#define SIG_FRAME_COL_YELLOW 0
...
...
@@ -355,6 +449,16 @@ public:
mHtml
=
renderFactory
(
mMsgPart
,
QSharedPointer
<
TestHtmlWriter
>
());
}
CSSHelperBase
*
cssHelper
()
const
{
return
mMsgPart
->
cssHelper
();
}
Interface
::
ObjectTreeSource
*
source
()
const
{
return
mMsgPart
->
source
();
}
void
renderSubParts
(
MessagePart
::
Ptr
msgPart
,
const
QSharedPointer
<
TestHtmlWriter
>
&
htmlWriter
)
{
foreach
(
const
auto
&
_m
,
msgPart
->
subParts
())
{
...
...
@@ -514,6 +618,199 @@ public:
return
htmlWriter
->
html
;
}
QString
quotedHTML
(
const
QString
&
s
,
bool
decorate
)
{
assert
(
cssHelper
());
KTextToHTML
::
Options
convertFlags
=
KTextToHTML
::
PreserveSpaces
|
KTextToHTML
::
HighlightText
;
if
(
decorate
&&
source
()
->
showEmoticons
())
{
convertFlags
|=
KTextToHTML
::
ReplaceSmileys
;
}
QString
htmlStr
;
const
QString
normalStartTag
=
cssHelper
()
->
nonQuotedFontTag
();
QString
quoteFontTag
[
3
];
QString
deepQuoteFontTag
[
3
];
for
(
int
i
=
0
;
i
<
3
;
++
i
)
{
quoteFontTag
[
i
]
=
cssHelper
()
->
quoteFontTag
(
i
);
deepQuoteFontTag
[
i
]
=
cssHelper
()
->
quoteFontTag
(
i
+
3
);
}
const
QString
normalEndTag
=
QStringLiteral
(
"</div>"
);
const
QString
quoteEnd
=
QStringLiteral
(
"</div>"
);
const
unsigned
int
length
=
s
.
length
();
bool
paraIsRTL
=
false
;
bool
startNewPara
=
true
;
unsigned
int
pos
,
beg
;
// skip leading empty lines
for
(
pos
=
0
;
pos
<
length
&&
s
[
pos
]
<=
QLatin1Char
(
' '
);
++
pos
)
;
while
(
pos
>
0
&&
(
s
[
pos
-
1
]
==
QLatin1Char
(
' '
)
||
s
[
pos
-
1
]
==
QLatin1Char
(
'\t'
)))
{
pos
--
;
}
beg
=
pos
;
int
currQuoteLevel
=
-
2
;
// -2 == no previous lines
bool
curHidden
=
false
;
// no hide any block
if
(
source
()
->
showExpandQuotesMark
())
{
// Cache Icons
if
(
mCollapseIcon
.
isEmpty
())
{
mCollapseIcon
=
iconToDataUrl
(
IconNameCache
::
instance
()
->
iconPath
(
QStringLiteral
(
"quotecollapse"
),
0
));
}
if
(
mExpandIcon
.
isEmpty
())
{
mExpandIcon
=
iconToDataUrl
(
IconNameCache
::
instance
()
->
iconPath
(
QStringLiteral
(
"quoteexpand"
),
0
));
}
}
int
previousQuoteDepth
=
-
1
;
while
(
beg
<
length
)
{
/* search next occurrence of '\n' */
pos
=
s
.
indexOf
(
QLatin1Char
(
'\n'
),
beg
,
Qt
::
CaseInsensitive
);
if
(
pos
==
(
unsigned
int
)(
-
1
))
{
pos
=
length
;
}
QString
line
(
s
.
mid
(
beg
,
pos
-
beg
));
beg
=
pos
+
1
;
bool
foundQuote
=
false
;
/* calculate line's current quoting depth */
int
actQuoteLevel
=
-
1
;
const
int
numberOfCaracters
(
line
.
length
());
int
quoteLength
=
0
;
for
(
int
p
=
0
;
p
<
numberOfCaracters
;
++
p
)
{
switch
(
line
[
p
].
toLatin1
())
{
case
'>'
:
case
'|'
:
actQuoteLevel
++
;
quoteLength
=
p
;
foundQuote
=
true
;
break
;
case
' '
:
// spaces and tabs are allowed between the quote markers
case
'\t'
:
case
'\r'
:
quoteLength
=
p
;
break
;
default:
// stop quoting depth calculation
p
=
numberOfCaracters
;
break
;
}
}
/* for() */
if
(
!
foundQuote
)
{
quoteLength
=
0
;
}
bool
actHidden
=
false
;
// This quoted line needs be hidden
if
(
source
()
->
showExpandQuotesMark
()
&&
source
()
->
levelQuote
()
>=
0
&&
source
()
->
levelQuote
()
<=
(
actQuoteLevel
))
{
actHidden
=
true
;
}
if
(
actQuoteLevel
!=
currQuoteLevel
)
{
/* finish last quotelevel */
if
(
currQuoteLevel
==
-
1
)
{
htmlStr
.
append
(
normalEndTag
);
}
else
if
(
currQuoteLevel
>=
0
&&
!
curHidden
)
{
htmlStr
.
append
(
quoteEnd
);
}
//Close blockquote
if
(
previousQuoteDepth
>
actQuoteLevel
)
{
htmlStr
+=
cssHelper
()
->
addEndBlockQuote
((
previousQuoteDepth
-
actQuoteLevel
));
}
/* start new quotelevel */
if
(
actQuoteLevel
==
-
1
)
{
htmlStr
+=
normalStartTag
;
}
else
{
if
(
source
()
->
showExpandQuotesMark
())
{
if
(
actHidden
)
{
//only show the QuoteMark when is the first line of the level hidden
if
(
!
curHidden
)
{
//Expand all quotes
htmlStr
+=
QLatin1String
(
"<div class=
\"
quotelevelmark
\"
>"
);
htmlStr
+=
QStringLiteral
(
"<a href=
\"
kmail:levelquote?%1
\"
>"
"<img src=
\"
%2
\"
/></a>"
)
.
arg
(
-
1
)
.
arg
(
mExpandIcon
);
htmlStr
+=
QLatin1String
(
"</div><br/>"
);
htmlStr
+=
quoteEnd
;
}
}
else
{
htmlStr
+=
QLatin1String
(
"<div class=
\"
quotelevelmark
\"
>"
);
htmlStr
+=
QStringLiteral
(
"<a href=
\"
kmail:levelquote?%1
\"
>"
"<img src=
\"
%2
\"
/></a>"
)
.
arg
(
actQuoteLevel
)
.
arg
(
mCollapseIcon
);
htmlStr
+=
QLatin1String
(
"</div>"
);
if
(
actQuoteLevel
<
3
)
{
htmlStr
+=
quoteFontTag
[
actQuoteLevel
];
}
else
{
htmlStr
+=
deepQuoteFontTag
[
actQuoteLevel
%
3
];
}
}
}
else
{
// Add blockquote
if
(
previousQuoteDepth
<
actQuoteLevel
)
{
htmlStr
+=
cssHelper
()
->
addStartBlockQuote
(
actQuoteLevel
-
previousQuoteDepth
);
}
if
(
actQuoteLevel
<
3
)
{
htmlStr
+=
quoteFontTag
[
actQuoteLevel
];
}
else
{
htmlStr
+=
deepQuoteFontTag
[
actQuoteLevel
%
3
];
}
}
}
currQuoteLevel
=
actQuoteLevel
;
}
curHidden
=
actHidden
;
if
(
!
actHidden
)
{
// don't write empty <div ...></div> blocks (they have zero height)
// ignore ^M DOS linebreaks
if
(
!
line
.
remove
(
QLatin1Char
(
'\015'
)).
isEmpty
())
{
if
(
startNewPara
)
{
paraIsRTL
=
line
.
isRightToLeft
();
}
htmlStr
+=
QStringLiteral
(
"<div dir=
\"
%1
\"
>"
).
arg
(
paraIsRTL
?
QStringLiteral
(
"rtl"
)
:
QStringLiteral
(
"ltr"
));
// if quoteLengh == 0 && foundQuote => a simple quote
if
(
foundQuote
)
{
quoteLength
++
;
htmlStr
+=
QStringLiteral
(
"<span class=
\"
quotemarks
\"
>%1</span>"
).
arg
(
line
.
left
(
quoteLength
));
const
int
rightString
=
(
line
.
length
())
-
quoteLength
;
if
(
rightString
>
0
)
{
htmlStr
+=
QStringLiteral
(
"<font color=
\"
%1
\"
>"
).
arg
(
cssHelper
()
->
quoteColorName
(
actQuoteLevel
))
+
KTextToHTML
::
convertToHtml
(
line
.
right
(
rightString
),
convertFlags
)
+
QStringLiteral
(
"</font>"
);
}
}
else
{
htmlStr
+=
KTextToHTML
::
convertToHtml
(
line
,
convertFlags
);
}
htmlStr
+=
QLatin1String
(
"</div>"
);
startNewPara
=
looksLikeParaBreak
(
s
,
pos
);
}
else
{
htmlStr
+=
QLatin1String
(
"<br/>"
);
// after an empty line, always start a new paragraph
startNewPara
=
true
;
}
}
previousQuoteDepth
=
actQuoteLevel
;
}
/* while() */
/* really finish the last quotelevel */
if
(
currQuoteLevel
==
-
1
)
{
htmlStr
.
append
(
normalEndTag
);
}
else
{
htmlStr
+=
quoteEnd
+
cssHelper
()
->
addEndBlockQuote
(
currQuoteLevel
+
1
);
}
// qCDebug(MIMETREEPARSER_LOG) << "========================================\n"
// << htmlStr
// << "\n======================================\n";
return
htmlStr
;
}
QString
render
(
MessagePart
::
Ptr
mp
)
{
auto
htmlWriter
=
QSharedPointer
<
TestHtmlWriter
>
(
new
TestHtmlWriter
(
mOldWriter
));
...
...
@@ -523,7 +820,7 @@ public:
aBlock
=
HTMLBlock
::
Ptr
(
new
AttachmentMarkBlock
(
htmlWriter
.
data
(),
mp
->
mAttachmentNode
));
}
htmlWriter
->
queue
(
mp
->
quotedHTML
(
mp
->
text
(),
false
));
htmlWriter
->
queue
(
quotedHTML
(
mp
->
text
(),
false
));
}
return
htmlWriter
->
html
;
}
...
...
@@ -1014,6 +1311,9 @@ public:
private:
HtmlRenderer
*
q
;
HtmlWriter
*
mOldWriter
;
QString
mCollapseIcon
;
QString
mExpandIcon
;
};
...
...
mimetreeparser/src/viewer/messagepart.cpp
View file @
1c3bd593
...
...
@@ -21,14 +21,12 @@
#include "mimetreeparser_debug.h"
#include "csshelperbase.h"
#include "cryptohelper.h"
#include "htmlblock.h"
#include "objecttreeparser.h"
#include "interfaces/htmlwriter.h"
#include "job/kleojobexecutor.h"
#include "memento/decryptverifybodypartmemento.h"
#include "memento/verifydetachedbodypartmemento.h"
#include "memento/verifyopaquebodypartmemento.h"
#include "utils/iconnamecache.h"
#include <KMime/Content>
...
...
@@ -43,14 +41,12 @@
#include <gpgme++/keylistresult.h>
#include <gpgme.h>
#include <QFile>
#include <QTextCodec>
#include <QWebPage>
#include <QWebElement>
#include <QWebFrame>
#include <KLocalizedString>
#include <KTextToHTML>
using
namespace
MimeTreeParser
;
...
...
@@ -94,14 +90,6 @@ KMime::Content *MessagePart::attachmentNode() const
return
mAttachmentNode
;
}
HTMLBlock
::
Ptr
MessagePart
::
attachmentBlock
()
const
{
if
(
htmlWriter
()
&&
isAttachment
())
{
return
HTMLBlock
::
Ptr
(
new
AttachmentMarkBlock
(
htmlWriter
(),
mAttachmentNode
));
}
return
HTMLBlock
::
Ptr
();
}
void
MessagePart
::
setIsRoot
(
bool
root
)
{
mRoot
=
root
;
...
...
@@ -112,14 +100,6 @@ bool MessagePart::isRoot() const
return
mRoot
;
}
HTMLBlock
::
Ptr
MessagePart
::
rootBlock
()
const
{
if
(
htmlWriter
()
&&
isRoot
())
{
return
HTMLBlock
::
Ptr
(
new
RootBlock
(
htmlWriter
()));
}
return
HTMLBlock
::
Ptr
();
}
QString
MessagePart
::
text
()
const
{
return
mText
;
...
...
@@ -153,300 +133,6 @@ void MessagePart::setHtmlWriter(HtmlWriter *htmlWriter) const
mOtp
->
mHtmlWriter
=
htmlWriter
;
}
static
QString
iconToDataUrl
(
const
QString
&
iconPath
)
{
QFile
f
(
iconPath
);
if
(
!
f
.
open
(
QIODevice
::
ReadOnly
))
{
return
QString
();
}
const
QByteArray
ba
=
f
.
readAll
();
return
QStringLiteral
(
"data:image/png;base64,%1"
).
arg
(
QLatin1String
(
ba
.
toBase64
().
constData
()));
}
/** Check if the newline at position @p newLinePos in string @p s
seems to separate two paragraphs (important for correct BiDi
behavior, but is heuristic because paragraphs are not
well-defined) */
// Guesstimate if the newline at newLinePos actually separates paragraphs in the text s
// We use several heuristics:
// 1. If newLinePos points after or before (=at the very beginning of) text, it is not between paragraphs
// 2. If the previous line was longer than the wrap size, we want to consider it a paragraph on its own
// (some clients, notably Outlook, send each para as a line in the plain-text version).
// 3. Otherwise, we check if the newline could have been inserted for wrapping around; if this
// was the case, then the previous line will be shorter than the wrap size (which we already
// know because of item 2 above), but adding the first word from the next line will make it
// longer than the wrap size.
bool
looksLikeParaBreak
(
const
QString
&
s
,
unsigned
int
newLinePos
)
{
const
unsigned
int
WRAP_COL
=
78
;
unsigned
int
length
=
s
.
length
();
// 1. Is newLinePos at an end of the text?
if
(
newLinePos
>=
length
-
1
||
newLinePos
==
0
)
{
return
false
;
}
// 2. Is the previous line really a paragraph -- longer than the wrap size?
// First char of prev line -- works also for first line
unsigned
prevStart
=
s
.
lastIndexOf
(
QLatin1Char
(
'\n'
),
newLinePos
-
1
)
+
1
;
unsigned
prevLineLength
=
newLinePos
-
prevStart
;
if
(
prevLineLength
>
WRAP_COL
)
{
return
true
;
}
// find next line to delimit search for first word
unsigned
int
nextStart
=
newLinePos
+
1
;
int
nextEnd
=
s
.
indexOf
(
QLatin1Char
(
'\n'
),
nextStart
);
if
(
nextEnd
==
-
1
)
{
nextEnd
=
length
;
}
QString
nextLine
=
s
.
mid
(
nextStart
,
nextEnd
-
nextStart
);
length
=
nextLine
.
length
();
// search for first word in next line
unsigned
int
wordStart
;
bool
found
=
false
;
for
(
wordStart
=
0
;
!
found
&&
wordStart
<
length
;
wordStart
++
)
{
switch
(
nextLine
[
wordStart
].
toLatin1
())
{
case
'>'
:
case
'|'
:
case
' '
:
// spaces, tabs and quote markers don't count
case
'\t'
:
case
'\r'
:
break
;
default:
found
=
true
;
break
;
}
}
/* for() */
if
(
!
found
)
{
// next line is essentially empty, it seems -- empty lines are
// para separators
return
true
;
}
//Find end of first word.
//Note: flowText (in kmmessage.cpp) separates words for wrap by
//spaces only. This should be consistent, which calls for some
//refactoring.