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_interactiveformfiller.h" 13#include "fpdfsdk/fsdk_common.h" 14#include "fpdfsdk/pwl/cpwl_combo_box.h" 15#include "third_party/base/ptr_util.h" 16 17CFFL_ComboBox::CFFL_ComboBox(CPDFSDK_FormFillEnvironment* pApp, 18 CPDFSDK_Widget* pWidget) 19 : CFFL_TextObject(pApp, pWidget) { 20 m_State.nIndex = 0; 21 m_State.nStart = 0; 22 m_State.nEnd = 0; 23} 24 25CFFL_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} 34 35CPWL_Wnd::CreateParams CFFL_ComboBox::GetCreateParam() { 36 CPWL_Wnd::CreateParams cp = CFFL_TextObject::GetCreateParam(); 37 if (m_pWidget->GetFieldFlags() & FIELDFLAG_EDIT) 38 cp.dwFlags |= PCBS_ALLOWCUSTOMTEXT; 39 40 cp.pFontMap = MaybeCreateFontMap(); 41 cp.pFocusHandler = this; 42 return cp; 43} 44 45CPWL_Wnd* CFFL_ComboBox::NewPDFWindow(const CPWL_Wnd::CreateParams& cp) { 46 auto* pWnd = new CPWL_ComboBox(); 47 pWnd->AttachFFLData(this); 48 pWnd->Create(cp); 49 50 CFFL_InteractiveFormFiller* pFormFiller = 51 m_pFormFillEnv->GetInteractiveFormFiller(); 52 pWnd->SetFillerNotify(pFormFiller); 53 54 int32_t nCurSel = m_pWidget->GetSelectedIndex(0); 55 WideString swText; 56 if (nCurSel < 0) 57 swText = m_pWidget->GetValue(); 58 else 59 swText = m_pWidget->GetOptionLabel(nCurSel); 60 61 for (int32_t i = 0, sz = m_pWidget->CountOptions(); i < sz; i++) { 62 pWnd->AddString(m_pWidget->GetOptionLabel(i)); 63 } 64 65 pWnd->SetSelect(nCurSel); 66 pWnd->SetText(swText); 67 return pWnd; 68} 69 70bool CFFL_ComboBox::OnChar(CPDFSDK_Annot* pAnnot, 71 uint32_t nChar, 72 uint32_t nFlags) { 73 return CFFL_TextObject::OnChar(pAnnot, nChar, nFlags); 74} 75 76bool CFFL_ComboBox::IsDataChanged(CPDFSDK_PageView* pPageView) { 77 CPWL_ComboBox* pWnd = (CPWL_ComboBox*)GetPDFWindow(pPageView, false); 78 if (!pWnd) 79 return false; 80 81 int32_t nCurSel = pWnd->GetSelect(); 82 if (!(m_pWidget->GetFieldFlags() & FIELDFLAG_EDIT)) 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 91void CFFL_ComboBox::SaveData(CPDFSDK_PageView* pPageView) { 92 CPWL_ComboBox* pWnd = 93 static_cast<CPWL_ComboBox*>(GetPDFWindow(pPageView, false)); 94 if (!pWnd) 95 return; 96 97 WideString swText = pWnd->GetText(); 98 int32_t nCurSel = pWnd->GetSelect(); 99 100 bool bSetValue = false; 101 102 if (m_pWidget->GetFieldFlags() & FIELDFLAG_EDIT) 103 bSetValue = (nCurSel < 0) || (swText != m_pWidget->GetOptionLabel(nCurSel)); 104 105 if (bSetValue) { 106 m_pWidget->SetValue(swText, false); 107 } else { 108 m_pWidget->GetSelectedIndex(0); 109 m_pWidget->SetOptionSelection(nCurSel, true, false); 110 } 111 CPDFSDK_Widget::ObservedPtr observed_widget(m_pWidget.Get()); 112 CFFL_ComboBox::ObservedPtr observed_this(this); 113 114 m_pWidget->ResetFieldAppearance(true); 115 if (!observed_widget) 116 return; 117 m_pWidget->UpdateField(); 118 if (!observed_widget || !observed_this) 119 return; 120 SetChangeMark(); 121 m_pWidget->GetPDFPage(); 122} 123 124void CFFL_ComboBox::GetActionData(CPDFSDK_PageView* pPageView, 125 CPDF_AAction::AActionType type, 126 PDFSDK_FieldAction& fa) { 127 switch (type) { 128 case CPDF_AAction::KeyStroke: 129 if (CPWL_ComboBox* pComboBox = 130 static_cast<CPWL_ComboBox*>(GetPDFWindow(pPageView, false))) { 131 if (CPWL_Edit* pEdit = pComboBox->GetEdit()) { 132 fa.bFieldFull = pEdit->IsTextFull(); 133 int nSelStart = 0; 134 int nSelEnd = 0; 135 pEdit->GetSelection(nSelStart, nSelEnd); 136 fa.nSelEnd = nSelEnd; 137 fa.nSelStart = nSelStart; 138 fa.sValue = pEdit->GetText(); 139 fa.sChangeEx = GetSelectExportText(); 140 141 if (fa.bFieldFull) { 142 fa.sChange = L""; 143 fa.sChangeEx = L""; 144 } 145 } 146 } 147 break; 148 case CPDF_AAction::Validate: 149 if (CPWL_ComboBox* pComboBox = 150 static_cast<CPWL_ComboBox*>(GetPDFWindow(pPageView, false))) { 151 if (CPWL_Edit* pEdit = pComboBox->GetEdit()) { 152 fa.sValue = pEdit->GetText(); 153 } 154 } 155 break; 156 case CPDF_AAction::LoseFocus: 157 case CPDF_AAction::GetFocus: 158 fa.sValue = m_pWidget->GetValue(); 159 break; 160 default: 161 break; 162 } 163} 164 165void CFFL_ComboBox::SetActionData(CPDFSDK_PageView* pPageView, 166 CPDF_AAction::AActionType type, 167 const PDFSDK_FieldAction& fa) { 168 switch (type) { 169 case CPDF_AAction::KeyStroke: 170 if (CPWL_ComboBox* pComboBox = 171 static_cast<CPWL_ComboBox*>(GetPDFWindow(pPageView, false))) { 172 if (CPWL_Edit* pEdit = pComboBox->GetEdit()) { 173 pEdit->SetSelection(fa.nSelStart, fa.nSelEnd); 174 pEdit->ReplaceSel(fa.sChange); 175 } 176 } 177 break; 178 default: 179 break; 180 } 181} 182 183bool CFFL_ComboBox::IsActionDataChanged(CPDF_AAction::AActionType type, 184 const PDFSDK_FieldAction& faOld, 185 const PDFSDK_FieldAction& faNew) { 186 switch (type) { 187 case CPDF_AAction::KeyStroke: 188 return (!faOld.bFieldFull && faOld.nSelEnd != faNew.nSelEnd) || 189 faOld.nSelStart != faNew.nSelStart || 190 faOld.sChange != faNew.sChange; 191 default: 192 break; 193 } 194 195 return false; 196} 197 198void CFFL_ComboBox::SaveState(CPDFSDK_PageView* pPageView) { 199 ASSERT(pPageView); 200 201 if (CPWL_ComboBox* pComboBox = 202 static_cast<CPWL_ComboBox*>(GetPDFWindow(pPageView, false))) { 203 m_State.nIndex = pComboBox->GetSelect(); 204 205 if (CPWL_Edit* pEdit = pComboBox->GetEdit()) { 206 pEdit->GetSelection(m_State.nStart, m_State.nEnd); 207 m_State.sValue = pEdit->GetText(); 208 } 209 } 210} 211 212void CFFL_ComboBox::RestoreState(CPDFSDK_PageView* pPageView) { 213 ASSERT(pPageView); 214 215 if (CPWL_ComboBox* pComboBox = 216 static_cast<CPWL_ComboBox*>(GetPDFWindow(pPageView, true))) { 217 if (m_State.nIndex >= 0) { 218 pComboBox->SetSelect(m_State.nIndex); 219 } else { 220 if (CPWL_Edit* pEdit = pComboBox->GetEdit()) { 221 pEdit->SetText(m_State.sValue); 222 pEdit->SetSelection(m_State.nStart, m_State.nEnd); 223 } 224 } 225 } 226} 227 228#ifdef PDF_ENABLE_XFA 229bool CFFL_ComboBox::IsFieldFull(CPDFSDK_PageView* pPageView) { 230 if (CPWL_ComboBox* pComboBox = 231 static_cast<CPWL_ComboBox*>(GetPDFWindow(pPageView, false))) { 232 if (CPWL_Edit* pEdit = pComboBox->GetEdit()) 233 return pEdit->IsTextFull(); 234 } 235 return false; 236} 237#endif // PDF_ENABLE_XFA 238 239void CFFL_ComboBox::OnSetFocus(CPWL_Edit* pEdit) { 240 pEdit->SetCharSet(FX_CHARSET_ChineseSimplified); 241 pEdit->SetReadyToInput(); 242 243 WideString wsText = pEdit->GetText(); 244 int nCharacters = wsText.GetLength(); 245 ByteString bsUTFText = wsText.UTF16LE_Encode(); 246 auto* pBuffer = reinterpret_cast<const unsigned short*>(bsUTFText.c_str()); 247 m_pFormFillEnv->OnSetFieldInputFocus(pBuffer, nCharacters, true); 248} 249 250WideString CFFL_ComboBox::GetSelectExportText() { 251 WideString swRet; 252 253 int nExport = -1; 254 CPDFSDK_PageView* pPageView = GetCurPageView(true); 255 if (CPWL_ComboBox* pComboBox = 256 (CPWL_ComboBox*)GetPDFWindow(pPageView, false)) { 257 nExport = pComboBox->GetSelect(); 258 } 259 260 if (nExport >= 0) { 261 if (CPDF_FormField* pFormField = m_pWidget->GetFormField()) { 262 swRet = pFormField->GetOptionValue(nExport); 263 if (swRet.IsEmpty()) 264 swRet = pFormField->GetOptionLabel(nExport); 265 } 266 } 267 268 return swRet; 269} 270