bugfix
[picodrive.git] / platform / uiq3 / CSimpleTextParser.cpp
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, &param);\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