/******************************************************************* * * File: CSimpleTextParser.cpp * * Author: Peter van Sebille (peter@yipton.net) * * (c) Copyright 2002, Peter van Sebille * All Rights Reserved * *******************************************************************/ #include "CSimpleTextParser.h" enum { EBadTag, EBadZeroLengthTag, EBadIntegerParam, EBadAlignmentParam, EBadRgbColorParam }; void Panic(TInt aPanic) { User::Panic(_L("STP"), aPanic); } CSimpleTextFormatParser* CSimpleTextFormatParser::NewLC() { CSimpleTextFormatParser* self = new(ELeave)CSimpleTextFormatParser; CleanupStack::PushL(self); self->ConstructL(); return self; } CSimpleTextFormatParser::~CSimpleTextFormatParser() { delete iParaFormat; } void CSimpleTextFormatParser::ConstructL() { iParaFormat = CParaFormat::NewL(); } void CSimpleTextFormatParser::SetBold(TBool aEnable) { iCharFormat.iFontSpec.iFontStyle.SetStrokeWeight(aEnable ? EStrokeWeightBold : EStrokeWeightNormal); iCharMask.ClearAll(); iCharMask.SetAttrib(EAttFontStrokeWeight); iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); } void CSimpleTextFormatParser::SetItalic(TBool aEnable) { iCharFormat.iFontSpec.iFontStyle.SetPosture(aEnable ? EPostureItalic : EPostureUpright); iCharMask.ClearAll(); iCharMask.SetAttrib(EAttFontPosture); iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); } void CSimpleTextFormatParser::SetUnderLine(TBool aEnable) { iCharFormat.iFontPresentation.iUnderline = aEnable ? EUnderlineOn : EUnderlineOff; iCharMask.ClearAll(); iCharMask.SetAttrib(EAttFontUnderline); iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); } void CSimpleTextFormatParser::SetHiddenText(TBool aEnable) { iCharFormat.iFontPresentation.iHiddenText = aEnable; iCharMask.ClearAll(); iCharMask.SetAttrib(EAttFontHiddenText); iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); } TRgb CSimpleTextFormatParser::ForegroundColor() { iCharMask.ClearAll(); iCharMask.SetAttrib(EAttColor); iRichText->GetCharFormat(iCharFormat, iCharMask, TextPos(), 0); return iCharFormat.iFontPresentation.iTextColor; } void CSimpleTextFormatParser::SetForegroundColor(const TRgb& aColor) { iCharFormat.iFontPresentation.iTextColor = aColor; iCharMask.ClearAll(); iCharMask.SetAttrib(EAttColor); iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); } void CSimpleTextFormatParser::SetBackgroundColor(const TRgb& aColor) { iParaFormat->iFillColor = aColor; iParaMask.ClearAll(); iParaMask.SetAttrib(EAttFillColor); iRichText->ApplyParaFormatL(iParaFormat, iParaMask, ParaPos(), 0); } void CSimpleTextFormatParser::NewParagraph() { iCurrentPara++; iRichText->AppendParagraphL(); AppendTextL(_L("")); } void CSimpleTextFormatParser::SetAlignment(CParaFormat::TAlignment aAlignment) { iParaFormat->iHorizontalAlignment = aAlignment; iParaMask.ClearAll(); iParaMask.SetAttrib(EAttAlignment); iRichText->ApplyParaFormatL(iParaFormat, iParaMask, ParaPos(), 0); } void CSimpleTextFormatParser::SetFontHeight(TInt aHeight) { iCharFormat.iFontSpec.iHeight = (aHeight * KTwipsPerInch)/KPointsPerInch; iCharMask.ClearAll(); iCharMask.SetAttrib(EAttFontHeight); iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); } void CSimpleTextFormatParser::SetFontName(const TDesC& aName) { iCharFormat.iFontSpec.iTypeface.iName = aName; iCharFormat.iFontSpec.iTypeface.SetAttributes(0); iCharFormat.iFontSpec.iTypeface.SetIsProportional(ETrue); iCharMask.ClearAll(); iCharMask.SetAttrib(EAttFontTypeface); iRichText->ApplyCharFormatL(iCharFormat, iCharMask, TextPos(), 0); } /* * Character formatting: * Bold on * Bold of * Italic on * Italic off * Underline on * Underline off * Hidden text on **doesn't work** * Hidden text off **doesn't work** * Fontname: name (type: string) * Fontsize: size (type: integer) * Foreground color: color (type: color) * Restore foreground color * * Paragraph formatting: *

