Home | History | Annotate | Download | only in app
      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 "xfa/fxfa/app/xfa_fftextedit.h"
      8 
      9 #include <vector>
     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_eventselectchanged.h"
     15 #include "xfa/fwl/cfwl_eventtextchanged.h"
     16 #include "xfa/fwl/cfwl_eventvalidate.h"
     17 #include "xfa/fwl/cfwl_messagekillfocus.h"
     18 #include "xfa/fwl/cfwl_messagemouse.h"
     19 #include "xfa/fwl/cfwl_messagesetfocus.h"
     20 #include "xfa/fwl/cfwl_notedriver.h"
     21 #include "xfa/fxfa/app/xfa_fffield.h"
     22 #include "xfa/fxfa/app/xfa_fwladapter.h"
     23 #include "xfa/fxfa/cxfa_eventparam.h"
     24 #include "xfa/fxfa/parser/xfa_localevalue.h"
     25 #include "xfa/fxfa/xfa_ffapp.h"
     26 #include "xfa/fxfa/xfa_ffdoc.h"
     27 #include "xfa/fxfa/xfa_ffdocview.h"
     28 #include "xfa/fxfa/xfa_ffpageview.h"
     29 #include "xfa/fxfa/xfa_ffwidget.h"
     30 
     31 CXFA_FFTextEdit::CXFA_FFTextEdit(CXFA_WidgetAcc* pDataAcc)
     32     : CXFA_FFField(pDataAcc), m_pOldDelegate(nullptr) {}
     33 
     34 CXFA_FFTextEdit::~CXFA_FFTextEdit() {
     35   if (m_pNormalWidget) {
     36     CFWL_NoteDriver* pNoteDriver =
     37         m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
     38     pNoteDriver->UnregisterEventTarget(m_pNormalWidget);
     39   }
     40 }
     41 
     42 bool CXFA_FFTextEdit::LoadWidget() {
     43   CFWL_Edit* pFWLEdit = new CFWL_Edit(
     44       GetFWLApp(), pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr);
     45   m_pNormalWidget = pFWLEdit;
     46   m_pNormalWidget->SetLayoutItem(this);
     47 
     48   CFWL_NoteDriver* pNoteDriver =
     49       m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
     50   pNoteDriver->RegisterEventTarget(m_pNormalWidget, m_pNormalWidget);
     51 
     52   m_pOldDelegate = m_pNormalWidget->GetDelegate();
     53   m_pNormalWidget->SetDelegate(this);
     54   m_pNormalWidget->LockUpdate();
     55 
     56   UpdateWidgetProperty();
     57   CFX_WideString wsText;
     58   m_pDataAcc->GetValue(wsText, XFA_VALUEPICTURE_Display);
     59   pFWLEdit->SetText(wsText);
     60   m_pNormalWidget->UnlockUpdate();
     61   return CXFA_FFField::LoadWidget();
     62 }
     63 void CXFA_FFTextEdit::UpdateWidgetProperty() {
     64   CFWL_Edit* pWidget = (CFWL_Edit*)m_pNormalWidget;
     65   if (!pWidget) {
     66     return;
     67   }
     68   uint32_t dwStyle = 0;
     69   uint32_t dwExtendedStyle = FWL_STYLEEXT_EDT_ShowScrollbarFocus |
     70                              FWL_STYLEEXT_EDT_OuterScrollbar |
     71                              FWL_STYLEEXT_EDT_LastLineHeight;
     72   dwExtendedStyle |= UpdateUIProperty();
     73   if (m_pDataAcc->IsMultiLine()) {
     74     dwExtendedStyle |= FWL_STYLEEXT_EDT_MultiLine | FWL_STYLEEXT_EDT_WantReturn;
     75     if (m_pDataAcc->GetVerticalScrollPolicy() != XFA_ATTRIBUTEENUM_Off) {
     76       dwStyle |= FWL_WGTSTYLE_VScroll;
     77       dwExtendedStyle |= FWL_STYLEEXT_EDT_AutoVScroll;
     78     }
     79   } else if (m_pDataAcc->GetHorizontalScrollPolicy() != XFA_ATTRIBUTEENUM_Off) {
     80     dwExtendedStyle |= FWL_STYLEEXT_EDT_AutoHScroll;
     81   }
     82   if (m_pDataAcc->GetAccess() != XFA_ATTRIBUTEENUM_Open ||
     83       !m_pDataAcc->GetDoc()->GetXFADoc()->IsInteractive()) {
     84     dwExtendedStyle |= FWL_STYLEEXT_EDT_ReadOnly;
     85     dwExtendedStyle |= FWL_STYLEEXT_EDT_MultiLine;
     86   }
     87   XFA_Element eType = XFA_Element::Unknown;
     88   int32_t iMaxChars = m_pDataAcc->GetMaxChars(eType);
     89   if (eType == XFA_Element::ExData) {
     90     iMaxChars = 0;
     91   }
     92   int32_t iNumCells = m_pDataAcc->GetNumberOfCells();
     93   if (iNumCells == 0) {
     94     dwExtendedStyle |= FWL_STYLEEXT_EDT_CombText;
     95     pWidget->SetLimit(iMaxChars > 0 ? iMaxChars : 1);
     96   } else if (iNumCells > 0) {
     97     dwExtendedStyle |= FWL_STYLEEXT_EDT_CombText;
     98     pWidget->SetLimit(iNumCells);
     99   } else {
    100     pWidget->SetLimit(iMaxChars);
    101   }
    102   dwExtendedStyle |= GetAlignment();
    103   m_pNormalWidget->ModifyStyles(dwStyle, 0xFFFFFFFF);
    104   m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
    105 }
    106 
    107 bool CXFA_FFTextEdit::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
    108   if (!PtInActiveRect(point))
    109     return false;
    110   if (!IsFocused()) {
    111     m_dwStatus |= XFA_WidgetStatus_Focused;
    112     UpdateFWLData();
    113     AddInvalidateRect();
    114   }
    115 
    116   SetButtonDown(true);
    117   CFWL_MessageMouse ms(nullptr, m_pNormalWidget);
    118   ms.m_dwCmd = FWL_MouseCommand::LeftButtonDown;
    119   ms.m_dwFlags = dwFlags;
    120   ms.m_pos = FWLToClient(point);
    121   TranslateFWLMessage(&ms);
    122   return true;
    123 }
    124 
    125 bool CXFA_FFTextEdit::OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
    126   if (m_pDataAcc->GetAccess() != XFA_ATTRIBUTEENUM_Open)
    127     return false;
    128   if (!PtInActiveRect(point))
    129     return false;
    130   if (!IsFocused()) {
    131     m_dwStatus |= XFA_WidgetStatus_Focused;
    132     UpdateFWLData();
    133     AddInvalidateRect();
    134   }
    135 
    136   SetButtonDown(true);
    137   CFWL_MessageMouse ms(nullptr, nullptr);
    138   ms.m_dwCmd = FWL_MouseCommand::RightButtonDown;
    139   ms.m_dwFlags = dwFlags;
    140   ms.m_pos = FWLToClient(point);
    141   TranslateFWLMessage(&ms);
    142   return true;
    143 }
    144 
    145 bool CXFA_FFTextEdit::OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
    146   if (!CXFA_FFField::OnRButtonUp(dwFlags, point))
    147     return false;
    148 
    149   GetDoc()->GetDocEnvironment()->PopupMenu(this, point);
    150   return true;
    151 }
    152 
    153 bool CXFA_FFTextEdit::OnSetFocus(CXFA_FFWidget* pOldWidget) {
    154   m_dwStatus &= ~XFA_WidgetStatus_TextEditValueChanged;
    155   if (!IsFocused()) {
    156     m_dwStatus |= XFA_WidgetStatus_Focused;
    157     UpdateFWLData();
    158     AddInvalidateRect();
    159   }
    160   CXFA_FFWidget::OnSetFocus(pOldWidget);
    161   CFWL_MessageSetFocus ms(nullptr, m_pNormalWidget);
    162   TranslateFWLMessage(&ms);
    163   return true;
    164 }
    165 bool CXFA_FFTextEdit::OnKillFocus(CXFA_FFWidget* pNewWidget) {
    166   CFWL_MessageKillFocus ms(nullptr, m_pNormalWidget);
    167   TranslateFWLMessage(&ms);
    168   m_dwStatus &= ~XFA_WidgetStatus_Focused;
    169   SetEditScrollOffset();
    170   ProcessCommittedData();
    171   UpdateFWLData();
    172   AddInvalidateRect();
    173   CXFA_FFWidget::OnKillFocus(pNewWidget);
    174   m_dwStatus &= ~XFA_WidgetStatus_TextEditValueChanged;
    175   return true;
    176 }
    177 bool CXFA_FFTextEdit::CommitData() {
    178   CFX_WideString wsText = static_cast<CFWL_Edit*>(m_pNormalWidget)->GetText();
    179   if (m_pDataAcc->SetValue(wsText, XFA_VALUEPICTURE_Edit)) {
    180     m_pDataAcc->UpdateUIDisplay(this);
    181     return true;
    182   }
    183   ValidateNumberField(wsText);
    184   return false;
    185 }
    186 void CXFA_FFTextEdit::ValidateNumberField(const CFX_WideString& wsText) {
    187   CXFA_WidgetAcc* pAcc = GetDataAcc();
    188   if (pAcc && pAcc->GetUIType() == XFA_Element::NumericEdit) {
    189     IXFA_AppProvider* pAppProvider = GetApp()->GetAppProvider();
    190     if (pAppProvider) {
    191       CFX_WideString wsSomField;
    192       pAcc->GetNode()->GetSOMExpression(wsSomField);
    193 
    194       CFX_WideString wsMessage;
    195       wsMessage.Format(L"%s can not contain %s", wsText.c_str(),
    196                        wsSomField.c_str());
    197       pAppProvider->MsgBox(wsMessage, pAppProvider->GetAppTitle(),
    198                            XFA_MBICON_Error, XFA_MB_OK);
    199     }
    200   }
    201 }
    202 bool CXFA_FFTextEdit::IsDataChanged() {
    203   return (m_dwStatus & XFA_WidgetStatus_TextEditValueChanged) != 0;
    204 }
    205 uint32_t CXFA_FFTextEdit::GetAlignment() {
    206   uint32_t dwExtendedStyle = 0;
    207   if (CXFA_Para para = m_pDataAcc->GetPara()) {
    208     int32_t iHorz = para.GetHorizontalAlign();
    209     switch (iHorz) {
    210       case XFA_ATTRIBUTEENUM_Center:
    211         dwExtendedStyle |= FWL_STYLEEXT_EDT_HCenter;
    212         break;
    213       case XFA_ATTRIBUTEENUM_Justify:
    214         dwExtendedStyle |= FWL_STYLEEXT_EDT_Justified;
    215         break;
    216       case XFA_ATTRIBUTEENUM_JustifyAll:
    217         break;
    218       case XFA_ATTRIBUTEENUM_Radix:
    219         break;
    220       case XFA_ATTRIBUTEENUM_Right:
    221         dwExtendedStyle |= FWL_STYLEEXT_EDT_HFar;
    222         break;
    223       default:
    224         dwExtendedStyle |= FWL_STYLEEXT_EDT_HNear;
    225         break;
    226     }
    227     int32_t iVert = para.GetVerticalAlign();
    228     switch (iVert) {
    229       case XFA_ATTRIBUTEENUM_Middle:
    230         dwExtendedStyle |= FWL_STYLEEXT_EDT_VCenter;
    231         break;
    232       case XFA_ATTRIBUTEENUM_Bottom:
    233         dwExtendedStyle |= FWL_STYLEEXT_EDT_VFar;
    234         break;
    235       default:
    236         dwExtendedStyle |= FWL_STYLEEXT_EDT_VNear;
    237         break;
    238     }
    239   }
    240   return dwExtendedStyle;
    241 }
    242 bool CXFA_FFTextEdit::UpdateFWLData() {
    243   if (!m_pNormalWidget) {
    244     return false;
    245   }
    246   XFA_VALUEPICTURE eType = XFA_VALUEPICTURE_Display;
    247   if (IsFocused()) {
    248     eType = XFA_VALUEPICTURE_Edit;
    249   }
    250   bool bUpdate = false;
    251   if (m_pDataAcc->GetUIType() == XFA_Element::TextEdit &&
    252       m_pDataAcc->GetNumberOfCells() < 0) {
    253     XFA_Element elementType = XFA_Element::Unknown;
    254     int32_t iMaxChars = m_pDataAcc->GetMaxChars(elementType);
    255     if (elementType == XFA_Element::ExData) {
    256       iMaxChars = eType == XFA_VALUEPICTURE_Edit ? iMaxChars : 0;
    257     }
    258     if (((CFWL_Edit*)m_pNormalWidget)->GetLimit() != iMaxChars) {
    259       ((CFWL_Edit*)m_pNormalWidget)->SetLimit(iMaxChars);
    260       bUpdate = true;
    261     }
    262   }
    263   if (m_pDataAcc->GetUIType() == XFA_Element::Barcode) {
    264     int32_t nDataLen = 0;
    265     if (eType == XFA_VALUEPICTURE_Edit)
    266       m_pDataAcc->GetBarcodeAttribute_DataLength(nDataLen);
    267     static_cast<CFWL_Edit*>(m_pNormalWidget)->SetLimit(nDataLen);
    268     bUpdate = true;
    269   }
    270   CFX_WideString wsText;
    271   m_pDataAcc->GetValue(wsText, eType);
    272   CFX_WideString wsOldText =
    273       static_cast<CFWL_Edit*>(m_pNormalWidget)->GetText();
    274   if (wsText != wsOldText || (eType == XFA_VALUEPICTURE_Edit && bUpdate)) {
    275     ((CFWL_Edit*)m_pNormalWidget)->SetText(wsText);
    276     bUpdate = true;
    277   }
    278   if (bUpdate) {
    279     m_pNormalWidget->Update();
    280   }
    281   return true;
    282 }
    283 void CXFA_FFTextEdit::OnTextChanged(CFWL_Widget* pWidget,
    284                                     const CFX_WideString& wsChanged,
    285                                     const CFX_WideString& wsPrevText) {
    286   m_dwStatus |= XFA_WidgetStatus_TextEditValueChanged;
    287   CXFA_EventParam eParam;
    288   eParam.m_eType = XFA_EVENT_Change;
    289   eParam.m_wsChange = wsChanged;
    290   eParam.m_pTarget = m_pDataAcc;
    291   eParam.m_wsPrevText = wsPrevText;
    292   CFWL_Edit* pEdit = ((CFWL_Edit*)m_pNormalWidget);
    293   if (m_pDataAcc->GetUIType() == XFA_Element::DateTimeEdit) {
    294     CFWL_DateTimePicker* pDateTime = (CFWL_DateTimePicker*)pEdit;
    295     eParam.m_wsNewText = pDateTime->GetEditText();
    296     int32_t iSels = pDateTime->CountSelRanges();
    297     if (iSels) {
    298       eParam.m_iSelEnd = pDateTime->GetSelRange(0, &eParam.m_iSelStart);
    299     }
    300   } else {
    301     eParam.m_wsNewText = pEdit->GetText();
    302     int32_t iSels = pEdit->CountSelRanges();
    303     if (iSels) {
    304       eParam.m_iSelEnd = pEdit->GetSelRange(0, &eParam.m_iSelStart);
    305     }
    306   }
    307   m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_Change, &eParam);
    308 }
    309 void CXFA_FFTextEdit::OnTextFull(CFWL_Widget* pWidget) {
    310   CXFA_EventParam eParam;
    311   eParam.m_eType = XFA_EVENT_Full;
    312   eParam.m_pTarget = m_pDataAcc;
    313   m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_Full, &eParam);
    314 }
    315 
    316 bool CXFA_FFTextEdit::CheckWord(const CFX_ByteStringC& sWord) {
    317   if (sWord.IsEmpty() || m_pDataAcc->GetUIType() != XFA_Element::TextEdit)
    318     return true;
    319   return false;
    320 }
    321 
    322 void CXFA_FFTextEdit::OnProcessMessage(CFWL_Message* pMessage) {
    323   m_pOldDelegate->OnProcessMessage(pMessage);
    324 }
    325 
    326 void CXFA_FFTextEdit::OnProcessEvent(CFWL_Event* pEvent) {
    327   CXFA_FFField::OnProcessEvent(pEvent);
    328   switch (pEvent->GetType()) {
    329     case CFWL_Event::Type::TextChanged: {
    330       CFWL_EventTextChanged* event =
    331           static_cast<CFWL_EventTextChanged*>(pEvent);
    332       CFX_WideString wsChange;
    333       OnTextChanged(m_pNormalWidget, wsChange, event->wsPrevText);
    334       break;
    335     }
    336     case CFWL_Event::Type::TextFull: {
    337       OnTextFull(m_pNormalWidget);
    338       break;
    339     }
    340     case CFWL_Event::Type::CheckWord: {
    341       CFX_WideString wstr(L"FWL_EVENT_DTP_SelectChanged");
    342       CFWL_EventCheckWord* event = static_cast<CFWL_EventCheckWord*>(pEvent);
    343       event->bCheckWord = CheckWord(event->bsWord.AsStringC());
    344       break;
    345     }
    346     default:
    347       break;
    348   }
    349   m_pOldDelegate->OnProcessEvent(pEvent);
    350 }
    351 
    352 void CXFA_FFTextEdit::OnDrawWidget(CFX_Graphics* pGraphics,
    353                                    const CFX_Matrix* pMatrix) {
    354   m_pOldDelegate->OnDrawWidget(pGraphics, pMatrix);
    355 }
    356 
    357 CXFA_FFNumericEdit::CXFA_FFNumericEdit(CXFA_WidgetAcc* pDataAcc)
    358     : CXFA_FFTextEdit(pDataAcc) {}
    359 
    360 CXFA_FFNumericEdit::~CXFA_FFNumericEdit() {}
    361 
    362 bool CXFA_FFNumericEdit::LoadWidget() {
    363   CFWL_Edit* pWidget = new CFWL_Edit(
    364       GetFWLApp(), pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr);
    365   m_pNormalWidget = pWidget;
    366 
    367   m_pNormalWidget->SetLayoutItem(this);
    368   CFWL_NoteDriver* pNoteDriver =
    369       m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
    370   pNoteDriver->RegisterEventTarget(m_pNormalWidget, m_pNormalWidget);
    371 
    372   m_pOldDelegate = m_pNormalWidget->GetDelegate();
    373   m_pNormalWidget->SetDelegate(this);
    374   m_pNormalWidget->LockUpdate();
    375 
    376   CFX_WideString wsText;
    377   m_pDataAcc->GetValue(wsText, XFA_VALUEPICTURE_Display);
    378   pWidget->SetText(wsText);
    379   UpdateWidgetProperty();
    380   m_pNormalWidget->UnlockUpdate();
    381   return CXFA_FFField::LoadWidget();
    382 }
    383 void CXFA_FFNumericEdit::UpdateWidgetProperty() {
    384   CFWL_Edit* pWidget = (CFWL_Edit*)m_pNormalWidget;
    385   if (!pWidget) {
    386     return;
    387   }
    388   uint32_t dwExtendedStyle =
    389       FWL_STYLEEXT_EDT_ShowScrollbarFocus | FWL_STYLEEXT_EDT_OuterScrollbar |
    390       FWL_STYLEEXT_EDT_Validate | FWL_STYLEEXT_EDT_Number |
    391       FWL_STYLEEXT_EDT_LastLineHeight;
    392   dwExtendedStyle |= UpdateUIProperty();
    393   if (m_pDataAcc->GetHorizontalScrollPolicy() != XFA_ATTRIBUTEENUM_Off) {
    394     dwExtendedStyle |= FWL_STYLEEXT_EDT_AutoHScroll;
    395   }
    396   int32_t iNumCells = m_pDataAcc->GetNumberOfCells();
    397   if (iNumCells > 0) {
    398     dwExtendedStyle |= FWL_STYLEEXT_EDT_CombText;
    399     pWidget->SetLimit(iNumCells);
    400   }
    401   dwExtendedStyle |= GetAlignment();
    402   if (m_pDataAcc->GetAccess() != XFA_ATTRIBUTEENUM_Open ||
    403       !m_pDataAcc->GetDoc()->GetXFADoc()->IsInteractive()) {
    404     dwExtendedStyle |= FWL_STYLEEXT_EDT_ReadOnly;
    405   }
    406   m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
    407 }
    408 
    409 void CXFA_FFNumericEdit::OnProcessEvent(CFWL_Event* pEvent) {
    410   if (pEvent->GetType() == CFWL_Event::Type::Validate) {
    411     CFWL_EventValidate* event = static_cast<CFWL_EventValidate*>(pEvent);
    412     event->bValidate = OnValidate(m_pNormalWidget, event->wsInsert);
    413     return;
    414   }
    415   CXFA_FFTextEdit::OnProcessEvent(pEvent);
    416 }
    417 
    418 bool CXFA_FFNumericEdit::OnValidate(CFWL_Widget* pWidget,
    419                                     CFX_WideString& wsText) {
    420   CFX_WideString wsPattern;
    421   m_pDataAcc->GetPictureContent(wsPattern, XFA_VALUEPICTURE_Edit);
    422   if (!wsPattern.IsEmpty()) {
    423     return true;
    424   }
    425   int32_t iLeads = 0;
    426   m_pDataAcc->GetLeadDigits(iLeads);
    427   int32_t iFracs = 0;
    428   m_pDataAcc->GetFracDigits(iFracs);
    429   CFX_WideString wsFormat;
    430   CXFA_LocaleValue widgetValue = XFA_GetLocaleValue(m_pDataAcc);
    431   widgetValue.GetNumbericFormat(wsFormat, iLeads, iFracs);
    432   return widgetValue.ValidateNumericTemp(wsText, wsFormat,
    433                                          m_pDataAcc->GetLocal());
    434 }
    435 
    436 CXFA_FFPasswordEdit::CXFA_FFPasswordEdit(CXFA_WidgetAcc* pDataAcc)
    437     : CXFA_FFTextEdit(pDataAcc) {}
    438 
    439 CXFA_FFPasswordEdit::~CXFA_FFPasswordEdit() {}
    440 
    441 bool CXFA_FFPasswordEdit::LoadWidget() {
    442   CFWL_Edit* pWidget = new CFWL_Edit(
    443       GetFWLApp(), pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr);
    444   m_pNormalWidget = pWidget;
    445   m_pNormalWidget->SetLayoutItem(this);
    446 
    447   CFWL_NoteDriver* pNoteDriver =
    448       m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
    449   pNoteDriver->RegisterEventTarget(m_pNormalWidget, m_pNormalWidget);
    450 
    451   m_pOldDelegate = m_pNormalWidget->GetDelegate();
    452   m_pNormalWidget->SetDelegate(this);
    453   m_pNormalWidget->LockUpdate();
    454 
    455   CFX_WideString wsText;
    456   m_pDataAcc->GetValue(wsText, XFA_VALUEPICTURE_Display);
    457   pWidget->SetText(wsText);
    458   UpdateWidgetProperty();
    459   m_pNormalWidget->UnlockUpdate();
    460   return CXFA_FFField::LoadWidget();
    461 }
    462 void CXFA_FFPasswordEdit::UpdateWidgetProperty() {
    463   CFWL_Edit* pWidget = (CFWL_Edit*)m_pNormalWidget;
    464   if (!pWidget) {
    465     return;
    466   }
    467   uint32_t dwExtendedStyle =
    468       FWL_STYLEEXT_EDT_ShowScrollbarFocus | FWL_STYLEEXT_EDT_OuterScrollbar |
    469       FWL_STYLEEXT_EDT_Password | FWL_STYLEEXT_EDT_LastLineHeight;
    470   dwExtendedStyle |= UpdateUIProperty();
    471   CFX_WideString wsPassWord;
    472   m_pDataAcc->GetPasswordChar(wsPassWord);
    473   if (!wsPassWord.IsEmpty()) {
    474     pWidget->SetAliasChar(wsPassWord.GetAt(0));
    475   }
    476   if (m_pDataAcc->GetHorizontalScrollPolicy() != XFA_ATTRIBUTEENUM_Off) {
    477     dwExtendedStyle |= FWL_STYLEEXT_EDT_AutoHScroll;
    478   }
    479   if (m_pDataAcc->GetAccess() != XFA_ATTRIBUTEENUM_Open ||
    480       !m_pDataAcc->GetDoc()->GetXFADoc()->IsInteractive()) {
    481     dwExtendedStyle |= FWL_STYLEEXT_EDT_ReadOnly;
    482   }
    483   dwExtendedStyle |= GetAlignment();
    484   m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
    485 }
    486 CXFA_FFDateTimeEdit::CXFA_FFDateTimeEdit(CXFA_WidgetAcc* pDataAcc)
    487     : CXFA_FFTextEdit(pDataAcc) {}
    488 
    489 CXFA_FFDateTimeEdit::~CXFA_FFDateTimeEdit() {}
    490 
    491 CFX_RectF CXFA_FFDateTimeEdit::GetBBox(uint32_t dwStatus, bool bDrawFocus) {
    492   if (bDrawFocus)
    493     return CFX_RectF();
    494   return CXFA_FFWidget::GetBBox(dwStatus);
    495 }
    496 
    497 bool CXFA_FFDateTimeEdit::PtInActiveRect(const CFX_PointF& point) {
    498   return m_pNormalWidget &&
    499          static_cast<CFWL_DateTimePicker*>(m_pNormalWidget)
    500              ->GetBBox()
    501              .Contains(point);
    502 }
    503 
    504 bool CXFA_FFDateTimeEdit::LoadWidget() {
    505   CFWL_DateTimePicker* pWidget = new CFWL_DateTimePicker(GetFWLApp());
    506   m_pNormalWidget = pWidget;
    507   m_pNormalWidget->SetLayoutItem(this);
    508   CFWL_NoteDriver* pNoteDriver =
    509       m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
    510   pNoteDriver->RegisterEventTarget(m_pNormalWidget, m_pNormalWidget);
    511 
    512   m_pOldDelegate = m_pNormalWidget->GetDelegate();
    513   m_pNormalWidget->SetDelegate(this);
    514   m_pNormalWidget->LockUpdate();
    515 
    516   CFX_WideString wsText;
    517   m_pDataAcc->GetValue(wsText, XFA_VALUEPICTURE_Display);
    518   pWidget->SetEditText(wsText);
    519   if (CXFA_Value value = m_pDataAcc->GetFormValue()) {
    520     switch (value.GetChildValueClassID()) {
    521       case XFA_Element::Date: {
    522         if (!wsText.IsEmpty()) {
    523           CXFA_LocaleValue lcValue = XFA_GetLocaleValue(m_pDataAcc);
    524           CFX_Unitime date = lcValue.GetDate();
    525           if ((FX_UNITIME)date != 0) {
    526             pWidget->SetCurSel(date.GetYear(), date.GetMonth(), date.GetDay());
    527           }
    528         }
    529       } break;
    530       default:
    531         break;
    532     }
    533   }
    534   UpdateWidgetProperty();
    535   m_pNormalWidget->UnlockUpdate();
    536   return CXFA_FFField::LoadWidget();
    537 }
    538 void CXFA_FFDateTimeEdit::UpdateWidgetProperty() {
    539   CFWL_DateTimePicker* pWidget = (CFWL_DateTimePicker*)m_pNormalWidget;
    540   if (!pWidget) {
    541     return;
    542   }
    543   uint32_t dwExtendedStyle = FWL_STYLEEXT_DTP_ShortDateFormat;
    544   dwExtendedStyle |= UpdateUIProperty();
    545   dwExtendedStyle |= GetAlignment();
    546   m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
    547   uint32_t dwEditStyles = FWL_STYLEEXT_EDT_LastLineHeight;
    548   int32_t iNumCells = m_pDataAcc->GetNumberOfCells();
    549   if (iNumCells > 0) {
    550     dwEditStyles |= FWL_STYLEEXT_EDT_CombText;
    551     pWidget->SetEditLimit(iNumCells);
    552   }
    553   if (m_pDataAcc->GetAccess() != XFA_ATTRIBUTEENUM_Open ||
    554       !m_pDataAcc->GetDoc()->GetXFADoc()->IsInteractive()) {
    555     dwEditStyles |= FWL_STYLEEXT_EDT_ReadOnly;
    556   }
    557   if (m_pDataAcc->GetHorizontalScrollPolicy() != XFA_ATTRIBUTEENUM_Off) {
    558     dwEditStyles |= FWL_STYLEEXT_EDT_AutoHScroll;
    559   }
    560   pWidget->ModifyEditStylesEx(dwEditStyles, 0xFFFFFFFF);
    561 }
    562 uint32_t CXFA_FFDateTimeEdit::GetAlignment() {
    563   uint32_t dwExtendedStyle = 0;
    564   if (CXFA_Para para = m_pDataAcc->GetPara()) {
    565     int32_t iHorz = para.GetHorizontalAlign();
    566     switch (iHorz) {
    567       case XFA_ATTRIBUTEENUM_Center:
    568         dwExtendedStyle |= FWL_STYLEEXT_DTP_EditHCenter;
    569         break;
    570       case XFA_ATTRIBUTEENUM_Justify:
    571         dwExtendedStyle |= FWL_STYLEEXT_DTP_EditJustified;
    572         break;
    573       case XFA_ATTRIBUTEENUM_JustifyAll:
    574         break;
    575       case XFA_ATTRIBUTEENUM_Radix:
    576         break;
    577       case XFA_ATTRIBUTEENUM_Right:
    578         dwExtendedStyle |= FWL_STYLEEXT_DTP_EditHFar;
    579         break;
    580       default:
    581         dwExtendedStyle |= FWL_STYLEEXT_DTP_EditHNear;
    582         break;
    583     }
    584     int32_t iVert = para.GetVerticalAlign();
    585     switch (iVert) {
    586       case XFA_ATTRIBUTEENUM_Middle:
    587         dwExtendedStyle |= FWL_STYLEEXT_DTP_EditVCenter;
    588         break;
    589       case XFA_ATTRIBUTEENUM_Bottom:
    590         dwExtendedStyle |= FWL_STYLEEXT_DTP_EditVFar;
    591         break;
    592       default:
    593         dwExtendedStyle |= FWL_STYLEEXT_DTP_EditVNear;
    594         break;
    595     }
    596   }
    597   return dwExtendedStyle;
    598 }
    599 bool CXFA_FFDateTimeEdit::CommitData() {
    600   CFX_WideString wsText =
    601       static_cast<CFWL_DateTimePicker*>(m_pNormalWidget)->GetEditText();
    602   if (m_pDataAcc->SetValue(wsText, XFA_VALUEPICTURE_Edit)) {
    603     m_pDataAcc->UpdateUIDisplay(this);
    604     return true;
    605   }
    606   return false;
    607 }
    608 bool CXFA_FFDateTimeEdit::UpdateFWLData() {
    609   if (!m_pNormalWidget) {
    610     return false;
    611   }
    612   XFA_VALUEPICTURE eType = XFA_VALUEPICTURE_Display;
    613   if (IsFocused()) {
    614     eType = XFA_VALUEPICTURE_Edit;
    615   }
    616   CFX_WideString wsText;
    617   m_pDataAcc->GetValue(wsText, eType);
    618   ((CFWL_DateTimePicker*)m_pNormalWidget)->SetEditText(wsText);
    619   if (IsFocused() && !wsText.IsEmpty()) {
    620     CXFA_LocaleValue lcValue = XFA_GetLocaleValue(m_pDataAcc);
    621     CFX_Unitime date = lcValue.GetDate();
    622     if (lcValue.IsValid()) {
    623       if ((FX_UNITIME)date != 0) {
    624         ((CFWL_DateTimePicker*)m_pNormalWidget)
    625             ->SetCurSel(date.GetYear(), date.GetMonth(), date.GetDay());
    626       }
    627     }
    628   }
    629   m_pNormalWidget->Update();
    630   return true;
    631 }
    632 bool CXFA_FFDateTimeEdit::IsDataChanged() {
    633   if (m_dwStatus & XFA_WidgetStatus_TextEditValueChanged) {
    634     return true;
    635   }
    636   CFX_WideString wsText =
    637       static_cast<CFWL_DateTimePicker*>(m_pNormalWidget)->GetEditText();
    638   CFX_WideString wsOldValue;
    639   m_pDataAcc->GetValue(wsOldValue, XFA_VALUEPICTURE_Edit);
    640   return wsOldValue != wsText;
    641 }
    642 
    643 void CXFA_FFDateTimeEdit::OnSelectChanged(CFWL_Widget* pWidget,
    644                                           int32_t iYear,
    645                                           int32_t iMonth,
    646                                           int32_t iDay) {
    647   CFX_WideString wsPicture;
    648   m_pDataAcc->GetPictureContent(wsPicture, XFA_VALUEPICTURE_Edit);
    649   CXFA_LocaleValue date(XFA_VT_DATE, GetDoc()->GetXFADoc()->GetLocalMgr());
    650   CFX_Unitime dt;
    651   dt.Set(iYear, iMonth, iDay);
    652   date.SetDate(dt);
    653   CFX_WideString wsDate;
    654   date.FormatPatterns(wsDate, wsPicture, m_pDataAcc->GetLocal(),
    655                       XFA_VALUEPICTURE_Edit);
    656   CFWL_DateTimePicker* pDateTime = (CFWL_DateTimePicker*)m_pNormalWidget;
    657   pDateTime->SetEditText(wsDate);
    658   pDateTime->Update();
    659   GetDoc()->GetDocEnvironment()->SetFocusWidget(GetDoc(), nullptr);
    660   CXFA_EventParam eParam;
    661   eParam.m_eType = XFA_EVENT_Change;
    662   eParam.m_pTarget = m_pDataAcc;
    663   m_pDataAcc->GetValue(eParam.m_wsNewText, XFA_VALUEPICTURE_Raw);
    664   m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_Change, &eParam);
    665 }
    666 
    667 void CXFA_FFDateTimeEdit::OnProcessEvent(CFWL_Event* pEvent) {
    668   if (pEvent->GetType() == CFWL_Event::Type::SelectChanged) {
    669     CFWL_EventSelectChanged* event =
    670         static_cast<CFWL_EventSelectChanged*>(pEvent);
    671     OnSelectChanged(m_pNormalWidget, event->iYear, event->iMonth, event->iDay);
    672     return;
    673   }
    674   CXFA_FFTextEdit::OnProcessEvent(pEvent);
    675 }
    676