1 // Copyright 2014 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7 #include "fpdfsdk/include/pdfwindow/PWL_Edit.h" 8 9 #include "core/include/fxcrt/fx_safe_types.h" 10 #include "core/include/fxcrt/fx_xml.h" 11 #include "fpdfsdk/include/pdfwindow/PWL_Caret.h" 12 #include "fpdfsdk/include/pdfwindow/PWL_EditCtrl.h" 13 #include "fpdfsdk/include/pdfwindow/PWL_FontMap.h" 14 #include "fpdfsdk/include/pdfwindow/PWL_ScrollBar.h" 15 #include "fpdfsdk/include/pdfwindow/PWL_Utils.h" 16 #include "fpdfsdk/include/pdfwindow/PWL_Wnd.h" 17 #include "public/fpdf_fwlevent.h" 18 19 CPWL_Edit::CPWL_Edit() 20 : m_pFillerNotify(NULL), m_pSpellCheck(NULL), m_bFocus(FALSE) { 21 m_pFormFiller = NULL; 22 } 23 24 CPWL_Edit::~CPWL_Edit() { 25 ASSERT(m_bFocus == FALSE); 26 } 27 28 CFX_ByteString CPWL_Edit::GetClassName() const { 29 return PWL_CLASSNAME_EDIT; 30 } 31 32 void CPWL_Edit::OnDestroy() {} 33 34 void CPWL_Edit::SetText(const FX_WCHAR* csText) { 35 CFX_WideString swText = csText; 36 37 if (HasFlag(PES_RICH)) { 38 CFX_ByteString sValue = CFX_ByteString::FromUnicode(swText); 39 40 if (CXML_Element* pXML = 41 CXML_Element::Parse(sValue.c_str(), sValue.GetLength())) { 42 int32_t nCount = pXML->CountChildren(); 43 FX_BOOL bFirst = TRUE; 44 45 swText.Empty(); 46 47 for (int32_t i = 0; i < nCount; i++) { 48 if (CXML_Element* pSubElement = pXML->GetElement(i)) { 49 CFX_ByteString tag = pSubElement->GetTagName(); 50 if (tag.EqualNoCase("p")) { 51 int nChild = pSubElement->CountChildren(); 52 CFX_WideString swSection; 53 for (int32_t j = 0; j < nChild; j++) { 54 swSection += pSubElement->GetContent(j); 55 } 56 57 if (bFirst) 58 bFirst = FALSE; 59 else 60 swText += FWL_VKEY_Return; 61 swText += swSection; 62 } 63 } 64 } 65 66 delete pXML; 67 } 68 } 69 70 m_pEdit->SetText(swText.c_str()); 71 } 72 73 void CPWL_Edit::RePosChildWnd() { 74 if (CPWL_ScrollBar* pVSB = GetVScrollBar()) { 75 CPDF_Rect rcWindow = m_rcOldWindow; 76 CPDF_Rect rcVScroll = 77 CPDF_Rect(rcWindow.right, rcWindow.bottom, 78 rcWindow.right + PWL_SCROLLBAR_WIDTH, rcWindow.top); 79 pVSB->Move(rcVScroll, TRUE, FALSE); 80 } 81 82 if (m_pEditCaret && !HasFlag(PES_TEXTOVERFLOW)) 83 m_pEditCaret->SetClipRect(CPWL_Utils::InflateRect( 84 GetClientRect(), 1.0f)); //+1 for caret beside border 85 86 CPWL_EditCtrl::RePosChildWnd(); 87 } 88 89 CPDF_Rect CPWL_Edit::GetClientRect() const { 90 CPDF_Rect rcClient = CPWL_Utils::DeflateRect( 91 GetWindowRect(), (FX_FLOAT)(GetBorderWidth() + GetInnerBorderWidth())); 92 93 if (CPWL_ScrollBar* pVSB = GetVScrollBar()) { 94 if (pVSB->IsVisible()) { 95 rcClient.right -= PWL_SCROLLBAR_WIDTH; 96 } 97 } 98 99 return rcClient; 100 } 101 102 void CPWL_Edit::SetAlignFormatH(PWL_EDIT_ALIGNFORMAT_H nFormat, 103 FX_BOOL bPaint) { 104 m_pEdit->SetAlignmentH((int32_t)nFormat, bPaint); 105 } 106 107 void CPWL_Edit::SetAlignFormatV(PWL_EDIT_ALIGNFORMAT_V nFormat, 108 FX_BOOL bPaint) { 109 m_pEdit->SetAlignmentV((int32_t)nFormat, bPaint); 110 } 111 112 FX_BOOL CPWL_Edit::CanSelectAll() const { 113 return GetSelectWordRange() != m_pEdit->GetWholeWordRange(); 114 } 115 116 FX_BOOL CPWL_Edit::CanClear() const { 117 return !IsReadOnly() && m_pEdit->IsSelected(); 118 } 119 120 FX_BOOL CPWL_Edit::CanCopy() const { 121 return !HasFlag(PES_PASSWORD) && !HasFlag(PES_NOREAD) && 122 m_pEdit->IsSelected(); 123 } 124 125 FX_BOOL CPWL_Edit::CanCut() const { 126 return CanCopy() && !IsReadOnly(); 127 } 128 129 FX_BOOL CPWL_Edit::CanPaste() const { 130 if (IsReadOnly()) 131 return FALSE; 132 133 CFX_WideString swClipboard; 134 if (IFX_SystemHandler* pSH = GetSystemHandler()) 135 swClipboard = pSH->GetClipboardText(GetAttachedHWnd()); 136 137 return !swClipboard.IsEmpty(); 138 } 139 140 void CPWL_Edit::CopyText() { 141 if (!CanCopy()) 142 return; 143 144 CFX_WideString str = m_pEdit->GetSelText(); 145 146 if (IFX_SystemHandler* pSH = GetSystemHandler()) 147 pSH->SetClipboardText(GetAttachedHWnd(), str); 148 } 149 150 void CPWL_Edit::PasteText() { 151 if (!CanPaste()) 152 return; 153 154 CFX_WideString swClipboard; 155 if (IFX_SystemHandler* pSH = GetSystemHandler()) 156 swClipboard = pSH->GetClipboardText(GetAttachedHWnd()); 157 158 if (m_pFillerNotify) { 159 FX_BOOL bRC = TRUE; 160 FX_BOOL bExit = FALSE; 161 CFX_WideString strChangeEx; 162 int nSelStart = 0; 163 int nSelEnd = 0; 164 GetSel(nSelStart, nSelEnd); 165 m_pFillerNotify->OnBeforeKeyStroke(GetAttachedData(), swClipboard, 166 strChangeEx, nSelStart, nSelEnd, TRUE, 167 bRC, bExit, 0); 168 if (!bRC) 169 return; 170 if (bExit) 171 return; 172 } 173 174 if (swClipboard.GetLength() > 0) { 175 Clear(); 176 InsertText(swClipboard.c_str()); 177 } 178 } 179 180 void CPWL_Edit::CutText() { 181 if (!CanCut()) 182 return; 183 184 CFX_WideString str = m_pEdit->GetSelText(); 185 186 if (IFX_SystemHandler* pSH = GetSystemHandler()) 187 pSH->SetClipboardText(GetAttachedHWnd(), str); 188 189 m_pEdit->Clear(); 190 } 191 192 void CPWL_Edit::OnCreated() { 193 CPWL_EditCtrl::OnCreated(); 194 195 if (CPWL_ScrollBar* pScroll = GetVScrollBar()) { 196 pScroll->RemoveFlag(PWS_AUTOTRANSPARENT); 197 pScroll->SetTransparency(255); 198 } 199 200 SetParamByFlag(); 201 202 m_rcOldWindow = GetWindowRect(); 203 204 m_pEdit->SetOprNotify(this); 205 m_pEdit->EnableOprNotify(TRUE); 206 } 207 208 void CPWL_Edit::SetParamByFlag() { 209 if (HasFlag(PES_RIGHT)) { 210 m_pEdit->SetAlignmentH(2, FALSE); 211 } else if (HasFlag(PES_MIDDLE)) { 212 m_pEdit->SetAlignmentH(1, FALSE); 213 } else { 214 m_pEdit->SetAlignmentH(0, FALSE); 215 } 216 217 if (HasFlag(PES_BOTTOM)) { 218 m_pEdit->SetAlignmentV(2, FALSE); 219 } else if (HasFlag(PES_CENTER)) { 220 m_pEdit->SetAlignmentV(1, FALSE); 221 } else { 222 m_pEdit->SetAlignmentV(0, FALSE); 223 } 224 225 if (HasFlag(PES_PASSWORD)) { 226 m_pEdit->SetPasswordChar('*', FALSE); 227 } 228 229 m_pEdit->SetMultiLine(HasFlag(PES_MULTILINE), FALSE); 230 m_pEdit->SetAutoReturn(HasFlag(PES_AUTORETURN), FALSE); 231 m_pEdit->SetAutoFontSize(HasFlag(PWS_AUTOFONTSIZE), FALSE); 232 m_pEdit->SetAutoScroll(HasFlag(PES_AUTOSCROLL), FALSE); 233 m_pEdit->EnableUndo(HasFlag(PES_UNDO)); 234 235 if (HasFlag(PES_TEXTOVERFLOW)) { 236 SetClipRect(CPDF_Rect(0.0f, 0.0f, 0.0f, 0.0f)); 237 m_pEdit->SetTextOverflow(TRUE, FALSE); 238 } else { 239 if (m_pEditCaret) { 240 m_pEditCaret->SetClipRect(CPWL_Utils::InflateRect( 241 GetClientRect(), 1.0f)); //+1 for caret beside border 242 } 243 } 244 245 if (HasFlag(PES_SPELLCHECK)) { 246 m_pSpellCheck = GetCreationParam().pSpellCheck; 247 } 248 } 249 250 void CPWL_Edit::GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) { 251 CPWL_Wnd::GetThisAppearanceStream(sAppStream); 252 253 CPDF_Rect rcClient = GetClientRect(); 254 CFX_ByteTextBuf sLine; 255 256 int32_t nCharArray = m_pEdit->GetCharArray(); 257 258 if (nCharArray > 0) { 259 switch (GetBorderStyle()) { 260 case PBS_SOLID: { 261 sLine << "q\n" << GetBorderWidth() << " w\n" 262 << CPWL_Utils::GetColorAppStream(GetBorderColor(), FALSE) 263 << " 2 J 0 j\n"; 264 265 for (int32_t i = 1; i < nCharArray; i++) { 266 sLine << rcClient.left + 267 ((rcClient.right - rcClient.left) / nCharArray) * i 268 << " " << rcClient.bottom << " m\n" 269 << rcClient.left + 270 ((rcClient.right - rcClient.left) / nCharArray) * i 271 << " " << rcClient.top << " l S\n"; 272 } 273 274 sLine << "Q\n"; 275 } break; 276 case PBS_DASH: { 277 sLine << "q\n" << GetBorderWidth() << " w\n" 278 << CPWL_Utils::GetColorAppStream(GetBorderColor(), FALSE) 279 << " 2 J 0 j\n" 280 << "[" << GetBorderDash().nDash << " " << GetBorderDash().nGap 281 << "] " << GetBorderDash().nPhase << " d\n"; 282 283 for (int32_t i = 1; i < nCharArray; i++) { 284 sLine << rcClient.left + 285 ((rcClient.right - rcClient.left) / nCharArray) * i 286 << " " << rcClient.bottom << " m\n" 287 << rcClient.left + 288 ((rcClient.right - rcClient.left) / nCharArray) * i 289 << " " << rcClient.top << " l S\n"; 290 } 291 292 sLine << "Q\n"; 293 } break; 294 } 295 } 296 297 sAppStream << sLine; 298 299 CFX_ByteTextBuf sText; 300 301 CPDF_Point ptOffset = CPDF_Point(0.0f, 0.0f); 302 303 CPVT_WordRange wrWhole = m_pEdit->GetWholeWordRange(); 304 CPVT_WordRange wrSelect = GetSelectWordRange(); 305 CPVT_WordRange wrVisible = 306 (HasFlag(PES_TEXTOVERFLOW) ? wrWhole : m_pEdit->GetVisibleWordRange()); 307 CPVT_WordRange wrSelBefore(wrWhole.BeginPos, wrSelect.BeginPos); 308 CPVT_WordRange wrSelAfter(wrSelect.EndPos, wrWhole.EndPos); 309 310 CPVT_WordRange wrTemp = 311 CPWL_Utils::OverlapWordRange(GetSelectWordRange(), wrVisible); 312 CFX_ByteString sEditSel = 313 CPWL_Utils::GetEditSelAppStream(m_pEdit, ptOffset, &wrTemp); 314 315 if (sEditSel.GetLength() > 0) 316 sText << CPWL_Utils::GetColorAppStream(PWL_DEFAULT_SELBACKCOLOR) 317 << sEditSel; 318 319 wrTemp = CPWL_Utils::OverlapWordRange(wrVisible, wrSelBefore); 320 CFX_ByteString sEditBefore = CPWL_Utils::GetEditAppStream( 321 m_pEdit, ptOffset, &wrTemp, !HasFlag(PES_CHARARRAY), 322 m_pEdit->GetPasswordChar()); 323 324 if (sEditBefore.GetLength() > 0) 325 sText << "BT\n" << CPWL_Utils::GetColorAppStream(GetTextColor()) 326 << sEditBefore << "ET\n"; 327 328 wrTemp = CPWL_Utils::OverlapWordRange(wrVisible, wrSelect); 329 CFX_ByteString sEditMid = CPWL_Utils::GetEditAppStream( 330 m_pEdit, ptOffset, &wrTemp, !HasFlag(PES_CHARARRAY), 331 m_pEdit->GetPasswordChar()); 332 333 if (sEditMid.GetLength() > 0) 334 sText << "BT\n" 335 << CPWL_Utils::GetColorAppStream(CPWL_Color(COLORTYPE_GRAY, 1)) 336 << sEditMid << "ET\n"; 337 338 wrTemp = CPWL_Utils::OverlapWordRange(wrVisible, wrSelAfter); 339 CFX_ByteString sEditAfter = CPWL_Utils::GetEditAppStream( 340 m_pEdit, ptOffset, &wrTemp, !HasFlag(PES_CHARARRAY), 341 m_pEdit->GetPasswordChar()); 342 343 if (sEditAfter.GetLength() > 0) 344 sText << "BT\n" << CPWL_Utils::GetColorAppStream(GetTextColor()) 345 << sEditAfter << "ET\n"; 346 347 if (HasFlag(PES_SPELLCHECK)) { 348 CFX_ByteString sSpellCheck = CPWL_Utils::GetSpellCheckAppStream( 349 m_pEdit, m_pSpellCheck, ptOffset, &wrVisible); 350 if (sSpellCheck.GetLength() > 0) 351 sText << CPWL_Utils::GetColorAppStream(CPWL_Color(COLORTYPE_RGB, 1, 0, 0), 352 FALSE) 353 << sSpellCheck; 354 } 355 356 if (sText.GetLength() > 0) { 357 CPDF_Rect rcClient = GetClientRect(); 358 sAppStream << "q\n/Tx BMC\n"; 359 360 if (!HasFlag(PES_TEXTOVERFLOW)) 361 sAppStream << rcClient.left << " " << rcClient.bottom << " " 362 << rcClient.right - rcClient.left << " " 363 << rcClient.top - rcClient.bottom << " re W n\n"; 364 365 sAppStream << sText; 366 367 sAppStream << "EMC\nQ\n"; 368 } 369 } 370 371 void CPWL_Edit::DrawThisAppearance(CFX_RenderDevice* pDevice, 372 CFX_Matrix* pUser2Device) { 373 CPWL_Wnd::DrawThisAppearance(pDevice, pUser2Device); 374 375 CPDF_Rect rcClient = GetClientRect(); 376 CFX_ByteTextBuf sLine; 377 378 int32_t nCharArray = m_pEdit->GetCharArray(); 379 FX_SAFE_INT32 nCharArraySafe = nCharArray; 380 nCharArraySafe -= 1; 381 nCharArraySafe *= 2; 382 383 if (nCharArray > 0 && nCharArraySafe.IsValid()) { 384 switch (GetBorderStyle()) { 385 case PBS_SOLID: { 386 CFX_GraphStateData gsd; 387 gsd.m_LineWidth = (FX_FLOAT)GetBorderWidth(); 388 389 CFX_PathData path; 390 path.SetPointCount(nCharArraySafe.ValueOrDie()); 391 392 for (int32_t i = 0; i < nCharArray - 1; i++) { 393 path.SetPoint( 394 i * 2, 395 rcClient.left + 396 ((rcClient.right - rcClient.left) / nCharArray) * (i + 1), 397 rcClient.bottom, FXPT_MOVETO); 398 path.SetPoint( 399 i * 2 + 1, 400 rcClient.left + 401 ((rcClient.right - rcClient.left) / nCharArray) * (i + 1), 402 rcClient.top, FXPT_LINETO); 403 } 404 if (path.GetPointCount() > 0) 405 pDevice->DrawPath( 406 &path, pUser2Device, &gsd, 0, 407 CPWL_Utils::PWLColorToFXColor(GetBorderColor(), 255), 408 FXFILL_ALTERNATE); 409 } break; 410 case PBS_DASH: { 411 CFX_GraphStateData gsd; 412 gsd.m_LineWidth = (FX_FLOAT)GetBorderWidth(); 413 414 gsd.SetDashCount(2); 415 gsd.m_DashArray[0] = (FX_FLOAT)GetBorderDash().nDash; 416 gsd.m_DashArray[1] = (FX_FLOAT)GetBorderDash().nGap; 417 gsd.m_DashPhase = (FX_FLOAT)GetBorderDash().nPhase; 418 419 CFX_PathData path; 420 path.SetPointCount(nCharArraySafe.ValueOrDie()); 421 422 for (int32_t i = 0; i < nCharArray - 1; i++) { 423 path.SetPoint( 424 i * 2, 425 rcClient.left + 426 ((rcClient.right - rcClient.left) / nCharArray) * (i + 1), 427 rcClient.bottom, FXPT_MOVETO); 428 path.SetPoint( 429 i * 2 + 1, 430 rcClient.left + 431 ((rcClient.right - rcClient.left) / nCharArray) * (i + 1), 432 rcClient.top, FXPT_LINETO); 433 } 434 if (path.GetPointCount() > 0) 435 pDevice->DrawPath( 436 &path, pUser2Device, &gsd, 0, 437 CPWL_Utils::PWLColorToFXColor(GetBorderColor(), 255), 438 FXFILL_ALTERNATE); 439 } break; 440 } 441 } 442 443 CPDF_Rect rcClip; 444 CPVT_WordRange wrRange = m_pEdit->GetVisibleWordRange(); 445 CPVT_WordRange* pRange = NULL; 446 447 if (!HasFlag(PES_TEXTOVERFLOW)) { 448 rcClip = GetClientRect(); 449 pRange = &wrRange; 450 } 451 IFX_SystemHandler* pSysHandler = GetSystemHandler(); 452 IFX_Edit::DrawEdit( 453 pDevice, pUser2Device, m_pEdit, 454 CPWL_Utils::PWLColorToFXColor(GetTextColor(), GetTransparency()), 455 CPWL_Utils::PWLColorToFXColor(GetTextStrokeColor(), GetTransparency()), 456 rcClip, CPDF_Point(0.0f, 0.0f), pRange, pSysHandler, m_pFormFiller); 457 458 if (HasFlag(PES_SPELLCHECK)) { 459 CPWL_Utils::DrawEditSpellCheck(pDevice, pUser2Device, m_pEdit, rcClip, 460 CPDF_Point(0.0f, 0.0f), pRange, 461 GetCreationParam().pSpellCheck); 462 } 463 } 464 465 FX_BOOL CPWL_Edit::OnLButtonDown(const CPDF_Point& point, FX_DWORD nFlag) { 466 CPWL_Wnd::OnLButtonDown(point, nFlag); 467 468 if (HasFlag(PES_TEXTOVERFLOW) || ClientHitTest(point)) { 469 if (m_bMouseDown) 470 InvalidateRect(); 471 472 m_bMouseDown = TRUE; 473 SetCapture(); 474 475 m_pEdit->OnMouseDown(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)); 476 } 477 478 return TRUE; 479 } 480 481 FX_BOOL CPWL_Edit::OnLButtonDblClk(const CPDF_Point& point, FX_DWORD nFlag) { 482 CPWL_Wnd::OnLButtonDblClk(point, nFlag); 483 484 if (HasFlag(PES_TEXTOVERFLOW) || ClientHitTest(point)) { 485 m_pEdit->SelectAll(); 486 } 487 488 return TRUE; 489 } 490 491 #define WM_PWLEDIT_UNDO 0x01 492 #define WM_PWLEDIT_REDO 0x02 493 #define WM_PWLEDIT_CUT 0x03 494 #define WM_PWLEDIT_COPY 0x04 495 #define WM_PWLEDIT_PASTE 0x05 496 #define WM_PWLEDIT_DELETE 0x06 497 #define WM_PWLEDIT_SELECTALL 0x07 498 #define WM_PWLEDIT_SUGGEST 0x08 499 500 FX_BOOL CPWL_Edit::OnRButtonUp(const CPDF_Point& point, FX_DWORD nFlag) { 501 if (m_bMouseDown) 502 return FALSE; 503 504 CPWL_Wnd::OnRButtonUp(point, nFlag); 505 506 if (!HasFlag(PES_TEXTOVERFLOW) && !ClientHitTest(point)) 507 return TRUE; 508 509 IFX_SystemHandler* pSH = GetSystemHandler(); 510 if (!pSH) 511 return FALSE; 512 513 SetFocus(); 514 515 CPVT_WordRange wrLatin = GetLatinWordsRange(point); 516 CFX_WideString swLatin = m_pEdit->GetRangeText(wrLatin); 517 518 FX_HMENU hPopup = pSH->CreatePopupMenu(); 519 if (!hPopup) 520 return FALSE; 521 522 CFX_ByteStringArray sSuggestWords; 523 CPDF_Point ptPopup = point; 524 525 if (!IsReadOnly()) { 526 if (HasFlag(PES_SPELLCHECK) && !swLatin.IsEmpty()) { 527 if (m_pSpellCheck) { 528 CFX_ByteString sLatin = CFX_ByteString::FromUnicode(swLatin); 529 530 if (!m_pSpellCheck->CheckWord(sLatin)) { 531 m_pSpellCheck->SuggestWords(sLatin, sSuggestWords); 532 533 int32_t nSuggest = sSuggestWords.GetSize(); 534 535 for (int32_t nWord = 0; nWord < nSuggest; nWord++) { 536 pSH->AppendMenuItem(hPopup, WM_PWLEDIT_SUGGEST + nWord, 537 sSuggestWords[nWord].UTF8Decode()); 538 } 539 540 if (nSuggest > 0) 541 pSH->AppendMenuItem(hPopup, 0, L""); 542 543 ptPopup = GetWordRightBottomPoint(wrLatin.EndPos); 544 } 545 } 546 } 547 } 548 549 IPWL_Provider* pProvider = GetProvider(); 550 551 if (HasFlag(PES_UNDO)) { 552 pSH->AppendMenuItem( 553 hPopup, WM_PWLEDIT_UNDO, 554 pProvider ? pProvider->LoadPopupMenuString(0) : L"&Undo"); 555 pSH->AppendMenuItem( 556 hPopup, WM_PWLEDIT_REDO, 557 pProvider ? pProvider->LoadPopupMenuString(1) : L"&Redo"); 558 pSH->AppendMenuItem(hPopup, 0, L""); 559 560 if (!m_pEdit->CanUndo()) 561 pSH->EnableMenuItem(hPopup, WM_PWLEDIT_UNDO, FALSE); 562 if (!m_pEdit->CanRedo()) 563 pSH->EnableMenuItem(hPopup, WM_PWLEDIT_REDO, FALSE); 564 } 565 566 pSH->AppendMenuItem(hPopup, WM_PWLEDIT_CUT, 567 pProvider ? pProvider->LoadPopupMenuString(2) : L"Cu&t"); 568 pSH->AppendMenuItem(hPopup, WM_PWLEDIT_COPY, 569 pProvider ? pProvider->LoadPopupMenuString(3) : L"&Copy"); 570 pSH->AppendMenuItem( 571 hPopup, WM_PWLEDIT_PASTE, 572 pProvider ? pProvider->LoadPopupMenuString(4) : L"&Paste"); 573 pSH->AppendMenuItem( 574 hPopup, WM_PWLEDIT_DELETE, 575 pProvider ? pProvider->LoadPopupMenuString(5) : L"&Delete"); 576 577 CFX_WideString swText = pSH->GetClipboardText(GetAttachedHWnd()); 578 if (swText.IsEmpty()) 579 pSH->EnableMenuItem(hPopup, WM_PWLEDIT_PASTE, FALSE); 580 581 if (!m_pEdit->IsSelected()) { 582 pSH->EnableMenuItem(hPopup, WM_PWLEDIT_CUT, FALSE); 583 pSH->EnableMenuItem(hPopup, WM_PWLEDIT_COPY, FALSE); 584 pSH->EnableMenuItem(hPopup, WM_PWLEDIT_DELETE, FALSE); 585 } 586 587 if (IsReadOnly()) { 588 pSH->EnableMenuItem(hPopup, WM_PWLEDIT_CUT, FALSE); 589 pSH->EnableMenuItem(hPopup, WM_PWLEDIT_DELETE, FALSE); 590 pSH->EnableMenuItem(hPopup, WM_PWLEDIT_PASTE, FALSE); 591 } 592 593 if (HasFlag(PES_PASSWORD)) { 594 pSH->EnableMenuItem(hPopup, WM_PWLEDIT_CUT, FALSE); 595 pSH->EnableMenuItem(hPopup, WM_PWLEDIT_COPY, FALSE); 596 } 597 598 if (HasFlag(PES_NOREAD)) { 599 pSH->EnableMenuItem(hPopup, WM_PWLEDIT_CUT, FALSE); 600 pSH->EnableMenuItem(hPopup, WM_PWLEDIT_COPY, FALSE); 601 } 602 603 pSH->AppendMenuItem(hPopup, 0, L""); 604 pSH->AppendMenuItem( 605 hPopup, WM_PWLEDIT_SELECTALL, 606 pProvider ? pProvider->LoadPopupMenuString(6) : L"&Select All"); 607 608 if (m_pEdit->GetTotalWords() == 0) { 609 pSH->EnableMenuItem(hPopup, WM_PWLEDIT_SELECTALL, FALSE); 610 } 611 612 int32_t x, y; 613 PWLtoWnd(ptPopup, x, y); 614 pSH->ClientToScreen(GetAttachedHWnd(), x, y); 615 pSH->SetCursor(FXCT_ARROW); 616 int32_t nCmd = pSH->TrackPopupMenu(hPopup, x, y, GetAttachedHWnd()); 617 618 switch (nCmd) { 619 case WM_PWLEDIT_UNDO: 620 Undo(); 621 break; 622 case WM_PWLEDIT_REDO: 623 Redo(); 624 break; 625 case WM_PWLEDIT_CUT: 626 CutText(); 627 break; 628 case WM_PWLEDIT_COPY: 629 CopyText(); 630 break; 631 case WM_PWLEDIT_PASTE: 632 PasteText(); 633 break; 634 case WM_PWLEDIT_DELETE: 635 Clear(); 636 break; 637 case WM_PWLEDIT_SELECTALL: 638 SelectAll(); 639 break; 640 case WM_PWLEDIT_SUGGEST + 0: 641 SetSel(m_pEdit->WordPlaceToWordIndex(wrLatin.BeginPos), 642 m_pEdit->WordPlaceToWordIndex(wrLatin.EndPos)); 643 ReplaceSel(sSuggestWords[0].UTF8Decode().c_str()); 644 break; 645 case WM_PWLEDIT_SUGGEST + 1: 646 SetSel(m_pEdit->WordPlaceToWordIndex(wrLatin.BeginPos), 647 m_pEdit->WordPlaceToWordIndex(wrLatin.EndPos)); 648 ReplaceSel(sSuggestWords[1].UTF8Decode().c_str()); 649 break; 650 case WM_PWLEDIT_SUGGEST + 2: 651 SetSel(m_pEdit->WordPlaceToWordIndex(wrLatin.BeginPos), 652 m_pEdit->WordPlaceToWordIndex(wrLatin.EndPos)); 653 ReplaceSel(sSuggestWords[2].UTF8Decode().c_str()); 654 break; 655 case WM_PWLEDIT_SUGGEST + 3: 656 SetSel(m_pEdit->WordPlaceToWordIndex(wrLatin.BeginPos), 657 m_pEdit->WordPlaceToWordIndex(wrLatin.EndPos)); 658 ReplaceSel(sSuggestWords[3].UTF8Decode().c_str()); 659 break; 660 case WM_PWLEDIT_SUGGEST + 4: 661 SetSel(m_pEdit->WordPlaceToWordIndex(wrLatin.BeginPos), 662 m_pEdit->WordPlaceToWordIndex(wrLatin.EndPos)); 663 ReplaceSel(sSuggestWords[4].UTF8Decode().c_str()); 664 break; 665 default: 666 break; 667 } 668 669 pSH->DestroyMenu(hPopup); 670 671 return TRUE; 672 } 673 674 void CPWL_Edit::OnSetFocus() { 675 SetEditCaret(TRUE); 676 677 if (!IsReadOnly()) { 678 if (IPWL_FocusHandler* pFocusHandler = GetFocusHandler()) 679 pFocusHandler->OnSetFocus(this); 680 } 681 682 m_bFocus = TRUE; 683 } 684 685 void CPWL_Edit::OnKillFocus() { 686 ShowVScrollBar(FALSE); 687 688 m_pEdit->SelectNone(); 689 SetCaret(FALSE, CPDF_Point(0.0f, 0.0f), CPDF_Point(0.0f, 0.0f)); 690 691 SetCharSet(0); 692 693 if (!IsReadOnly()) { 694 if (IPWL_FocusHandler* pFocusHandler = GetFocusHandler()) 695 pFocusHandler->OnKillFocus(this); 696 } 697 698 m_bFocus = FALSE; 699 } 700 701 void CPWL_Edit::SetHorzScale(int32_t nHorzScale, FX_BOOL bPaint /* = TRUE*/) { 702 m_pEdit->SetHorzScale(nHorzScale, bPaint); 703 } 704 705 void CPWL_Edit::SetCharSpace(FX_FLOAT fCharSpace, FX_BOOL bPaint /* = TRUE*/) { 706 m_pEdit->SetCharSpace(fCharSpace, bPaint); 707 } 708 709 void CPWL_Edit::SetLineLeading(FX_FLOAT fLineLeading, 710 FX_BOOL bPaint /* = TRUE*/) { 711 m_pEdit->SetLineLeading(fLineLeading, bPaint); 712 } 713 714 CFX_ByteString CPWL_Edit::GetSelectAppearanceStream( 715 const CPDF_Point& ptOffset) const { 716 CPVT_WordRange wr = GetSelectWordRange(); 717 return CPWL_Utils::GetEditSelAppStream(m_pEdit, ptOffset, &wr); 718 } 719 720 CPVT_WordRange CPWL_Edit::GetSelectWordRange() const { 721 if (m_pEdit->IsSelected()) { 722 int32_t nStart = -1; 723 int32_t nEnd = -1; 724 725 m_pEdit->GetSel(nStart, nEnd); 726 727 CPVT_WordPlace wpStart = m_pEdit->WordIndexToWordPlace(nStart); 728 CPVT_WordPlace wpEnd = m_pEdit->WordIndexToWordPlace(nEnd); 729 730 return CPVT_WordRange(wpStart, wpEnd); 731 } 732 733 return CPVT_WordRange(); 734 } 735 736 CFX_ByteString CPWL_Edit::GetTextAppearanceStream( 737 const CPDF_Point& ptOffset) const { 738 CFX_ByteTextBuf sRet; 739 CFX_ByteString sEdit = CPWL_Utils::GetEditAppStream(m_pEdit, ptOffset); 740 741 if (sEdit.GetLength() > 0) { 742 sRet << "BT\n" << CPWL_Utils::GetColorAppStream(GetTextColor()) << sEdit 743 << "ET\n"; 744 } 745 746 return sRet.GetByteString(); 747 } 748 749 CFX_ByteString CPWL_Edit::GetCaretAppearanceStream( 750 const CPDF_Point& ptOffset) const { 751 if (m_pEditCaret) 752 return m_pEditCaret->GetCaretAppearanceStream(ptOffset); 753 754 return CFX_ByteString(); 755 } 756 757 CPDF_Point CPWL_Edit::GetWordRightBottomPoint(const CPVT_WordPlace& wpWord) { 758 CPDF_Point pt(0.0f, 0.0f); 759 760 if (IFX_Edit_Iterator* pIterator = m_pEdit->GetIterator()) { 761 CPVT_WordPlace wpOld = pIterator->GetAt(); 762 pIterator->SetAt(wpWord); 763 CPVT_Word word; 764 if (pIterator->GetWord(word)) { 765 pt = CPDF_Point(word.ptWord.x + word.fWidth, 766 word.ptWord.y + word.fDescent); 767 } 768 769 pIterator->SetAt(wpOld); 770 } 771 772 return pt; 773 } 774 775 FX_BOOL CPWL_Edit::IsTextFull() const { 776 return m_pEdit->IsTextFull(); 777 } 778 779 FX_FLOAT CPWL_Edit::GetCharArrayAutoFontSize(CPDF_Font* pFont, 780 const CPDF_Rect& rcPlate, 781 int32_t nCharArray) { 782 if (pFont && !pFont->IsStandardFont()) { 783 FX_RECT rcBBox; 784 pFont->GetFontBBox(rcBBox); 785 786 CPDF_Rect rcCell = rcPlate; 787 FX_FLOAT xdiv = rcCell.Width() / nCharArray * 1000.0f / rcBBox.Width(); 788 FX_FLOAT ydiv = -rcCell.Height() * 1000.0f / rcBBox.Height(); 789 790 return xdiv < ydiv ? xdiv : ydiv; 791 } 792 793 return 0.0f; 794 } 795 796 void CPWL_Edit::SetCharArray(int32_t nCharArray) { 797 if (HasFlag(PES_CHARARRAY) && nCharArray > 0) { 798 m_pEdit->SetCharArray(nCharArray); 799 m_pEdit->SetTextOverflow(TRUE); 800 801 if (HasFlag(PWS_AUTOFONTSIZE)) { 802 if (IFX_Edit_FontMap* pFontMap = GetFontMap()) { 803 FX_FLOAT fFontSize = GetCharArrayAutoFontSize( 804 pFontMap->GetPDFFont(0), GetClientRect(), nCharArray); 805 if (fFontSize > 0.0f) { 806 m_pEdit->SetAutoFontSize(FALSE); 807 m_pEdit->SetFontSize(fFontSize); 808 } 809 } 810 } 811 } 812 } 813 814 void CPWL_Edit::SetLimitChar(int32_t nLimitChar) { 815 m_pEdit->SetLimitChar(nLimitChar); 816 } 817 818 void CPWL_Edit::ReplaceSel(const FX_WCHAR* csText) { 819 m_pEdit->Clear(); 820 m_pEdit->InsertText(csText); 821 } 822 823 CPDF_Rect CPWL_Edit::GetFocusRect() const { 824 return CPDF_Rect(); 825 } 826 827 void CPWL_Edit::ShowVScrollBar(FX_BOOL bShow) { 828 if (CPWL_ScrollBar* pScroll = GetVScrollBar()) { 829 if (bShow) { 830 if (!pScroll->IsVisible()) { 831 pScroll->SetVisible(TRUE); 832 CPDF_Rect rcWindow = GetWindowRect(); 833 m_rcOldWindow = rcWindow; 834 rcWindow.right += PWL_SCROLLBAR_WIDTH; 835 Move(rcWindow, TRUE, TRUE); 836 } 837 } else { 838 if (pScroll->IsVisible()) { 839 pScroll->SetVisible(FALSE); 840 Move(m_rcOldWindow, TRUE, TRUE); 841 } 842 } 843 } 844 } 845 846 FX_BOOL CPWL_Edit::IsVScrollBarVisible() const { 847 if (CPWL_ScrollBar* pScroll = GetVScrollBar()) { 848 return pScroll->IsVisible(); 849 } 850 851 return FALSE; 852 } 853 854 void CPWL_Edit::EnableSpellCheck(FX_BOOL bEnabled) { 855 if (bEnabled) 856 AddFlag(PES_SPELLCHECK); 857 else 858 RemoveFlag(PES_SPELLCHECK); 859 } 860 861 FX_BOOL CPWL_Edit::OnKeyDown(FX_WORD nChar, FX_DWORD nFlag) { 862 if (m_bMouseDown) 863 return TRUE; 864 865 if (nChar == FWL_VKEY_Delete) { 866 if (m_pFillerNotify) { 867 FX_BOOL bRC = TRUE; 868 FX_BOOL bExit = FALSE; 869 CFX_WideString strChange; 870 CFX_WideString strChangeEx; 871 872 int nSelStart = 0; 873 int nSelEnd = 0; 874 GetSel(nSelStart, nSelEnd); 875 876 if (nSelStart == nSelEnd) 877 nSelEnd = nSelStart + 1; 878 m_pFillerNotify->OnBeforeKeyStroke(GetAttachedData(), strChange, 879 strChangeEx, nSelStart, nSelEnd, TRUE, 880 bRC, bExit, nFlag); 881 if (!bRC) 882 return FALSE; 883 if (bExit) 884 return FALSE; 885 } 886 } 887 888 FX_BOOL bRet = CPWL_EditCtrl::OnKeyDown(nChar, nFlag); 889 890 // In case of implementation swallow the OnKeyDown event. 891 if (IsProceedtoOnChar(nChar, nFlag)) 892 return TRUE; 893 894 return bRet; 895 } 896 897 /** 898 *In case of implementation swallow the OnKeyDown event. 899 *If the event is swallowed, implementation may do other unexpected things, which 900 *is not the control means to do. 901 */ 902 FX_BOOL CPWL_Edit::IsProceedtoOnChar(FX_WORD nKeyCode, FX_DWORD nFlag) { 903 FX_BOOL bCtrl = IsCTRLpressed(nFlag); 904 FX_BOOL bAlt = IsALTpressed(nFlag); 905 if (bCtrl && !bAlt) { 906 // hot keys for edit control. 907 switch (nKeyCode) { 908 case 'C': 909 case 'V': 910 case 'X': 911 case 'A': 912 case 'Z': 913 return TRUE; 914 default: 915 break; 916 } 917 } 918 // control characters. 919 switch (nKeyCode) { 920 case FWL_VKEY_Escape: 921 case FWL_VKEY_Back: 922 case FWL_VKEY_Return: 923 case FWL_VKEY_Space: 924 return TRUE; 925 default: 926 return FALSE; 927 } 928 } 929 930 FX_BOOL CPWL_Edit::OnChar(FX_WORD nChar, FX_DWORD nFlag) { 931 if (m_bMouseDown) 932 return TRUE; 933 934 FX_BOOL bRC = TRUE; 935 FX_BOOL bExit = FALSE; 936 937 if (!IsCTRLpressed(nFlag)) { 938 if (m_pFillerNotify) { 939 CFX_WideString swChange; 940 941 int nSelStart = 0; 942 int nSelEnd = 0; 943 GetSel(nSelStart, nSelEnd); 944 945 switch (nChar) { 946 case FWL_VKEY_Back: 947 if (nSelStart == nSelEnd) 948 nSelStart = nSelEnd - 1; 949 break; 950 case FWL_VKEY_Return: 951 break; 952 default: 953 swChange += nChar; 954 break; 955 } 956 957 CFX_WideString strChangeEx; 958 m_pFillerNotify->OnBeforeKeyStroke(GetAttachedData(), swChange, 959 strChangeEx, nSelStart, nSelEnd, TRUE, 960 bRC, bExit, nFlag); 961 } 962 } 963 964 if (!bRC) 965 return TRUE; 966 if (bExit) 967 return FALSE; 968 969 if (IFX_Edit_FontMap* pFontMap = GetFontMap()) { 970 int32_t nOldCharSet = GetCharSet(); 971 int32_t nNewCharSet = pFontMap->CharSetFromUnicode(nChar, DEFAULT_CHARSET); 972 if (nOldCharSet != nNewCharSet) { 973 SetCharSet(nNewCharSet); 974 } 975 } 976 977 return CPWL_EditCtrl::OnChar(nChar, nFlag); 978 } 979 980 FX_BOOL CPWL_Edit::OnMouseWheel(short zDelta, 981 const CPDF_Point& point, 982 FX_DWORD nFlag) { 983 if (HasFlag(PES_MULTILINE)) { 984 CPDF_Point ptScroll = GetScrollPos(); 985 986 if (zDelta > 0) { 987 ptScroll.y += GetFontSize(); 988 } else { 989 ptScroll.y -= GetFontSize(); 990 } 991 SetScrollPos(ptScroll); 992 993 return TRUE; 994 } 995 996 return FALSE; 997 } 998 999 void CPWL_Edit::OnInsertReturn(const CPVT_WordPlace& place, 1000 const CPVT_WordPlace& oldplace) { 1001 if (HasFlag(PES_SPELLCHECK)) { 1002 m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace), 1003 GetLatinWordsRange(place))); 1004 } 1005 1006 if (m_pEditNotify) { 1007 m_pEditNotify->OnInsertReturn(place, oldplace); 1008 } 1009 } 1010 1011 void CPWL_Edit::OnBackSpace(const CPVT_WordPlace& place, 1012 const CPVT_WordPlace& oldplace) { 1013 if (HasFlag(PES_SPELLCHECK)) { 1014 m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace), 1015 GetLatinWordsRange(place))); 1016 } 1017 1018 if (m_pEditNotify) { 1019 m_pEditNotify->OnBackSpace(place, oldplace); 1020 } 1021 } 1022 1023 void CPWL_Edit::OnDelete(const CPVT_WordPlace& place, 1024 const CPVT_WordPlace& oldplace) { 1025 if (HasFlag(PES_SPELLCHECK)) { 1026 m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace), 1027 GetLatinWordsRange(place))); 1028 } 1029 1030 if (m_pEditNotify) { 1031 m_pEditNotify->OnDelete(place, oldplace); 1032 } 1033 } 1034 1035 void CPWL_Edit::OnClear(const CPVT_WordPlace& place, 1036 const CPVT_WordPlace& oldplace) { 1037 if (HasFlag(PES_SPELLCHECK)) { 1038 m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace), 1039 GetLatinWordsRange(place))); 1040 } 1041 1042 if (m_pEditNotify) { 1043 m_pEditNotify->OnClear(place, oldplace); 1044 } 1045 } 1046 1047 void CPWL_Edit::OnInsertWord(const CPVT_WordPlace& place, 1048 const CPVT_WordPlace& oldplace) { 1049 if (HasFlag(PES_SPELLCHECK)) { 1050 m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace), 1051 GetLatinWordsRange(place))); 1052 } 1053 1054 if (m_pEditNotify) { 1055 m_pEditNotify->OnInsertWord(place, oldplace); 1056 } 1057 } 1058 1059 void CPWL_Edit::OnSetText(const CPVT_WordPlace& place, 1060 const CPVT_WordPlace& oldplace) {} 1061 1062 void CPWL_Edit::OnInsertText(const CPVT_WordPlace& place, 1063 const CPVT_WordPlace& oldplace) { 1064 if (HasFlag(PES_SPELLCHECK)) { 1065 m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace), 1066 GetLatinWordsRange(place))); 1067 } 1068 1069 if (m_pEditNotify) { 1070 m_pEditNotify->OnInsertText(place, oldplace); 1071 } 1072 } 1073 1074 void CPWL_Edit::OnAddUndo(IFX_Edit_UndoItem* pUndoItem) { 1075 if (m_pEditNotify) { 1076 m_pEditNotify->OnAddUndo(this); 1077 } 1078 } 1079 1080 CPVT_WordRange CPWL_Edit::CombineWordRange(const CPVT_WordRange& wr1, 1081 const CPVT_WordRange& wr2) { 1082 CPVT_WordRange wrRet; 1083 1084 if (wr1.BeginPos.WordCmp(wr2.BeginPos) < 0) { 1085 wrRet.BeginPos = wr1.BeginPos; 1086 } else { 1087 wrRet.BeginPos = wr2.BeginPos; 1088 } 1089 1090 if (wr1.EndPos.WordCmp(wr2.EndPos) < 0) { 1091 wrRet.EndPos = wr2.EndPos; 1092 } else { 1093 wrRet.EndPos = wr1.EndPos; 1094 } 1095 1096 return wrRet; 1097 } 1098 1099 CPVT_WordRange CPWL_Edit::GetLatinWordsRange(const CPDF_Point& point) const { 1100 return GetSameWordsRange(m_pEdit->SearchWordPlace(point), TRUE, FALSE); 1101 } 1102 1103 CPVT_WordRange CPWL_Edit::GetLatinWordsRange( 1104 const CPVT_WordPlace& place) const { 1105 return GetSameWordsRange(place, TRUE, FALSE); 1106 } 1107 1108 CPVT_WordRange CPWL_Edit::GetArabicWordsRange( 1109 const CPVT_WordPlace& place) const { 1110 return GetSameWordsRange(place, FALSE, TRUE); 1111 } 1112 1113 #define PWL_ISARABICWORD(word) \ 1114 ((word >= 0x0600 && word <= 0x06FF) || (word >= 0xFB50 && word <= 0xFEFC)) 1115 1116 CPVT_WordRange CPWL_Edit::GetSameWordsRange(const CPVT_WordPlace& place, 1117 FX_BOOL bLatin, 1118 FX_BOOL bArabic) const { 1119 CPVT_WordRange range; 1120 1121 if (IFX_Edit_Iterator* pIterator = m_pEdit->GetIterator()) { 1122 CPVT_Word wordinfo; 1123 CPVT_WordPlace wpStart(place), wpEnd(place); 1124 pIterator->SetAt(place); 1125 1126 if (bLatin) { 1127 while (pIterator->NextWord()) { 1128 if (!pIterator->GetWord(wordinfo) || 1129 !FX_EDIT_ISLATINWORD(wordinfo.Word)) { 1130 break; 1131 } 1132 1133 wpEnd = pIterator->GetAt(); 1134 } 1135 } else if (bArabic) { 1136 while (pIterator->NextWord()) { 1137 if (!pIterator->GetWord(wordinfo) || !PWL_ISARABICWORD(wordinfo.Word)) 1138 break; 1139 1140 wpEnd = pIterator->GetAt(); 1141 } 1142 } 1143 1144 pIterator->SetAt(place); 1145 1146 if (bLatin) { 1147 do { 1148 if (!pIterator->GetWord(wordinfo) || 1149 !FX_EDIT_ISLATINWORD(wordinfo.Word)) { 1150 break; 1151 } 1152 1153 wpStart = pIterator->GetAt(); 1154 } while (pIterator->PrevWord()); 1155 } else if (bArabic) { 1156 do { 1157 if (!pIterator->GetWord(wordinfo) || !PWL_ISARABICWORD(wordinfo.Word)) 1158 break; 1159 1160 wpStart = pIterator->GetAt(); 1161 } while (pIterator->PrevWord()); 1162 } 1163 1164 range.Set(wpStart, wpEnd); 1165 } 1166 1167 return range; 1168 } 1169 1170 void CPWL_Edit::GeneratePageObjects( 1171 CPDF_PageObjects* pPageObjects, 1172 const CPDF_Point& ptOffset, 1173 CFX_ArrayTemplate<CPDF_TextObject*>& ObjArray) { 1174 IFX_Edit::GeneratePageObjects( 1175 pPageObjects, m_pEdit, ptOffset, NULL, 1176 CPWL_Utils::PWLColorToFXColor(GetTextColor(), GetTransparency()), 1177 ObjArray); 1178 } 1179 1180 void CPWL_Edit::GeneratePageObjects(CPDF_PageObjects* pPageObjects, 1181 const CPDF_Point& ptOffset) { 1182 CFX_ArrayTemplate<CPDF_TextObject*> ObjArray; 1183 IFX_Edit::GeneratePageObjects( 1184 pPageObjects, m_pEdit, ptOffset, NULL, 1185 CPWL_Utils::PWLColorToFXColor(GetTextColor(), GetTransparency()), 1186 ObjArray); 1187 } 1188