cc68a136 |
1 | /*******************************************************************\r |
2 | *\r |
3 | * File: CSimpleTextParser.cpp\r |
4 | *\r |
5 | * Author: Peter van Sebille (peter@yipton.net)\r |
6 | *\r |
7 | * (c) Copyright 2002, Peter van Sebille\r |
8 | * All Rights Reserved\r |
9 | *\r |
10 | *******************************************************************/\r |
11 | \r |
12 | #include "CSimpleTextParser.h"\r |
13 | \r |
14 | enum\r |
15 | {\r |
16 | EBadTag,\r |
17 | EBadZeroLengthTag,\r |
18 | EBadIntegerParam,\r |
19 | EBadAlignmentParam,\r |
20 | EBadRgbColorParam\r |
21 | };\r |
22 | \r |
23 | void Panic(TInt aPanic)\r |
24 | {\r |
25 | User::Panic(_L("STP"), aPanic);\r |
26 | }\r |
27 | \r |
28 | CSimpleTextFormatParser* CSimpleTextFormatParser::NewLC()\r |
29 | {\r |
30 | CSimpleTextFormatParser* self = new(ELeave)CSimpleTextFormatParser;\r |
31 | CleanupStack::PushL(self);\r |
32 | self->ConstructL();\r |
33 | return self;\r |
34 | }\r |
35 | \r |
36 | CSimpleTextFormatParser::~CSimpleTextFormatParser()\r |
37 | {\r |
38 | delete iParaFormat;\r |
39 | }\r |
40 | \r |
41 | void CSimpleTextFormatParser::ConstructL()\r |
42 | {\r |
43 | iParaFormat = CParaFormat::NewL();\r |
44 | }\r |
45 | \r |
46 | \r |
47 | void CSimpleTextFormatParser::SetBold(TBool aEnable)\r |
48 | {\r |
49 | iCharFormat.iFontSpec.iFontStyle.SetStrokeWeight(aEnable ? EStrokeWeightBold : EStrokeWeightNormal);\r |
50 | iCharMask.ClearAll();\r |
51 | iCharMask.SetAttrib(EAttFontStrokeWeight);\r |
52 | iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0);\r |
53 | }\r |
54 | \r |
55 | void CSimpleTextFormatParser::SetItalic(TBool aEnable)\r |
56 | {\r |
57 | iCharFormat.iFontSpec.iFontStyle.SetPosture(aEnable ? EPostureItalic : EPostureUpright);\r |
58 | iCharMask.ClearAll();\r |
59 | iCharMask.SetAttrib(EAttFontPosture);\r |
60 | iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0);\r |
61 | }\r |
62 | \r |
63 | void CSimpleTextFormatParser::SetUnderLine(TBool aEnable)\r |
64 | {\r |
65 | iCharFormat.iFontPresentation.iUnderline = aEnable ? EUnderlineOn : EUnderlineOff;\r |
66 | iCharMask.ClearAll();\r |
67 | iCharMask.SetAttrib(EAttFontUnderline);\r |
68 | iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0);\r |
69 | }\r |
70 | \r |
71 | void CSimpleTextFormatParser::SetHiddenText(TBool aEnable)\r |
72 | {\r |
73 | iCharFormat.iFontPresentation.iHiddenText = aEnable;\r |
74 | iCharMask.ClearAll();\r |
75 | iCharMask.SetAttrib(EAttFontHiddenText);\r |
76 | iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0);\r |
77 | }\r |
78 | \r |
79 | TRgb CSimpleTextFormatParser::ForegroundColor()\r |
80 | {\r |
81 | iCharMask.ClearAll();\r |
82 | iCharMask.SetAttrib(EAttColor);\r |
83 | iRichText->GetCharFormat(iCharFormat, iCharMask, TextPos(), 0);\r |
84 | return iCharFormat.iFontPresentation.iTextColor;\r |
85 | }\r |
86 | \r |
87 | void CSimpleTextFormatParser::SetForegroundColor(const TRgb& aColor)\r |
88 | {\r |
89 | iCharFormat.iFontPresentation.iTextColor = aColor;\r |
90 | iCharMask.ClearAll();\r |
91 | iCharMask.SetAttrib(EAttColor);\r |
92 | iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0);\r |
93 | }\r |
94 | \r |
95 | void CSimpleTextFormatParser::SetBackgroundColor(const TRgb& aColor)\r |
96 | {\r |
97 | iParaFormat->iFillColor = aColor;\r |
98 | iParaMask.ClearAll();\r |
99 | iParaMask.SetAttrib(EAttFillColor);\r |
100 | iRichText->ApplyParaFormatL(iParaFormat, iParaMask, ParaPos(), 0);\r |
101 | }\r |
102 | \r |
103 | void CSimpleTextFormatParser::NewParagraph()\r |
104 | {\r |
105 | iCurrentPara++;\r |
106 | iRichText->AppendParagraphL();\r |
107 | AppendTextL(_L(""));\r |
108 | }\r |
109 | \r |
110 | \r |
111 | void CSimpleTextFormatParser::SetAlignment(CParaFormat::TAlignment aAlignment)\r |
112 | {\r |
113 | iParaFormat->iHorizontalAlignment = aAlignment;\r |
114 | iParaMask.ClearAll();\r |
115 | iParaMask.SetAttrib(EAttAlignment);\r |
116 | iRichText->ApplyParaFormatL(iParaFormat, iParaMask, ParaPos(), 0);\r |
117 | }\r |
118 | \r |
119 | \r |
120 | void CSimpleTextFormatParser::SetFontHeight(TInt aHeight)\r |
121 | {\r |
122 | iCharFormat.iFontSpec.iHeight = (aHeight * KTwipsPerInch)/KPointsPerInch;\r |
123 | iCharMask.ClearAll();\r |
124 | iCharMask.SetAttrib(EAttFontHeight);\r |
125 | iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0);\r |
126 | }\r |
127 | \r |
128 | void CSimpleTextFormatParser::SetFontName(const TDesC& aName)\r |
129 | {\r |
130 | iCharFormat.iFontSpec.iTypeface.iName = aName;\r |
131 | iCharFormat.iFontSpec.iTypeface.SetAttributes(0);\r |
132 | iCharFormat.iFontSpec.iTypeface.SetIsProportional(ETrue);\r |
133 | iCharMask.ClearAll();\r |
134 | iCharMask.SetAttrib(EAttFontTypeface);\r |
135 | iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0);\r |
136 | }\r |
137 | \r |
138 | \r |
139 | /*\r |
140 | * Character formatting:\r |
141 | * <b> Bold on\r |
142 | * </b> Bold of\r |
143 | * <i> Italic on\r |
144 | * </i> Italic off\r |
145 | * <u> Underline on\r |
146 | * </u> Underline off\r |
147 | * <h> Hidden text on **doesn't work**\r |
148 | * </h> Hidden text off **doesn't work**\r |
149 | * <f=name> Fontname: name (type: string)\r |
150 | * <s=size> Fontsize: size (type: integer)\r |
151 | * <fg=color> Foreground color: color (type: color)\r |
152 | * </fg> Restore foreground color\r |
153 | *\r |
154 | * Paragraph formatting:\r |
155 | * <p> New paragraph - will reset both character & paragraph formatting to defaults\r |
156 | * <a=align> Alignment: aling (type: alignement)\r |
157 | * <bg=color> Background color: color (type: color) **doesn't work**\r |
158 | *\r |
159 | * Special characters:\r |
160 | * </<> The character: <\r |
161 | *\r |
162 | * Types:\r |
163 | * - string:\r |
164 | * - integer: Either decimal or hexidecimal value\r |
165 | * - color: Either integer specifing rgb value, or (r,g,b) in which r, g and b are of type integer\r |
166 | * - align: element of enumeration {center, left, right}\r |
167 | *\r |
168 | * Comments:\r |
169 | * The syntax/parser is fairly simplistic. The parser is not trying to match a tag like \r |
170 | * <tag> </tag> as XML/HTML do. Basically, when it encounters a tag (e.g., <b>) it will \r |
171 | * simply instruct the the editor to apply the formatting from the current position as \r |
172 | * specified by the tag (e.g., enable bold). For example, <b><b>Hello</b>World</b> results\r |
173 | * in Hello displayed in a Bold font and World in a normal font.\r |
174 | *\r |
175 | * The only case where state is maintained is when using <fg=color> and </fg>. The current\r |
176 | * fg color is stored when parsing <fg=color> and restored when doing </fg>. Again, <fg> and \r |
177 | * </fg> don't have the XML/HTML <tag> </tag> behavior. For example:\r |
178 | * <fg=red>Peter<fg=blue>was</fg></fg>here\r |
179 | * results in "Peter" displayed in red, "was" displayed in blue and "here" displayed in red.\r |
180 | * It literally goes like this:\r |
181 | * 1) <fg=red> --> apply editor text color red, previous color = whatever the editor's text color is now\r |
182 | * 2) <fg=blue> --> apply editor text color blue, previous color = whatever the editor's text color \r |
183 | * is now --> red\r |
184 | * 3) </fg> --> apply editor text to previous color --> red\r |
185 | * 4) </fg> --> apply editor text to previous color --> red\r |
186 | *\r |
187 | * What you probably wanted was:\r |
188 | * <fg=red>Peter</fg><fg=blue>was</fg>here\r |
189 | * Now "Peter" is displayed in red, "was" in blue and "here" in the default editor's color\r |
190 | */\r |
191 | \r |
192 | static TUint32 ParseInteger(const TDesC& aString)\r |
193 | {\r |
194 | TUint32 val = 0;\r |
195 | TBool parsed = EFalse;\r |
196 | if (aString.Length() > 2)\r |
197 | {\r |
198 | if ((aString[0] == '0') && ((aString[0] == 'x') || (aString[0] == 'X')))\r |
199 | {\r |
200 | TLex lex(aString.Right(aString.Length()-2));\r |
201 | if (lex.Val(val, EHex) != KErrNone)\r |
202 | {\r |
203 | __ASSERT_DEBUG(ETrue, Panic(EBadIntegerParam));\r |
204 | }\r |
205 | parsed = ETrue;\r |
206 | }\r |
207 | }\r |
208 | if (!parsed)\r |
209 | {\r |
210 | TLex lex(aString);\r |
211 | if (lex.Val(val, EDecimal) != KErrNone)\r |
212 | {\r |
213 | __ASSERT_DEBUG(ETrue, Panic(EBadIntegerParam));\r |
214 | }\r |
215 | }\r |
216 | return val;\r |
217 | }\r |
218 | \r |
219 | static TRgb ParseColor(const TDesC& aString)\r |
220 | {\r |
221 | if (aString.Length() > 0)\r |
222 | {\r |
223 | if (aString[0] == 'R')\r |
224 | {\r |
225 | if (aString.Compare(_L("RgbBlack")) == 0)\r |
226 | return KRgbBlack;\r |
227 | else if (aString.Compare(_L("RgbDarkGray")) == 0)\r |
228 | return KRgbDarkGray;\r |
229 | else if (aString.Compare(_L("RgbDarkRed")) == 0)\r |
230 | return KRgbDarkRed;\r |
231 | else if (aString.Compare(_L("RgbDarkGreen")) == 0)\r |
232 | return KRgbDarkGreen;\r |
233 | else if (aString.Compare(_L("RgbDarkYellow")) == 0)\r |
234 | return KRgbDarkYellow;\r |
235 | else if (aString.Compare(_L("RgbDarkBlue")) == 0)\r |
236 | return KRgbDarkBlue;\r |
237 | else if (aString.Compare(_L("RgbDarkMagenta")) == 0)\r |
238 | return KRgbDarkMagenta;\r |
239 | else if (aString.Compare(_L("RgbDarkCyan")) == 0)\r |
240 | return KRgbDarkCyan;\r |
241 | else if (aString.Compare(_L("RgbRed")) == 0)\r |
242 | return KRgbRed;\r |
243 | else if (aString.Compare(_L("RgbGreen")) == 0)\r |
244 | return KRgbGreen;\r |
245 | else if (aString.Compare(_L("RgbYellow")) == 0)\r |
246 | return KRgbYellow;\r |
247 | else if (aString.Compare(_L("RgbBlue")) == 0)\r |
248 | return KRgbBlue;\r |
249 | else if (aString.Compare(_L("RgbMagenta")) == 0)\r |
250 | return KRgbMagenta;\r |
251 | else if (aString.Compare(_L("RgbCyan")) == 0)\r |
252 | return KRgbCyan;\r |
253 | else if (aString.Compare(_L("RgbGray")) == 0)\r |
254 | return KRgbGray;\r |
255 | else if (aString.Compare(_L("RgbWhite")) == 0)\r |
256 | return KRgbWhite;\r |
257 | else\r |
258 | {\r |
259 | __ASSERT_DEBUG(ETrue, Panic(EBadRgbColorParam));\r |
260 | }\r |
261 | }\r |
262 | return ParseInteger(aString);\r |
263 | }\r |
264 | __ASSERT_DEBUG(ETrue, Panic(EBadRgbColorParam));\r |
265 | \r |
266 | return KRgbBlack;\r |
267 | }\r |
268 | \r |
269 | \r |
270 | \r |
271 | static CParaFormat::TAlignment ParseAlignment(const TDesC& aString)\r |
272 | {\r |
273 | if (aString.Compare(_L("center")) == 0)\r |
274 | {\r |
275 | return CParaFormat::ECenterAlign;\r |
276 | }\r |
277 | else if (aString.Compare(_L("left")) == 0)\r |
278 | {\r |
279 | return CParaFormat::ELeftAlign;\r |
280 | }\r |
281 | else if (aString.Compare(_L("right")) == 0)\r |
282 | {\r |
283 | return CParaFormat::ERightAlign;\r |
284 | }\r |
285 | __ASSERT_DEBUG(ETrue, Panic(EBadAlignmentParam));\r |
286 | \r |
287 | return CParaFormat::ECenterAlign;\r |
288 | }\r |
289 | \r |
290 | void CSimpleTextFormatParser::ParseTagL(const TDesC& aTag)\r |
291 | {\r |
292 | TInt tagLength = aTag.Length();\r |
293 | if (tagLength == 0)\r |
294 | {\r |
295 | __ASSERT_DEBUG(ETrue, Panic(EBadZeroLengthTag));\r |
296 | return;\r |
297 | }\r |
298 | \r |
299 | TPtrC param(_L(""));\r |
300 | TInt pos = aTag.Find(_L("="));\r |
301 | if (pos>0)\r |
302 | {\r |
303 | param.Set(aTag.Right(aTag.Length()-pos-1));\r |
304 | tagLength = pos;\r |
305 | }\r |
306 | TPtrC tag = aTag.Left(tagLength);\r |
307 | \r |
308 | // RDebug::Print(_L("tag=%S, param=%S"), &tag, ¶m);\r |
309 | \r |
310 | switch (tagLength)\r |
311 | {\r |
312 | case 1:\r |
313 | {\r |
314 | if (tag.Compare(_L("a")) == 0)\r |
315 | SetAlignment(ParseAlignment(param));\r |
316 | else if (tag.Compare(_L("b")) == 0)\r |
317 | SetBold();\r |
318 | else if (tag.Compare(_L("f")) == 0)\r |
319 | SetFontName(param);\r |
320 | else if (tag.Compare(_L("h")) == 0)\r |
321 | SetHiddenText();\r |
322 | else if (tag.Compare(_L("i")) == 0)\r |
323 | SetItalic();\r |
324 | else if (tag.Compare(_L("p")) == 0)\r |
325 | NewParagraph();\r |
326 | else if (tag.Compare(_L("s")) == 0)\r |
327 | SetFontHeight(ParseInteger(param));\r |
328 | else if (tag.Compare(_L("u")) == 0)\r |
329 | SetUnderLine();\r |
330 | else\r |
331 | {\r |
332 | __ASSERT_DEBUG(ETrue, Panic(EBadTag));\r |
333 | }\r |
334 | break;\r |
335 | }\r |
336 | \r |
337 | case 2:\r |
338 | {\r |
339 | if (tag.Compare(_L("/b")) == 0)\r |
340 | SetBold(EFalse);\r |
341 | if (tag.Compare(_L("bg")) == 0)\r |
342 | SetBackgroundColor(ParseColor(param));\r |
343 | if (tag.Compare(_L("fg")) == 0)\r |
344 | {\r |
345 | iPrevFgColor = ForegroundColor();\r |
346 | SetForegroundColor(ParseColor(param));\r |
347 | }\r |
348 | else if (tag.Compare(_L("/h")) == 0)\r |
349 | SetHiddenText(EFalse);\r |
350 | else if (tag.Compare(_L("/i")) == 0)\r |
351 | SetItalic(EFalse);\r |
352 | else if (tag.Compare(_L("/u")) == 0)\r |
353 | SetUnderLine(EFalse);\r |
354 | else if (tag.Compare(_L("/<")) == 0)\r |
355 | AppendTextL(_L("<"));\r |
356 | break;\r |
357 | }\r |
358 | case 3:\r |
359 | {\r |
360 | if (tag.Compare(_L("/fg")) == 0)\r |
361 | SetForegroundColor(iPrevFgColor);\r |
362 | break;\r |
363 | }\r |
364 | default:\r |
365 | ;\r |
366 | }\r |
367 | }\r |
368 | \r |
369 | void CSimpleTextFormatParser::ParseL(const TDesC& aSimpleText, CRichText& aRichText)\r |
370 | {\r |
371 | iRichText = &aRichText;\r |
372 | iCurrentPara = 0;\r |
373 | \r |
374 | TBool done = EFalse;\r |
375 | TPtrC simpleText(aSimpleText);\r |
376 | do\r |
377 | {\r |
378 | TInt pos = simpleText.Locate('<');\r |
379 | if (pos > 0)\r |
380 | {\r |
381 | AppendTextL(simpleText.Left(pos));\r |
382 | simpleText.Set(simpleText.Right(simpleText.Length() - pos));\r |
383 | }\r |
384 | else if (pos == 0)\r |
385 | {\r |
386 | pos = simpleText.Locate('>');\r |
387 | if (pos<=0)\r |
388 | User::Leave(KErrArgument);\r |
389 | ParseTagL(simpleText.Mid(1, pos-1));\r |
390 | simpleText.Set(simpleText.Right(simpleText.Length() - pos - 1));\r |
391 | }\r |
392 | else\r |
393 | {\r |
394 | AppendTextL(simpleText);\r |
395 | done = ETrue;\r |
396 | }\r |
397 | } while (!done);\r |
398 | }\r |
399 | \r |
400 | \r |
401 | TInt CSimpleTextFormatParser::TextPos()\r |
402 | {\r |
403 | return iRichText->DocumentLength();\r |
404 | #if 0\r |
405 | TInt pos, length;\r |
406 | pos = iRichText->CharPosOfParagraph(length, iCurrentPara);\r |
407 | return pos+length-1;\r |
408 | #endif\r |
409 | }\r |
410 | \r |
411 | TInt CSimpleTextFormatParser::ParaPos()\r |
412 | {\r |
413 | return TextPos();\r |
414 | #if 0\r |
415 | TInt pos, length;\r |
416 | pos = iRichText->CharPosOfParagraph(length, iCurrentPara);\r |
417 | return pos+length-1;\r |
418 | #endif\r |
419 | }\r |
420 | \r |
421 | \r |
422 | void CSimpleTextFormatParser::AppendTextL(const TDesC& aText)\r |
423 | {\r |
424 | // RDebug::Print(_L("text=%S"), &aText);\r |
425 | iRichText->InsertL(TextPos(), aText);\r |
426 | }\r |
427 | \r |
428 | \r |
429 | #if 0\r |
430 | void CTestDialog::ShowTextL(CRichText& aRichText)\r |
431 | {\r |
432 | aRichText.Reset();\r |
433 | \r |
434 | TCharFormat charFormat;\r |
435 | TCharFormatMask charMask;\r |
436 | aRichText.GetCharFormat(charFormat, charMask, 0, 0);\r |
437 | \r |
438 | TInt para = 0;\r |
439 | AppendTextL(_L("http://www.yipton.net"), aRichText);\r |
440 | \r |
441 | para++;\r |
442 | aRichText.AppendParagraphL();\r |
443 | \r |
444 | CParaFormat* paraFormat = CParaFormat::NewLC();\r |
445 | TParaFormatMask paraMask;\r |
446 | aRichText.GetParaFormatL(paraFormat, paraMask, ParaPos(aRichText, para), 0);\r |
447 | paraFormat->iHorizontalAlignment = CParaFormat::ECenterAlign;\r |
448 | paraMask.ClearAll();\r |
449 | paraMask.SetAttrib(EAttAlignment);\r |
450 | aRichText.ApplyParaFormatL(paraFormat, paraMask, ParaPos(aRichText, para), 0);\r |
451 | \r |
452 | charFormat.iFontPresentation.iUnderline = EUnderlineOn;\r |
453 | charFormat.iFontSpec.iFontStyle.SetPosture(EPostureItalic);\r |
454 | charMask.ClearAll();\r |
455 | charMask.SetAttrib(EAttFontPosture);\r |
456 | charMask.SetAttrib(EAttFontUnderline);\r |
457 | aRichText.ApplyCharFormatL(charFormat, charMask, TextPos(aRichText, para));\r |
458 | AppendTextL(_L("mailto:Peter is here"), aRichText, para);\r |
459 | \r |
460 | para++;\r |
461 | aRichText.AppendParagraphL();\r |
462 | \r |
463 | TFontSpec fontSpec(_L("edmunds"), 20 * KPointsPerInch);\r |
464 | // CFont* font = NULL;\r |
465 | // iCoeEnv->ScreenDevice()->GetNearestFontInTwips(font, fontSpec);\r |
466 | \r |
467 | charFormat.iFontSpec = fontSpec;\r |
468 | charMask.ClearAll();\r |
469 | charMask.SetAttrib(EAttFontHeight);\r |
470 | charMask.SetAttrib(EAttFontTypeface);\r |
471 | aRichText.ApplyCharFormatL(charFormat, charMask, TextPos(aRichText, para));\r |
472 | AppendTextL(_L("mailto:Peter is here"), aRichText, para);\r |
473 | \r |
474 | CleanupStack::PopAndDestroy();\r |
475 | }\r |
476 | \r |
477 | #endif\r |