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 
CXFA_FFDateTimeEdit(CXFA_Node * pNode)22 CXFA_FFDateTimeEdit::CXFA_FFDateTimeEdit(CXFA_Node* pNode)
23     : CXFA_FFTextEdit(pNode) {}
24 
~CXFA_FFDateTimeEdit()25 CXFA_FFDateTimeEdit::~CXFA_FFDateTimeEdit() {}
26 
GetBBox(uint32_t dwStatus,bool bDrawFocus)27 CFX_RectF CXFA_FFDateTimeEdit::GetBBox(uint32_t dwStatus, bool bDrawFocus) {
28   if (bDrawFocus)
29     return CFX_RectF();
30   return CXFA_FFWidget::GetBBox(dwStatus);
31 }
32 
PtInActiveRect(const CFX_PointF & point)33 bool 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 
LoadWidget()38 bool 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 
UpdateWidgetProperty()76 void 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 
GetAlignment()101 uint32_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 
CommitData()139 bool 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 
UpdateFWLData()150 bool 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 
IsDataChanged()173 bool 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 
OnSelectChanged(CFWL_Widget * pWidget,int32_t iYear,int32_t iMonth,int32_t iDay)182 void 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 
OnProcessEvent(CFWL_Event * pEvent)208 void 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