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