Home | History | Annotate | Download | only in fxfa
      1 // Copyright 2017 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 "xfa/fxfa/cxfa_fftextedit.h"
      8 
      9 #include <utility>
     10 
     11 #include "xfa/fwl/cfwl_datetimepicker.h"
     12 #include "xfa/fwl/cfwl_edit.h"
     13 #include "xfa/fwl/cfwl_eventcheckword.h"
     14 #include "xfa/fwl/cfwl_eventtarget.h"
     15 #include "xfa/fwl/cfwl_eventtextchanged.h"
     16 #include "xfa/fwl/cfwl_messagekillfocus.h"
     17 #include "xfa/fwl/cfwl_messagesetfocus.h"
     18 #include "xfa/fwl/cfwl_notedriver.h"
     19 #include "xfa/fxfa/cxfa_eventparam.h"
     20 #include "xfa/fxfa/cxfa_ffapp.h"
     21 #include "xfa/fxfa/cxfa_ffdoc.h"
     22 #include "xfa/fxfa/parser/cxfa_node.h"
     23 #include "xfa/fxfa/parser/cxfa_para.h"
     24 
     25 namespace {
     26 
     27 CFWL_Edit* ToEdit(CFWL_Widget* widget) {
     28   return static_cast<CFWL_Edit*>(widget);
     29 }
     30 
     31 }  // namespace
     32 
     33 CXFA_FFTextEdit::CXFA_FFTextEdit(CXFA_Node* pNode)
     34     : CXFA_FFField(pNode), m_pOldDelegate(nullptr) {}
     35 
     36 CXFA_FFTextEdit::~CXFA_FFTextEdit() {
     37   if (m_pNormalWidget) {
     38     CFWL_NoteDriver* pNoteDriver =
     39         m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
     40     pNoteDriver->UnregisterEventTarget(m_pNormalWidget.get());
     41   }
     42 }
     43 
     44 bool CXFA_FFTextEdit::LoadWidget() {
     45   auto pNewWidget = pdfium::MakeUnique<CFWL_Edit>(
     46       GetFWLApp(), pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr);
     47   CFWL_Edit* pFWLEdit = pNewWidget.get();
     48   m_pNormalWidget = std::move(pNewWidget);
     49   m_pNormalWidget->SetLayoutItem(this);
     50 
     51   CFWL_NoteDriver* pNoteDriver =
     52       m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
     53   pNoteDriver->RegisterEventTarget(m_pNormalWidget.get(),
     54                                    m_pNormalWidget.get());
     55   m_pOldDelegate = m_pNormalWidget->GetDelegate();
     56   m_pNormalWidget->SetDelegate(this);
     57   m_pNormalWidget->LockUpdate();
     58   UpdateWidgetProperty();
     59 
     60   pFWLEdit->SetText(
     61       m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Display));
     62   m_pNormalWidget->UnlockUpdate();
     63   return CXFA_FFField::LoadWidget();
     64 }
     65 
     66 void CXFA_FFTextEdit::UpdateWidgetProperty() {
     67   CFWL_Edit* pWidget = static_cast<CFWL_Edit*>(m_pNormalWidget.get());
     68   if (!pWidget)
     69     return;
     70 
     71   uint32_t dwStyle = 0;
     72   uint32_t dwExtendedStyle =
     73       FWL_STYLEEXT_EDT_ShowScrollbarFocus | FWL_STYLEEXT_EDT_OuterScrollbar;
     74   dwExtendedStyle |= UpdateUIProperty();
     75   if (m_pNode->GetWidgetAcc()->IsMultiLine()) {
     76     dwExtendedStyle |= FWL_STYLEEXT_EDT_MultiLine | FWL_STYLEEXT_EDT_WantReturn;
     77     if (!m_pNode->GetWidgetAcc()->IsVerticalScrollPolicyOff()) {
     78       dwStyle |= FWL_WGTSTYLE_VScroll;
     79       dwExtendedStyle |= FWL_STYLEEXT_EDT_AutoVScroll;
     80     }
     81   } else if (!m_pNode->GetWidgetAcc()->IsHorizontalScrollPolicyOff()) {
     82     dwExtendedStyle |= FWL_STYLEEXT_EDT_AutoHScroll;
     83   }
     84   if (!m_pNode->IsOpenAccess() || !GetDoc()->GetXFADoc()->IsInteractive()) {
     85     dwExtendedStyle |= FWL_STYLEEXT_EDT_ReadOnly;
     86     dwExtendedStyle |= FWL_STYLEEXT_EDT_MultiLine;
     87   }
     88 
     89   XFA_Element eType;
     90   int32_t iMaxChars;
     91   std::tie(eType, iMaxChars) = m_pNode->GetWidgetAcc()->GetMaxChars();
     92   if (eType == XFA_Element::ExData)
     93     iMaxChars = 0;
     94 
     95   Optional<int32_t> numCells = m_pNode->GetWidgetAcc()->GetNumberOfCells();
     96   if (!numCells) {
     97     pWidget->SetLimit(iMaxChars);
     98   } else if (*numCells == 0) {
     99     dwExtendedStyle |= FWL_STYLEEXT_EDT_CombText;
    100     pWidget->SetLimit(iMaxChars > 0 ? iMaxChars : 1);
    101   } else {
    102     dwExtendedStyle |= FWL_STYLEEXT_EDT_CombText;
    103     pWidget->SetLimit(*numCells);
    104   }
    105 
    106   dwExtendedStyle |= GetAlignment();
    107   m_pNormalWidget->ModifyStyles(dwStyle, 0xFFFFFFFF);
    108   m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
    109 }
    110 
    111 bool CXFA_FFTextEdit::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
    112   if (!PtInActiveRect(point))
    113     return false;
    114   if (!IsFocused()) {
    115     m_dwStatus |= XFA_WidgetStatus_Focused;
    116     UpdateFWLData();
    117     AddInvalidateRect();
    118   }
    119 
    120   SetButtonDown(true);
    121   CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
    122   ms.m_dwCmd = FWL_MouseCommand::LeftButtonDown;
    123   ms.m_dwFlags = dwFlags;
    124   ms.m_pos = FWLToClient(point);
    125   TranslateFWLMessage(&ms);
    126   return true;
    127 }
    128 
    129 bool CXFA_FFTextEdit::OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
    130   if (!m_pNode->IsOpenAccess())
    131     return false;
    132   if (!PtInActiveRect(point))
    133     return false;
    134   if (!IsFocused()) {
    135     m_dwStatus |= XFA_WidgetStatus_Focused;
    136     UpdateFWLData();
    137     AddInvalidateRect();
    138   }
    139 
    140   SetButtonDown(true);
    141   CFWL_MessageMouse ms(nullptr, nullptr);
    142   ms.m_dwCmd = FWL_MouseCommand::RightButtonDown;
    143   ms.m_dwFlags = dwFlags;
    144   ms.m_pos = FWLToClient(point);
    145   TranslateFWLMessage(&ms);
    146   return true;
    147 }
    148 
    149 bool CXFA_FFTextEdit::OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
    150   if (!CXFA_FFField::OnRButtonUp(dwFlags, point))
    151     return false;
    152 
    153   GetDoc()->GetDocEnvironment()->PopupMenu(this, point);
    154   return true;
    155 }
    156 
    157 bool CXFA_FFTextEdit::OnSetFocus(CXFA_FFWidget* pOldWidget) {
    158   m_dwStatus &= ~XFA_WidgetStatus_TextEditValueChanged;
    159   if (!IsFocused()) {
    160     m_dwStatus |= XFA_WidgetStatus_Focused;
    161     UpdateFWLData();
    162     AddInvalidateRect();
    163   }
    164   CXFA_FFWidget::OnSetFocus(pOldWidget);
    165   CFWL_MessageSetFocus ms(nullptr, m_pNormalWidget.get());
    166   TranslateFWLMessage(&ms);
    167   return true;
    168 }
    169 
    170 bool CXFA_FFTextEdit::OnKillFocus(CXFA_FFWidget* pNewWidget) {
    171   CFWL_MessageKillFocus ms(nullptr, m_pNormalWidget.get());
    172   TranslateFWLMessage(&ms);
    173   m_dwStatus &= ~XFA_WidgetStatus_Focused;
    174 
    175   SetEditScrollOffset();
    176   ProcessCommittedData();
    177   UpdateFWLData();
    178   AddInvalidateRect();
    179   CXFA_FFWidget::OnKillFocus(pNewWidget);
    180 
    181   m_dwStatus &= ~XFA_WidgetStatus_TextEditValueChanged;
    182   return true;
    183 }
    184 
    185 bool CXFA_FFTextEdit::CommitData() {
    186   WideString wsText = static_cast<CFWL_Edit*>(m_pNormalWidget.get())->GetText();
    187   if (m_pNode->GetWidgetAcc()->SetValue(XFA_VALUEPICTURE_Edit, wsText)) {
    188     m_pNode->GetWidgetAcc()->UpdateUIDisplay(GetDoc()->GetDocView(), this);
    189     return true;
    190   }
    191   ValidateNumberField(wsText);
    192   return false;
    193 }
    194 
    195 void CXFA_FFTextEdit::ValidateNumberField(const WideString& wsText) {
    196   CXFA_WidgetAcc* pAcc = GetNode()->GetWidgetAcc();
    197   if (!pAcc || pAcc->GetUIType() != XFA_Element::NumericEdit)
    198     return;
    199 
    200   IXFA_AppProvider* pAppProvider = GetApp()->GetAppProvider();
    201   if (!pAppProvider)
    202     return;
    203 
    204   WideString wsSomField = pAcc->GetNode()->GetSOMExpression();
    205   pAppProvider->MsgBox(WideString::Format(L"%ls can not contain %ls",
    206                                           wsText.c_str(), wsSomField.c_str()),
    207                        pAppProvider->GetAppTitle(), XFA_MBICON_Error,
    208                        XFA_MB_OK);
    209 }
    210 
    211 bool CXFA_FFTextEdit::IsDataChanged() {
    212   return (m_dwStatus & XFA_WidgetStatus_TextEditValueChanged) != 0;
    213 }
    214 
    215 uint32_t CXFA_FFTextEdit::GetAlignment() {
    216   CXFA_Para* para = m_pNode->GetParaIfExists();
    217   if (!para)
    218     return 0;
    219 
    220   uint32_t dwExtendedStyle = 0;
    221   switch (para->GetHorizontalAlign()) {
    222     case XFA_AttributeEnum::Center:
    223       dwExtendedStyle |= FWL_STYLEEXT_EDT_HCenter;
    224       break;
    225     case XFA_AttributeEnum::Justify:
    226       dwExtendedStyle |= FWL_STYLEEXT_EDT_Justified;
    227       break;
    228     case XFA_AttributeEnum::JustifyAll:
    229     case XFA_AttributeEnum::Radix:
    230       break;
    231     case XFA_AttributeEnum::Right:
    232       dwExtendedStyle |= FWL_STYLEEXT_EDT_HFar;
    233       break;
    234     default:
    235       dwExtendedStyle |= FWL_STYLEEXT_EDT_HNear;
    236       break;
    237   }
    238 
    239   switch (para->GetVerticalAlign()) {
    240     case XFA_AttributeEnum::Middle:
    241       dwExtendedStyle |= FWL_STYLEEXT_EDT_VCenter;
    242       break;
    243     case XFA_AttributeEnum::Bottom:
    244       dwExtendedStyle |= FWL_STYLEEXT_EDT_VFar;
    245       break;
    246     default:
    247       dwExtendedStyle |= FWL_STYLEEXT_EDT_VNear;
    248       break;
    249   }
    250   return dwExtendedStyle;
    251 }
    252 
    253 bool CXFA_FFTextEdit::UpdateFWLData() {
    254   if (!m_pNormalWidget)
    255     return false;
    256 
    257   CFWL_Edit* pEdit = static_cast<CFWL_Edit*>(m_pNormalWidget.get());
    258   XFA_VALUEPICTURE eType = XFA_VALUEPICTURE_Display;
    259   if (IsFocused())
    260     eType = XFA_VALUEPICTURE_Edit;
    261 
    262   bool bUpdate = false;
    263   if (m_pNode->GetWidgetAcc()->GetUIType() == XFA_Element::TextEdit &&
    264       !m_pNode->GetWidgetAcc()->GetNumberOfCells()) {
    265     XFA_Element elementType;
    266     int32_t iMaxChars;
    267     std::tie(elementType, iMaxChars) = m_pNode->GetWidgetAcc()->GetMaxChars();
    268     if (elementType == XFA_Element::ExData)
    269       iMaxChars = eType == XFA_VALUEPICTURE_Edit ? iMaxChars : 0;
    270     if (pEdit->GetLimit() != iMaxChars) {
    271       pEdit->SetLimit(iMaxChars);
    272       bUpdate = true;
    273     }
    274   } else if (m_pNode->GetWidgetAcc()->GetUIType() == XFA_Element::Barcode) {
    275     int32_t nDataLen = 0;
    276     if (eType == XFA_VALUEPICTURE_Edit)
    277       nDataLen = m_pNode->GetBarcodeAttribute_DataLength().value_or(0);
    278 
    279     pEdit->SetLimit(nDataLen);
    280     bUpdate = true;
    281   }
    282 
    283   WideString wsText = m_pNode->GetWidgetAcc()->GetValue(eType);
    284   WideString wsOldText = pEdit->GetText();
    285   if (wsText != wsOldText || (eType == XFA_VALUEPICTURE_Edit && bUpdate)) {
    286     pEdit->SetText(wsText);
    287     bUpdate = true;
    288   }
    289   if (bUpdate)
    290     m_pNormalWidget->Update();
    291 
    292   return true;
    293 }
    294 
    295 void CXFA_FFTextEdit::OnTextChanged(CFWL_Widget* pWidget,
    296                                     const WideString& wsChanged,
    297                                     const WideString& wsPrevText) {
    298   m_dwStatus |= XFA_WidgetStatus_TextEditValueChanged;
    299   CXFA_EventParam eParam;
    300   eParam.m_eType = XFA_EVENT_Change;
    301   eParam.m_wsChange = wsChanged;
    302   eParam.m_pTarget = m_pNode->GetWidgetAcc();
    303   eParam.m_wsPrevText = wsPrevText;
    304   CFWL_Edit* pEdit = static_cast<CFWL_Edit*>(m_pNormalWidget.get());
    305   if (m_pNode->GetWidgetAcc()->GetUIType() == XFA_Element::DateTimeEdit) {
    306     CFWL_DateTimePicker* pDateTime = (CFWL_DateTimePicker*)pEdit;
    307     eParam.m_wsNewText = pDateTime->GetEditText();
    308     if (pDateTime->HasSelection()) {
    309       size_t count;
    310       std::tie(eParam.m_iSelStart, count) = pDateTime->GetSelection();
    311       eParam.m_iSelEnd = eParam.m_iSelStart + count;
    312     }
    313   } else {
    314     eParam.m_wsNewText = pEdit->GetText();
    315     if (pEdit->HasSelection())
    316       std::tie(eParam.m_iSelStart, eParam.m_iSelEnd) = pEdit->GetSelection();
    317   }
    318   m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Change, &eParam);
    319 }
    320 
    321 void CXFA_FFTextEdit::OnTextFull(CFWL_Widget* pWidget) {
    322   CXFA_EventParam eParam;
    323   eParam.m_eType = XFA_EVENT_Full;
    324   eParam.m_pTarget = m_pNode->GetWidgetAcc();
    325   m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Full, &eParam);
    326 }
    327 
    328 bool CXFA_FFTextEdit::CheckWord(const ByteStringView& sWord) {
    329   return sWord.IsEmpty() ||
    330          m_pNode->GetWidgetAcc()->GetUIType() != XFA_Element::TextEdit;
    331 }
    332 
    333 void CXFA_FFTextEdit::OnProcessMessage(CFWL_Message* pMessage) {
    334   m_pOldDelegate->OnProcessMessage(pMessage);
    335 }
    336 
    337 void CXFA_FFTextEdit::OnProcessEvent(CFWL_Event* pEvent) {
    338   CXFA_FFField::OnProcessEvent(pEvent);
    339   switch (pEvent->GetType()) {
    340     case CFWL_Event::Type::TextChanged: {
    341       CFWL_EventTextChanged* event =
    342           static_cast<CFWL_EventTextChanged*>(pEvent);
    343       WideString wsChange;
    344       OnTextChanged(m_pNormalWidget.get(), wsChange, event->wsPrevText);
    345       break;
    346     }
    347     case CFWL_Event::Type::TextFull: {
    348       OnTextFull(m_pNormalWidget.get());
    349       break;
    350     }
    351     case CFWL_Event::Type::CheckWord: {
    352       WideString wstr(L"FWL_EVENT_DTP_SelectChanged");
    353       CFWL_EventCheckWord* event = static_cast<CFWL_EventCheckWord*>(pEvent);
    354       event->bCheckWord = CheckWord(event->bsWord.AsStringView());
    355       break;
    356     }
    357     default:
    358       break;
    359   }
    360   m_pOldDelegate->OnProcessEvent(pEvent);
    361 }
    362 
    363 void CXFA_FFTextEdit::OnDrawWidget(CXFA_Graphics* pGraphics,
    364                                    const CFX_Matrix& matrix) {
    365   m_pOldDelegate->OnDrawWidget(pGraphics, matrix);
    366 }
    367 
    368 bool CXFA_FFTextEdit::CanUndo() {
    369   return ToEdit(m_pNormalWidget.get())->CanUndo();
    370 }
    371 
    372 bool CXFA_FFTextEdit::CanRedo() {
    373   return ToEdit(m_pNormalWidget.get())->CanRedo();
    374 }
    375 
    376 bool CXFA_FFTextEdit::Undo() {
    377   return ToEdit(m_pNormalWidget.get())->Undo();
    378 }
    379 
    380 bool CXFA_FFTextEdit::Redo() {
    381   return ToEdit(m_pNormalWidget.get())->Redo();
    382 }
    383 
    384 bool CXFA_FFTextEdit::CanCopy() {
    385   return ToEdit(m_pNormalWidget.get())->HasSelection();
    386 }
    387 
    388 bool CXFA_FFTextEdit::CanCut() {
    389   if (ToEdit(m_pNormalWidget.get())->GetStylesEx() & FWL_STYLEEXT_EDT_ReadOnly)
    390     return false;
    391   return ToEdit(m_pNormalWidget.get())->HasSelection();
    392 }
    393 
    394 bool CXFA_FFTextEdit::CanPaste() {
    395   return !(ToEdit(m_pNormalWidget.get())->GetStylesEx() &
    396            FWL_STYLEEXT_EDT_ReadOnly);
    397 }
    398 
    399 bool CXFA_FFTextEdit::CanSelectAll() {
    400   return ToEdit(m_pNormalWidget.get())->GetTextLength() > 0;
    401 }
    402 
    403 Optional<WideString> CXFA_FFTextEdit::Copy() {
    404   return ToEdit(m_pNormalWidget.get())->Copy();
    405 }
    406 
    407 Optional<WideString> CXFA_FFTextEdit::Cut() {
    408   return ToEdit(m_pNormalWidget.get())->Cut();
    409 }
    410 
    411 bool CXFA_FFTextEdit::Paste(const WideString& wsPaste) {
    412   return ToEdit(m_pNormalWidget.get())->Paste(wsPaste);
    413 }
    414 
    415 void CXFA_FFTextEdit::SelectAll() {
    416   ToEdit(m_pNormalWidget.get())->SelectAll();
    417 }
    418 
    419 void CXFA_FFTextEdit::Delete() {
    420   ToEdit(m_pNormalWidget.get())->ClearText();
    421 }
    422 
    423 void CXFA_FFTextEdit::DeSelect() {
    424   ToEdit(m_pNormalWidget.get())->ClearSelection();
    425 }
    426 
    427 FormFieldType CXFA_FFTextEdit::GetFormFieldType() {
    428   return FormFieldType::kXFA_TextField;
    429 }
    430