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 "fpdfsdk/cpdfsdk_formfillenvironment.h"
10 #include "fpdfsdk/cpdfsdk_widget.h"
11 #include "fpdfsdk/formfiller/cba_fontmap.h"
12 #include "fpdfsdk/formfiller/cffl_formfiller.h"
13 #include "fpdfsdk/formfiller/cffl_interactiveformfiller.h"
14 #include "fpdfsdk/fsdk_common.h"
15 #include "fpdfsdk/pdfwindow/PWL_ComboBox.h"
16
CFFL_ComboBox(CPDFSDK_FormFillEnvironment * pApp,CPDFSDK_Annot * pAnnot)17 CFFL_ComboBox::CFFL_ComboBox(CPDFSDK_FormFillEnvironment* pApp,
18 CPDFSDK_Annot* pAnnot)
19 : CFFL_FormFiller(pApp, pAnnot), m_pFontMap(nullptr) {
20 m_State.nIndex = 0;
21 m_State.nStart = 0;
22 m_State.nEnd = 0;
23 }
24
~CFFL_ComboBox()25 CFFL_ComboBox::~CFFL_ComboBox() {
26 for (const auto& it : m_Maps)
27 it.second->InvalidateFocusHandler(this);
28
29 // See comment in cffl_formfiller.h.
30 // The font map should be stored somewhere more appropriate so it will live
31 // until the PWL_Edit is done with it. pdfium:566
32 DestroyWindows();
33 delete m_pFontMap;
34 }
35
GetCreateParam()36 PWL_CREATEPARAM CFFL_ComboBox::GetCreateParam() {
37 PWL_CREATEPARAM cp = CFFL_FormFiller::GetCreateParam();
38
39 int nFlags = m_pWidget->GetFieldFlags();
40 if (nFlags & FIELDFLAG_EDIT) {
41 cp.dwFlags |= PCBS_ALLOWCUSTOMTEXT;
42 }
43
44 if (!m_pFontMap)
45 m_pFontMap = new CBA_FontMap(m_pWidget, GetSystemHandler());
46 cp.pFontMap = m_pFontMap;
47 cp.pFocusHandler = this;
48
49 return cp;
50 }
51
NewPDFWindow(const PWL_CREATEPARAM & cp,CPDFSDK_PageView * pPageView)52 CPWL_Wnd* CFFL_ComboBox::NewPDFWindow(const PWL_CREATEPARAM& cp,
53 CPDFSDK_PageView* pPageView) {
54 CPWL_ComboBox* pWnd = new CPWL_ComboBox();
55 pWnd->AttachFFLData(this);
56 pWnd->Create(cp);
57
58 CFFL_InteractiveFormFiller* pFormFiller =
59 m_pFormFillEnv->GetInteractiveFormFiller();
60 pWnd->SetFillerNotify(pFormFiller);
61
62 int32_t nCurSel = m_pWidget->GetSelectedIndex(0);
63 CFX_WideString swText;
64 if (nCurSel < 0)
65 swText = m_pWidget->GetValue();
66 else
67 swText = m_pWidget->GetOptionLabel(nCurSel);
68
69 for (int32_t i = 0, sz = m_pWidget->CountOptions(); i < sz; i++) {
70 pWnd->AddString(m_pWidget->GetOptionLabel(i));
71 }
72
73 pWnd->SetSelect(nCurSel);
74 pWnd->SetText(swText);
75 return pWnd;
76 }
77
OnChar(CPDFSDK_Annot * pAnnot,uint32_t nChar,uint32_t nFlags)78 bool CFFL_ComboBox::OnChar(CPDFSDK_Annot* pAnnot,
79 uint32_t nChar,
80 uint32_t nFlags) {
81 return CFFL_FormFiller::OnChar(pAnnot, nChar, nFlags);
82 }
83
IsDataChanged(CPDFSDK_PageView * pPageView)84 bool CFFL_ComboBox::IsDataChanged(CPDFSDK_PageView* pPageView) {
85 CPWL_ComboBox* pWnd = (CPWL_ComboBox*)GetPDFWindow(pPageView, false);
86 if (!pWnd)
87 return false;
88
89 int32_t nCurSel = pWnd->GetSelect();
90 if (!(m_pWidget->GetFieldFlags() & FIELDFLAG_EDIT))
91 return nCurSel != m_pWidget->GetSelectedIndex(0);
92
93 if (nCurSel >= 0)
94 return nCurSel != m_pWidget->GetSelectedIndex(0);
95
96 return pWnd->GetText() != m_pWidget->GetValue();
97 }
98
SaveData(CPDFSDK_PageView * pPageView)99 void CFFL_ComboBox::SaveData(CPDFSDK_PageView* pPageView) {
100 CPWL_ComboBox* pWnd =
101 static_cast<CPWL_ComboBox*>(GetPDFWindow(pPageView, false));
102 if (!pWnd)
103 return;
104
105 CFX_WideString swText = pWnd->GetText();
106 int32_t nCurSel = pWnd->GetSelect();
107
108 bool bSetValue = false;
109
110 if (m_pWidget->GetFieldFlags() & FIELDFLAG_EDIT)
111 bSetValue = (nCurSel < 0) || (swText != m_pWidget->GetOptionLabel(nCurSel));
112
113 if (bSetValue) {
114 m_pWidget->SetValue(swText, false);
115 } else {
116 m_pWidget->GetSelectedIndex(0);
117 m_pWidget->SetOptionSelection(nCurSel, true, false);
118 }
119
120 m_pWidget->ResetFieldAppearance(true);
121 m_pWidget->UpdateField();
122 SetChangeMark();
123
124 m_pWidget->GetPDFPage();
125 }
126
GetActionData(CPDFSDK_PageView * pPageView,CPDF_AAction::AActionType type,PDFSDK_FieldAction & fa)127 void CFFL_ComboBox::GetActionData(CPDFSDK_PageView* pPageView,
128 CPDF_AAction::AActionType type,
129 PDFSDK_FieldAction& fa) {
130 switch (type) {
131 case CPDF_AAction::KeyStroke:
132 if (CPWL_ComboBox* pComboBox =
133 static_cast<CPWL_ComboBox*>(GetPDFWindow(pPageView, false))) {
134 if (CPWL_Edit* pEdit = pComboBox->GetEdit()) {
135 fa.bFieldFull = pEdit->IsTextFull();
136 int nSelStart = 0;
137 int nSelEnd = 0;
138 pEdit->GetSel(nSelStart, nSelEnd);
139 fa.nSelEnd = nSelEnd;
140 fa.nSelStart = nSelStart;
141 fa.sValue = pEdit->GetText();
142 fa.sChangeEx = GetSelectExportText();
143
144 if (fa.bFieldFull) {
145 fa.sChange = L"";
146 fa.sChangeEx = L"";
147 }
148 }
149 }
150 break;
151 case CPDF_AAction::Validate:
152 if (CPWL_ComboBox* pComboBox =
153 static_cast<CPWL_ComboBox*>(GetPDFWindow(pPageView, false))) {
154 if (CPWL_Edit* pEdit = pComboBox->GetEdit()) {
155 fa.sValue = pEdit->GetText();
156 }
157 }
158 break;
159 case CPDF_AAction::LoseFocus:
160 case CPDF_AAction::GetFocus:
161 fa.sValue = m_pWidget->GetValue();
162 break;
163 default:
164 break;
165 }
166 }
167
SetActionData(CPDFSDK_PageView * pPageView,CPDF_AAction::AActionType type,const PDFSDK_FieldAction & fa)168 void CFFL_ComboBox::SetActionData(CPDFSDK_PageView* pPageView,
169 CPDF_AAction::AActionType type,
170 const PDFSDK_FieldAction& fa) {
171 switch (type) {
172 case CPDF_AAction::KeyStroke:
173 if (CPWL_ComboBox* pComboBox =
174 static_cast<CPWL_ComboBox*>(GetPDFWindow(pPageView, false))) {
175 if (CPWL_Edit* pEdit = pComboBox->GetEdit()) {
176 pEdit->SetSel(fa.nSelStart, fa.nSelEnd);
177 pEdit->ReplaceSel(fa.sChange);
178 }
179 }
180 break;
181 default:
182 break;
183 }
184 }
185
IsActionDataChanged(CPDF_AAction::AActionType type,const PDFSDK_FieldAction & faOld,const PDFSDK_FieldAction & faNew)186 bool CFFL_ComboBox::IsActionDataChanged(CPDF_AAction::AActionType type,
187 const PDFSDK_FieldAction& faOld,
188 const PDFSDK_FieldAction& faNew) {
189 switch (type) {
190 case CPDF_AAction::KeyStroke:
191 return (!faOld.bFieldFull && faOld.nSelEnd != faNew.nSelEnd) ||
192 faOld.nSelStart != faNew.nSelStart ||
193 faOld.sChange != faNew.sChange;
194 default:
195 break;
196 }
197
198 return false;
199 }
200
SaveState(CPDFSDK_PageView * pPageView)201 void CFFL_ComboBox::SaveState(CPDFSDK_PageView* pPageView) {
202 ASSERT(pPageView);
203
204 if (CPWL_ComboBox* pComboBox =
205 static_cast<CPWL_ComboBox*>(GetPDFWindow(pPageView, false))) {
206 m_State.nIndex = pComboBox->GetSelect();
207
208 if (CPWL_Edit* pEdit = pComboBox->GetEdit()) {
209 pEdit->GetSel(m_State.nStart, m_State.nEnd);
210 m_State.sValue = pEdit->GetText();
211 }
212 }
213 }
214
RestoreState(CPDFSDK_PageView * pPageView)215 void CFFL_ComboBox::RestoreState(CPDFSDK_PageView* pPageView) {
216 ASSERT(pPageView);
217
218 if (CPWL_ComboBox* pComboBox =
219 static_cast<CPWL_ComboBox*>(GetPDFWindow(pPageView, true))) {
220 if (m_State.nIndex >= 0) {
221 pComboBox->SetSelect(m_State.nIndex);
222 } else {
223 if (CPWL_Edit* pEdit = pComboBox->GetEdit()) {
224 pEdit->SetText(m_State.sValue);
225 pEdit->SetSel(m_State.nStart, m_State.nEnd);
226 }
227 }
228 }
229 }
230
ResetPDFWindow(CPDFSDK_PageView * pPageView,bool bRestoreValue)231 CPWL_Wnd* CFFL_ComboBox::ResetPDFWindow(CPDFSDK_PageView* pPageView,
232 bool bRestoreValue) {
233 if (bRestoreValue)
234 SaveState(pPageView);
235
236 DestroyPDFWindow(pPageView);
237
238 CPWL_Wnd* pRet = nullptr;
239
240 if (bRestoreValue) {
241 RestoreState(pPageView);
242 pRet = GetPDFWindow(pPageView, false);
243 } else {
244 pRet = GetPDFWindow(pPageView, true);
245 }
246
247 m_pWidget->UpdateField();
248
249 return pRet;
250 }
251
252 #ifdef PDF_ENABLE_XFA
IsFieldFull(CPDFSDK_PageView * pPageView)253 bool CFFL_ComboBox::IsFieldFull(CPDFSDK_PageView* pPageView) {
254 if (CPWL_ComboBox* pComboBox =
255 static_cast<CPWL_ComboBox*>(GetPDFWindow(pPageView, false))) {
256 if (CPWL_Edit* pEdit = pComboBox->GetEdit())
257 return pEdit->IsTextFull();
258 }
259 return false;
260 }
261 #endif // PDF_ENABLE_XFA
262
OnSetFocus(CPWL_Wnd * pWnd)263 void CFFL_ComboBox::OnSetFocus(CPWL_Wnd* pWnd) {
264 ASSERT(m_pFormFillEnv);
265
266 if (pWnd->GetClassName() == PWL_CLASSNAME_EDIT) {
267 CPWL_Edit* pEdit = (CPWL_Edit*)pWnd;
268 pEdit->SetCharSet(FXFONT_GB2312_CHARSET);
269 pEdit->SetCodePage(936);
270
271 pEdit->SetReadyToInput();
272 CFX_WideString wsText = pEdit->GetText();
273 int nCharacters = wsText.GetLength();
274 CFX_ByteString bsUTFText = wsText.UTF16LE_Encode();
275 unsigned short* pBuffer = (unsigned short*)bsUTFText.c_str();
276 m_pFormFillEnv->OnSetFieldInputFocus(pBuffer, nCharacters, true);
277 }
278 }
279
GetSelectExportText()280 CFX_WideString CFFL_ComboBox::GetSelectExportText() {
281 CFX_WideString swRet;
282
283 int nExport = -1;
284 CPDFSDK_PageView* pPageView = GetCurPageView(true);
285 if (CPWL_ComboBox* pComboBox =
286 (CPWL_ComboBox*)GetPDFWindow(pPageView, false)) {
287 nExport = pComboBox->GetSelect();
288 }
289
290 if (nExport >= 0) {
291 if (CPDF_FormField* pFormField = m_pWidget->GetFormField()) {
292 swRet = pFormField->GetOptionValue(nExport);
293 if (swRet.IsEmpty())
294 swRet = pFormField->GetOptionLabel(nExport);
295 }
296 }
297
298 return swRet;
299 }
300