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_combobox.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_combo_box.h"
17 #include "fpdfsdk/pwl/cpwl_edit.h"
18
CFFL_ComboBox(CFFL_InteractiveFormFiller * pFormFiller,CPDFSDK_Widget * pWidget)19 CFFL_ComboBox::CFFL_ComboBox(CFFL_InteractiveFormFiller* pFormFiller,
20 CPDFSDK_Widget* pWidget)
21 : CFFL_TextObject(pFormFiller, pWidget) {}
22
~CFFL_ComboBox()23 CFFL_ComboBox::~CFFL_ComboBox() {
24 // See comment in cffl_formfiller.h.
25 // The font map should be stored somewhere more appropriate so it will live
26 // until the PWL_Edit is done with it. pdfium:566
27 DestroyWindows();
28 }
29
GetCreateParam()30 CPWL_Wnd::CreateParams CFFL_ComboBox::GetCreateParam() {
31 CPWL_Wnd::CreateParams cp = CFFL_TextObject::GetCreateParam();
32 if (m_pWidget->GetFieldFlags() & pdfium::form_flags::kChoiceEdit)
33 cp.dwFlags |= PCBS_ALLOWCUSTOMTEXT;
34
35 cp.pFontMap = GetOrCreateFontMap();
36 return cp;
37 }
38
NewPWLWindow(const CPWL_Wnd::CreateParams & cp,std::unique_ptr<IPWL_FillerNotify::PerWindowData> pAttachedData)39 std::unique_ptr<CPWL_Wnd> CFFL_ComboBox::NewPWLWindow(
40 const CPWL_Wnd::CreateParams& cp,
41 std::unique_ptr<IPWL_FillerNotify::PerWindowData> pAttachedData) {
42 static_cast<CFFL_PerWindowData*>(pAttachedData.get())->SetFormField(this);
43 auto pWnd = std::make_unique<CPWL_ComboBox>(cp, std::move(pAttachedData));
44 pWnd->Realize();
45
46 int32_t nCurSel = m_pWidget->GetSelectedIndex(0);
47 WideString swText;
48 if (nCurSel < 0)
49 swText = m_pWidget->GetValue();
50 else
51 swText = m_pWidget->GetOptionLabel(nCurSel);
52
53 for (int32_t i = 0, sz = m_pWidget->CountOptions(); i < sz; i++)
54 pWnd->AddString(m_pWidget->GetOptionLabel(i));
55
56 pWnd->SetSelect(nCurSel);
57 pWnd->SetText(swText);
58 return pWnd;
59 }
60
OnChar(CPDFSDK_Widget * pWidget,uint32_t nChar,Mask<FWL_EVENTFLAG> nFlags)61 bool CFFL_ComboBox::OnChar(CPDFSDK_Widget* pWidget,
62 uint32_t nChar,
63 Mask<FWL_EVENTFLAG> nFlags) {
64 return CFFL_TextObject::OnChar(pWidget, nChar, nFlags);
65 }
66
IsDataChanged(const CPDFSDK_PageView * pPageView)67 bool CFFL_ComboBox::IsDataChanged(const CPDFSDK_PageView* pPageView) {
68 auto* pWnd = GetPWLComboBox(pPageView);
69 if (!pWnd)
70 return false;
71
72 int32_t nCurSel = pWnd->GetSelect();
73 if (!(m_pWidget->GetFieldFlags() & pdfium::form_flags::kChoiceEdit))
74 return nCurSel != m_pWidget->GetSelectedIndex(0);
75
76 if (nCurSel >= 0)
77 return nCurSel != m_pWidget->GetSelectedIndex(0);
78
79 return pWnd->GetText() != m_pWidget->GetValue();
80 }
81
SaveData(const CPDFSDK_PageView * pPageView)82 void CFFL_ComboBox::SaveData(const CPDFSDK_PageView* pPageView) {
83 ObservedPtr<CFFL_ComboBox> observed_this(this);
84 CPWL_ComboBox* pWnd = observed_this->GetPWLComboBox(pPageView);
85 if (!pWnd) {
86 return;
87 }
88 WideString swText = pWnd->GetText();
89 int32_t nCurSel = pWnd->GetSelect();
90 bool bSetValue = false;
91 ObservedPtr<CPDFSDK_Widget> observed_widget(observed_this->m_pWidget);
92 if (observed_widget->GetFieldFlags() & pdfium::form_flags::kChoiceEdit) {
93 bSetValue =
94 (nCurSel < 0) || (swText != observed_widget->GetOptionLabel(nCurSel));
95 }
96 if (bSetValue) {
97 observed_widget->SetValue(swText);
98 } else {
99 observed_widget->GetSelectedIndex(0);
100 observed_widget->SetOptionSelection(nCurSel);
101 }
102 if (!observed_widget) {
103 return;
104 }
105 observed_widget->ResetFieldAppearance();
106 if (!observed_widget) {
107 return;
108 }
109 observed_widget->UpdateField();
110 if (!observed_widget || !observed_this) {
111 return;
112 }
113 observed_this->SetChangeMark();
114 }
115
GetActionData(const CPDFSDK_PageView * pPageView,CPDF_AAction::AActionType type,CFFL_FieldAction & fa)116 void CFFL_ComboBox::GetActionData(const CPDFSDK_PageView* pPageView,
117 CPDF_AAction::AActionType type,
118 CFFL_FieldAction& fa) {
119 switch (type) {
120 case CPDF_AAction::kKeyStroke:
121 if (CPWL_ComboBox* pComboBox = GetPWLComboBox(pPageView)) {
122 if (CPWL_Edit* pEdit = pComboBox->GetEdit()) {
123 fa.bFieldFull = pEdit->IsTextFull();
124 std::tie(fa.nSelStart, fa.nSelEnd) = pEdit->GetSelection();
125 fa.sValue = pEdit->GetText();
126 fa.sChangeEx = GetSelectExportText();
127
128 if (fa.bFieldFull) {
129 fa.sChange.clear();
130 fa.sChangeEx.clear();
131 }
132 }
133 }
134 break;
135 case CPDF_AAction::kValidate:
136 if (CPWL_ComboBox* pComboBox = GetPWLComboBox(pPageView)) {
137 if (CPWL_Edit* pEdit = pComboBox->GetEdit()) {
138 fa.sValue = pEdit->GetText();
139 }
140 }
141 break;
142 case CPDF_AAction::kLoseFocus:
143 case CPDF_AAction::kGetFocus:
144 fa.sValue = m_pWidget->GetValue();
145 break;
146 default:
147 break;
148 }
149 }
150
SetActionData(const CPDFSDK_PageView * pPageView,CPDF_AAction::AActionType type,const CFFL_FieldAction & fa)151 void CFFL_ComboBox::SetActionData(const CPDFSDK_PageView* pPageView,
152 CPDF_AAction::AActionType type,
153 const CFFL_FieldAction& fa) {
154 switch (type) {
155 case CPDF_AAction::kKeyStroke:
156 if (CPWL_ComboBox* pComboBox = GetPWLComboBox(pPageView)) {
157 if (CPWL_Edit* pEdit = pComboBox->GetEdit()) {
158 pEdit->SetSelection(fa.nSelStart, fa.nSelEnd);
159 pEdit->ReplaceSelection(fa.sChange);
160 }
161 }
162 break;
163 default:
164 break;
165 }
166 }
167
SavePWLWindowState(const CPDFSDK_PageView * pPageView)168 void CFFL_ComboBox::SavePWLWindowState(const CPDFSDK_PageView* pPageView) {
169 CPWL_ComboBox* pComboBox = GetPWLComboBox(pPageView);
170 if (!pComboBox)
171 return;
172
173 m_State.nIndex = pComboBox->GetSelect();
174
175 CPWL_Edit* pEdit = pComboBox->GetEdit();
176 if (!pEdit)
177 return;
178
179 std::tie(m_State.nStart, m_State.nEnd) = pEdit->GetSelection();
180 m_State.sValue = pEdit->GetText();
181 }
182
RecreatePWLWindowFromSavedState(const CPDFSDK_PageView * pPageView)183 void CFFL_ComboBox::RecreatePWLWindowFromSavedState(
184 const CPDFSDK_PageView* pPageView) {
185 CPWL_ComboBox* pComboBox = CreateOrUpdatePWLComboBox(pPageView);
186 if (!pComboBox)
187 return;
188
189 if (m_State.nIndex >= 0) {
190 pComboBox->SetSelect(m_State.nIndex);
191 return;
192 }
193
194 CPWL_Edit* pEdit = pComboBox->GetEdit();
195 if (!pEdit)
196 return;
197
198 pEdit->SetText(m_State.sValue);
199 pEdit->SetSelection(m_State.nStart, m_State.nEnd);
200 }
201
SetIndexSelected(int index,bool selected)202 bool CFFL_ComboBox::SetIndexSelected(int index, bool selected) {
203 if (!IsValid() || !selected)
204 return false;
205
206 if (index < 0 || index >= m_pWidget->CountOptions())
207 return false;
208
209 CPWL_ComboBox* pWnd = GetPWLComboBox(GetCurPageView());
210 if (!pWnd)
211 return false;
212
213 pWnd->SetSelect(index);
214 return true;
215 }
216
IsIndexSelected(int index)217 bool CFFL_ComboBox::IsIndexSelected(int index) {
218 if (!IsValid())
219 return false;
220
221 if (index < 0 || index >= m_pWidget->CountOptions())
222 return false;
223
224 CPWL_ComboBox* pWnd = GetPWLComboBox(GetCurPageView());
225 return pWnd && index == pWnd->GetSelect();
226 }
227
228 #ifdef PDF_ENABLE_XFA
IsFieldFull(const CPDFSDK_PageView * pPageView)229 bool CFFL_ComboBox::IsFieldFull(const CPDFSDK_PageView* pPageView) {
230 CPWL_ComboBox* pComboBox = GetPWLComboBox(pPageView);
231 if (!pComboBox)
232 return false;
233
234 CPWL_Edit* pEdit = pComboBox->GetEdit();
235 return pEdit && pEdit->IsTextFull();
236 }
237 #endif // PDF_ENABLE_XFA
238
OnSetFocusForEdit(CPWL_Edit * pEdit)239 void CFFL_ComboBox::OnSetFocusForEdit(CPWL_Edit* pEdit) {
240 pEdit->SetCharSet(FX_Charset::kChineseSimplified);
241 pEdit->SetReadyToInput();
242 m_pFormFiller->OnSetFieldInputFocus(pEdit->GetText());
243 }
244
GetSelectExportText()245 WideString CFFL_ComboBox::GetSelectExportText() {
246 CPWL_ComboBox* pComboBox = GetPWLComboBox(GetCurPageView());
247 int nExport = pComboBox ? pComboBox->GetSelect() : -1;
248 return m_pWidget->GetSelectExportText(nExport);
249 }
250
GetPWLComboBox(const CPDFSDK_PageView * pPageView) const251 CPWL_ComboBox* CFFL_ComboBox::GetPWLComboBox(
252 const CPDFSDK_PageView* pPageView) const {
253 return static_cast<CPWL_ComboBox*>(GetPWLWindow(pPageView));
254 }
255
CreateOrUpdatePWLComboBox(const CPDFSDK_PageView * pPageView)256 CPWL_ComboBox* CFFL_ComboBox::CreateOrUpdatePWLComboBox(
257 const CPDFSDK_PageView* pPageView) {
258 return static_cast<CPWL_ComboBox*>(CreateOrUpdatePWLWindow(pPageView));
259 }
260