1 // Copyright 2014 The PDFium Authors
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 "fpdfsdk/formfiller/cffl_listbox.h"
8
9 #include <utility>
10
11 #include "constants/form_flags.h"
12 #include "core/fpdfdoc/cpdf_bafontmap.h"
13 #include "fpdfsdk/cpdfsdk_widget.h"
14 #include "fpdfsdk/formfiller/cffl_interactiveformfiller.h"
15 #include "fpdfsdk/formfiller/cffl_perwindowdata.h"
16 #include "fpdfsdk/pwl/cpwl_list_box.h"
17 #include "third_party/base/containers/contains.h"
18
CFFL_ListBox(CFFL_InteractiveFormFiller * pFormFiller,CPDFSDK_Widget * pWidget)19 CFFL_ListBox::CFFL_ListBox(CFFL_InteractiveFormFiller* pFormFiller,
20 CPDFSDK_Widget* pWidget)
21 : CFFL_TextObject(pFormFiller, pWidget) {}
22
23 CFFL_ListBox::~CFFL_ListBox() = default;
24
GetCreateParam()25 CPWL_Wnd::CreateParams CFFL_ListBox::GetCreateParam() {
26 CPWL_Wnd::CreateParams cp = CFFL_TextObject::GetCreateParam();
27 uint32_t dwFieldFlag = m_pWidget->GetFieldFlags();
28 if (dwFieldFlag & pdfium::form_flags::kChoiceMultiSelect)
29 cp.dwFlags |= PLBS_MULTIPLESEL;
30
31 cp.dwFlags |= PWS_VSCROLL;
32
33 if (cp.dwFlags & PWS_AUTOFONTSIZE) {
34 constexpr float kDefaultListBoxFontSize = 12.0f;
35 cp.fFontSize = kDefaultListBoxFontSize;
36 }
37
38 cp.pFontMap = GetOrCreateFontMap();
39 return cp;
40 }
41
NewPWLWindow(const CPWL_Wnd::CreateParams & cp,std::unique_ptr<IPWL_FillerNotify::PerWindowData> pAttachedData)42 std::unique_ptr<CPWL_Wnd> CFFL_ListBox::NewPWLWindow(
43 const CPWL_Wnd::CreateParams& cp,
44 std::unique_ptr<IPWL_FillerNotify::PerWindowData> pAttachedData) {
45 static_cast<CFFL_PerWindowData*>(pAttachedData.get())->SetFormField(this);
46 auto pWnd = std::make_unique<CPWL_ListBox>(cp, std::move(pAttachedData));
47 pWnd->Realize();
48
49 for (int32_t i = 0, sz = m_pWidget->CountOptions(); i < sz; i++)
50 pWnd->AddString(m_pWidget->GetOptionLabel(i));
51
52 if (pWnd->HasFlag(PLBS_MULTIPLESEL)) {
53 m_OriginSelections.clear();
54
55 bool bSetCaret = false;
56 for (int32_t i = 0, sz = m_pWidget->CountOptions(); i < sz; i++) {
57 if (m_pWidget->IsOptionSelected(i)) {
58 if (!bSetCaret) {
59 pWnd->SetCaret(i);
60 bSetCaret = true;
61 }
62 pWnd->Select(i);
63 m_OriginSelections.insert(i);
64 }
65 }
66 } else {
67 for (int i = 0, sz = m_pWidget->CountOptions(); i < sz; i++) {
68 if (m_pWidget->IsOptionSelected(i)) {
69 pWnd->Select(i);
70 break;
71 }
72 }
73 }
74
75 pWnd->SetTopVisibleIndex(m_pWidget->GetTopVisibleIndex());
76 return std::move(pWnd);
77 }
78
OnChar(CPDFSDK_Widget * pWidget,uint32_t nChar,Mask<FWL_EVENTFLAG> nFlags)79 bool CFFL_ListBox::OnChar(CPDFSDK_Widget* pWidget,
80 uint32_t nChar,
81 Mask<FWL_EVENTFLAG> nFlags) {
82 return CFFL_TextObject::OnChar(pWidget, nChar, nFlags);
83 }
84
IsDataChanged(const CPDFSDK_PageView * pPageView)85 bool CFFL_ListBox::IsDataChanged(const CPDFSDK_PageView* pPageView) {
86 CPWL_ListBox* pListBox = GetPWLListBox(pPageView);
87 if (!pListBox)
88 return false;
89
90 if (m_pWidget->GetFieldFlags() & pdfium::form_flags::kChoiceMultiSelect) {
91 size_t nSelCount = 0;
92 for (int32_t i = 0, sz = pListBox->GetCount(); i < sz; ++i) {
93 if (pListBox->IsItemSelected(i)) {
94 if (!pdfium::Contains(m_OriginSelections, i))
95 return true;
96
97 ++nSelCount;
98 }
99 }
100
101 return nSelCount != m_OriginSelections.size();
102 }
103 return pListBox->GetCurSel() != m_pWidget->GetSelectedIndex(0);
104 }
105
SaveData(const CPDFSDK_PageView * pPageView)106 void CFFL_ListBox::SaveData(const CPDFSDK_PageView* pPageView) {
107 CPWL_ListBox* pListBox = GetPWLListBox(pPageView);
108 if (!pListBox) {
109 return;
110 }
111 int32_t nNewTopIndex = pListBox->GetTopVisibleIndex();
112 ObservedPtr<CPWL_ListBox> observed_box(pListBox);
113 m_pWidget->ClearSelection();
114 if (!observed_box) {
115 return;
116 }
117 if (m_pWidget->GetFieldFlags() & pdfium::form_flags::kChoiceMultiSelect) {
118 for (int32_t i = 0, sz = pListBox->GetCount(); i < sz; i++) {
119 if (pListBox->IsItemSelected(i)) {
120 m_pWidget->SetOptionSelection(i);
121 if (!observed_box) {
122 return;
123 }
124 }
125 }
126 } else {
127 m_pWidget->SetOptionSelection(pListBox->GetCurSel());
128 if (!observed_box) {
129 return;
130 }
131 }
132 ObservedPtr<CPDFSDK_Widget> observed_widget(m_pWidget);
133 ObservedPtr<CFFL_ListBox> observed_this(this);
134 m_pWidget->SetTopVisibleIndex(nNewTopIndex);
135 if (!observed_widget) {
136 return;
137 }
138 m_pWidget->ResetFieldAppearance();
139 if (!observed_widget) {
140 return;
141 }
142 m_pWidget->UpdateField();
143 if (!observed_widget || !observed_this) {
144 return;
145 }
146 SetChangeMark();
147 }
148
GetActionData(const CPDFSDK_PageView * pPageView,CPDF_AAction::AActionType type,CFFL_FieldAction & fa)149 void CFFL_ListBox::GetActionData(const CPDFSDK_PageView* pPageView,
150 CPDF_AAction::AActionType type,
151 CFFL_FieldAction& fa) {
152 switch (type) {
153 case CPDF_AAction::kValidate:
154 if (m_pWidget->GetFieldFlags() & pdfium::form_flags::kChoiceMultiSelect) {
155 fa.sValue.clear();
156 } else {
157 CPWL_ListBox* pListBox = GetPWLListBox(pPageView);
158 if (pListBox) {
159 int32_t nCurSel = pListBox->GetCurSel();
160 if (nCurSel >= 0)
161 fa.sValue = m_pWidget->GetOptionLabel(nCurSel);
162 }
163 }
164 break;
165 case CPDF_AAction::kLoseFocus:
166 case CPDF_AAction::kGetFocus:
167 if (m_pWidget->GetFieldFlags() & pdfium::form_flags::kChoiceMultiSelect) {
168 fa.sValue.clear();
169 } else {
170 int32_t nCurSel = m_pWidget->GetSelectedIndex(0);
171 if (nCurSel >= 0)
172 fa.sValue = m_pWidget->GetOptionLabel(nCurSel);
173 }
174 break;
175 default:
176 break;
177 }
178 }
179
SavePWLWindowState(const CPDFSDK_PageView * pPageView)180 void CFFL_ListBox::SavePWLWindowState(const CPDFSDK_PageView* pPageView) {
181 CPWL_ListBox* pListBox = GetPWLListBox(pPageView);
182 if (!pListBox)
183 return;
184
185 for (int32_t i = 0, sz = pListBox->GetCount(); i < sz; i++) {
186 if (pListBox->IsItemSelected(i))
187 m_State.push_back(i);
188 }
189 }
190
RecreatePWLWindowFromSavedState(const CPDFSDK_PageView * pPageView)191 void CFFL_ListBox::RecreatePWLWindowFromSavedState(
192 const CPDFSDK_PageView* pPageView) {
193 CPWL_ListBox* pListBox = CreateOrUpdatePWLListBox(pPageView);
194 if (!pListBox)
195 return;
196
197 for (const auto& item : m_State)
198 pListBox->Select(item);
199 }
200
SetIndexSelected(int index,bool selected)201 bool CFFL_ListBox::SetIndexSelected(int index, bool selected) {
202 if (!IsValid())
203 return false;
204
205 if (index < 0 || index >= m_pWidget->CountOptions())
206 return false;
207
208 CPWL_ListBox* pListBox = GetPWLListBox(GetCurPageView());
209 if (!pListBox)
210 return false;
211
212 if (selected) {
213 pListBox->Select(index);
214 pListBox->SetCaret(index);
215 } else {
216 pListBox->Deselect(index);
217 pListBox->SetCaret(index);
218 }
219
220 return true;
221 }
222
IsIndexSelected(int index)223 bool CFFL_ListBox::IsIndexSelected(int index) {
224 if (!IsValid())
225 return false;
226
227 if (index < 0 || index >= m_pWidget->CountOptions())
228 return false;
229
230 CPWL_ListBox* pListBox = GetPWLListBox(GetCurPageView());
231 return pListBox && pListBox->IsItemSelected(index);
232 }
233
GetPWLListBox(const CPDFSDK_PageView * pPageView) const234 CPWL_ListBox* CFFL_ListBox::GetPWLListBox(
235 const CPDFSDK_PageView* pPageView) const {
236 return static_cast<CPWL_ListBox*>(GetPWLWindow(pPageView));
237 }
238
CreateOrUpdatePWLListBox(const CPDFSDK_PageView * pPageView)239 CPWL_ListBox* CFFL_ListBox::CreateOrUpdatePWLListBox(
240 const CPDFSDK_PageView* pPageView) {
241 return static_cast<CPWL_ListBox*>(CreateOrUpdatePWLWindow(pPageView));
242 }
243