00001
00007
00008
00009 #include "NMEMFC.h"
00010 #include "NMEStyleCpp.h"
00011
00013 #define isFirstUTF8Byte(c) \
00014 (((c) & 0x80) == 0 || ((c) & 0xe0) == 0xc0 || ((c) & 0xf0) == 0xe0)
00015
00020 static CString utf8ToCString(char const *utf8, int len = -1)
00021 {
00022 int i, j, wlen;
00023 WCHAR *wstr;
00024 CString s;
00025
00026
00027 if (len < 0)
00028 for (len = 0; utf8[len]; len++)
00029 ;
00030
00031
00032 for (i = wlen = 0; i < len; i++)
00033 if (isFirstUTF8Byte(utf8[i]))
00034 wlen++;
00035
00036
00037 wstr = (WCHAR *)malloc((len + 1) * sizeof(WCHAR));
00038
00039
00040 for (i = j = 0; j < len; i++)
00041 {
00042 if ((utf8[j] & 0x80) == 0)
00043 wstr[i] = (WCHAR)utf8[j++];
00044 else if (j + 1 < len
00045 && (utf8[j] & 0xe0) == 0xc0 && (utf8[j + 1] & 0xc0) == 0x80)
00046 {
00047 wstr[i] = ((WCHAR)utf8[j++] & 0x1f) << 6;
00048 wstr[i] |= utf8[j++] & 0x3f;
00049 }
00050 else if (j + 2 < len
00051 && (utf8[j] & 0xf0) == 0xe0 && (utf8[j + 1] & 0xc0) == 0x80
00052 && (utf8[j + 2] & 0xc0) == 0x80)
00053 {
00054 wstr[i] = (WCHAR)utf8[j++] << 12;
00055 wstr[i] |= (utf8[j++] & 0x3f) << 6;
00056 wstr[i] |= utf8[j++] & 0x3f;
00057 }
00058 else
00059 {
00060 j++;
00061 i--;
00062 }
00063 }
00064 wstr[i] = 0;
00065
00066
00067 s = wstr;
00068
00069
00070 free((void *)wstr);
00071
00072 return s;
00073 }
00074
00081 static char *cStringToUtf8(WCHAR const *wstr, int len = -1)
00082 {
00083 int len8;
00084 int i, j;
00085 char *s;
00086
00087
00088 for (i = len8 = 0; len < 0 ? wstr[i] : i < len; i++)
00089 if (!(wstr[i] & 0xff80))
00090 len8++;
00091 else if (!(wstr[i] & 0xf800))
00092 len8 += 2;
00093 else
00094 len8 += 3;
00095
00096
00097 s = new char [len8 + 1];
00098 if (!s)
00099 return s;
00100
00101
00102 for (i = j = 0; len < 0 ? wstr[i] : i < len; i++)
00103 if (!(wstr[i] & 0xff80))
00104 s[j++] = (char)wstr[i];
00105 else if (!(wstr[i] & 0xf800))
00106 {
00107 s[j++] = 0xc0 | (wstr[i] >> 6);
00108 s[j++] = 0x80 | wstr[i] & 0x3f;
00109 }
00110 else
00111 {
00112 s[j++] = 0xe0 | (wstr[i] >> 12) & 0x0f;
00113 s[j++] = 0x80 | (wstr[i] >> 6) & 0x3f;
00114 s[j++] = 0x80 | wstr[i] & 0x3f;
00115 }
00116
00117
00118 s[j] = '\0';
00119 return s;
00120 }
00121
00122 void NMEMFCSetRichText(CRichEditCtrl &c,
00123 char const *input, int inputLength,
00124 bool replaceSel,
00125 CHARFORMAT const *plainTextCharFormat,
00126 bool links)
00127 {
00128
00129 NMEStyle nme(input, inputLength);
00130 NMEOutputFormat f = NMEOutputFormatBasicText;
00131 f.parHookFun = NMEStyleSpanHook;
00132 if (links)
00133 f.sepLink = "|";
00134 nme.setFormat(f);
00135 #if defined(_UNICODE)
00136 nme.setUnicodeStyleOffsets(TRUE);
00137 #endif
00138 NMEConstText output;
00139 NMEInt outputLength;
00140 if (nme.getOutput(&output, &outputLength) != kNMEErrOk)
00141 return;
00142 NMEStyleTable const *styleTable = nme.getStyleTable();
00143
00144
00145 long offset = 0;
00146 long length = outputLength;
00147 #if defined(_UNICODE)
00148 CString str = utf8ToCString(output, outputLength);
00149 length = str.GetLength();
00150 if (replaceSel)
00151 {
00152 long endSel;
00153
00154 c.GetSel(offset, endSel);
00155 c.ReplaceSel(str);
00156 }
00157 else
00158 c.SetWindowText(str);
00159 #else
00160 length = outputLength;
00161 if (replaceSel)
00162 {
00163 long endSel;
00164
00165 c.GetSel(offset, endSel);
00166 c.ReplaceSel(CString(output, outputLength));
00167 }
00168 else
00169 c.SetWindowText(CString(output, outputLength));
00170 #endif
00171
00172
00173 CHARFORMAT cf;
00174 PARAFORMAT pf;
00175 if (plainTextCharFormat)
00176 cf = *plainTextCharFormat;
00177 else
00178 c.GetDefaultCharFormat(cf);
00179 c.SetSel(offset, offset + length);
00180 c.SetSelectionCharFormat(cf);
00181 cf.cbSize = sizeof(cf);
00182 pf.cbSize = sizeof(pf);
00183 for (int i = 0; i < styleTable->n; i++)
00184 {
00185 cf.dwMask = 0;
00186 pf.dwMask = 0;
00187 switch (styleTable->span[i].style)
00188 {
00189 case kNMEStyleCharBold:
00190 case kNMEStyleCharDT:
00191 case kNMEStyleCharTH:
00192 cf.dwMask = CFM_BOLD;
00193 cf.dwEffects = CFE_BOLD;
00194 break;
00195 case kNMEStyleCharItalic:
00196 cf.dwMask = CFM_ITALIC;
00197 cf.dwEffects = CFE_ITALIC;
00198 break;
00199 case kNMEStyleCharUnderline:
00200 cf.dwMask = CFM_UNDERLINE;
00201 cf.dwEffects = CFE_UNDERLINE;
00202 break;
00203 case kNMEStyleCharSuperscript:
00204 cf.dwMask = CFM_OFFSET;
00205 cf.yOffset = 100;
00206 break;
00207 case kNMEStyleCharSubscript:
00208 cf.dwMask = CFM_OFFSET;
00209 cf.yOffset = -100;
00210 break;
00211 case kNMEStyleCharMonospace:
00212 cf.dwMask = CFM_FACE;
00213 strcpy(cf.szFaceName, "Courier");
00214 break;
00215 case kNMEStyleCharLink:
00216 if (links)
00217 {
00218
00219 CHARFORMAT2 c2;
00220 int j;
00221 #if defined(_UNICODE)
00222 for (j = 0; j < length && str.GetAt(styleTable->span[i].begin + j) != _T('|'); j++)
00223 ;
00224 #else
00225 for (j = 0; j < length && output[j] != '|'; j++)
00226 ;
00227 #endif
00228 if (j < length)
00229 j++;
00230 c2.cbSize = sizeof(c2);
00231 c2.dwMask = CFM_HIDDEN;
00232 c2.dwEffects = CFE_HIDDEN;
00233 c.SetSel(offset + styleTable->span[i].begin, offset + styleTable->span[i].begin + j);
00234 ::SendMessage(c.m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&c2);
00235 cf.dwMask = CFM_LINK;
00236 cf.dwEffects = CFE_LINK;
00237 c.SetSel(offset + styleTable->span[i].begin, offset + styleTable->span[i].end);
00238 c.SetSelectionCharFormat(cf);
00239 cf.dwMask = 0;
00240 }
00241 break;
00242 case kNMEStyleParPlain:
00243 pf.dwMask = PFM_OFFSETINDENT | PFM_OFFSET;
00244 pf.dxStartIndent = 300;
00245 pf.dxOffset = -300;
00246 break;
00247 case kNMEStyleParIndentedPar:
00248 pf.dwMask = PFM_OFFSETINDENT | PFM_OFFSET;
00249 pf.dxStartIndent = 600 * styleTable->span[i].level + 300;
00250 pf.dxOffset = -300;
00251 break;
00252 case kNMEStyleParHeading:
00253 cf.dwMask = CFM_SIZE;
00254 cf.yHeight = 20 * (20 - 2 * styleTable->span[i].level);
00255 if (styleTable->span[i].level == 1)
00256 {
00257 pf.dwMask = PFM_ALIGNMENT;
00258 pf.wAlignment = PFA_CENTER;
00259 }
00260 break;
00261 }
00262 if (cf.dwMask != 0 || pf.dwMask != 0)
00263 c.SetSel(offset + styleTable->span[i].begin, offset + styleTable->span[i].end);
00264 if (cf.dwMask != 0)
00265 c.SetSelectionCharFormat(cf);
00266 if (pf.dwMask != 0)
00267 c.SetParaFormat(pf);
00268 }
00269
00270 c.SetSel(0, 0);
00271 }
00272
00273 void NMEMFCSetRichText(CRichEditCtrl &c,
00274 WCHAR const *input, int inputLength,
00275 bool replaceSel,
00276 CHARFORMAT const *plainTextCharFormat,
00277 bool links)
00278 {
00279 char *str8 = cStringToUtf8(input, inputLength);
00280 NMEMFCSetRichText(c, str8, -1, replaceSel, plainTextCharFormat, links);
00281 delete [] str8;
00282 }
00283
00284 void NMEMFCEnLink(NMHDR const *pNMHDR, LRESULT *pResult,
00285 NMEMFCLinkFun linkFun, void *linkFunData)
00286 {
00287 ENLINK *event = (ENLINK *)pNMHDR;
00288 if (event->msg == WM_LBUTTONDOWN)
00289 {
00290
00291 TEXTRANGE range;
00292 range.chrg = event->chrg;
00293 range.lpstrText = new char[range.chrg.cpMax - range.chrg.cpMin + 1];
00294 ::SendMessage(pNMHDR->hwndFrom, EM_GETTEXTRANGE, 0 , (LPARAM)&range);
00295 CString s(range.lpstrText);
00296 if (s.Find('|') >= 0)
00297 s = s.Left(s.Find('|'));
00298 #if defined(_UNICODE)
00299 char *url = cStringToUtf8(s);
00300 #else
00301 char const *url = s;
00302 #endif
00303 if (url && linkFun)
00304 linkFun(url, linkFunData);
00305 #if defined(_UNICODE)
00306 if (url)
00307 delete [] url;
00308 #endif
00309 ShellExecute(NULL, _T("open"), s, NULL, NULL, SW_SHOWNORMAL);
00310 delete [] range.lpstrText;
00311 }
00312 *pResult = 0;
00313 }
00314
00315 void NMEMFCLinkFunURL(NMEConstText link, void *data)
00316 {
00317 ShellExecute(NULL, _T("open"), utf8ToCString(link), NULL, NULL, SW_RESTORE);
00318 }