* Added a quote_context structure that FillInQuoteTextRuns() can now optionally

use to keep track of the current context. This should not only make it faster,
  but may also fix the occasionally seen bug of the previous solution.
* Added a simple diff mode coloring as well - only enabled when quote coloring
  is enabled.
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25364 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2008-05-08 10:27:55 +00:00
parent 5a5ff85178
commit e06c7fe5d8
3 changed files with 187 additions and 87 deletions

View File

@ -89,14 +89,19 @@ const rgb_color kSpellTextColor = {255, 0, 0, 255};
const rgb_color kHyperLinkColor = {0, 0, 255, 255};
const rgb_color kHeaderColor = {72, 72, 72, 255};
const rgb_color kQuoteColors[] =
{
{0, 0, 0x80, 0}, // 3rd, 6th, ... quote level color
{0, 0x80, 0, 0}, // 1st, 4th, ... quote level color
{0x80, 0, 0, 0} // 2nd, ...
const rgb_color kQuoteColors[] = {
{0, 0, 0x80, 0}, // 3rd, 6th, ... quote level color (blue)
{0, 0x80, 0, 0}, // 1st, 4th, ... quote level color (green)
{0x80, 0, 0, 0} // 2nd, ... (red)
};
const int32 kNumQuoteColors = 3;
const rgb_color kDiffColors[] = {
{0xb0, 0, 0, 0}, // '-', red
{0, 0x90, 0, 0}, // '+', green
{0x6a, 0x6a, 0x6a, 0} // '@@', dark grey
};
void Unicode2UTF8(int32 c, char **out);
@ -422,6 +427,23 @@ CopyQuotes(const char *text, size_t length, char *outText, size_t &outLength)
}
int32
diff_mode(char c)
{
if (c == '+')
return 2;
if (c == '-')
return 1;
if (c == '@')
return 3;
if (c == ' ')
return 0;
// everything else ends the diff mode
return -1;
}
bool
is_quote_char(char c)
{
@ -429,33 +451,42 @@ is_quote_char(char c)
}
/** Fills the specified text_run_array with the correct values for the
* specified text.
* If "view" is NULL, it will assume that "line" lies on a line break,
* if not, it will correctly retrieve the number of quotes the current
* line already has.
*/
/*! Fills the specified text_run_array with the correct values for the
specified text.
If "view" is NULL, it will assume that "line" lies on a line break,
if not, it will correctly retrieve the number of quotes the current
line already has.
*/
void
FillInQuoteTextRuns(BTextView *view, const char *line, int32 length, const BFont &font,
text_run_array *style, int32 maxStyles)
FillInQuoteTextRuns(BTextView* view, quote_context* context, const char* line,
int32 length, const BFont& font, text_run_array* style, int32 maxStyles)
{
text_run *runs = style->runs;
text_run* runs = style->runs;
int32 index = style->count;
bool begin;
int32 pos = 0;
int32 diffMode = 0;
bool inDiff = false;
bool wasDiff = false;
int32 level = 0;
// get index to the beginning of the current line
if (view != NULL) {
if (context != NULL) {
level = context->level;
diffMode = context->diff_mode;
begin = context->begin;
inDiff = context->in_diff;
wasDiff = context->was_diff;
} else if (view != NULL) {
int32 start, end;
view->GetSelection(&end, &end);
begin = view->TextLength() == 0 || view->ByteAt(view->TextLength() - 1) == '\n';
begin = view->TextLength() == 0
|| view->ByteAt(view->TextLength() - 1) == '\n';
// the following line works only reliable when text wrapping is set to off;
// so the complicated version actually used here is necessary:
// the following line works only reliable when text wrapping is set to
// off; so the complicated version actually used here is necessary:
// start = view->OffsetAt(view->CurrentLine());
const char *text = view->Text();
@ -472,19 +503,28 @@ FillInQuoteTextRuns(BTextView *view, const char *line, int32 length, const BFont
// get number of nested qoutes for current line
if (!begin && start < end) {
begin = true; // if there was no text in this line, there may come more nested quotes
begin = true;
// if there was no text in this line, there may come
// more nested quotes
for (int32 i = start; i < end; i++) {
if (is_quote_char(text[i]))
level++;
else if (text[i] != ' ' && text[i] != '\t') {
begin = false;
break;
diffMode = diff_mode(text[start]);
if (diffMode == 0) {
for (int32 i = start; i < end; i++) {
if (is_quote_char(text[i]))
level++;
else if (text[i] != ' ' && text[i] != '\t') {
begin = false;
break;
}
}
}
if (begin) // skip leading spaces (tabs & newlines aren't allowed here)
} else
inDiff = true;
if (begin) {
// skip leading spaces (tabs & newlines aren't allowed here)
while (line[pos] == ' ')
pos++;
}
}
} else
begin = true;
@ -494,7 +534,10 @@ FillInQuoteTextRuns(BTextView *view, const char *line, int32 length, const BFont
for (int32 pos = 0; pos < length;) {
int32 next;
if (begin && is_quote_char(line[pos])) {
begin = false;
while (pos < length && line[pos] != '\n') {
// insert style for each quote level
level++;
bool search = true;
@ -502,46 +545,84 @@ FillInQuoteTextRuns(BTextView *view, const char *line, int32 length, const BFont
if (search && is_quote_char(line[next])
|| line[next] == '\n')
break;
else if (line[next] != ' ' && line[next] != '\t')
else if (search && line[next] != ' ' && line[next] != '\t')
search = false;
}
runs[index].offset = pos;
runs[index].font = font;
runs[index].color = level > 0 ? kQuoteColors[level % kNumQuoteColors] : kNormalTextColor;
runs[index].color = level > 0
? kQuoteColors[level % kNumQuoteColors] : kNormalTextColor;
pos = next;
if (++index >= maxStyles)
break;
}
} else {
if (begin) {
if (!inDiff) {
inDiff = !strncmp(&line[pos], "--- ", 4);
wasDiff = false;
}
if (inDiff) {
diffMode = diff_mode(line[pos]);
if (diffMode < 0) {
inDiff = false;
wasDiff = true;
}
}
}
runs[index].offset = pos;
runs[index].font = font;
runs[index].color = level > 0 ? kQuoteColors[level % kNumQuoteColors] : kNormalTextColor;
index++;
if (wasDiff)
runs[index].color = kDiffColors[diff_mode('@') - 1];
else if (diffMode <= 0) {
runs[index].color = level > 0
? kQuoteColors[level % kNumQuoteColors] : kNormalTextColor;
} else
runs[index].color = kDiffColors[diffMode - 1];
begin = false;
for (next = pos; next < length; next++) {
if (line[next] == '\n')
if (line[next] == '\n') {
begin = true;
wasDiff = false;
break;
}
}
pos = next;
index++;
}
if (pos < length)
begin = line[pos] == '\n';
if (begin) {
pos++;
level = 0;
wasDiff = false;
// skip one leading space (tabs & newlines aren't allowed here)
if (!inDiff && pos < length && line[pos] == ' ')
pos++;
}
if (index >= maxStyles)
break;
level = 0;
if (pos < length && line[pos] == '\n') {
pos++;
begin = true;
// skip leading spaces (tabs & newlines aren't allowed here)
while (pos < length && line[pos] == ' ')
pos++;
}
}
style->count = index;
if (context) {
// update context for next run
context->level = level;
context->diff_mode = diffMode;
context->begin = begin;
context->in_diff = inDiff;
context->was_diff = wasDiff;
}
}
@ -2171,12 +2252,12 @@ TTextView::AddAsContent(BEmailMessage *mail, bool wrap, uint32 charset, mail_enc
}
//--------------------------------------------------------------------
// #pragma mark -
TTextView::Reader::Reader(bool header, bool raw, bool quote, bool incoming, bool stripHeader,
bool mime, TTextView *view, BEmailMessage *mail, BList *list, sem_id sem)
TTextView::Reader::Reader(bool header, bool raw, bool quote, bool incoming,
bool stripHeader, bool mime, TTextView *view, BEmailMessage *mail,
BList *list, sem_id sem)
:
fHeader(header),
fRaw(raw),
@ -2193,7 +2274,8 @@ TTextView::Reader::Reader(bool header, bool raw, bool quote, bool incoming, bool
bool
TTextView::Reader::ParseMail(BMailContainer *container, BTextMailComponent *ignore)
TTextView::Reader::ParseMail(BMailContainer *container,
BTextMailComponent *ignore)
{
int32 count = 0;
for (int32 i = 0; i < container->CountComponents(); i++) {
@ -2337,7 +2419,8 @@ TTextView::Reader::Process(const char *data, int32 data_len, bool isHeader)
bool
TTextView::Reader::Insert(const char *line, int32 count, bool isHyperLink, bool isHeader)
TTextView::Reader::Insert(const char *line, int32 count, bool isHyperLink,
bool isHeader)
{
if (!count)
return true;
@ -2345,17 +2428,20 @@ TTextView::Reader::Insert(const char *line, int32 count, bool isHyperLink, bool
BFont font(fView->Font());
TextRunArray style(count / 8 + 8);
if (fView->fColoredQuotes && !isHeader && !isHyperLink)
FillInQuoteTextRuns(fView, line, count, font, &style.Array(), style.MaxEntries());
else {
if (fView->fColoredQuotes && !isHeader && !isHyperLink) {
FillInQuoteTextRuns(fView, &fQuoteContext, line, count, font,
&style.Array(), style.MaxEntries());
} else {
text_run_array &array = style.Array();
array.count = 1;
array.runs[0].offset = 0;
if (isHeader) {
array.runs[0].color = isHyperLink ? kHyperLinkColor : kHeaderColor;
font.SetSize(font.Size() * 0.9);
} else
array.runs[0].color = isHyperLink ? kHyperLinkColor : kNormalTextColor;
} else {
array.runs[0].color = isHyperLink
? kHyperLinkColor : kNormalTextColor;
}
array.runs[0].font = font;
}
@ -3061,7 +3147,8 @@ TTextView::AddQuote(int32 start, int32 finish)
const BFont *font = Font();
TextRunArray style(targetLength / 8 + 8);
FillInQuoteTextRuns(NULL, target, targetLength, font, &style.Array(), style.MaxEntries());
FillInQuoteTextRuns(NULL, NULL, target, targetLength, font,
&style.Array(), style.MaxEntries());
Insert(target, targetLength, &style.Array());
} else
Insert(target, targetLength);
@ -3138,7 +3225,8 @@ TTextView::RemoveQuote(int32 start, int32 finish)
const BFont *font = Font();
TextRunArray style(length / 8 + 8);
FillInQuoteTextRuns(NULL, target, length, font, &style.Array(), style.MaxEntries());
FillInQuoteTextRuns(NULL, NULL, target, length, font,
&style.Array(), style.MaxEntries());
Insert(target, length, &style.Array());
} else
Insert(target, length);

View File

@ -31,13 +31,6 @@ of Be Incorporated in the United States and other countries. Other brand product
names are registered trademarks or trademarks of their respective holders.
All rights reserved.
*/
//--------------------------------------------------------------------
//
// Content.h
//
//--------------------------------------------------------------------
#ifndef _CONTENT_H
#define _CONTENT_H
@ -72,8 +65,7 @@ class BPopupMenu;
struct text_run_array;
typedef struct
{
typedef struct {
bool header;
bool raw;
bool quote;
@ -86,8 +78,7 @@ typedef struct
sem_id *stop_sem;
} reader_info;
enum ENCLOSURE_TYPE
{
enum ENCLOSURE_TYPE {
TYPE_ENCLOSURE = 100,
TYPE_BE_ENCLOSURE,
TYPE_URL,
@ -113,8 +104,7 @@ class TSavePanel;
//====================================================================
class TContentView : public BView
{
class TContentView : public BView {
public:
TContentView(BRect, bool incoming, BEmailMessage *mail, BFont*,
bool showHeader, bool coloredQuotes);
@ -138,8 +128,25 @@ enum {
S_SHOW_ERRORS = 2
};
class TTextView : public BTextView
{
struct quote_context {
quote_context()
:
level(0),
diff_mode(0),
begin(true),
in_diff(false),
was_diff(false)
{
}
int32 level;
int32 diff_mode;
bool begin;
bool in_diff;
bool was_diff;
};
class TTextView : public BTextView {
public:
TTextView(BRect, BRect, bool incoming, BEmailMessage *mail,
TContentView *, BFont *, bool showHeader, bool coloredQuotes);
@ -220,8 +227,7 @@ class TTextView : public BTextView
bool fRaw;
bool fCursor;
struct spell_mark
{
struct spell_mark {
spell_mark *next;
int32 start;
int32 end;
@ -230,18 +236,21 @@ class TTextView : public BTextView
spell_mark *fFirstSpellMark;
class Reader
{
class Reader {
public:
Reader(bool header,bool raw,bool quote,bool incoming,bool stripHeaders,bool mime,
TTextView *view,BEmailMessage *mail,BList *list,sem_id sem);
Reader(bool header, bool raw, bool quote, bool incoming,
bool stripHeaders, bool mime, TTextView* view,
BEmailMessage* mail, BList* list, sem_id sem);
static status_t Run(void *);
static status_t Run(void* _dummy);
private:
bool ParseMail(BMailContainer *container,BTextMailComponent *ignore);
bool Process(const char *data, int32 len, bool isHeader = false);
bool Insert(const char *line, int32 count, bool isHyperLink, bool isHeader = false);
bool ParseMail(BMailContainer* container,
BTextMailComponent* ignore);
bool Process(const char* data, int32 length,
bool isHeader = false);
bool Insert(const char* line, int32 count, bool isHyperLink,
bool isHeader = false);
bool Lock();
status_t Unlock();
@ -249,11 +258,12 @@ class TTextView : public BTextView
bool fHeader;
bool fRaw;
bool fQuote;
quote_context fQuoteContext;
bool fIncoming;
bool fStripHeader;
bool fMime;
TTextView *fView;
BEmailMessage *fMail;
TTextView* fView;
BEmailMessage* fMail;
BList *fEnclosures;
sem_id fStopSem;
};
@ -288,7 +298,8 @@ class TextRunArray {
size_t fNumEntries;
};
extern void FillInQuoteTextRuns(BTextView *view, const char *line, int32 length,
const BFont &font, text_run_array *style, int32 maxStyles = 5);
extern void FillInQuoteTextRuns(BTextView* view, quote_context* context,
const char* line, int32 length, const BFont& font, text_run_array* style,
int32 maxStyles = 5);
#endif /* #ifndef _CONTENT_H */

View File

@ -2169,8 +2169,9 @@ TMailWindow::Reply(entry_ref *ref, TMailWindow *window, uint32 type)
TextRunArray style(length / 8 + 8);
FillInQuoteTextRuns(fContentView->fTextView, fContentView->fTextView->Text(),
length, font, &style.Array(), style.MaxEntries());
FillInQuoteTextRuns(fContentView->fTextView, NULL,
fContentView->fTextView->Text(), length, font, &style.Array(),
style.MaxEntries());
fContentView->fTextView->SetRunArray(0, length, &style.Array());
}