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_ffdatetimeedit.h"
8
9#include <utility>
10
11#include "xfa/fwl/cfwl_datetimepicker.h"
12#include "xfa/fwl/cfwl_eventselectchanged.h"
13#include "xfa/fwl/cfwl_notedriver.h"
14#include "xfa/fwl/cfwl_widget.h"
15#include "xfa/fxfa/cxfa_eventparam.h"
16#include "xfa/fxfa/cxfa_ffdoc.h"
17#include "xfa/fxfa/parser/cxfa_localevalue.h"
18#include "xfa/fxfa/parser/cxfa_para.h"
19#include "xfa/fxfa/parser/cxfa_value.h"
20#include "xfa/fxfa/parser/xfa_utils.h"
21
22CXFA_FFDateTimeEdit::CXFA_FFDateTimeEdit(CXFA_Node* pNode)
23    : CXFA_FFTextEdit(pNode) {}
24
25CXFA_FFDateTimeEdit::~CXFA_FFDateTimeEdit() {}
26
27CFX_RectF CXFA_FFDateTimeEdit::GetBBox(uint32_t dwStatus, bool bDrawFocus) {
28  if (bDrawFocus)
29    return CFX_RectF();
30  return CXFA_FFWidget::GetBBox(dwStatus);
31}
32
33bool CXFA_FFDateTimeEdit::PtInActiveRect(const CFX_PointF& point) {
34  auto* pPicker = static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get());
35  return pPicker && pPicker->GetBBox().Contains(point);
36}
37
38bool CXFA_FFDateTimeEdit::LoadWidget() {
39  auto pNewPicker = pdfium::MakeUnique<CFWL_DateTimePicker>(GetFWLApp());
40  CFWL_DateTimePicker* pWidget = pNewPicker.get();
41  m_pNormalWidget = std::move(pNewPicker);
42  m_pNormalWidget->SetLayoutItem(this);
43
44  CFWL_NoteDriver* pNoteDriver =
45      m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
46  pNoteDriver->RegisterEventTarget(m_pNormalWidget.get(),
47                                   m_pNormalWidget.get());
48  m_pOldDelegate = m_pNormalWidget->GetDelegate();
49  m_pNormalWidget->SetDelegate(this);
50  m_pNormalWidget->LockUpdate();
51
52  WideString wsText =
53      m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Display);
54  pWidget->SetEditText(wsText);
55
56  CXFA_Value* value = m_pNode->GetFormValueIfExists();
57  if (value) {
58    switch (value->GetChildValueClassID()) {
59      case XFA_Element::Date: {
60        if (!wsText.IsEmpty()) {
61          CXFA_LocaleValue lcValue = XFA_GetLocaleValue(m_pNode.Get());
62          CFX_DateTime date = lcValue.GetDate();
63          if (date.IsSet())
64            pWidget->SetCurSel(date.GetYear(), date.GetMonth(), date.GetDay());
65        }
66      } break;
67      default:
68        break;
69    }
70  }
71  UpdateWidgetProperty();
72  m_pNormalWidget->UnlockUpdate();
73  return CXFA_FFField::LoadWidget();
74}
75
76void CXFA_FFDateTimeEdit::UpdateWidgetProperty() {
77  CFWL_DateTimePicker* pWidget =
78      static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get());
79  if (!pWidget)
80    return;
81
82  uint32_t dwExtendedStyle = FWL_STYLEEXT_DTP_ShortDateFormat;
83  dwExtendedStyle |= UpdateUIProperty();
84  dwExtendedStyle |= GetAlignment();
85  m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
86
87  uint32_t dwEditStyles = 0;
88  Optional<int32_t> numCells = m_pNode->GetWidgetAcc()->GetNumberOfCells();
89  if (numCells && *numCells > 0) {
90    dwEditStyles |= FWL_STYLEEXT_EDT_CombText;
91    pWidget->SetEditLimit(*numCells);
92  }
93  if (!m_pNode->IsOpenAccess() || !GetDoc()->GetXFADoc()->IsInteractive())
94    dwEditStyles |= FWL_STYLEEXT_EDT_ReadOnly;
95  if (!m_pNode->GetWidgetAcc()->IsHorizontalScrollPolicyOff())
96    dwEditStyles |= FWL_STYLEEXT_EDT_AutoHScroll;
97
98  pWidget->ModifyEditStylesEx(dwEditStyles, 0xFFFFFFFF);
99}
100
101uint32_t CXFA_FFDateTimeEdit::GetAlignment() {
102  CXFA_Para* para = m_pNode->GetParaIfExists();
103  if (!para)
104    return 0;
105
106  uint32_t dwExtendedStyle = 0;
107  switch (para->GetHorizontalAlign()) {
108    case XFA_AttributeEnum::Center:
109      dwExtendedStyle |= FWL_STYLEEXT_DTP_EditHCenter;
110      break;
111    case XFA_AttributeEnum::Justify:
112      dwExtendedStyle |= FWL_STYLEEXT_DTP_EditJustified;
113      break;
114    case XFA_AttributeEnum::JustifyAll:
115    case XFA_AttributeEnum::Radix:
116      break;
117    case XFA_AttributeEnum::Right:
118      dwExtendedStyle |= FWL_STYLEEXT_DTP_EditHFar;
119      break;
120    default:
121      dwExtendedStyle |= FWL_STYLEEXT_DTP_EditHNear;
122      break;
123  }
124
125  switch (para->GetVerticalAlign()) {
126    case XFA_AttributeEnum::Middle:
127      dwExtendedStyle |= FWL_STYLEEXT_DTP_EditVCenter;
128      break;
129    case XFA_AttributeEnum::Bottom:
130      dwExtendedStyle |= FWL_STYLEEXT_DTP_EditVFar;
131      break;
132    default:
133      dwExtendedStyle |= FWL_STYLEEXT_DTP_EditVNear;
134      break;
135  }
136  return dwExtendedStyle;
137}
138
139bool CXFA_FFDateTimeEdit::CommitData() {
140  auto* pPicker = static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get());
141  if (!m_pNode->GetWidgetAcc()->SetValue(XFA_VALUEPICTURE_Edit,
142                                         pPicker->GetEditText())) {
143    return false;
144  }
145
146  m_pNode->GetWidgetAcc()->UpdateUIDisplay(GetDoc()->GetDocView(), this);
147  return true;
148}
149
150bool CXFA_FFDateTimeEdit::UpdateFWLData() {
151  if (!m_pNormalWidget)
152    return false;
153
154  XFA_VALUEPICTURE eType = XFA_VALUEPICTURE_Display;
155  if (IsFocused())
156    eType = XFA_VALUEPICTURE_Edit;
157
158  WideString wsText = m_pNode->GetWidgetAcc()->GetValue(eType);
159  auto* normalWidget = static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get());
160  normalWidget->SetEditText(wsText);
161  if (IsFocused() && !wsText.IsEmpty()) {
162    CXFA_LocaleValue lcValue = XFA_GetLocaleValue(m_pNode.Get());
163    CFX_DateTime date = lcValue.GetDate();
164    if (lcValue.IsValid()) {
165      if (date.IsSet())
166        normalWidget->SetCurSel(date.GetYear(), date.GetMonth(), date.GetDay());
167    }
168  }
169  m_pNormalWidget->Update();
170  return true;
171}
172
173bool CXFA_FFDateTimeEdit::IsDataChanged() {
174  if (m_dwStatus & XFA_WidgetStatus_TextEditValueChanged)
175    return true;
176
177  WideString wsText =
178      static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get())->GetEditText();
179  return m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Edit) != wsText;
180}
181
182void CXFA_FFDateTimeEdit::OnSelectChanged(CFWL_Widget* pWidget,
183                                          int32_t iYear,
184                                          int32_t iMonth,
185                                          int32_t iDay) {
186  WideString wsPicture =
187      m_pNode->GetWidgetAcc()->GetPictureContent(XFA_VALUEPICTURE_Edit);
188
189  CXFA_LocaleValue date(XFA_VT_DATE, GetDoc()->GetXFADoc()->GetLocalMgr());
190  date.SetDate(CFX_DateTime(iYear, iMonth, iDay, 0, 0, 0, 0));
191
192  WideString wsDate;
193  date.FormatPatterns(wsDate, wsPicture, m_pNode->GetLocale(),
194                      XFA_VALUEPICTURE_Edit);
195
196  auto* pDateTime = static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get());
197  pDateTime->SetEditText(wsDate);
198  pDateTime->Update();
199  GetDoc()->GetDocEnvironment()->SetFocusWidget(GetDoc(), nullptr);
200
201  CXFA_EventParam eParam;
202  eParam.m_eType = XFA_EVENT_Change;
203  eParam.m_pTarget = m_pNode->GetWidgetAcc();
204  eParam.m_wsNewText = m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw);
205  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Change, &eParam);
206}
207
208void CXFA_FFDateTimeEdit::OnProcessEvent(CFWL_Event* pEvent) {
209  if (pEvent->GetType() == CFWL_Event::Type::SelectChanged) {
210    auto* event = static_cast<CFWL_EventSelectChanged*>(pEvent);
211    OnSelectChanged(m_pNormalWidget.get(), event->iYear, event->iMonth,
212                    event->iDay);
213    return;
214  }
215  CXFA_FFTextEdit::OnProcessEvent(pEvent);
216}
217