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 "third_party/base/ptr_util.h"
12 #include "xfa/fwl/cfwl_datetimepicker.h"
13 #include "xfa/fwl/cfwl_eventselectchanged.h"
14 #include "xfa/fwl/cfwl_notedriver.h"
15 #include "xfa/fwl/cfwl_widget.h"
16 #include "xfa/fxfa/cxfa_eventparam.h"
17 #include "xfa/fxfa/cxfa_ffdoc.h"
18 #include "xfa/fxfa/cxfa_ffdocview.h"
19 #include "xfa/fxfa/parser/cxfa_localevalue.h"
20 #include "xfa/fxfa/parser/cxfa_para.h"
21 #include "xfa/fxfa/parser/cxfa_value.h"
22 #include "xfa/fxfa/parser/xfa_utils.h"
23 
CXFA_FFDateTimeEdit(CXFA_Node * pNode)24 CXFA_FFDateTimeEdit::CXFA_FFDateTimeEdit(CXFA_Node* pNode)
25     : CXFA_FFTextEdit(pNode) {}
26 
27 CXFA_FFDateTimeEdit::~CXFA_FFDateTimeEdit() = default;
28 
GetPickerWidget()29 CFWL_DateTimePicker* CXFA_FFDateTimeEdit::GetPickerWidget() {
30   return static_cast<CFWL_DateTimePicker*>(GetNormalWidget());
31 }
32 
GetBBox(FocusOption focus)33 CFX_RectF CXFA_FFDateTimeEdit::GetBBox(FocusOption focus) {
34   if (focus == kDrawFocus)
35     return CFX_RectF();
36   return CXFA_FFWidget::GetBBox(kDoNotDrawFocus);
37 }
38 
PtInActiveRect(const CFX_PointF & point)39 bool CXFA_FFDateTimeEdit::PtInActiveRect(const CFX_PointF& point) {
40   CFWL_DateTimePicker* pPicker = GetPickerWidget();
41   return pPicker && pPicker->GetBBox().Contains(point);
42 }
43 
LoadWidget()44 bool CXFA_FFDateTimeEdit::LoadWidget() {
45   ASSERT(!IsLoaded());
46   auto pNewPicker = pdfium::MakeUnique<CFWL_DateTimePicker>(GetFWLApp());
47   CFWL_DateTimePicker* pWidget = pNewPicker.get();
48   SetNormalWidget(std::move(pNewPicker));
49   pWidget->SetAdapterIface(this);
50 
51   CFWL_NoteDriver* pNoteDriver = pWidget->GetOwnerApp()->GetNoteDriver();
52   pNoteDriver->RegisterEventTarget(pWidget, pWidget);
53   m_pOldDelegate = pWidget->GetDelegate();
54   pWidget->SetDelegate(this);
55 
56   {
57     CFWL_Widget::ScopedUpdateLock update_lock(pWidget);
58     WideString wsText = m_pNode->GetValue(XFA_VALUEPICTURE_Display);
59     pWidget->SetEditText(wsText);
60 
61     CXFA_Value* value = m_pNode->GetFormValueIfExists();
62     if (value) {
63       switch (value->GetChildValueClassID()) {
64         case XFA_Element::Date: {
65           if (!wsText.IsEmpty()) {
66             CXFA_LocaleValue lcValue = XFA_GetLocaleValue(m_pNode.Get());
67             CFX_DateTime date = lcValue.GetDate();
68             if (date.IsSet())
69               pWidget->SetCurSel(date.GetYear(), date.GetMonth(),
70                                  date.GetDay());
71           }
72         } break;
73         default:
74           break;
75       }
76     }
77     UpdateWidgetProperty();
78   }
79 
80   return CXFA_FFField::LoadWidget();
81 }
82 
UpdateWidgetProperty()83 void CXFA_FFDateTimeEdit::UpdateWidgetProperty() {
84   CFWL_DateTimePicker* pPicker = GetPickerWidget();
85   if (!pPicker)
86     return;
87 
88   uint32_t dwExtendedStyle = FWL_STYLEEXT_DTP_ShortDateFormat;
89   dwExtendedStyle |= UpdateUIProperty();
90   dwExtendedStyle |= GetAlignment();
91   GetNormalWidget()->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
92 
93   uint32_t dwEditStyles = 0;
94   Optional<int32_t> numCells = m_pNode->GetNumberOfCells();
95   if (numCells && *numCells > 0) {
96     dwEditStyles |= FWL_STYLEEXT_EDT_CombText;
97     pPicker->SetEditLimit(*numCells);
98   }
99   if (!m_pNode->IsOpenAccess() || !GetDoc()->GetXFADoc()->IsInteractive())
100     dwEditStyles |= FWL_STYLEEXT_EDT_ReadOnly;
101   if (!m_pNode->IsHorizontalScrollPolicyOff())
102     dwEditStyles |= FWL_STYLEEXT_EDT_AutoHScroll;
103 
104   pPicker->ModifyEditStylesEx(dwEditStyles, 0xFFFFFFFF);
105 }
106 
GetAlignment()107 uint32_t CXFA_FFDateTimeEdit::GetAlignment() {
108   CXFA_Para* para = m_pNode->GetParaIfExists();
109   if (!para)
110     return 0;
111 
112   uint32_t dwExtendedStyle = 0;
113   switch (para->GetHorizontalAlign()) {
114     case XFA_AttributeValue::Center:
115       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditHCenter;
116       break;
117     case XFA_AttributeValue::Justify:
118       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditJustified;
119       break;
120     case XFA_AttributeValue::JustifyAll:
121     case XFA_AttributeValue::Radix:
122       break;
123     case XFA_AttributeValue::Right:
124       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditHFar;
125       break;
126     default:
127       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditHNear;
128       break;
129   }
130 
131   switch (para->GetVerticalAlign()) {
132     case XFA_AttributeValue::Middle:
133       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditVCenter;
134       break;
135     case XFA_AttributeValue::Bottom:
136       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditVFar;
137       break;
138     default:
139       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditVNear;
140       break;
141   }
142   return dwExtendedStyle;
143 }
144 
CommitData()145 bool CXFA_FFDateTimeEdit::CommitData() {
146   CFWL_DateTimePicker* pPicker = GetPickerWidget();
147   if (!m_pNode->SetValue(XFA_VALUEPICTURE_Edit, pPicker->GetEditText()))
148     return false;
149 
150   GetDoc()->GetDocView()->UpdateUIDisplay(m_pNode.Get(), this);
151   return true;
152 }
153 
UpdateFWLData()154 bool CXFA_FFDateTimeEdit::UpdateFWLData() {
155   if (!GetNormalWidget())
156     return false;
157 
158   XFA_VALUEPICTURE eType = XFA_VALUEPICTURE_Display;
159   if (IsFocused())
160     eType = XFA_VALUEPICTURE_Edit;
161 
162   WideString wsText = m_pNode->GetValue(eType);
163   CFWL_DateTimePicker* pPicker = GetPickerWidget();
164   pPicker->SetEditText(wsText);
165   if (IsFocused() && !wsText.IsEmpty()) {
166     CXFA_LocaleValue lcValue = XFA_GetLocaleValue(m_pNode.Get());
167     CFX_DateTime date = lcValue.GetDate();
168     if (lcValue.IsValid()) {
169       if (date.IsSet())
170         pPicker->SetCurSel(date.GetYear(), date.GetMonth(), date.GetDay());
171     }
172   }
173   GetNormalWidget()->Update();
174   return true;
175 }
176 
IsDataChanged()177 bool CXFA_FFDateTimeEdit::IsDataChanged() {
178   if (GetLayoutItem()->TestStatusBits(XFA_WidgetStatus_TextEditValueChanged))
179     return true;
180 
181   WideString wsText = GetPickerWidget()->GetEditText();
182   return m_pNode->GetValue(XFA_VALUEPICTURE_Edit) != wsText;
183 }
184 
OnSelectChanged(CFWL_Widget * pWidget,int32_t iYear,int32_t iMonth,int32_t iDay)185 void CXFA_FFDateTimeEdit::OnSelectChanged(CFWL_Widget* pWidget,
186                                           int32_t iYear,
187                                           int32_t iMonth,
188                                           int32_t iDay) {
189   WideString wsPicture = m_pNode->GetPictureContent(XFA_VALUEPICTURE_Edit);
190 
191   CXFA_LocaleValue date(XFA_VT_DATE, GetDoc()->GetXFADoc()->GetLocaleMgr());
192   date.SetDate(CFX_DateTime(iYear, iMonth, iDay, 0, 0, 0, 0));
193 
194   WideString wsDate;
195   date.FormatPatterns(wsDate, wsPicture, m_pNode->GetLocale(),
196                       XFA_VALUEPICTURE_Edit);
197 
198   CFWL_DateTimePicker* pPicker = GetPickerWidget();
199   pPicker->SetEditText(wsDate);
200   pPicker->Update();
201   GetDoc()->GetDocEnvironment()->SetFocusWidget(GetDoc(), nullptr);
202 
203   CXFA_EventParam eParam;
204   eParam.m_eType = XFA_EVENT_Change;
205   eParam.m_pTarget = m_pNode.Get();
206   eParam.m_wsPrevText = m_pNode->GetValue(XFA_VALUEPICTURE_Raw);
207   m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Change, &eParam);
208 }
209 
OnProcessEvent(CFWL_Event * pEvent)210 void CXFA_FFDateTimeEdit::OnProcessEvent(CFWL_Event* pEvent) {
211   if (pEvent->GetType() == CFWL_Event::Type::SelectChanged) {
212     auto* event = static_cast<CFWL_EventSelectChanged*>(pEvent);
213     OnSelectChanged(GetNormalWidget(), event->iYear, event->iMonth,
214                     event->iDay);
215     return;
216   }
217   CXFA_FFTextEdit::OnProcessEvent(pEvent);
218 }
219 
CanUndo()220 bool CXFA_FFDateTimeEdit::CanUndo() {
221   return GetPickerWidget()->CanUndo();
222 }
223 
CanRedo()224 bool CXFA_FFDateTimeEdit::CanRedo() {
225   return GetPickerWidget()->CanRedo();
226 }
227 
Undo()228 bool CXFA_FFDateTimeEdit::Undo() {
229   return GetPickerWidget()->Undo();
230 }
231 
Redo()232 bool CXFA_FFDateTimeEdit::Redo() {
233   return GetPickerWidget()->Redo();
234 }
235 
CanCopy()236 bool CXFA_FFDateTimeEdit::CanCopy() {
237   return GetPickerWidget()->HasSelection();
238 }
239 
CanCut()240 bool CXFA_FFDateTimeEdit::CanCut() {
241   if (GetPickerWidget()->GetStylesEx() & FWL_STYLEEXT_EDT_ReadOnly)
242     return false;
243   return GetPickerWidget()->HasSelection();
244 }
245 
CanPaste()246 bool CXFA_FFDateTimeEdit::CanPaste() {
247   return !(GetPickerWidget()->GetStylesEx() & FWL_STYLEEXT_EDT_ReadOnly);
248 }
249 
CanSelectAll()250 bool CXFA_FFDateTimeEdit::CanSelectAll() {
251   return GetPickerWidget()->GetEditTextLength() > 0;
252 }
253 
Copy()254 Optional<WideString> CXFA_FFDateTimeEdit::Copy() {
255   return GetPickerWidget()->Copy();
256 }
257 
Cut()258 Optional<WideString> CXFA_FFDateTimeEdit::Cut() {
259   return GetPickerWidget()->Cut();
260 }
261 
Paste(const WideString & wsPaste)262 bool CXFA_FFDateTimeEdit::Paste(const WideString& wsPaste) {
263   return GetPickerWidget()->Paste(wsPaste);
264 }
265 
SelectAll()266 void CXFA_FFDateTimeEdit::SelectAll() {
267   GetPickerWidget()->SelectAll();
268 }
269 
Delete()270 void CXFA_FFDateTimeEdit::Delete() {
271   GetPickerWidget()->ClearText();
272 }
273 
DeSelect()274 void CXFA_FFDateTimeEdit::DeSelect() {
275   GetPickerWidget()->ClearSelection();
276 }
277 
GetText()278 WideString CXFA_FFDateTimeEdit::GetText() {
279   return GetPickerWidget()->GetEditText();
280 }
281