| // Copyright 2017 The PDFium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 
 |  | 
 | #include "xfa/fxfa/cxfa_ffdatetimeedit.h" | 
 |  | 
 | #include "core/fxcrt/cfx_datetime.h" | 
 | #include "core/fxcrt/check.h" | 
 | #include "xfa/fwl/cfwl_datetimepicker.h" | 
 | #include "xfa/fwl/cfwl_eventselectchanged.h" | 
 | #include "xfa/fwl/cfwl_notedriver.h" | 
 | #include "xfa/fwl/cfwl_widget.h" | 
 | #include "xfa/fxfa/cxfa_eventparam.h" | 
 | #include "xfa/fxfa/cxfa_ffdoc.h" | 
 | #include "xfa/fxfa/cxfa_ffdocview.h" | 
 | #include "xfa/fxfa/parser/cxfa_localevalue.h" | 
 | #include "xfa/fxfa/parser/cxfa_para.h" | 
 | #include "xfa/fxfa/parser/cxfa_value.h" | 
 | #include "xfa/fxfa/parser/xfa_utils.h" | 
 |  | 
 | CXFA_FFDateTimeEdit::CXFA_FFDateTimeEdit(CXFA_Node* pNode) | 
 |     : CXFA_FFTextEdit(pNode) {} | 
 |  | 
 | CXFA_FFDateTimeEdit::~CXFA_FFDateTimeEdit() = default; | 
 |  | 
 | CFWL_DateTimePicker* CXFA_FFDateTimeEdit::GetPickerWidget() { | 
 |   return static_cast<CFWL_DateTimePicker*>(GetNormalWidget()); | 
 | } | 
 |  | 
 | CFX_RectF CXFA_FFDateTimeEdit::GetBBox(FocusOption focus) { | 
 |   if (focus == kDrawFocus) | 
 |     return CFX_RectF(); | 
 |   return CXFA_FFWidget::GetBBox(kDoNotDrawFocus); | 
 | } | 
 |  | 
 | bool CXFA_FFDateTimeEdit::PtInActiveRect(const CFX_PointF& point) { | 
 |   CFWL_DateTimePicker* pPicker = GetPickerWidget(); | 
 |   return pPicker && pPicker->GetBBox().Contains(point); | 
 | } | 
 |  | 
 | bool CXFA_FFDateTimeEdit::LoadWidget() { | 
 |   DCHECK(!IsLoaded()); | 
 |  | 
 |   CFWL_DateTimePicker* pWidget = | 
 |       cppgc::MakeGarbageCollected<CFWL_DateTimePicker>( | 
 |           GetFWLApp()->GetHeap()->GetAllocationHandle(), GetFWLApp()); | 
 |   SetNormalWidget(pWidget); | 
 |   pWidget->SetAdapterIface(this); | 
 |  | 
 |   CFWL_NoteDriver* pNoteDriver = pWidget->GetFWLApp()->GetNoteDriver(); | 
 |   pNoteDriver->RegisterEventTarget(pWidget, pWidget); | 
 |   m_pOldDelegate = pWidget->GetDelegate(); | 
 |   pWidget->SetDelegate(this); | 
 |  | 
 |   { | 
 |     CFWL_Widget::ScopedUpdateLock update_lock(pWidget); | 
 |     WideString wsText = m_pNode->GetValue(XFA_ValuePicture::kDisplay); | 
 |     pWidget->SetEditText(wsText); | 
 |  | 
 |     CXFA_Value* value = m_pNode->GetFormValueIfExists(); | 
 |     if (value) { | 
 |       switch (value->GetChildValueClassID()) { | 
 |         case XFA_Element::Date: { | 
 |           if (!wsText.IsEmpty()) { | 
 |             CXFA_LocaleValue lcValue = XFA_GetLocaleValue(m_pNode.Get()); | 
 |             CFX_DateTime date = lcValue.GetDate(); | 
 |             if (date.IsSet()) | 
 |               pWidget->SetCurSel(date.GetYear(), date.GetMonth(), | 
 |                                  date.GetDay()); | 
 |           } | 
 |         } break; | 
 |         default: | 
 |           break; | 
 |       } | 
 |     } | 
 |     UpdateWidgetProperty(); | 
 |   } | 
 |  | 
 |   return CXFA_FFField::LoadWidget(); | 
 | } | 
 |  | 
 | void CXFA_FFDateTimeEdit::UpdateWidgetProperty() { | 
 |   CFWL_DateTimePicker* pPicker = GetPickerWidget(); | 
 |   if (!pPicker) | 
 |     return; | 
 |  | 
 |   uint32_t dwExtendedStyle = FWL_STYLEEXT_DTP_ShortDateFormat; | 
 |   dwExtendedStyle |= UpdateUIProperty(); | 
 |   dwExtendedStyle |= GetAlignment(); | 
 |   GetNormalWidget()->ModifyStyleExts(dwExtendedStyle, 0xFFFFFFFF); | 
 |  | 
 |   uint32_t dwEditStyles = 0; | 
 |   std::optional<int32_t> numCells = m_pNode->GetNumberOfCells(); | 
 |   if (numCells.has_value() && numCells.value() > 0) { | 
 |     dwEditStyles |= FWL_STYLEEXT_EDT_CombText; | 
 |     pPicker->SetEditLimit(numCells.value()); | 
 |   } | 
 |   if (!m_pNode->IsOpenAccess() || !GetDoc()->GetXFADoc()->IsInteractive()) | 
 |     dwEditStyles |= FWL_STYLEEXT_EDT_ReadOnly; | 
 |   if (!m_pNode->IsHorizontalScrollPolicyOff()) | 
 |     dwEditStyles |= FWL_STYLEEXT_EDT_AutoHScroll; | 
 |  | 
 |   pPicker->ModifyEditStyleExts(dwEditStyles, 0xFFFFFFFF); | 
 | } | 
 |  | 
 | uint32_t CXFA_FFDateTimeEdit::GetAlignment() { | 
 |   CXFA_Para* para = m_pNode->GetParaIfExists(); | 
 |   if (!para) | 
 |     return 0; | 
 |  | 
 |   uint32_t dwExtendedStyle = 0; | 
 |   switch (para->GetHorizontalAlign()) { | 
 |     case XFA_AttributeValue::Center: | 
 |       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditHCenter; | 
 |       break; | 
 |     case XFA_AttributeValue::Justify: | 
 |       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditJustified; | 
 |       break; | 
 |     case XFA_AttributeValue::JustifyAll: | 
 |     case XFA_AttributeValue::Radix: | 
 |       break; | 
 |     case XFA_AttributeValue::Right: | 
 |       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditHFar; | 
 |       break; | 
 |     default: | 
 |       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditHNear; | 
 |       break; | 
 |   } | 
 |  | 
 |   switch (para->GetVerticalAlign()) { | 
 |     case XFA_AttributeValue::Middle: | 
 |       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditVCenter; | 
 |       break; | 
 |     case XFA_AttributeValue::Bottom: | 
 |       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditVFar; | 
 |       break; | 
 |     default: | 
 |       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditVNear; | 
 |       break; | 
 |   } | 
 |   return dwExtendedStyle; | 
 | } | 
 |  | 
 | bool CXFA_FFDateTimeEdit::CommitData() { | 
 |   CFWL_DateTimePicker* pPicker = GetPickerWidget(); | 
 |   if (!m_pNode->SetValue(XFA_ValuePicture::kEdit, pPicker->GetEditText())) | 
 |     return false; | 
 |  | 
 |   GetDoc()->GetDocView()->UpdateUIDisplay(m_pNode.Get(), this); | 
 |   return true; | 
 | } | 
 |  | 
 | bool CXFA_FFDateTimeEdit::UpdateFWLData() { | 
 |   if (!GetNormalWidget()) | 
 |     return false; | 
 |  | 
 |   XFA_ValuePicture eType = XFA_ValuePicture::kDisplay; | 
 |   if (IsFocused()) | 
 |     eType = XFA_ValuePicture::kEdit; | 
 |  | 
 |   WideString wsText = m_pNode->GetValue(eType); | 
 |   CFWL_DateTimePicker* pPicker = GetPickerWidget(); | 
 |   pPicker->SetEditText(wsText); | 
 |   if (IsFocused() && !wsText.IsEmpty()) { | 
 |     CXFA_LocaleValue lcValue = XFA_GetLocaleValue(m_pNode.Get()); | 
 |     CFX_DateTime date = lcValue.GetDate(); | 
 |     if (lcValue.IsValid()) { | 
 |       if (date.IsSet()) | 
 |         pPicker->SetCurSel(date.GetYear(), date.GetMonth(), date.GetDay()); | 
 |     } | 
 |   } | 
 |   GetNormalWidget()->Update(); | 
 |   return true; | 
 | } | 
 |  | 
 | bool CXFA_FFDateTimeEdit::IsDataChanged() { | 
 |   if (GetLayoutItem()->TestStatusBits(XFA_WidgetStatus::kTextEditValueChanged)) | 
 |     return true; | 
 |  | 
 |   WideString wsText = GetPickerWidget()->GetEditText(); | 
 |   return m_pNode->GetValue(XFA_ValuePicture::kEdit) != wsText; | 
 | } | 
 |  | 
 | void CXFA_FFDateTimeEdit::OnSelectChanged(CFWL_Widget* pWidget, | 
 |                                           int32_t iYear, | 
 |                                           int32_t iMonth, | 
 |                                           int32_t iDay) { | 
 |   WideString wsPicture = m_pNode->GetPictureContent(XFA_ValuePicture::kEdit); | 
 |   CXFA_LocaleValue date(CXFA_LocaleValue::ValueType::kDate, | 
 |                         GetDoc()->GetXFADoc()->GetLocaleMgr()); | 
 |   date.SetDate(CFX_DateTime(iYear, iMonth, iDay, 0, 0, 0, 0)); | 
 |  | 
 |   WideString wsDate; | 
 |   date.FormatPatterns(wsDate, wsPicture, m_pNode->GetLocale(), | 
 |                       XFA_ValuePicture::kEdit); | 
 |  | 
 |   CFWL_DateTimePicker* pPicker = GetPickerWidget(); | 
 |   pPicker->SetEditText(wsDate); | 
 |   pPicker->Update(); | 
 |   GetDoc()->SetFocusWidget(nullptr); | 
 |  | 
 |   CXFA_EventParam eParam(XFA_EVENT_Unknown); | 
 |   eParam.m_eType = XFA_EVENT_Change; | 
 |   eParam.m_wsPrevText = m_pNode->GetValue(XFA_ValuePicture::kRaw); | 
 |   m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Change, &eParam); | 
 | } | 
 |  | 
 | void CXFA_FFDateTimeEdit::OnProcessEvent(CFWL_Event* pEvent) { | 
 |   if (pEvent->GetType() == CFWL_Event::Type::SelectChanged) { | 
 |     auto* event = static_cast<CFWL_EventSelectChanged*>(pEvent); | 
 |     OnSelectChanged(GetNormalWidget(), event->GetYear(), event->GetMonth(), | 
 |                     event->GetDay()); | 
 |     return; | 
 |   } | 
 |   CXFA_FFTextEdit::OnProcessEvent(pEvent); | 
 | } | 
 |  | 
 | bool CXFA_FFDateTimeEdit::CanUndo() { | 
 |   return GetPickerWidget()->CanUndo(); | 
 | } | 
 |  | 
 | bool CXFA_FFDateTimeEdit::CanRedo() { | 
 |   return GetPickerWidget()->CanRedo(); | 
 | } | 
 |  | 
 | bool CXFA_FFDateTimeEdit::CanCopy() { | 
 |   return GetPickerWidget()->HasSelection(); | 
 | } | 
 |  | 
 | bool CXFA_FFDateTimeEdit::CanCut() { | 
 |   if (GetPickerWidget()->GetStyleExts() & FWL_STYLEEXT_EDT_ReadOnly) | 
 |     return false; | 
 |   return GetPickerWidget()->HasSelection(); | 
 | } | 
 |  | 
 | bool CXFA_FFDateTimeEdit::CanPaste() { | 
 |   return !(GetPickerWidget()->GetStyleExts() & FWL_STYLEEXT_EDT_ReadOnly); | 
 | } | 
 |  | 
 | bool CXFA_FFDateTimeEdit::CanSelectAll() { | 
 |   return GetPickerWidget()->GetEditTextLength() > 0; | 
 | } | 
 |  | 
 | std::optional<WideString> CXFA_FFDateTimeEdit::Copy() { | 
 |   return GetPickerWidget()->Copy(); | 
 | } | 
 |  | 
 | bool CXFA_FFDateTimeEdit::Undo() { | 
 |   return GetPickerWidget()->Undo(); | 
 | } | 
 |  | 
 | bool CXFA_FFDateTimeEdit::Redo() { | 
 |   return GetPickerWidget()->Redo(); | 
 | } | 
 |  | 
 | std::optional<WideString> CXFA_FFDateTimeEdit::Cut() { | 
 |   return GetPickerWidget()->Cut(); | 
 | } | 
 |  | 
 | bool CXFA_FFDateTimeEdit::Paste(const WideString& wsPaste) { | 
 |   return GetPickerWidget()->Paste(wsPaste); | 
 | } | 
 |  | 
 | void CXFA_FFDateTimeEdit::SelectAll() { | 
 |   GetPickerWidget()->SelectAll(); | 
 | } | 
 |  | 
 | void CXFA_FFDateTimeEdit::Delete() { | 
 |   GetPickerWidget()->ClearText(); | 
 | } | 
 |  | 
 | void CXFA_FFDateTimeEdit::DeSelect() { | 
 |   GetPickerWidget()->ClearSelection(); | 
 | } | 
 |  | 
 | WideString CXFA_FFDateTimeEdit::GetText() { | 
 |   return GetPickerWidget()->GetEditText(); | 
 | } |