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