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