//--------------------------------------------------------------------------- #include #pragma hdrstop #include "TntSystem.hpp" #include "RxRichEditX.h" #include "PrintFrm.h" #include #include "swdisprtf.h" #include "swdisprtfchap.h" #include "mainfrm.h" #include #include #include #include #include // because stupid commdlg.h defines this and messes up our calls to our parent FindText method #undef FindText char TRxRichEditX::platformID = 0; TRxRichEditX::TRxRichEditX(TWinControl *parent) : TRxRichEdit(parent) { OSVERSIONINFO osvi; memset(&osvi, 0, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osvi); platformID = osvi.dwPlatformId; type = "Default"; } void TRxRichEditX::RenderModule(SWModule* module/*, RTF_FORMAT format*/) { //format_ops = format; this->module = module; TMemoryStream* RTFStream = new TMemoryStream(); recalcAppearance(); AnsiString rtfText = RTFHeader; rtfText += RTFHeadMargin; rtfText += GetFormattedText(module); rtfText += RTFTrailer; RTFStream->Clear(); RTFStream->WriteBuffer(rtfText.c_str(), rtfText.Length()); RTFStream->Position = 0; Lines->LoadFromStream(RTFStream); delete RTFStream; clearHTMLTags(); } AnsiString TRxRichEditX::GetFormattedText(SWModule* module) { AnsiString rtfText = ""; VerseKey key; int lastChap, lastBook; AnsiString bookName; key = (VerseKey)module->Key(); lastChap = key.Chapter(); lastBook = key.Book(); bookName = (AnsiString)key.getText(); bookName = bookName.SubString(0,bookName.Pos(lastChap) - 2); if(dispAttribs.prBookHeadings) rtfText += BookHeading(module, bookName); if(dispAttribs.prChHeadings) rtfText += ChapterHeading(module, lastChap); for ((*module) = TOP; !module->Error(); (*module)++){ key = (VerseKey)module->Key(); if(key.Book() != lastBook){ rtfText += "\\par\\par"; bookName = (AnsiString)key.getText(); bookName = bookName.SubString(0,bookName.Pos(key.Chapter()) - 2); if(dispAttribs.prBookHeadings) rtfText += BookHeading(module, bookName); lastBook = key.Book(); lastChap = -1; // Reset the last Chapter since we could jump from Jude 1 to Revelation 1 } if(key.Chapter() != lastChap){ rtfText += "\\par"; if(dispAttribs.prChHeadings) rtfText += ChapterHeading(module, key.Chapter()); lastChap = key.Chapter(); } rtfText += PrintEntry(module, key.Verse()); } return rtfText; } AnsiString TRxRichEditX::PrintEntry(SWModule* module, int nVerse) { AnsiString rtfText = ""; if (module->Direction() == DIRECTION_RTL) { rtfText += "\\qr "; }else rtfText += "\\ql "; if (module->Direction() == DIRECTION_RTL && (platformID == WINNT && (!strnicmp(module->Lang(), "he", 2) || !strnicmp(module->Lang(), "fa", 2) || !strnicmp(module->Lang(), "ar", 2)))) { rtfText = rtfText + "\\rtlpar "; } if(!dispAttribs.paragraph) rtfText += "\\par"; if(dispAttribs.prPreFix) rtfText += PrintFix(module) + (AnsiString)" "; if(dispAttribs.prVerseNum){ rtfText += (AnsiString)"{\\fs" + (dispAttribs.vsNumFontSize * 2); if(dispAttribs.superVSNum) rtfText += "\\super "; else rtfText += " "; rtfText += IntToStr(nVerse); rtfText += " }"; } rtfText += (AnsiString)"{\\fs" + (dispAttribs.fontSize * 2) + (AnsiString)" "; rtfText += module->RenderText(); rtfText += " }"; if(dispAttribs.prPostFix) rtfText += (AnsiString)" " + PrintFix(module); return rtfText; } AnsiString TRxRichEditX::ChapterHeading(SWModule* module, int nChapter) { AnsiString rtfText = ""; rtfText += (AnsiString)" \\qc{\\f1\\cf7\\fs" + (dispAttribs.chFontHeadSize * 2) + (AnsiString)"\\b "; rtfText += _tr("Chapter"); rtfText += " "; rtfText += IntToStr(nChapter); rtfText += "\\par\\par}"; return rtfText; } AnsiString TRxRichEditX::BookHeading(SWModule* module, AnsiString name) { AnsiString rtfText = ""; rtfText += (AnsiString)" \\qc{\\f1\\cf7\\fs" + (dispAttribs.chFontHeadSize * 2) + (AnsiString)"\\b\\ul "; rtfText += name; rtfText += "\\par\\par}"; return rtfText; } AnsiString TRxRichEditX::PrintFix(SWModule* module) { AnsiString rtfText = ""; rtfText += (AnsiString)"{\\fs" + (dispAttribs.vsNumFontSize * 2); rtfText += (AnsiString)"(" + (AnsiString)module->KeyText() + (AnsiString)" " + (AnsiString)module->Name() + (AnsiString)")}"; return rtfText; } int TRxRichEditX::paintTo(HDC hdc, TRect *size, int margin) { TFormatRange Range; int LastChar, MaxLen, LogX, LogY, OldMap; TRect SaveRect; TGetTextLengthEx TextLenEx; bool calcBestSize = (size) ? IsRectEmpty(size): true; TRect trySizeRect[] = { TRect(0, 0, 200, 50), TRect(0, 0, 200, 100), TRect(0, 0, 250, 100), TRect(0, 0, 300, 50), TRect(0, 0, 300, 100), TRect(0, 0, 350, 100), TRect(0, 0, 400, 50), TRect(0, 0, 400, 100), TRect(0, 0, 400, 150), TRect(0, 0, 400, 200), TRect(0, 0, 500, 100), TRect(0, 0, 500, 150), TRect(0, 0, 500, 200), TRect(0, 0, 500, 250), TRect(0, 0, 550, 300), TRect(0, 0, 550, 350), TRect(0, 0, 0, 0) }; int trySize = 0; TRect *dispSize = size; LogX = GetDeviceCaps(hdc, LOGPIXELSX); LogY = GetDeviceCaps(hdc, LOGPIXELSY); do { if (calcBestSize) { dispSize = &trySizeRect[trySize++]; if (IsRectEmpty(dispSize)) { dispSize = &trySizeRect[trySize-2]; break; } } memset(&Range, 0, sizeof(TFormatRange)); // with Printer, Range do begin Range.hdc = hdc; Range.hdcTarget = Range.hdc; // if (IsRectEmpty(&PageRect)) { // Range.rc.right = dispSize->Right * 1440 / LogX; // Range.rc.bottom = dispSize->Bottom * 1440 / LogY; // } // else { Range.rc.left = (dispSize->Left + margin) * 1440 / LogX; Range.rc.top = (dispSize->Top + margin) * 1440 / LogY; Range.rc.right = dispSize->Right * 1440 / LogX; Range.rc.bottom = (dispSize->Bottom)* 1440 / LogY; // } Range.rcPage = Range.rc; SaveRect = Range.rc; // Range.rcPage.top = Range.rcPage.top + (5 * 1440) / LogY; // Range.rcPage.bottom = Range.rcPage.bottom + (5 * 1440) / LogY; LastChar = 0; if (RichEditVersion >= 2) { // with TextLenEx do begin TextLenEx.flags = GTL_DEFAULT; TextLenEx.codepage = CP_ACP; MaxLen = Perform(EM_GETTEXTLENGTHEX, (WPARAM)&TextLenEx, 0); } else MaxLen = GetTextLen(); Range.chrg.cpMax = -1; // { ensure printer DC is in text map mode } OldMap = SetMapMode(hdc, MM_TEXT); SendMessage(Handle, EM_FORMATRANGE, 0, 0); // { flush buffer } try { Range.rc = SaveRect; Range.chrg.cpMin = LastChar; LastChar = SendMessage(Handle, EM_FORMATRANGE, 1, Longint(&Range)); // if ((LastChar < MaxLen) && (LastChar != -1)) ;//NewPage(); // } while ((LastChar >= MaxLen) || (LastChar = -1)); } __finally { SendMessage(Handle, EM_FORMATRANGE, 0, 0);// { flush buffer } SetMapMode(hdc, OldMap); // { restore previous map mode } } LastChar = (LastChar < 0) ? 0: MaxLen - LastChar; LastChar = (LastChar < 0) ? 0: LastChar; } while (LastChar && calcBestSize); if (calcBestSize && size) *size = *dispSize; return LastChar; } void TRxRichEditX::fillWithRTFString(SWModule *module, const char *text, const char *type) { TMemoryStream *RTFStream = new TMemoryStream(); System::AnsiString newtext, tmptext; this->module = module; this->type = type; recalcAppearance(); newtext = RTFHeader; newtext += RTFHeadMargin; newtext += "\\pard \\nowidctlpar \\cf7\\f0 "; newtext += "{"; tmptext = ""; for (const char *loop = text; *loop; loop++) { if (*loop == '\n') { tmptext += "\\par "; } else tmptext += *loop; } newtext += RTFVersePre + tmptext + RTFVersePost; newtext += "}"; newtext += RTFTrailer; RTFStream->Clear(); RTFStream->WriteBuffer(newtext.c_str(), newtext.Length()); RTFStream->Position = 0; Lines->LoadFromStream(RTFStream); Repaint(); delete RTFStream; makeLinks(); } bool TRxRichEditX::fillWithVerses(SWModule *module, ListKey *verses, const char *introText, bool heading, bool verseNum, const char *type, bool stripNewlines) { SWBuf fontname; TMemoryStream *RTFStream = new TMemoryStream(); System::AnsiString newtext, tmptext; static UnicodeRTF filter; SWBuf buf; bool atLeastOneEntry = false; this->module = module; this->type = type; recalcAppearance(); newtext = RTFHeader; newtext += RTFHeadMargin; // newtext += "\\pard\\nowidctlpar\\cf7\\f0 "; if (module->Direction() == DIRECTION_RTL) { newtext += "\\qr "; } if (module->Direction() == DIRECTION_RTL && (platformID == WINNT && (!strnicmp(module->Lang(), "he", 2) || !strnicmp(module->Lang(), "fa", 2) || !strnicmp(module->Lang(), "ar", 2)))) { newtext += "\\rtlpar "; } verses->Persist(1); (*verses) = TOP; SWKey *saveKey = (SWKey *)(*module); SWKey origKeyValue = *saveKey; if (!saveKey->Persist()) saveKey = 0; module->setKey(verses); if (introText) { newtext += RTFHeadingPre; newtext += introText; newtext += RTFHeadingPost; newtext += "{\\par ________ \\par\\par}"; } SWKey *lastKey = 0; bool first = true; SWKey *testKey = module->CreateKey(); while (verses->Count() && !module->Error() && newtext.Length() < 40000 ) { if (heading) { if (SWDYNAMIC_CAST(VerseKey, testKey)) { if (lastKey != verses->GetElement()) { if (!first) newtext += "{\\par\\par}"; newtext += RTFHeadingPre; buf = verses->GetElement()->getRangeText(); filter.processText(buf, *module, module); newtext += buf.c_str(); newtext += ":"; newtext += RTFHeadingPost; newtext += "{\\par}"; } } else { char *buf2 = 0; stdstr(&buf2, (const char *)*verses, 2); toupperstr_utf8(buf2, strlen(buf2)*2); module->getRawEntry(); char *buf3 = 0; stdstr(&buf3, (const char *)module->KeyText(), 2); toupperstr_utf8(buf3, strlen(buf3)*2); int i; char *start1 = buf3; char *start2 = buf2; int len = strlen(buf3); for (i = 0; i < len; i++) { if (*start1 == '0') { start1++; } if (*start2 == '0') { start2++; } if ((start1[0] != '0') && (start2[0] != '0')) // if ((buf[i] == buf2[i]) || (buf[i] != '0')) break; } for (i = 0; i < strlen(start1) && (i < strlen(start2)); i++) { if ((start1[i] != start2[i]) && (SW_toupper(start1[i]) != SW_toupper(start2[i]))) break; } if (!i || i < (strlen(start1)/2)) { delete [] buf2; delete [] buf3; verses->Remove(); continue; } delete [] buf2; delete [] buf3; if (!first) newtext += "{\\par\\par}"; newtext += RTFHeadingPre; buf = module->KeyText(); // VerseKey locales are not yet UTF8, so don't try to convert them. // if (!SWDYNAMIC_CAST(VerseKey, testKey)) filter.processText(buf, *module, module); newtext = newtext + RTFHeadingPre + buf.c_str() + RTFHeadingPost + ":\\par "; newtext += RTFHeadingPost; newtext += "{\\par}"; atLeastOneEntry = true; } // newtext += RTFHeadingPost; } else { // hack to make searchlist entries fit in box better newtext += ""; } lastKey = verses->GetElement(); first = false; newtext = newtext + "{"; tmptext = ""; // When stripNewlines == true, replace multiple sequences of "newlines" with a single space boolean handleNL = true; for (const char *loop = module->RenderText(); *loop; loop++) { if (stripNewlines) { if (!strnicmp(loop, "\\par", 4)) { loop += (loop[4] == 'd') ? 4 : 3; if (handleNL) tmptext += " "; handleNL = false; } else if (*loop == '\n') { if (handleNL) tmptext += " "; handleNL = false; } else { tmptext += *loop; handleNL = true; } } else if (*loop == '\n') { tmptext += "{\\par}"; } else tmptext += *loop; } if (tmptext.Length() > 3) { // make sure we have an entry if (module->Direction() == DIRECTION_RTL && (SWDispRTFChap::platformID == WIN9X || (module->Lang() && strnicmp(module->Lang(), "he", 2) && strnicmp(module->Lang(), "fa", 2) && strnicmp(module->Lang(), "ar", 2)))) { newtext = newtext + RTFVersePre + tmptext + RTFVersePost; if (verseNum) newtext = newtext + RTFVerseMarkPre + IntToStr(VerseKey(module->KeyText()).Verse()) + RTFVerseMarkPost; newtext = newtext + "{\\par}"; } else { if (verseNum) newtext = newtext + RTFVerseMarkPre + IntToStr(VerseKey(module->KeyText()).Verse()) + RTFVerseMarkPost; newtext = newtext + RTFVersePre + tmptext + RTFVersePost; } } newtext = newtext + "}"; (*module)++; } delete testKey; if (saveKey) module->setKey(saveKey); else module->setKey(origKeyValue); //remove our persist key newtext += RTFTrailer; RTFStream->Clear(); RTFStream->WriteBuffer(newtext.c_str(), newtext.Length()); RTFStream->Position = 0; Lines->LoadFromStream(RTFStream); makeLinks(); makeImages(); if (Visible) { TComponent *owner = this->Owner; TForm *parentForm = dynamic_cast(owner); TWinControl *focus = 0; if (parentForm) focus = parentForm->ActiveControl; this->SetFocus(); SelStart = 0; SelLength = 0; SendMessage(Handle, EM_SCROLLCARET, 0, 0); if (focus) focus->SetFocus(); } Repaint(); delete RTFStream; return atLeastOneEntry; } void TRxRichEditX::getDisplayPrefs(DISP_ATTRIBS *attribs, SWModule *module ) { AnsiString fontSize; SWBuf keyFontName, keyFontSize; ConfigEntMap::const_iterator eit; SWBuf modType = (SWBuf)getType().c_str(); // If we are printing to a page rather than the screen we want to grab the // correct settings from that section of the conf file. SWBuf dispType = (type == "PrintedPage") ? "PrintedPage" : "Appearance"; //**** Font Name ****// // If the module uses it's own font load that else we will try the config file // else we will use the default while (true) { if (module) { eit = module->getConfig().find("Font"); if (eit != module->getConfig().end()) { attribs->fontName = (*eit).second.c_str(); break; } } keyFontName = modType + "FontName"; attribs->fontName = (AnsiString)Form1->optionsconf->Sections[dispType][keyFontName].c_str(); break; } // If we still have no name we will set it to a default value if (attribs->fontName == "") attribs->fontName = "Times New Roman"; //**** Font Size ****// // If the module uses it's own font size load that else we will try the config // file else we will use the default while (true) { if (module) { eit = module->getConfig().find("FontSize"); if (eit != module->getConfig().end()) { fontSize = (*eit).second.c_str(); break; } } keyFontSize = modType + "FontSize"; fontSize = (AnsiString)Form1->optionsconf->Sections[dispType][keyFontSize].c_str(); break; } // If we still have no size we will set it to a default value if (fontSize == "") attribs->fontSize = 10; else attribs->fontSize = StrToInt(fontSize); //**** Chapter Heading Font Size ****// fontSize = ""; while (true) { if (module) { eit = module->getConfig().find("ChHeadSize"); if (eit != module->getConfig().end()) { fontSize = (*eit).second.c_str(); break; } } keyFontSize = modType + "ChHeadSize"; fontSize = (AnsiString)Form1->optionsconf->Sections[dispType][keyFontSize].c_str(); break; } // If we still have no size we will set it to a default value if (fontSize == "") attribs->chFontHeadSize = 16; else attribs->chFontHeadSize = StrToInt(fontSize); //**** Verse Numbering Font Size ****// fontSize = ""; while (true) { if (module) { eit = module->getConfig().find("VSNumSize"); if (eit != module->getConfig().end()) { fontSize = (*eit).second.c_str(); break; } } keyFontSize = modType + "VSNumSize"; fontSize = (AnsiString)Form1->optionsconf->Sections[dispType][keyFontSize].c_str(); break; } // If we still have no size we will set it to a default value if (fontSize == "") attribs->vsNumFontSize = 10; else attribs->vsNumFontSize = StrToInt(fontSize); //**** Main Background Color ****// SWBuf keyBackColor = modType + "BackColor"; SWBuf backColor = Form1->optionsconf->Sections[dispType][keyBackColor]; // This portion of the code sets the default values (If needed) of the background // for either typical windows or for popup windows if (backColor == "") { if (modType == "Popup") { attribs->backColor = 14680063; } else attribs->backColor = clWindow; } else attribs->backColor = StrToInt((AnsiString)backColor.c_str()); //**** Main Font Color ****// SWBuf keyFontColor = modType + "FontColor"; SWBuf fontColor = Form1->optionsconf->Sections[dispType][keyFontColor]; // This portion of the code sets the default values (If needed) of the background // for either typical windows or for popup windows if (backColor == "") { attribs->fontColor = clBlack; } else attribs->fontColor = StrToInt((AnsiString)fontColor.c_str()); //**** EntryKey Color ****// SWBuf entryColor = Form1->optionsconf->Sections[dispType]["VSNumberColor"]; if (entryColor == "") attribs->entryKeyColor = clBlue; else attribs->entryKeyColor = StrToInt((AnsiString)entryColor.c_str()); //**** Current Verse Color ****// SWBuf currentVSColor = Form1->optionsconf->Sections[dispType]["CurrentVSColor"]; if (currentVSColor == "") attribs->currentVSColor = clBlue; else attribs->currentVSColor = StrToInt((AnsiString)currentVSColor.c_str()); //**** Morphological Numbers Color ****// SWBuf morphColor = Form1->optionsconf->Sections[dispType]["MorphColor"]; if (morphColor == "") attribs->morphColor = clBlue; else attribs->morphColor = StrToInt((AnsiString)morphColor.c_str()); //**** Strongs Numbers Color ****// SWBuf strongColor = Form1->optionsconf->Sections[dispType]["StrongsColor"]; if (strongColor == "") attribs->strongsColor = clBlue; else attribs->strongsColor = StrToInt((AnsiString)strongColor.c_str()); //**** Field Lookup Color ****// SWBuf fieldColor = Form1->optionsconf->Sections[dispType]["FieldColor"]; if (fieldColor == "") attribs->lookupFieldColor = clBlue; else attribs->lookupFieldColor = StrToInt((AnsiString)fieldColor.c_str()); //**** Mark Current Verse? ****// SWBuf autoVSColor = Form1->optionsconf->Sections[dispType]["AutoVSColor"]; if (autoVSColor == "") attribs->markCurrentVerse = true; else attribs->markCurrentVerse = (atoi(autoVSColor.c_str())) ? true : false; //**** Mark Current Verse? ****// SWBuf verseNewLine = Form1->optionsconf->Sections[dispType]["VerseNewLine"]; if (verseNewLine == "") attribs->verseNewLine = false; else attribs->verseNewLine = (atoi(verseNewLine.c_str())) ? true : false; //**** Print Chapter Headings? ****// SWBuf prChHeadings = Form1->optionsconf->Sections[dispType][(modType + "ChHead")]; if (prChHeadings == "") attribs->prChHeadings = true; else attribs->prChHeadings = (atoi(prChHeadings.c_str())) ? true : false; //**** Print Book Name? ****// SWBuf prBookHeadings = Form1->optionsconf->Sections[dispType][(modType +"BkName")]; if (prBookHeadings == "") attribs->prBookHeadings = true; else attribs->prBookHeadings = (atoi(prBookHeadings.c_str())) ? true : false; //**** Prefix Each Verse? ****// SWBuf prPreFix = Form1->optionsconf->Sections[dispType][(modType +"PreFixTag")]; if (prPreFix == "") attribs->prPreFix = true; else attribs->prPreFix = (atoi(prPreFix.c_str())) ? true : false; //**** Postfix Each Verse? ****// SWBuf prPostFix = Form1->optionsconf->Sections[dispType][(modType +"PostFixTag")]; if (prPostFix == "") attribs->prPostFix = true; else attribs->prPostFix = (atoi(prPostFix.c_str())) ? true : false; //**** Print the verse number? ****// SWBuf prVerseNum = Form1->optionsconf->Sections[dispType][(modType + "VSNum")]; if (prVerseNum == "") attribs->prVerseNum = true; else attribs->prVerseNum = (atoi(prVerseNum.c_str())) ? true : false; //**** Superscript the verse number? ****// SWBuf superVSNum = Form1->optionsconf->Sections[dispType][(modType + "SuperVS")]; if (superVSNum == "") attribs->superVSNum = true; else attribs->superVSNum = (atoi(superVSNum.c_str())) ? true : false; //**** Print as a paragraph? ****// SWBuf paragraph = Form1->optionsconf->Sections[dispType][(modType + "Paragraph")]; if (paragraph == "") attribs->paragraph = true; else attribs->paragraph = (atoi(paragraph.c_str())) ? true : false; } void TRxRichEditX::recalcAppearance() { static UnicodeRTF filter; char buf[4096]; getDisplayPrefs(&dispAttribs, module /*, type.c_str()*/); Color = dispAttribs.backColor; Font->Name = dispAttribs.fontName; Font->Size = dispAttribs.fontSize; RTFHeadMargin = "{\\cf1\\pard}"; RTFVerseMarkPost = "}"; RTFVersePost = " }"; buildRTFHeader(); // build headers with proportional font sizes to single user selected // font size. double fontBase = dispAttribs.fontSize; fontBase /= 4.0; sprintf(buf, "{\\fs%d \\par }}", (int)(fontBase * 8)); RTFTrailer = buf; SWBuf chapBuf; chapBuf = WideStringToUTF8(_tr("Chapter")).c_str(); // chapBuf = _tr("Chapter"); filter.processText(chapBuf); sprintf(buf, "\\pard \\qc\\nowidctlpar{\\f1\\cf7\\fs%d\\b %s ", (int)(fontBase * 10), chapBuf.c_str()); RTFChapterMarkPre = buf; sprintf(buf, "\\par\\fs%d\\par}", (int)(fontBase * 4)); RTFChapterMarkPost = buf; sprintf(buf, "{\\fs%d\\cf1\\b ", (int)(fontBase * 7)); RTFHeadingPre = buf; RTFHeadingPost = "}"; sprintf(buf, "{\\fs%d\\cf1\\super ", (int)(fontBase * 7)); RTFVerseMarkPre = buf; sprintf(buf, "{\\fs%d\\cf7 ", (int)(fontBase * 8)); RTFVersePre = buf; } void TRxRichEditX::TColorToRGB(const TColor& color, int& red, int& green, int& blue) { red = (color & 0xFF); green = ((color >> 8) & 0xFF); blue =((color >> 16) & 0xFF); } void TRxRichEditX::buildRTFHeader() { char buf1[1024], buf2[1024]; SectionMap::iterator sit; SWBuf value; ConfigEntMap::iterator entry; SWBuf tmpval; int CurrVSRed, CurrVSGreen, CurrVSBlue, BodyRed, BodyGreen, BodyBlue, VSNumRed, VSNumGreen, VSNumBlue, MorphRed, MorphGreen, MorphBlue, StrongsRed, StrongsGreen, StrongsBlue; TColor CurrVSColor, VSNumColor, BodyColor, MorphColor, StrongsColor; sprintf(buf1, "{\\rtf1\\ansi"); if (dispAttribs.fontName.Length()) { // Font Table // 0: Text Body sprintf(buf2, "{\\fonttbl{\\f0\\fdecor\\fprq2 %s;}" , dispAttribs.fontName.c_str()); strcat(buf1, buf2); // 1: Chapter Heading sprintf(buf2, "{\\f1\\froman\\fcharset0\\fprq2 %s;}", dispAttribs.fontName.c_str()); strcat(buf1, buf2); // 2: Unknown sprintf(buf2, "{\\f2\\froman\\fcharset0\\fprq2 %s;}", dispAttribs.fontName.c_str()); strcat(buf1, buf2); // 3: Unknown sprintf(buf2, "{\\f3\\froman\\fcharset0\\fprq2 %s;}", dispAttribs.fontName.c_str()); strcat(buf1, buf2); // 4: Unknown sprintf(buf2, "{\\f4\\froman\\fcharset0\\fprq2 %s;}", dispAttribs.fontName.c_str()); strcat(buf1, buf2); // 7, 8: Unknown strcat(buf1, "{\\f7\\froman\\fcharset2\\fprq2 Symbol;}{\\f8\\froman\\fcharset2\\fprq2 Courier;}}"); } else { sprintf(buf2, "{\\fonttbl{\\f0\\fdecor\\fprq2 Times New Roman;}{\\f1\\froman\\fcharset0\\fprq2 Times New Roman;}{\\f7\\froman\\fcharset2\\fprq2 Symbol;}{\\f8\\froman\\fcharset2\\fprq2 Courier;}}"); strcat(buf1, buf2); } TColorToRGB(dispAttribs.currentVSColor, CurrVSRed, CurrVSGreen, CurrVSBlue); TColorToRGB(dispAttribs.entryKeyColor, VSNumRed, VSNumGreen, VSNumBlue); TColorToRGB(dispAttribs.strongsColor, StrongsRed, StrongsGreen, StrongsBlue); TColorToRGB(dispAttribs.morphColor, MorphRed, MorphGreen, MorphBlue); TColorToRGB(dispAttribs.fontColor, BodyRed, BodyGreen, BodyBlue); // Color Table: // 1: Verse Number/ Verse info sprintf(buf2, "{\\colortbl;\\red%d\\green%d\\blue%d;" , VSNumRed, VSNumGreen, VSNumBlue); strcat(buf1, buf2); // 2: Current Verse Color sprintf(buf2, "\\red%d\\green%d\\blue%d;", CurrVSRed, CurrVSGreen, CurrVSBlue); strcat(buf1, buf2); // 3: Strong's Def sprintf(buf2, "\\red%d\\green%d\\blue%d;", StrongsRed, StrongsGreen, StrongsBlue); strcat(buf1, buf2); // 4: Strongs' Tense (Morph) sprintf(buf2, "\\red%d\\green%d\\blue%d;", MorphRed, MorphGreen, MorphBlue); strcat(buf1, buf2); // 5: Unknown strcat(buf1, "\\red0\\green0\\blue255;"); // 6: Unknown strcat(buf1, "\\red255\\green0\\blue0;"); // 7: Verse/Body Text Color sprintf(buf2, "\\red%d\\green%d\\blue%d;}",BodyRed, BodyGreen, BodyBlue); strcat(buf1, buf2); /* } else { sprintf(buf2, "{\\colortbl;\\red0\\green0\\blue255;\\red0\\green200\\blue50;\\red0\\green0\\blue255;\\red0\\green200\\blue50;\\red0\\green0\\blue255;\\red255\\green0\\blue0;\\red0\\green\\blue0;\\red0\\green\\blue0;\\red0\\green\\blue0;}"); strcat(buf1, buf2); } */ RTFHeader = buf1; } AnsiString TRxRichEditX::getType() { AnsiString retVal = "Default"; if (!strcmp(type.c_str(), "Default")) { if (module) { if (!strcmp(module->Type(), "Biblical Texts")) retVal = "Text"; else if ((!strcmp(module->Type(), "Commentaries")) || (!strcmp(module->Type(), "Generic Books"))) retVal = "Comment"; else if (!strcmp(module->Type(), "Lexicons / Dictionaries")) retVal = "LD"; } } else if(!strcmp(type.c_str(), "PrintedPage")){ if(PrintForm->radText->Checked) retVal = "Text"; else if(PrintForm->radComm->Checked) retVal = "Comment"; else if(PrintForm->radLD->Checked) retVal = "LD"; }else retVal = type; return retVal; } long __fastcall TRxRichEditX::TextLen() { long MaxLen; if (RichEditVersion >= 2) { TGetTextLengthEx TextLenEx; // with TextLenEx do begin TextLenEx.flags = GTL_DEFAULT; TextLenEx.codepage = 1200; MaxLen = Perform(EM_GETTEXTLENGTHEX, (WPARAM)&TextLenEx, 0); } else MaxLen = GetTextLen(); return MaxLen; } WideString __fastcall TRxRichEditX::GetText() { long MaxLen = TextLen(); wchar_t *buf = new wchar_t [ MaxLen + 2 ]; GETTEXTEX params; params.cb = (MaxLen + 1) * sizeof(wchar_t); params.flags = GT_DEFAULT; params.codepage = 1200; //CP_ACP; params.lpDefaultChar = 0; params.lpUsedDefChar = 0; LONG lResult; lResult = SendMessage(Handle, EM_GETTEXTEX, (WPARAM)¶ms, (LPARAM)buf); WideString Result = buf; delete [] buf; return Result; } WideString __fastcall TRxRichEditX::GetTextRange(int StartPos, int EndPos) { WideString Result = GetText(); Result = Result.SubString(StartPos+1, (EndPos - StartPos)); return Result; } WideString TRxRichEditX::Trim(WideString &src) { WideString Result = src; int length = Result.Length(); int start = 1; while (length) { if (Result[length] != ' ') break; Result.SetLength(--length); } while (start < length) { if (Result[start] != ' ') break; start++; } if (start > 1) Result = Result.SubString(start, (length - start)+1); return Result; } WideString __fastcall TRxRichEditX::WordAtCursor(void) { TCharRange Range, resultRange; WideString TestStr = ""; WideString retVal = ""; if (HandleAllocated()) { long max = TextLen() - 1; bool pre = true; for (int i = 0; (SelStart + i) < max; i++) { Range.cpMax = SelStart + i; if (!Range.cpMax) Range.cpMin = 0; else if (SendMessage(Handle, EM_FINDWORDBREAK, WB_ISDELIMITER, Range.cpMax)) Range.cpMin = SendMessage(Handle, EM_FINDWORDBREAK, WB_MOVEWORDLEFT, Range.cpMax); else Range.cpMin = SendMessage(Handle, EM_FINDWORDBREAK, WB_LEFT, Range.cpMax); while (SendMessage(Handle, EM_FINDWORDBREAK, WB_ISDELIMITER, Range.cpMin)) Range.cpMin++; Range.cpMax = SendMessage(Handle, EM_FINDWORDBREAK, WB_RIGHTBREAK, Range.cpMax); TestStr = Trim(GetTextRange(Range.cpMin, Range.cpMax)); if (pre) { resultRange = Range; } else { resultRange.cpMax = Range.cpMax; } if (Range.cpMin > 1) Range.cpMin--; TestStr = Trim(GetTextRange(Range.cpMin, Range.cpMax)); int testlen = TestStr.Length(); if (!testlen) continue; if ((pre) && (TestStr[1] == '-') && (Range.cpMin > 1)) { if (testlen > 1) { if ((isdigit(TestStr[2])) || (toupper(TestStr[2]) == TestStr[2])) { i = 0; SelStart = Range.cpMin-1; continue; } } } if ((TestStr[testlen] == '-') && (Range.cpMax < (max-1))) { if (testlen > 1) { if ((isdigit(TestStr[testlen-1])) || (toupper(TestStr[testlen-1]) == TestStr[testlen-1])) { i = 0; SelStart = Range.cpMax+1; pre = false; continue; } } } retVal = Trim(GetTextRange(resultRange.cpMin, resultRange.cpMax)); if (retVal.Length()) break; } } int start = 1; int end = retVal.Length(); if (end) { if (strchr(",", retVal[end])) end--; if (strchr(",", retVal[start])) start++; // see if we're a verse number if (isdigit(retVal[start]) && (end > 3)) { if (isalpha(retVal[start+3])) { start++; if (isdigit(retVal[start])) start++; if (isdigit(retVal[start])) start++; } } retVal = retVal.SubString(start, end-(start-1)); } return retVal; } void TRxRichEditX::makeLinks() { while (true) { int start, len, foundAt, endAt; start = (SelLength) ? SelStart + SelLength : 0; len = Text.Length() - start; foundAt = FindText("", start, len, TRichSearchTypes()); if (foundAt == -1) break; SelStart = foundAt; SelLength = 11; this->SelText = ""; endAt = FindText("", foundAt, len, TRichSearchTypes()); if (foundAt == -1) break; SelStart = endAt; SelLength = 4; this->SelText = ""; SelStart = foundAt; SelLength = endAt - foundAt; this->SelAttributes->Link = true; } } void TRxRichEditX::clearHTMLTags() { while (true) { int start, len, foundAt, endAt; start = (SelLength) ? SelStart + SelLength : 0; len = Text.Length() - start; foundAt = FindText("", start, len, TRichSearchTypes()); if (foundAt == -1) break; SelStart = foundAt; SelLength = 11; this->SelText = ""; endAt = FindText("", foundAt, len, TRichSearchTypes()); if (foundAt == -1) break; SelStart = endAt; SelLength = 4; this->SelText = ""; SelStart = foundAt; SelLength = endAt - foundAt; //this->SelAttributes->Link = true; } SelLength = 0; } void TRxRichEditX::makeImages() { while (true) { int start, len, foundAt, endAt; start = (SelLength) ? SelStart + SelLength : 0; len = Text.Length() - start; foundAt = FindText("
", foundAt, len, TRichSearchTypes()); if (foundAt == -1) break; SelStart = foundAt; SelLength = (endAt - foundAt)+4; XMLTag tag(this->SelText.c_str()); SelText = ""; insertImage(tag.getAttribute("src")); } } void TRxRichEditX::insertImage(const char *filePath) { /* //static char *tmp = "D:/Program Files/Borland/Borland Shared/Images/Buttons/alarm.bmp"; //filePath=tmp; TImage *image = new TImage(this); TJPEGImage *ji = new TJPEGImage(); Graphics::TBitmap *bitmap = new Graphics::TBitmap(); try { int len = strlen(filePath); if ((len > 4) && (!stricmp(filePath+(len-4), ".jpg"))) { // ji->LoadFromFile(filePath); TFileStream* imageFile; imageFile = new TFileStream(filePath,fmOpenRead|fmShareCompat); ji->LoadFromStream(imageFile); // load the jpeg from the disk file stream bitmap->Assign(ji); image->Picture->Assign(bitmap); delete imageFile; // image->Width = ji->Width; // image->Height = ji->Height; image->Canvas->Draw(0, 0, ji); // image->Picture->Bitmap->Assign(ji); } else image->Picture->LoadFromFile(filePath); insertRTF(bitmapToRTF(image->Picture->Bitmap)); } catch (...){} delete ji; delete image; delete bitmap; */ } // EditStreamInCallback callback function DWORD __stdcall editStreamInCallBack(unsigned long dwCookie, unsigned char *pbBuff, long cb, long *pcb) { unsigned long dataAvail; TStream *stream = (TStream *)dwCookie; dataAvail = stream->Size - stream->Position; unsigned long retVal = 0; if (dataAvail <= cb) { *pcb = stream->Read(pbBuff, dataAvail); if (*pcb != dataAvail) retVal = E_FAIL; } else { *pcb = stream->Read(pbBuff, cb); if (*pcb != cb) retVal = E_FAIL; } return retVal; } // Insert Stream into RichEdit void TRxRichEditX::insertRTF(const char *rtf) { TStringStream *ss = new TStringStream(rtf); try { EDITSTREAM editStream; editStream.dwCookie = (unsigned long)ss; editStream.dwError = 0; editStream.pfnCallback = editStreamInCallBack; Perform(EM_STREAMIN, SF_RTF | SFF_SELECTION, (int)&editStream); } catch (...) {} delete ss; } /* // Example to insert image from Image1 into RxRichEdit1 procedure TForm1.Button1Click(Sender: TObject); var SS: TStringStream; BMP: TBitmap; begin BMP := TBitmap.Create; BMP := Image1.Picture.Bitmap; SS := TStringStream.Create(BitmapToRTF(BMP)); try PutRTFSelection(RxRichEdit1, SS); finally SS.Free; end; end; */ // Convert Bitmap to RTF Code SWBuf TRxRichEditX::bitmapToRTF(Graphics::TBitmap *pict) { unsigned char *bi, *bb; SWBuf rtf; unsigned int bis, bbs; char achar[10]; char *hexpict; int i; GetDIBSizes(pict->Handle, bis, bbs); bi = new char [bis + 1]; bb = new char [bbs + 1]; GetDIB(pict->Handle, pict->Palette, bi, bb); rtf = "{\\rtf1 {\\pict\\dibitmap "; hexpict = new char[((bbs + bis) * 2)+1]; i = 0; for (int x = 0; x < bis; x++) { sprintf(achar, "%02x", (unsigned int)bi[x]); hexpict[i++] = achar[0]; hexpict[i++] = achar[1]; } for (int x = 0; x < bbs; x++) { sprintf(achar, "%02x", (unsigned int)bb[x]); hexpict[i++] = achar[0]; hexpict[i++] = achar[1]; } hexpict[i] = 0; rtf += hexpict; rtf += " }}"; delete [] bi; delete [] bb; delete [] hexpict; return rtf; } /* uses RichEdit; // Stream Callback function type TEditStreamCallBack = function(dwCookie: Longint; pbBuff: PByte; cb: Longint; var pcb: Longint): DWORD; stdcall; TEditStream = record dwCookie: Longint; dwError: Longint; pfnCallback: TEditStreamCallBack; end; // RichEdit Type type TMyRichEdit = TRxRichEdit; // EditStreamInCallback callback function function EditStreamInCallback(dwCookie: Longint; pbBuff: PByte; cb: Longint; var pcb: Longint): DWORD; stdcall; // by P. Below var theStream: TStream; dataAvail: LongInt; begin theStream := TStream(dwCookie); with theStream do begin dataAvail := Size - Position; Result := 0; if dataAvail <= cb then begin pcb := read(pbBuff^, dataAvail); if pcb <> dataAvail then Result := UINT(E_FAIL); end else begin pcb := read(pbBuff^, cb); if pcb <> cb then Result := UINT(E_FAIL); end; end; end; // Insert Stream into RichEdit procedure PutRTFSelection(RichEdit: TMyRichEdit; SourceStream: TStream); // by P. Below var EditStream: TEditStream; begin with EditStream do begin dwCookie := Longint(SourceStream); dwError := 0; pfnCallback := EditStreamInCallBack; end; RichEdit.Perform(EM_STREAMIN, SF_RTF or SFF_SELECTION, Longint(@EditStream)); end; // Convert Bitmap to RTF Code function BitmapToRTF(pict: TBitmap): string; // by D3k var bi, bb, rtf: string; bis, bbs: Cardinal; achar: ShortString; hexpict: string; I: Integer; begin GetDIBSizes(pict.Handle, bis, bbs); SetLength(bi, bis); SetLength(bb, bbs); GetDIB(pict.Handle, pict.Palette, PChar(bi)^, PChar(bb)^); rtf := '{\rtf1 {\pict\dibitmap '; SetLength(hexpict, (Length(bb) + Length(bi)) * 2); I := 2; for bis := 1 to Length(bi) do begin achar := Format('%x', [Integer(bi[bis])]); if Length(achar) = 1 then achar := '0' + achar; hexpict[I - 1] := achar[1]; hexpict[I] := achar[2]; Inc(I, 2); end; for bbs := 1 to Length(bb) do begin achar := Format('%x', [Integer(bb[bbs])]); if Length(achar) = 1 then achar := '0' + achar; hexpict[I - 1] := achar[1]; hexpict[I] := achar[2]; Inc(I, 2); end; rtf := rtf + hexpict + ' }}'; Result := rtf; end; // Example to insert image from Image1 into RxRichEdit1 procedure TForm1.Button1Click(Sender: TObject); var SS: TStringStream; BMP: TBitmap; begin BMP := TBitmap.Create; BMP := Image1.Picture.Bitmap; SS := TStringStream.Create(BitmapToRTF(BMP)); try PutRTFSelection(RxRichEdit1, SS); finally SS.Free; end; end; */