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 "fpdfsdk/formfiller/cffl_listbox.h"
8
9 #include <utility>
10
11 #include "constants/form_flags.h"
12 #include "core/fpdfdoc/cba_fontmap.h"
13 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
14 #include "fpdfsdk/cpdfsdk_widget.h"
15 #include "fpdfsdk/formfiller/cffl_interactiveformfiller.h"
16 #include "fpdfsdk/pwl/cpwl_list_box.h"
17 #include "third_party/base/ptr_util.h"
18
CFFL_ListBox(CPDFSDK_FormFillEnvironment * pApp,CPDFSDK_Widget * pWidget)19 CFFL_ListBox::CFFL_ListBox(CPDFSDK_FormFillEnvironment* pApp,
20 CPDFSDK_Widget* pWidget)
21 : CFFL_TextObject(pApp, 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 = MaybeCreateFontMap();
39 return cp;
40 }
41
NewPWLWindow(const CPWL_Wnd::CreateParams & cp,std::unique_ptr<IPWL_SystemHandler::PerWindowData> pAttachedData)42 std::unique_ptr<CPWL_Wnd> CFFL_ListBox::NewPWLWindow(
43 const CPWL_Wnd::CreateParams& cp,
44 std::unique_ptr<IPWL_SystemHandler::PerWindowData> pAttachedData) {
45 auto pWnd = pdfium::MakeUnique<CPWL_ListBox>(cp, std::move(pAttachedData));
46 pWnd->AttachFFLData(this);
47 pWnd->Realize();
48 pWnd->SetFillerNotify(m_pFormFillEnv->GetInteractiveFormFiller());
49
50 for (int32_t i = 0, sz = m_pWidget->CountOptions(); i < sz; i++)
51 pWnd->AddString(m_pWidget->GetOptionLabel(i));
52
53 if (pWnd->HasFlag(PLBS_MULTIPLESEL)) {
54 m_OriginSelections.clear();
55
56 bool bSetCaret = false;
57 for (int32_t i = 0, sz = m_pWidget->CountOptions(); i < sz; i++) {
58 if (m_pWidget->IsOptionSelected(i)) {
59 if (!bSetCaret) {
60 pWnd->SetCaret(i);
61 bSetCaret = true;
62 }
63 pWnd->Select(i);
64 m_OriginSelections.insert(i);
65 }
66 }
67 } else {
68 for (int i = 0, sz = m_pWidget->CountOptions(); i < sz; i++) {
69 if (m_pWidget->IsOptionSelected(i)) {
70 pWnd->Select(i);
71 break;
72 }
73 }
74 }
75
76 pWnd->SetTopVisibleIndex(m_pWidget->GetTopVisibleIndex());
77 return std::move(pWnd);
78 }
79
OnChar(CPDFSDK_Annot * pAnnot,uint32_t nChar,uint32_t nFlags)80 bool CFFL_ListBox::OnChar(CPDFSDK_Annot* pAnnot,
81 uint32_t nChar,
82 uint32_t nFlags) {
83 return CFFL_TextObject::OnChar(pAnnot, nChar, nFlags);
84 }
85
IsDataChanged(CPDFSDK_PageView * pPageView)86 bool CFFL_ListBox::IsDataChanged(CPDFSDK_PageView* pPageView) {
87 CPWL_ListBox* pListBox = GetListBox(pPageView);
88 if (!pListBox)
89 return false;
90
91 if (m_pWidget->GetFieldFlags() & pdfium::form_flags::kChoiceMultiSelect) {
92 size_t nSelCount = 0;
93 for (int32_t i = 0, sz = pListBox->GetCount(); i < sz; ++i) {
94 if (pListBox->IsItemSelected(i)) {
95 if (m_OriginSelections.count(i) == 0)
96 return true;
97
98 ++nSelCount;
99 }
100 }
101
102 return nSelCount != m_OriginSelections.size();
103 }
104 return pListBox->GetCurSel() != m_pWidget->GetSelectedIndex(0);
105 }
106
SaveData(CPDFSDK_PageView * pPageView)107 void CFFL_ListBox::SaveData(CPDFSDK_PageView* pPageView) {
108 CPWL_ListBox* pListBox = GetListBox(pPageView);
109 if (!pListBox)
110 return;
111
112 int32_t nNewTopIndex = pListBox->GetTopVisibleIndex();
113 m_pWidget->ClearSelection(NotificationOption::kDoNotNotify);
114 if (m_pWidget->GetFieldFlags() & pdfium::form_flags::kChoiceMultiSelect) {
115 for (int32_t i = 0, sz = pListBox->GetCount(); i < sz; i++) {
116 if (pListBox->IsItemSelected(i)) {
117 m_pWidget->SetOptionSelection(i, true,
118 NotificationOption::kDoNotNotify);
119 }
120 }
121 } else {
122 m_pWidget->SetOptionSelection(pListBox->GetCurSel(), true,
123 NotificationOption::kDoNotNotify);
124 }
125 ObservedPtr<CPDFSDK_Widget> observed_widget(m_pWidget.Get());
126 ObservedPtr<CFFL_ListBox> observed_this(this);
127 m_pWidget->SetTopVisibleIndex(nNewTopIndex);
128 if (!observed_widget)
129 return;
130
131 m_pWidget->ResetFieldAppearance();
132 if (!observed_widget)
133 return;
134
135 m_pWidget->UpdateField();
136 if (!observed_widget || !observed_this)
137 return;
138
139 SetChangeMark();
140 }
141
GetActionData(CPDFSDK_PageView * pPageView,CPDF_AAction::AActionType type,CPDFSDK_FieldAction & fa)142 void CFFL_ListBox::GetActionData(CPDFSDK_PageView* pPageView,
143 CPDF_AAction::AActionType type,
144 CPDFSDK_FieldAction& fa) {
145 switch (type) {
146 case CPDF_AAction::kValidate:
147 if (m_pWidget->GetFieldFlags() & pdfium::form_flags::kChoiceMultiSelect) {
148 fa.sValue.clear();
149 } else {
150 CPWL_ListBox* pListBox = GetListBox(pPageView);
151 if (pListBox) {
152 int32_t nCurSel = pListBox->GetCurSel();
153 if (nCurSel >= 0)
154 fa.sValue = m_pWidget->GetOptionLabel(nCurSel);
155 }
156 }
157 break;
158 case CPDF_AAction::kLoseFocus:
159 case CPDF_AAction::kGetFocus:
160 if (m_pWidget->GetFieldFlags() & pdfium::form_flags::kChoiceMultiSelect) {
161 fa.sValue.clear();
162 } else {
163 int32_t nCurSel = m_pWidget->GetSelectedIndex(0);
164 if (nCurSel >= 0)
165 fa.sValue = m_pWidget->GetOptionLabel(nCurSel);
166 }
167 break;
168 default:
169 break;
170 }
171 }
172
SaveState(CPDFSDK_PageView * pPageView)173 void CFFL_ListBox::SaveState(CPDFSDK_PageView* pPageView) {
174 CPWL_ListBox* pListBox = GetListBox(pPageView);
175 if (!pListBox)
176 return;
177
178 for (int32_t i = 0, sz = pListBox->GetCount(); i < sz; i++) {
179 if (pListBox->IsItemSelected(i))
180 m_State.push_back(i);
181 }
182 }
183
RestoreState(CPDFSDK_PageView * pPageView)184 void CFFL_ListBox::RestoreState(CPDFSDK_PageView* pPageView) {
185 CPWL_ListBox* pListBox = GetListBox(pPageView);
186 if (!pListBox)
187 return;
188
189 for (const auto& item : m_State)
190 pListBox->Select(item);
191 }
192
SetIndexSelected(int index,bool selected)193 bool CFFL_ListBox::SetIndexSelected(int index, bool selected) {
194 if (!IsValid())
195 return false;
196
197 if (index < 0 || index >= m_pWidget->CountOptions())
198 return false;
199
200 CPWL_ListBox* pListBox = GetListBox(GetCurPageView(true));
201 if (!pListBox)
202 return false;
203
204 if (selected) {
205 pListBox->Select(index);
206 pListBox->SetCaret(index);
207 } else {
208 pListBox->Deselect(index);
209 pListBox->SetCaret(index);
210 }
211
212 return true;
213 }
214
IsIndexSelected(int index)215 bool CFFL_ListBox::IsIndexSelected(int index) {
216 if (!IsValid())
217 return false;
218
219 if (index < 0 || index >= m_pWidget->CountOptions())
220 return false;
221
222 CPWL_ListBox* pListBox = GetListBox(GetCurPageView(true));
223 return pListBox && pListBox->IsItemSelected(index);
224 }
225
GetListBox(CPDFSDK_PageView * pPageView)226 CPWL_ListBox* CFFL_ListBox::GetListBox(CPDFSDK_PageView* pPageView) {
227 return static_cast<CPWL_ListBox*>(GetPWLWindow(pPageView, /*bNew=*/false));
228 }
229