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/cxfa_ffcombobox.h"
8
9 #include <utility>
10 #include <vector>
11
12 #include "xfa/fwl/cfwl_combobox.h"
13 #include "xfa/fwl/cfwl_eventselectchanged.h"
14 #include "xfa/fwl/cfwl_notedriver.h"
15 #include "xfa/fxfa/cxfa_eventparam.h"
16 #include "xfa/fxfa/cxfa_ffdocview.h"
17 #include "xfa/fxfa/parser/cxfa_para.h"
18
19 namespace {
20
ToComboBox(CFWL_Widget * widget)21 CFWL_ComboBox* ToComboBox(CFWL_Widget* widget) {
22 return static_cast<CFWL_ComboBox*>(widget);
23 }
24
25 } // namespace
26
CXFA_FFComboBox(CXFA_Node * pNode)27 CXFA_FFComboBox::CXFA_FFComboBox(CXFA_Node* pNode)
28 : CXFA_FFField(pNode), m_pOldDelegate(nullptr) {}
29
~CXFA_FFComboBox()30 CXFA_FFComboBox::~CXFA_FFComboBox() {}
31
GetBBox(uint32_t dwStatus,bool bDrawFocus)32 CFX_RectF CXFA_FFComboBox::GetBBox(uint32_t dwStatus, bool bDrawFocus) {
33 return bDrawFocus ? CFX_RectF() : CXFA_FFWidget::GetBBox(dwStatus);
34 }
35
PtInActiveRect(const CFX_PointF & point)36 bool CXFA_FFComboBox::PtInActiveRect(const CFX_PointF& point) {
37 auto* pComboBox = ToComboBox(m_pNormalWidget.get());
38 return pComboBox && pComboBox->GetBBox().Contains(point);
39 }
40
LoadWidget()41 bool CXFA_FFComboBox::LoadWidget() {
42 auto pNew = pdfium::MakeUnique<CFWL_ComboBox>(GetFWLApp());
43 CFWL_ComboBox* pComboBox = pNew.get();
44 m_pNormalWidget = std::move(pNew);
45 m_pNormalWidget->SetLayoutItem(this);
46
47 CFWL_NoteDriver* pNoteDriver =
48 m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
49 pNoteDriver->RegisterEventTarget(m_pNormalWidget.get(),
50 m_pNormalWidget.get());
51 m_pOldDelegate = m_pNormalWidget->GetDelegate();
52 m_pNormalWidget->SetDelegate(this);
53 m_pNormalWidget->LockUpdate();
54
55 for (const auto& label : m_pNode->GetWidgetAcc()->GetChoiceListItems(false))
56 pComboBox->AddString(label.AsStringView());
57
58 std::vector<int32_t> iSelArray = m_pNode->GetWidgetAcc()->GetSelectedItems();
59 if (iSelArray.empty()) {
60 pComboBox->SetEditText(
61 m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw));
62 } else {
63 pComboBox->SetCurSel(iSelArray.front());
64 }
65
66 UpdateWidgetProperty();
67 m_pNormalWidget->UnlockUpdate();
68 return CXFA_FFField::LoadWidget();
69 }
70
UpdateWidgetProperty()71 void CXFA_FFComboBox::UpdateWidgetProperty() {
72 auto* pComboBox = ToComboBox(m_pNormalWidget.get());
73 if (!pComboBox)
74 return;
75
76 uint32_t dwExtendedStyle = 0;
77 uint32_t dwEditStyles = FWL_STYLEEXT_EDT_ReadOnly;
78 dwExtendedStyle |= UpdateUIProperty();
79 if (m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry()) {
80 dwEditStyles &= ~FWL_STYLEEXT_EDT_ReadOnly;
81 dwExtendedStyle |= FWL_STYLEEXT_CMB_DropDown;
82 }
83 if (!m_pNode->IsOpenAccess() || !GetDoc()->GetXFADoc()->IsInteractive()) {
84 dwEditStyles |= FWL_STYLEEXT_EDT_ReadOnly;
85 dwExtendedStyle |= FWL_STYLEEXT_CMB_ReadOnly;
86 }
87 dwExtendedStyle |= GetAlignment();
88 m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
89
90 if (!m_pNode->GetWidgetAcc()->IsHorizontalScrollPolicyOff())
91 dwEditStyles |= FWL_STYLEEXT_EDT_AutoHScroll;
92
93 pComboBox->EditModifyStylesEx(dwEditStyles, 0xFFFFFFFF);
94 }
95
OnRButtonUp(uint32_t dwFlags,const CFX_PointF & point)96 bool CXFA_FFComboBox::OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
97 if (!CXFA_FFField::OnRButtonUp(dwFlags, point))
98 return false;
99
100 GetDoc()->GetDocEnvironment()->PopupMenu(this, point);
101 return true;
102 }
103
OnKillFocus(CXFA_FFWidget * pNewWidget)104 bool CXFA_FFComboBox::OnKillFocus(CXFA_FFWidget* pNewWidget) {
105 if (!ProcessCommittedData())
106 UpdateFWLData();
107
108 CXFA_FFField::OnKillFocus(pNewWidget);
109 return true;
110 }
111
OpenDropDownList()112 void CXFA_FFComboBox::OpenDropDownList() {
113 ToComboBox(m_pNormalWidget.get())->OpenDropDownList(true);
114 }
115
CommitData()116 bool CXFA_FFComboBox::CommitData() {
117 return m_pNode->GetWidgetAcc()->SetValue(XFA_VALUEPICTURE_Raw, m_wsNewValue);
118 }
119
IsDataChanged()120 bool CXFA_FFComboBox::IsDataChanged() {
121 auto* pFWLcombobox = ToComboBox(m_pNormalWidget.get());
122 WideString wsText = pFWLcombobox->GetEditText();
123 int32_t iCursel = pFWLcombobox->GetCurSel();
124 if (iCursel >= 0) {
125 WideString wsSel = pFWLcombobox->GetTextByIndex(iCursel);
126 if (wsSel == wsText)
127 wsText = m_pNode->GetWidgetAcc()
128 ->GetChoiceListItem(iCursel, true)
129 .value_or(L"");
130 }
131 if (m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw) == wsText)
132 return false;
133
134 m_wsNewValue = wsText;
135 return true;
136 }
137
FWLEventSelChange(CXFA_EventParam * pParam)138 void CXFA_FFComboBox::FWLEventSelChange(CXFA_EventParam* pParam) {
139 pParam->m_eType = XFA_EVENT_Change;
140 pParam->m_pTarget = m_pNode->GetWidgetAcc();
141 pParam->m_wsNewText = ToComboBox(m_pNormalWidget.get())->GetEditText();
142 m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Change, pParam);
143 }
144
GetAlignment()145 uint32_t CXFA_FFComboBox::GetAlignment() {
146 CXFA_Para* para = m_pNode->GetParaIfExists();
147 if (!para)
148 return 0;
149
150 uint32_t dwExtendedStyle = 0;
151 switch (para->GetHorizontalAlign()) {
152 case XFA_AttributeEnum::Center:
153 dwExtendedStyle |=
154 FWL_STYLEEXT_CMB_EditHCenter | FWL_STYLEEXT_CMB_ListItemCenterAlign;
155 break;
156 case XFA_AttributeEnum::Justify:
157 dwExtendedStyle |= FWL_STYLEEXT_CMB_EditJustified;
158 break;
159 case XFA_AttributeEnum::JustifyAll:
160 break;
161 case XFA_AttributeEnum::Radix:
162 break;
163 case XFA_AttributeEnum::Right:
164 break;
165 default:
166 dwExtendedStyle |=
167 FWL_STYLEEXT_CMB_EditHNear | FWL_STYLEEXT_CMB_ListItemLeftAlign;
168 break;
169 }
170
171 switch (para->GetVerticalAlign()) {
172 case XFA_AttributeEnum::Middle:
173 dwExtendedStyle |= FWL_STYLEEXT_CMB_EditVCenter;
174 break;
175 case XFA_AttributeEnum::Bottom:
176 dwExtendedStyle |= FWL_STYLEEXT_CMB_EditVFar;
177 break;
178 default:
179 dwExtendedStyle |= FWL_STYLEEXT_CMB_EditVNear;
180 break;
181 }
182 return dwExtendedStyle;
183 }
184
UpdateFWLData()185 bool CXFA_FFComboBox::UpdateFWLData() {
186 auto* pComboBox = ToComboBox(m_pNormalWidget.get());
187 if (!pComboBox)
188 return false;
189
190 std::vector<int32_t> iSelArray = m_pNode->GetWidgetAcc()->GetSelectedItems();
191 if (!iSelArray.empty()) {
192 pComboBox->SetCurSel(iSelArray.front());
193 } else {
194 pComboBox->SetCurSel(-1);
195 pComboBox->SetEditText(
196 m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw));
197 }
198 pComboBox->Update();
199 return true;
200 }
201
CanUndo()202 bool CXFA_FFComboBox::CanUndo() {
203 return m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
204 ToComboBox(m_pNormalWidget.get())->EditCanUndo();
205 }
206
CanRedo()207 bool CXFA_FFComboBox::CanRedo() {
208 return m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
209 ToComboBox(m_pNormalWidget.get())->EditCanRedo();
210 }
211
Undo()212 bool CXFA_FFComboBox::Undo() {
213 return m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
214 ToComboBox(m_pNormalWidget.get())->EditUndo();
215 }
216
Redo()217 bool CXFA_FFComboBox::Redo() {
218 return m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
219 ToComboBox(m_pNormalWidget.get())->EditRedo();
220 }
221
CanCopy()222 bool CXFA_FFComboBox::CanCopy() {
223 return ToComboBox(m_pNormalWidget.get())->EditCanCopy();
224 }
225
CanCut()226 bool CXFA_FFComboBox::CanCut() {
227 return m_pNode->IsOpenAccess() &&
228 m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
229 ToComboBox(m_pNormalWidget.get())->EditCanCut();
230 }
231
CanPaste()232 bool CXFA_FFComboBox::CanPaste() {
233 return m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
234 m_pNode->IsOpenAccess();
235 }
236
CanSelectAll()237 bool CXFA_FFComboBox::CanSelectAll() {
238 return ToComboBox(m_pNormalWidget.get())->EditCanSelectAll();
239 }
240
Copy()241 Optional<WideString> CXFA_FFComboBox::Copy() {
242 return ToComboBox(m_pNormalWidget.get())->EditCopy();
243 }
244
Cut()245 Optional<WideString> CXFA_FFComboBox::Cut() {
246 if (!m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry())
247 return {};
248
249 return ToComboBox(m_pNormalWidget.get())->EditCut();
250 }
251
Paste(const WideString & wsPaste)252 bool CXFA_FFComboBox::Paste(const WideString& wsPaste) {
253 return m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
254 ToComboBox(m_pNormalWidget.get())->EditPaste(wsPaste);
255 }
256
SelectAll()257 void CXFA_FFComboBox::SelectAll() {
258 ToComboBox(m_pNormalWidget.get())->EditSelectAll();
259 }
260
Delete()261 void CXFA_FFComboBox::Delete() {
262 ToComboBox(m_pNormalWidget.get())->EditDelete();
263 }
264
DeSelect()265 void CXFA_FFComboBox::DeSelect() {
266 ToComboBox(m_pNormalWidget.get())->EditDeSelect();
267 }
268
GetFormFieldType()269 FormFieldType CXFA_FFComboBox::GetFormFieldType() {
270 return FormFieldType::kXFA_ComboBox;
271 }
272
SetItemState(int32_t nIndex,bool bSelected)273 void CXFA_FFComboBox::SetItemState(int32_t nIndex, bool bSelected) {
274 ToComboBox(m_pNormalWidget.get())->SetCurSel(bSelected ? nIndex : -1);
275 m_pNormalWidget->Update();
276 AddInvalidateRect();
277 }
278
InsertItem(const WideStringView & wsLabel,int32_t nIndex)279 void CXFA_FFComboBox::InsertItem(const WideStringView& wsLabel,
280 int32_t nIndex) {
281 ToComboBox(m_pNormalWidget.get())->AddString(wsLabel);
282 m_pNormalWidget->Update();
283 AddInvalidateRect();
284 }
285
DeleteItem(int32_t nIndex)286 void CXFA_FFComboBox::DeleteItem(int32_t nIndex) {
287 if (nIndex < 0)
288 ToComboBox(m_pNormalWidget.get())->RemoveAll();
289 else
290 ToComboBox(m_pNormalWidget.get())->RemoveAt(nIndex);
291
292 m_pNormalWidget->Update();
293 AddInvalidateRect();
294 }
295
OnTextChanged(CFWL_Widget * pWidget,const WideString & wsChanged)296 void CXFA_FFComboBox::OnTextChanged(CFWL_Widget* pWidget,
297 const WideString& wsChanged) {
298 CXFA_EventParam eParam;
299 eParam.m_wsPrevText = m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw);
300 eParam.m_wsChange = wsChanged;
301 FWLEventSelChange(&eParam);
302 }
303
OnSelectChanged(CFWL_Widget * pWidget,bool bLButtonUp)304 void CXFA_FFComboBox::OnSelectChanged(CFWL_Widget* pWidget, bool bLButtonUp) {
305 CXFA_EventParam eParam;
306 eParam.m_wsPrevText = m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw);
307 FWLEventSelChange(&eParam);
308 if (m_pNode->GetWidgetAcc()->IsChoiceListCommitOnSelect() && bLButtonUp)
309 m_pDocView->SetFocusWidgetAcc(nullptr);
310 }
311
OnPreOpen(CFWL_Widget * pWidget)312 void CXFA_FFComboBox::OnPreOpen(CFWL_Widget* pWidget) {
313 CXFA_EventParam eParam;
314 eParam.m_eType = XFA_EVENT_PreOpen;
315 eParam.m_pTarget = m_pNode->GetWidgetAcc();
316 m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::PreOpen, &eParam);
317 }
318
OnPostOpen(CFWL_Widget * pWidget)319 void CXFA_FFComboBox::OnPostOpen(CFWL_Widget* pWidget) {
320 CXFA_EventParam eParam;
321 eParam.m_eType = XFA_EVENT_PostOpen;
322 eParam.m_pTarget = m_pNode->GetWidgetAcc();
323 m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::PostOpen, &eParam);
324 }
325
OnProcessMessage(CFWL_Message * pMessage)326 void CXFA_FFComboBox::OnProcessMessage(CFWL_Message* pMessage) {
327 m_pOldDelegate->OnProcessMessage(pMessage);
328 }
329
OnProcessEvent(CFWL_Event * pEvent)330 void CXFA_FFComboBox::OnProcessEvent(CFWL_Event* pEvent) {
331 CXFA_FFField::OnProcessEvent(pEvent);
332 switch (pEvent->GetType()) {
333 case CFWL_Event::Type::SelectChanged: {
334 auto* postEvent = static_cast<CFWL_EventSelectChanged*>(pEvent);
335 OnSelectChanged(m_pNormalWidget.get(), postEvent->bLButtonUp);
336 break;
337 }
338 case CFWL_Event::Type::EditChanged: {
339 WideString wsChanged;
340 OnTextChanged(m_pNormalWidget.get(), wsChanged);
341 break;
342 }
343 case CFWL_Event::Type::PreDropDown: {
344 OnPreOpen(m_pNormalWidget.get());
345 break;
346 }
347 case CFWL_Event::Type::PostDropDown: {
348 OnPostOpen(m_pNormalWidget.get());
349 break;
350 }
351 default:
352 break;
353 }
354 m_pOldDelegate->OnProcessEvent(pEvent);
355 }
356
OnDrawWidget(CXFA_Graphics * pGraphics,const CFX_Matrix & matrix)357 void CXFA_FFComboBox::OnDrawWidget(CXFA_Graphics* pGraphics,
358 const CFX_Matrix& matrix) {
359 m_pOldDelegate->OnDrawWidget(pGraphics, matrix);
360 }
361