New paragraph - will reset both character & paragraph formatting to defaults * Alignment: aling (type: alignement) * Background color: color (type: color) **doesn't work** * * Special characters: * The character: < * * Types: * - string: * - integer: Either decimal or hexidecimal value * - color: Either integer specifing rgb value, or (r,g,b) in which r, g and b are of type integer * - align: element of enumeration {center, left, right} * * Comments: * The syntax/parser is fairly simplistic. The parser is not trying to match a tag like * as XML/HTML do. Basically, when it encounters a tag (e.g., ) it will * simply instruct the the editor to apply the formatting from the current position as * specified by the tag (e.g., enable bold). For example, HelloWorld results * in Hello displayed in a Bold font and World in a normal font. * * The only case where state is maintained is when using and . The current * fg color is stored when parsing and restored when doing . Again, and * don't have the XML/HTML behavior. For example: * Peterwashere * results in "Peter" displayed in red, "was" displayed in blue and "here" displayed in red. * It literally goes like this: * 1) --> apply editor text color red, previous color = whatever the editor's text color is now * 2) --> apply editor text color blue, previous color = whatever the editor's text color * is now --> red * 3) --> apply editor text to previous color --> red * 4) --> apply editor text to previous color --> red * * What you probably wanted was: * Peterwashere * Now "Peter" is displayed in red, "was" in blue and "here" in the default editor's color */ static TUint32 ParseInteger(const TDesC& aString) { TUint32 val = 0; TBool parsed = EFalse; if (aString.Length() > 2) { if ((aString[0] == '0') && ((aString[0] == 'x') || (aString[0] == 'X'))) { TLex lex(aString.Right(aString.Length()-2)); if (lex.Val(val, EHex) != KErrNone) { __ASSERT_DEBUG(ETrue, Panic(EBadIntegerParam)); } parsed = ETrue; } } if (!parsed) { TLex lex(aString); if (lex.Val(val, EDecimal) != KErrNone) { __ASSERT_DEBUG(ETrue, Panic(EBadIntegerParam)); } } return val; } static TRgb ParseColor(const TDesC& aString) { if (aString.Length() > 0) { if (aString[0] == 'R') { if (aString.Compare(_L("RgbBlack")) == 0) return KRgbBlack; else if (aString.Compare(_L("RgbDarkGray")) == 0) return KRgbDarkGray; else if (aString.Compare(_L("RgbDarkRed")) == 0) return KRgbDarkRed; else if (aString.Compare(_L("RgbDarkGreen")) == 0) return KRgbDarkGreen; else if (aString.Compare(_L("RgbDarkYellow")) == 0) return KRgbDarkYellow; else if (aString.Compare(_L("RgbDarkBlue")) == 0) return KRgbDarkBlue; else if (aString.Compare(_L("RgbDarkMagenta")) == 0) return KRgbDarkMagenta; else if (aString.Compare(_L("RgbDarkCyan")) == 0) return KRgbDarkCyan; else if (aString.Compare(_L("RgbRed")) == 0) return KRgbRed; else if (aString.Compare(_L("RgbGreen")) == 0) return KRgbGreen; else if (aString.Compare(_L("RgbYellow")) == 0) return KRgbYellow; else if (aString.Compare(_L("RgbBlue")) == 0) return KRgbBlue; else if (aString.Compare(_L("RgbMagenta")) == 0) return KRgbMagenta; else if (aString.Compare(_L("RgbCyan")) == 0) return KRgbCyan; else if (aString.Compare(_L("RgbGray")) == 0) return KRgbGray; else if (aString.Compare(_L("RgbWhite")) == 0) return KRgbWhite; else { __ASSERT_DEBUG(ETrue, Panic(EBadRgbColorParam)); } } return ParseInteger(aString); } __ASSERT_DEBUG(ETrue, Panic(EBadRgbColorParam)); return KRgbBlack; } static CParaFormat::TAlignment ParseAlignment(const TDesC& aString) { if (aString.Compare(_L("center")) == 0) { return CParaFormat::ECenterAlign; } else if (aString.Compare(_L("left")) == 0) { return CParaFormat::ELeftAlign; } else if (aString.Compare(_L("right")) == 0) { return CParaFormat::ERightAlign; } __ASSERT_DEBUG(ETrue, Panic(EBadAlignmentParam)); return CParaFormat::ECenterAlign; } void CSimpleTextFormatParser::ParseTagL(const TDesC& aTag) { TInt tagLength = aTag.Length(); if (tagLength == 0) { __ASSERT_DEBUG(ETrue, Panic(EBadZeroLengthTag)); return; } TPtrC param(_L("")); TInt pos = aTag.Find(_L("=")); if (pos>0) { param.Set(aTag.Right(aTag.Length()-pos-1)); tagLength = pos; } TPtrC tag = aTag.Left(tagLength); // RDebug::Print(_L("tag=%S, param=%S"), &tag, ¶m); switch (tagLength) { case 1: { if (tag.Compare(_L("a")) == 0) SetAlignment(ParseAlignment(param)); else if (tag.Compare(_L("b")) == 0) SetBold(); else if (tag.Compare(_L("f")) == 0) SetFontName(param); else if (tag.Compare(_L("h")) == 0) SetHiddenText(); else if (tag.Compare(_L("i")) == 0) SetItalic(); else if (tag.Compare(_L("p")) == 0) NewParagraph(); else if (tag.Compare(_L("s")) == 0) SetFontHeight(ParseInteger(param)); else if (tag.Compare(_L("u")) == 0) SetUnderLine(); else { __ASSERT_DEBUG(ETrue, Panic(EBadTag)); } break; } case 2: { if (tag.Compare(_L("/b")) == 0) SetBold(EFalse); if (tag.Compare(_L("bg")) == 0) SetBackgroundColor(ParseColor(param)); if (tag.Compare(_L("fg")) == 0) { iPrevFgColor = ForegroundColor(); SetForegroundColor(ParseColor(param)); } else if (tag.Compare(_L("/h")) == 0) SetHiddenText(EFalse); else if (tag.Compare(_L("/i")) == 0) SetItalic(EFalse); else if (tag.Compare(_L("/u")) == 0) SetUnderLine(EFalse); else if (tag.Compare(_L("/<")) == 0) AppendTextL(_L("<")); break; } case 3: { if (tag.Compare(_L("/fg")) == 0) SetForegroundColor(iPrevFgColor); break; } default: ; } } void CSimpleTextFormatParser::ParseL(const TDesC& aSimpleText, CRichText& aRichText) { iRichText = &aRichText; iCurrentPara = 0; TBool done = EFalse; TPtrC simpleText(aSimpleText); do { TInt pos = simpleText.Locate('<'); if (pos > 0) { AppendTextL(simpleText.Left(pos)); simpleText.Set(simpleText.Right(simpleText.Length() - pos)); } else if (pos == 0) { pos = simpleText.Locate('>'); if (pos<=0) User::Leave(KErrArgument); ParseTagL(simpleText.Mid(1, pos-1)); simpleText.Set(simpleText.Right(simpleText.Length() - pos - 1)); } else { AppendTextL(simpleText); done = ETrue; } } while (!done); } TInt CSimpleTextFormatParser::TextPos() { return iRichText->DocumentLength(); #if 0 TInt pos, length; pos = iRichText->CharPosOfParagraph(length, iCurrentPara); return pos+length-1; #endif } TInt CSimpleTextFormatParser::ParaPos() { return TextPos(); #if 0 TInt pos, length; pos = iRichText->CharPosOfParagraph(length, iCurrentPara); return pos+length-1; #endif } void CSimpleTextFormatParser::AppendTextL(const TDesC& aText) { // RDebug::Print(_L("text=%S"), &aText); iRichText->InsertL(TextPos(), aText); } #if 0 void CTestDialog::ShowTextL(CRichText& aRichText) { aRichText.Reset(); TCharFormat charFormat; TCharFormatMask charMask; aRichText.GetCharFormat(charFormat, charMask, 0, 0); TInt para = 0; AppendTextL(_L("http://www.yipton.net"), aRichText); para++; aRichText.AppendParagraphL(); CParaFormat* paraFormat = CParaFormat::NewLC(); TParaFormatMask paraMask; aRichText.GetParaFormatL(paraFormat, paraMask, ParaPos(aRichText, para), 0); paraFormat->iHorizontalAlignment = CParaFormat::ECenterAlign; paraMask.ClearAll(); paraMask.SetAttrib(EAttAlignment); aRichText.ApplyParaFormatL(paraFormat, paraMask, ParaPos(aRichText, para), 0); charFormat.iFontPresentation.iUnderline = EUnderlineOn; charFormat.iFontSpec.iFontStyle.SetPosture(EPostureItalic); charMask.ClearAll(); charMask.SetAttrib(EAttFontPosture); charMask.SetAttrib(EAttFontUnderline); aRichText.ApplyCharFormatL(charFormat, charMask, TextPos(aRichText, para)); AppendTextL(_L("mailto:Peter is here"), aRichText, para); para++; aRichText.AppendParagraphL(); TFontSpec fontSpec(_L("edmunds"), 20 * KPointsPerInch); // CFont* font = NULL; // iCoeEnv->ScreenDevice()->GetNearestFontInTwips(font, fontSpec); charFormat.iFontSpec = fontSpec; charMask.ClearAll(); charMask.SetAttrib(EAttFontHeight); charMask.SetAttrib(EAttFontTypeface); aRichText.ApplyCharFormatL(charFormat, charMask, TextPos(aRichText, para)); AppendTextL(_L("mailto:Peter is here"), aRichText, para); CleanupStack::PopAndDestroy(); } #endif