xref: /aosp_15_r20/external/pdfium/fpdfsdk/formfiller/cffl_listbox.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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