blob: dc45fbcec7833066ebd9f4ffb4fcc043c129440a [file] [log] [blame]
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001// 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.
Lei Zhang95e854f2015-06-13 00:58:06 -07004
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07005// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
dsinclair1727aee2016-09-29 13:12:56 -07007#include "core/fpdfdoc/cpdf_formfield.h"
dsinclaircac704d2016-07-28 12:59:09 -07008
thestig695aac52016-08-25 09:13:52 -07009#include <set>
10
dsinclair488b7ad2016-10-04 11:55:50 -070011#include "core/fpdfapi/parser/cfdf_document.h"
12#include "core/fpdfapi/parser/cpdf_array.h"
13#include "core/fpdfapi/parser/cpdf_document.h"
14#include "core/fpdfapi/parser/cpdf_number.h"
15#include "core/fpdfapi/parser/cpdf_simple_parser.h"
16#include "core/fpdfapi/parser/cpdf_string.h"
17#include "core/fpdfapi/parser/fpdf_parser_decode.h"
dsinclair1727aee2016-09-29 13:12:56 -070018#include "core/fpdfdoc/cpdf_formcontrol.h"
19#include "core/fpdfdoc/cpdf_interform.h"
dsinclair777b3332016-03-31 20:03:08 -070020#include "core/fpdfdoc/cpvt_generateap.h"
thestig695aac52016-08-25 09:13:52 -070021#include "third_party/base/stl_util.h"
Tom Sepezeff208f2015-05-08 13:45:01 -070022
thestigdb1a24e2016-05-23 16:55:09 -070023namespace {
24
dsinclair27053d82016-08-02 15:43:46 -070025const int kMaxRecursion = 32;
26
dsinclaircac704d2016-07-28 12:59:09 -070027const int kFormListMultiSelect = 0x100;
28
29const int kFormComboEdit = 0x100;
30
31const int kFormFieldReadOnly = 0x01;
32const int kFormFieldRequired = 0x02;
33const int kFormFieldNoExport = 0x04;
34
35const int kFormRadioNoToggleOff = 0x100;
36const int kFormRadioUnison = 0x200;
37
38const int kFormTextMultiLine = 0x100;
39const int kFormTextPassword = 0x200;
40const int kFormTextNoScroll = 0x400;
41const int kFormTextComb = 0x800;
42
dsinclair27053d82016-08-02 15:43:46 -070043bool IsUnison(CPDF_FormField* pField) {
thestigdb1a24e2016-05-23 16:55:09 -070044 if (pField->GetType() == CPDF_FormField::CheckBox)
45 return true;
thestigdb1a24e2016-05-23 16:55:09 -070046 return (pField->GetFieldFlags() & 0x2000000) != 0;
Nico Weber9d8ec5a2015-08-04 13:00:21 -070047}
thestigdb1a24e2016-05-23 16:55:09 -070048
49} // namespace
50
dsinclair27053d82016-08-02 15:43:46 -070051CPDF_Object* FPDF_GetFieldAttr(CPDF_Dictionary* pFieldDict,
52 const FX_CHAR* name,
53 int nLevel) {
54 if (nLevel > kMaxRecursion)
55 return nullptr;
56 if (!pFieldDict)
57 return nullptr;
58
dsinclair38fd8442016-09-15 10:15:32 -070059 CPDF_Object* pAttr = pFieldDict->GetDirectObjectFor(name);
dsinclair27053d82016-08-02 15:43:46 -070060 if (pAttr)
61 return pAttr;
62
dsinclair38fd8442016-09-15 10:15:32 -070063 CPDF_Dictionary* pParent = pFieldDict->GetDictFor("Parent");
dsinclair27053d82016-08-02 15:43:46 -070064 if (!pParent)
65 return nullptr;
66 return FPDF_GetFieldAttr(pParent, name, nLevel + 1);
67}
68
69CFX_WideString FPDF_GetFullName(CPDF_Dictionary* pFieldDict) {
70 CFX_WideString full_name;
thestig695aac52016-08-25 09:13:52 -070071 std::set<CPDF_Dictionary*> visited;
dsinclair27053d82016-08-02 15:43:46 -070072 CPDF_Dictionary* pLevel = pFieldDict;
73 while (pLevel) {
thestig695aac52016-08-25 09:13:52 -070074 visited.insert(pLevel);
dsinclair38fd8442016-09-15 10:15:32 -070075 CFX_WideString short_name = pLevel->GetUnicodeTextFor("T");
thestig695aac52016-08-25 09:13:52 -070076 if (!short_name.IsEmpty()) {
77 if (full_name.IsEmpty())
dsinclair27053d82016-08-02 15:43:46 -070078 full_name = short_name;
79 else
80 full_name = short_name + L"." + full_name;
81 }
dsinclair38fd8442016-09-15 10:15:32 -070082 pLevel = pLevel->GetDictFor("Parent");
thestig695aac52016-08-25 09:13:52 -070083 if (pdfium::ContainsKey(visited, pLevel))
84 break;
dsinclair27053d82016-08-02 15:43:46 -070085 }
86 return full_name;
87}
88
thestigdb1a24e2016-05-23 16:55:09 -070089CPDF_FormField::CPDF_FormField(CPDF_InterForm* pForm, CPDF_Dictionary* pDict)
90 : m_Type(Unknown),
91 m_pForm(pForm),
92 m_pDict(pDict),
93 m_FontSize(0),
94 m_pFont(nullptr) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -070095 SyncFieldFlags();
96}
thestigdb1a24e2016-05-23 16:55:09 -070097
Nico Weber9d8ec5a2015-08-04 13:00:21 -070098CPDF_FormField::~CPDF_FormField() {}
thestigdb1a24e2016-05-23 16:55:09 -070099
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700100void CPDF_FormField::SyncFieldFlags() {
101 CFX_ByteString type_name = FPDF_GetFieldAttr(m_pDict, "FT")
102 ? FPDF_GetFieldAttr(m_pDict, "FT")->GetString()
103 : CFX_ByteString();
tsepezb5e8f142016-03-25 15:18:35 -0700104 uint32_t flags = FPDF_GetFieldAttr(m_pDict, "Ff")
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700105 ? FPDF_GetFieldAttr(m_pDict, "Ff")->GetInteger()
106 : 0;
107 m_Flags = 0;
dsinclair27053d82016-08-02 15:43:46 -0700108 if (flags & 1)
dsinclaircac704d2016-07-28 12:59:09 -0700109 m_Flags |= kFormFieldReadOnly;
dsinclair27053d82016-08-02 15:43:46 -0700110 if (flags & 2)
dsinclaircac704d2016-07-28 12:59:09 -0700111 m_Flags |= kFormFieldRequired;
dsinclair27053d82016-08-02 15:43:46 -0700112 if (flags & 4)
dsinclaircac704d2016-07-28 12:59:09 -0700113 m_Flags |= kFormFieldNoExport;
dsinclair27053d82016-08-02 15:43:46 -0700114
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700115 if (type_name == "Btn") {
116 if (flags & 0x8000) {
117 m_Type = RadioButton;
dsinclair27053d82016-08-02 15:43:46 -0700118 if (flags & 0x4000)
dsinclaircac704d2016-07-28 12:59:09 -0700119 m_Flags |= kFormRadioNoToggleOff;
dsinclair27053d82016-08-02 15:43:46 -0700120 if (flags & 0x2000000)
dsinclaircac704d2016-07-28 12:59:09 -0700121 m_Flags |= kFormRadioUnison;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700122 } else if (flags & 0x10000) {
123 m_Type = PushButton;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700124 } else {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700125 m_Type = CheckBox;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700126 }
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700127 } else if (type_name == "Tx") {
128 if (flags & 0x100000) {
129 m_Type = File;
130 } else if (flags & 0x2000000) {
131 m_Type = RichText;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700132 } else {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700133 m_Type = Text;
dsinclair27053d82016-08-02 15:43:46 -0700134 if (flags & 0x1000)
dsinclaircac704d2016-07-28 12:59:09 -0700135 m_Flags |= kFormTextMultiLine;
dsinclair27053d82016-08-02 15:43:46 -0700136 if (flags & 0x2000)
dsinclaircac704d2016-07-28 12:59:09 -0700137 m_Flags |= kFormTextPassword;
dsinclair27053d82016-08-02 15:43:46 -0700138 if (flags & 0x800000)
dsinclaircac704d2016-07-28 12:59:09 -0700139 m_Flags |= kFormTextNoScroll;
dsinclair27053d82016-08-02 15:43:46 -0700140 if (flags & 0x100000)
dsinclaircac704d2016-07-28 12:59:09 -0700141 m_Flags |= kFormTextComb;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700142 }
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700143 LoadDA();
144 } else if (type_name == "Ch") {
145 if (flags & 0x20000) {
146 m_Type = ComboBox;
dsinclair27053d82016-08-02 15:43:46 -0700147 if (flags & 0x40000)
dsinclaircac704d2016-07-28 12:59:09 -0700148 m_Flags |= kFormComboEdit;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700149 } else {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700150 m_Type = ListBox;
dsinclair27053d82016-08-02 15:43:46 -0700151 if (flags & 0x200000)
dsinclaircac704d2016-07-28 12:59:09 -0700152 m_Flags |= kFormListMultiSelect;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700153 }
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700154 LoadDA();
155 } else if (type_name == "Sig") {
156 m_Type = Sign;
157 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700158}
dsinclair27053d82016-08-02 15:43:46 -0700159
tsepezc1835612016-06-08 13:30:06 -0700160CFX_WideString CPDF_FormField::GetFullName() const {
dsinclair27053d82016-08-02 15:43:46 -0700161 return FPDF_GetFullName(m_pDict);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700162}
thestigdb1a24e2016-05-23 16:55:09 -0700163
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700164FX_BOOL CPDF_FormField::ResetField(FX_BOOL bNotify) {
165 switch (m_Type) {
166 case CPDF_FormField::CheckBox:
167 case CPDF_FormField::RadioButton: {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700168 int iCount = CountControls();
169 if (iCount) {
Wei Li97da9762016-03-11 17:00:48 -0800170 // TODO(weili): Check whether anything special needs to be done for
171 // unison field. Otherwise, merge these branches.
dsinclair27053d82016-08-02 15:43:46 -0700172 if (IsUnison(this)) {
173 for (int i = 0; i < iCount; i++)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700174 CheckControl(i, GetControl(i)->IsDefaultChecked(), FALSE);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700175 } else {
dsinclair27053d82016-08-02 15:43:46 -0700176 for (int i = 0; i < iCount; i++)
Wei Li97da9762016-03-11 17:00:48 -0800177 CheckControl(i, GetControl(i)->IsDefaultChecked(), FALSE);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700178 }
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700179 }
dsinclair27053d82016-08-02 15:43:46 -0700180 if (bNotify && m_pForm->m_pFormNotify)
Tom Sepezed5d7aa2016-02-02 16:02:03 -0800181 m_pForm->m_pFormNotify->AfterCheckedStatusChange(this);
dsinclair27053d82016-08-02 15:43:46 -0700182 break;
183 }
thestigdb1a24e2016-05-23 16:55:09 -0700184 case CPDF_FormField::ComboBox:
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700185 case CPDF_FormField::ListBox: {
186 CFX_WideString csValue;
187 ClearSelection();
188 int iIndex = GetDefaultSelectedItem();
thestigdb1a24e2016-05-23 16:55:09 -0700189 if (iIndex >= 0)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700190 csValue = GetOptionLabel(iIndex);
thestigdb1a24e2016-05-23 16:55:09 -0700191
192 if (bNotify && !NotifyListOrComboBoxBeforeChange(csValue))
193 return FALSE;
194
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700195 SetItemSelection(iIndex, TRUE);
thestigdb1a24e2016-05-23 16:55:09 -0700196 if (bNotify)
197 NotifyListOrComboBoxAfterChange();
dsinclair27053d82016-08-02 15:43:46 -0700198 break;
199 }
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700200 case CPDF_FormField::Text:
201 case CPDF_FormField::RichText:
202 case CPDF_FormField::File:
203 default: {
204 CPDF_Object* pDV = FPDF_GetFieldAttr(m_pDict, "DV");
205 CFX_WideString csDValue;
thestigdb1a24e2016-05-23 16:55:09 -0700206 if (pDV)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700207 csDValue = pDV->GetUnicodeText();
thestigdb1a24e2016-05-23 16:55:09 -0700208
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700209 CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V");
210 CFX_WideString csValue;
thestigdb1a24e2016-05-23 16:55:09 -0700211 if (pV)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700212 csValue = pV->GetUnicodeText();
thestigdb1a24e2016-05-23 16:55:09 -0700213
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700214 CPDF_Object* pRV = FPDF_GetFieldAttr(m_pDict, "RV");
thestigdb1a24e2016-05-23 16:55:09 -0700215 if (!pRV && (csDValue == csValue))
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700216 return FALSE;
thestigdb1a24e2016-05-23 16:55:09 -0700217
218 if (bNotify && !NotifyBeforeValueChange(csDValue))
219 return FALSE;
220
Lei Zhang412e9082015-12-14 18:34:00 -0800221 if (pDV) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700222 CPDF_Object* pClone = pDV->Clone();
thestigdb1a24e2016-05-23 16:55:09 -0700223 if (!pClone)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700224 return FALSE;
thestigdb1a24e2016-05-23 16:55:09 -0700225
dsinclair38fd8442016-09-15 10:15:32 -0700226 m_pDict->SetFor("V", pClone);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700227 if (pRV) {
228 CPDF_Object* pCloneR = pDV->Clone();
dsinclair38fd8442016-09-15 10:15:32 -0700229 m_pDict->SetFor("RV", pCloneR);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700230 }
Lei Zhang412e9082015-12-14 18:34:00 -0800231 } else {
dsinclair38fd8442016-09-15 10:15:32 -0700232 m_pDict->RemoveFor("V");
233 m_pDict->RemoveFor("RV");
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700234 }
thestigdb1a24e2016-05-23 16:55:09 -0700235 if (bNotify)
236 NotifyAfterValueChange();
dsinclair27053d82016-08-02 15:43:46 -0700237 break;
238 }
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700239 }
240 return TRUE;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700241}
thestigdb1a24e2016-05-23 16:55:09 -0700242
tsepezc1835612016-06-08 13:30:06 -0700243int CPDF_FormField::GetControlIndex(const CPDF_FormControl* pControl) const {
thestigdb1a24e2016-05-23 16:55:09 -0700244 if (!pControl)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700245 return -1;
thestigdb1a24e2016-05-23 16:55:09 -0700246
Tom Sepezbd573f12015-12-09 16:39:40 -0800247 for (int i = 0; i < m_ControlList.GetSize(); i++) {
248 if (m_ControlList.GetAt(i) == pControl)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700249 return i;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700250 }
251 return -1;
252}
tsepezc1835612016-06-08 13:30:06 -0700253
254int CPDF_FormField::GetFieldType() const {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700255 switch (m_Type) {
256 case PushButton:
257 return FIELDTYPE_PUSHBUTTON;
258 case CheckBox:
259 return FIELDTYPE_CHECKBOX;
260 case RadioButton:
261 return FIELDTYPE_RADIOBUTTON;
262 case ComboBox:
263 return FIELDTYPE_COMBOBOX;
264 case ListBox:
265 return FIELDTYPE_LISTBOX;
266 case Text:
267 case RichText:
268 case File:
269 return FIELDTYPE_TEXTFIELD;
270 case Sign:
271 return FIELDTYPE_SIGNATURE;
272 default:
273 break;
274 }
275 return FIELDTYPE_UNKNOWN;
276}
Wei Li0fc6b252016-03-01 16:29:41 -0800277
tsepezc1835612016-06-08 13:30:06 -0700278CPDF_AAction CPDF_FormField::GetAdditionalAction() const {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700279 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "AA");
Wei Li0fc6b252016-03-01 16:29:41 -0800280 return CPDF_AAction(pObj ? pObj->GetDict() : nullptr);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700281}
Wei Li0fc6b252016-03-01 16:29:41 -0800282
tsepezc1835612016-06-08 13:30:06 -0700283CFX_WideString CPDF_FormField::GetAlternateName() const {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700284 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TU");
dsinclair27053d82016-08-02 15:43:46 -0700285 return pObj ? pObj->GetUnicodeText() : L"";
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700286}
dsinclair27053d82016-08-02 15:43:46 -0700287
tsepezc1835612016-06-08 13:30:06 -0700288CFX_WideString CPDF_FormField::GetMappingName() const {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700289 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TM");
dsinclair27053d82016-08-02 15:43:46 -0700290 return pObj ? pObj->GetUnicodeText() : L"";
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700291}
dsinclair27053d82016-08-02 15:43:46 -0700292
tsepezc1835612016-06-08 13:30:06 -0700293uint32_t CPDF_FormField::GetFieldFlags() const {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700294 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "Ff");
dsinclair27053d82016-08-02 15:43:46 -0700295 return pObj ? pObj->GetInteger() : 0;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700296}
dsinclair27053d82016-08-02 15:43:46 -0700297
tsepezc1835612016-06-08 13:30:06 -0700298CFX_ByteString CPDF_FormField::GetDefaultStyle() const {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700299 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "DS");
dsinclair27053d82016-08-02 15:43:46 -0700300 return pObj ? pObj->GetString() : "";
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700301}
dsinclair27053d82016-08-02 15:43:46 -0700302
tsepezc1835612016-06-08 13:30:06 -0700303CFX_WideString CPDF_FormField::GetRichTextString() const {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700304 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "RV");
dsinclair27053d82016-08-02 15:43:46 -0700305 return pObj ? pObj->GetUnicodeText() : L"";
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700306}
dsinclair27053d82016-08-02 15:43:46 -0700307
tsepezc1835612016-06-08 13:30:06 -0700308CFX_WideString CPDF_FormField::GetValue(FX_BOOL bDefault) const {
thestigdb1a24e2016-05-23 16:55:09 -0700309 if (GetType() == CheckBox || GetType() == RadioButton)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700310 return GetCheckValue(bDefault);
thestigdb1a24e2016-05-23 16:55:09 -0700311
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700312 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, bDefault ? "DV" : "V");
Lei Zhang412e9082015-12-14 18:34:00 -0800313 if (!pValue) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700314 if (!bDefault) {
dsinclair27053d82016-08-02 15:43:46 -0700315 if (m_Type == RichText)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700316 pValue = FPDF_GetFieldAttr(m_pDict, "V");
dsinclair27053d82016-08-02 15:43:46 -0700317 if (!pValue && m_Type != Text)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700318 pValue = FPDF_GetFieldAttr(m_pDict, "DV");
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700319 }
thestigdb1a24e2016-05-23 16:55:09 -0700320 if (!pValue)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700321 return CFX_WideString();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700322 }
dsinclair27053d82016-08-02 15:43:46 -0700323
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700324 switch (pValue->GetType()) {
Tom Sepez8e5cd192016-01-26 13:20:26 -0800325 case CPDF_Object::STRING:
326 case CPDF_Object::STREAM:
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700327 return pValue->GetUnicodeText();
Tom Sepez8e5cd192016-01-26 13:20:26 -0800328 case CPDF_Object::ARRAY:
tsepezbd567552016-03-29 14:51:50 -0700329 pValue = pValue->AsArray()->GetDirectObjectAt(0);
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400330 if (pValue)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700331 return pValue->GetUnicodeText();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700332 break;
Tom Sepez8e5cd192016-01-26 13:20:26 -0800333 default:
334 break;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700335 }
336 return CFX_WideString();
337}
thestigdb1a24e2016-05-23 16:55:09 -0700338
tsepezc1835612016-06-08 13:30:06 -0700339CFX_WideString CPDF_FormField::GetValue() const {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700340 return GetValue(FALSE);
341}
thestigdb1a24e2016-05-23 16:55:09 -0700342
tsepezc1835612016-06-08 13:30:06 -0700343CFX_WideString CPDF_FormField::GetDefaultValue() const {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700344 return GetValue(TRUE);
345}
thestigdb1a24e2016-05-23 16:55:09 -0700346
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700347FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value,
348 FX_BOOL bDefault,
349 FX_BOOL bNotify) {
350 switch (m_Type) {
351 case CheckBox:
352 case RadioButton: {
353 SetCheckValue(value, bDefault, bNotify);
354 return TRUE;
355 }
356 case File:
357 case RichText:
358 case Text:
359 case ComboBox: {
360 CFX_WideString csValue = value;
thestigdb1a24e2016-05-23 16:55:09 -0700361 if (bNotify && !NotifyBeforeValueChange(csValue))
362 return FALSE;
363
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700364 int iIndex = FindOptionValue(csValue);
365 if (iIndex < 0) {
366 CFX_ByteString bsEncodeText = PDF_EncodeText(csValue);
dsinclair38fd8442016-09-15 10:15:32 -0700367 m_pDict->SetStringFor(bDefault ? "DV" : "V", bsEncodeText);
thestigdb1a24e2016-05-23 16:55:09 -0700368 if (m_Type == RichText && !bDefault)
dsinclair38fd8442016-09-15 10:15:32 -0700369 m_pDict->SetStringFor("RV", bsEncodeText);
370 m_pDict->RemoveFor("I");
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700371 } else {
dsinclair38fd8442016-09-15 10:15:32 -0700372 m_pDict->SetStringFor(bDefault ? "DV" : "V", PDF_EncodeText(csValue));
thestigdb1a24e2016-05-23 16:55:09 -0700373 if (!bDefault) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700374 ClearSelection();
375 SetItemSelection(iIndex, TRUE);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700376 }
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700377 }
thestigdb1a24e2016-05-23 16:55:09 -0700378 if (bNotify)
379 NotifyAfterValueChange();
dsinclair27053d82016-08-02 15:43:46 -0700380 break;
381 }
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700382 case ListBox: {
383 int iIndex = FindOptionValue(value);
thestigdb1a24e2016-05-23 16:55:09 -0700384 if (iIndex < 0)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700385 return FALSE;
thestigdb1a24e2016-05-23 16:55:09 -0700386
387 if (bDefault && iIndex == GetDefaultSelectedItem())
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700388 return FALSE;
thestigdb1a24e2016-05-23 16:55:09 -0700389
390 if (bNotify && !NotifyBeforeSelectionChange(value))
391 return FALSE;
392
393 if (!bDefault) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700394 ClearSelection();
395 SetItemSelection(iIndex, TRUE);
396 }
thestigdb1a24e2016-05-23 16:55:09 -0700397 if (bNotify)
398 NotifyAfterSelectionChange();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700399 break;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700400 }
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700401 default:
402 break;
403 }
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700404 return TRUE;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700405}
thestigdb1a24e2016-05-23 16:55:09 -0700406
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700407FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value, FX_BOOL bNotify) {
408 return SetValue(value, FALSE, bNotify);
409}
thestigdb1a24e2016-05-23 16:55:09 -0700410
tsepezc1835612016-06-08 13:30:06 -0700411int CPDF_FormField::GetMaxLen() const {
Tom Sepezbd573f12015-12-09 16:39:40 -0800412 if (CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "MaxLen"))
413 return pObj->GetInteger();
414
415 for (int i = 0; i < m_ControlList.GetSize(); i++) {
416 CPDF_FormControl* pControl = m_ControlList.GetAt(i);
417 if (!pControl)
418 continue;
419
420 CPDF_Dictionary* pWidgetDict = pControl->m_pWidgetDict;
421 if (pWidgetDict->KeyExist("MaxLen"))
dsinclair38fd8442016-09-15 10:15:32 -0700422 return pWidgetDict->GetIntegerFor("MaxLen");
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700423 }
Tom Sepezbd573f12015-12-09 16:39:40 -0800424 return 0;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700425}
Wei Lie1aebd42016-04-11 10:02:09 -0700426
tsepezc1835612016-06-08 13:30:06 -0700427int CPDF_FormField::CountSelectedItems() const {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700428 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400429 if (!pValue) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700430 pValue = FPDF_GetFieldAttr(m_pDict, "I");
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400431 if (!pValue)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700432 return 0;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700433 }
Dan Sinclair316eb862015-10-21 13:29:23 -0400434
435 if (pValue->IsString() || pValue->IsNumber())
436 return pValue->GetString().IsEmpty() ? 0 : 1;
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400437 if (CPDF_Array* pArray = pValue->AsArray())
438 return pArray->GetCount();
439 return 0;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700440}
Wei Lie1aebd42016-04-11 10:02:09 -0700441
tsepezc1835612016-06-08 13:30:06 -0700442int CPDF_FormField::GetSelectedIndex(int index) const {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700443 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400444 if (!pValue) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700445 pValue = FPDF_GetFieldAttr(m_pDict, "I");
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400446 if (!pValue)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700447 return -1;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700448 }
Dan Sinclair43ce9032015-10-21 11:07:42 -0400449 if (pValue->IsNumber())
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700450 return pValue->GetInteger();
Dan Sinclair43ce9032015-10-21 11:07:42 -0400451
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700452 CFX_WideString sel_value;
Dan Sinclair316eb862015-10-21 13:29:23 -0400453 if (pValue->IsString()) {
454 if (index != 0)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700455 return -1;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700456 sel_value = pValue->GetUnicodeText();
457 } else {
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400458 CPDF_Array* pArray = pValue->AsArray();
459 if (!pArray || index < 0)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700460 return -1;
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400461
tsepezbd567552016-03-29 14:51:50 -0700462 CPDF_Object* elementValue = pArray->GetDirectObjectAt(index);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700463 sel_value =
464 elementValue ? elementValue->GetUnicodeText() : CFX_WideString();
465 }
466 if (index < CountSelectedOptions()) {
467 int iOptIndex = GetSelectedOptionIndex(index);
468 CFX_WideString csOpt = GetOptionValue(iOptIndex);
dsinclair27053d82016-08-02 15:43:46 -0700469 if (csOpt == sel_value)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700470 return iOptIndex;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700471 }
Wei Li05d53f02016-03-29 16:42:53 -0700472 for (int i = 0; i < CountOptions(); i++) {
473 if (sel_value == GetOptionValue(i))
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700474 return i;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700475 }
476 return -1;
477}
thestigdb1a24e2016-05-23 16:55:09 -0700478
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700479FX_BOOL CPDF_FormField::ClearSelection(FX_BOOL bNotify) {
Lei Zhang96660d62015-12-14 18:27:25 -0800480 if (bNotify && m_pForm->m_pFormNotify) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700481 CFX_WideString csValue;
482 int iIndex = GetSelectedIndex(0);
thestigdb1a24e2016-05-23 16:55:09 -0700483 if (iIndex >= 0)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700484 csValue = GetOptionLabel(iIndex);
thestigdb1a24e2016-05-23 16:55:09 -0700485
486 if (!NotifyListOrComboBoxBeforeChange(csValue))
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700487 return FALSE;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700488 }
dsinclair38fd8442016-09-15 10:15:32 -0700489 m_pDict->RemoveFor("V");
490 m_pDict->RemoveFor("I");
thestigdb1a24e2016-05-23 16:55:09 -0700491 if (bNotify)
492 NotifyListOrComboBoxAfterChange();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700493 return TRUE;
494}
Wei Li05d53f02016-03-29 16:42:53 -0700495
tsepezc1835612016-06-08 13:30:06 -0700496FX_BOOL CPDF_FormField::IsItemSelected(int index) const {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700497 ASSERT(GetType() == ComboBox || GetType() == ListBox);
dsinclair27053d82016-08-02 15:43:46 -0700498 if (index < 0 || index >= CountOptions())
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700499 return FALSE;
dsinclair27053d82016-08-02 15:43:46 -0700500 if (IsOptionSelected(index))
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700501 return TRUE;
dsinclair27053d82016-08-02 15:43:46 -0700502
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700503 CFX_WideString opt_value = GetOptionValue(index);
504 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
Lei Zhang412e9082015-12-14 18:34:00 -0800505 if (!pValue) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700506 pValue = FPDF_GetFieldAttr(m_pDict, "I");
dsinclair27053d82016-08-02 15:43:46 -0700507 if (!pValue)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700508 return FALSE;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700509 }
Dan Sinclair316eb862015-10-21 13:29:23 -0400510
511 if (pValue->IsString())
Dan Sinclair710c9092015-10-21 15:46:10 -0400512 return pValue->GetUnicodeText() == opt_value;
Dan Sinclair316eb862015-10-21 13:29:23 -0400513
Dan Sinclair43ce9032015-10-21 11:07:42 -0400514 if (pValue->IsNumber()) {
Dan Sinclair316eb862015-10-21 13:29:23 -0400515 if (pValue->GetString().IsEmpty())
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700516 return FALSE;
Dan Sinclair316eb862015-10-21 13:29:23 -0400517 return (pValue->GetInteger() == index);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700518 }
Dan Sinclair316eb862015-10-21 13:29:23 -0400519
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400520 CPDF_Array* pArray = pValue->AsArray();
521 if (!pArray)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700522 return FALSE;
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400523
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700524 int iPos = -1;
525 for (int j = 0; j < CountSelectedOptions(); j++) {
526 if (GetSelectedOptionIndex(j) == index) {
527 iPos = j;
528 break;
529 }
530 }
Wei Lie1aebd42016-04-11 10:02:09 -0700531 for (int i = 0; i < static_cast<int>(pArray->GetCount()); i++)
tsepezbd567552016-03-29 14:51:50 -0700532 if (pArray->GetDirectObjectAt(i)->GetUnicodeText() == opt_value &&
Wei Lie1aebd42016-04-11 10:02:09 -0700533 i == iPos) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700534 return TRUE;
535 }
536 return FALSE;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700537}
Wei Li05d53f02016-03-29 16:42:53 -0700538
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700539FX_BOOL CPDF_FormField::SetItemSelection(int index,
540 FX_BOOL bSelected,
541 FX_BOOL bNotify) {
542 ASSERT(GetType() == ComboBox || GetType() == ListBox);
thestigdb1a24e2016-05-23 16:55:09 -0700543 if (index < 0 || index >= CountOptions())
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700544 return FALSE;
thestigdb1a24e2016-05-23 16:55:09 -0700545
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700546 CFX_WideString opt_value = GetOptionValue(index);
thestigdb1a24e2016-05-23 16:55:09 -0700547 if (bNotify && !NotifyListOrComboBoxBeforeChange(opt_value))
548 return FALSE;
549
550 if (bSelected) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700551 if (GetType() == ListBox) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700552 SelectOption(index, TRUE);
dsinclaircac704d2016-07-28 12:59:09 -0700553 if (!(m_Flags & kFormListMultiSelect)) {
dsinclair38fd8442016-09-15 10:15:32 -0700554 m_pDict->SetStringFor("V", PDF_EncodeText(opt_value));
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700555 } else {
Lei Zhang4880d1a2015-12-18 17:05:11 -0800556 CPDF_Array* pArray = new CPDF_Array;
Wei Li05d53f02016-03-29 16:42:53 -0700557 for (int i = 0; i < CountOptions(); i++) {
558 if (i == index || IsItemSelected(i)) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700559 opt_value = GetOptionValue(i);
560 pArray->AddString(PDF_EncodeText(opt_value));
561 }
562 }
dsinclair38fd8442016-09-15 10:15:32 -0700563 m_pDict->SetFor("V", pArray);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700564 }
thestigdb1a24e2016-05-23 16:55:09 -0700565 } else {
dsinclair38fd8442016-09-15 10:15:32 -0700566 m_pDict->SetStringFor("V", PDF_EncodeText(opt_value));
Lei Zhang4880d1a2015-12-18 17:05:11 -0800567 CPDF_Array* pI = new CPDF_Array;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700568 pI->AddInteger(index);
dsinclair38fd8442016-09-15 10:15:32 -0700569 m_pDict->SetFor("I", pI);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700570 }
thestigdb1a24e2016-05-23 16:55:09 -0700571 } else {
572 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
573 if (pValue) {
574 if (GetType() == ListBox) {
575 SelectOption(index, FALSE);
576 if (pValue->IsString()) {
577 if (pValue->GetUnicodeText() == opt_value)
dsinclair38fd8442016-09-15 10:15:32 -0700578 m_pDict->RemoveFor("V");
thestigdb1a24e2016-05-23 16:55:09 -0700579 } else if (pValue->IsArray()) {
tsepez298880f2016-09-21 14:04:25 -0700580 std::unique_ptr<CPDF_Array, ReleaseDeleter<CPDF_Array>> pArray(
581 new CPDF_Array);
thestigdb1a24e2016-05-23 16:55:09 -0700582 for (int i = 0; i < CountOptions(); i++) {
583 if (i != index && IsItemSelected(i)) {
584 opt_value = GetOptionValue(i);
585 pArray->AddString(PDF_EncodeText(opt_value));
586 }
587 }
tsepez298880f2016-09-21 14:04:25 -0700588 if (pArray->GetCount() > 0)
589 m_pDict->SetFor("V", pArray.release()); // std::move someday
thestigdb1a24e2016-05-23 16:55:09 -0700590 }
591 } else {
dsinclair38fd8442016-09-15 10:15:32 -0700592 m_pDict->RemoveFor("V");
593 m_pDict->RemoveFor("I");
thestigdb1a24e2016-05-23 16:55:09 -0700594 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700595 }
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700596 }
thestigdb1a24e2016-05-23 16:55:09 -0700597 if (bNotify)
598 NotifyListOrComboBoxAfterChange();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700599 return TRUE;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700600}
Wei Li05d53f02016-03-29 16:42:53 -0700601
tsepezc1835612016-06-08 13:30:06 -0700602FX_BOOL CPDF_FormField::IsItemDefaultSelected(int index) const {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700603 ASSERT(GetType() == ComboBox || GetType() == ListBox);
Wei Li05d53f02016-03-29 16:42:53 -0700604 if (index < 0 || index >= CountOptions())
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700605 return FALSE;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700606 int iDVIndex = GetDefaultSelectedItem();
Wei Li05d53f02016-03-29 16:42:53 -0700607 return iDVIndex >= 0 && iDVIndex == index;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700608}
Wei Li05d53f02016-03-29 16:42:53 -0700609
tsepezc1835612016-06-08 13:30:06 -0700610int CPDF_FormField::GetDefaultSelectedItem() const {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700611 ASSERT(GetType() == ComboBox || GetType() == ListBox);
612 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "DV");
Wei Li05d53f02016-03-29 16:42:53 -0700613 if (!pValue)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700614 return -1;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700615 CFX_WideString csDV = pValue->GetUnicodeText();
Wei Li05d53f02016-03-29 16:42:53 -0700616 if (csDV.IsEmpty())
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700617 return -1;
Wei Li05d53f02016-03-29 16:42:53 -0700618 for (int i = 0; i < CountOptions(); i++) {
619 if (csDV == GetOptionValue(i))
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700620 return i;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700621 }
622 return -1;
623}
Wei Li05d53f02016-03-29 16:42:53 -0700624
tsepezc1835612016-06-08 13:30:06 -0700625int CPDF_FormField::CountOptions() const {
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400626 CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "Opt"));
627 return pArray ? pArray->GetCount() : 0;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700628}
Wei Li05d53f02016-03-29 16:42:53 -0700629
tsepezc1835612016-06-08 13:30:06 -0700630CFX_WideString CPDF_FormField::GetOptionText(int index, int sub_index) const {
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400631 CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "Opt"));
632 if (!pArray)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700633 return CFX_WideString();
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400634
tsepezbd567552016-03-29 14:51:50 -0700635 CPDF_Object* pOption = pArray->GetDirectObjectAt(index);
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400636 if (!pOption)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700637 return CFX_WideString();
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400638 if (CPDF_Array* pOptionArray = pOption->AsArray())
tsepezbd567552016-03-29 14:51:50 -0700639 pOption = pOptionArray->GetDirectObjectAt(sub_index);
Dan Sinclair316eb862015-10-21 13:29:23 -0400640
641 CPDF_String* pString = ToString(pOption);
642 return pString ? pString->GetUnicodeText() : CFX_WideString();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700643}
dsinclair27053d82016-08-02 15:43:46 -0700644
tsepezc1835612016-06-08 13:30:06 -0700645CFX_WideString CPDF_FormField::GetOptionLabel(int index) const {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700646 return GetOptionText(index, 1);
647}
dsinclair27053d82016-08-02 15:43:46 -0700648
tsepezc1835612016-06-08 13:30:06 -0700649CFX_WideString CPDF_FormField::GetOptionValue(int index) const {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700650 return GetOptionText(index, 0);
651}
Wei Li05d53f02016-03-29 16:42:53 -0700652
tsepezc1835612016-06-08 13:30:06 -0700653int CPDF_FormField::FindOption(CFX_WideString csOptLabel) const {
Wei Li05d53f02016-03-29 16:42:53 -0700654 for (int i = 0; i < CountOptions(); i++) {
655 if (GetOptionValue(i) == csOptLabel)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700656 return i;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700657 }
658 return -1;
659}
Wei Li05d53f02016-03-29 16:42:53 -0700660
tsepezc1835612016-06-08 13:30:06 -0700661int CPDF_FormField::FindOptionValue(const CFX_WideString& csOptValue) const {
Wei Li05d53f02016-03-29 16:42:53 -0700662 for (int i = 0; i < CountOptions(); i++) {
663 if (GetOptionValue(i) == csOptValue)
664 return i;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700665 }
666 return -1;
667}
Wei Li05d53f02016-03-29 16:42:53 -0700668
Tom Sepez5c4c1932015-11-25 12:15:38 -0800669#ifdef PDF_ENABLE_XFA
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700670int CPDF_FormField::InsertOption(CFX_WideString csOptLabel,
671 int index,
672 FX_BOOL bNotify) {
673 if (csOptLabel.IsEmpty())
674 return -1;
675
thestigdb1a24e2016-05-23 16:55:09 -0700676 if (bNotify && !NotifyListOrComboBoxBeforeChange(csOptLabel))
677 return -1;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700678
tsepezbd9748d2016-04-13 21:40:19 -0700679 CFX_ByteString csStr =
680 PDF_EncodeText(csOptLabel.c_str(), csOptLabel.GetLength());
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700681 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "Opt");
Lei Zhang4880d1a2015-12-18 17:05:11 -0800682 CPDF_Array* pOpt = ToArray(pValue);
683 if (!pOpt) {
684 pOpt = new CPDF_Array;
dsinclair38fd8442016-09-15 10:15:32 -0700685 m_pDict->SetFor("Opt", pOpt);
Lei Zhang4880d1a2015-12-18 17:05:11 -0800686 }
687
thestig695aac52016-08-25 09:13:52 -0700688 int iCount = pdfium::base::checked_cast<int, size_t>(pOpt->GetCount());
689 if (index >= iCount) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700690 pOpt->AddString(csStr);
691 index = iCount;
692 } else {
Lei Zhang4880d1a2015-12-18 17:05:11 -0800693 CPDF_String* pString = new CPDF_String(csStr, FALSE);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700694 pOpt->InsertAt(index, pString);
695 }
696
thestigdb1a24e2016-05-23 16:55:09 -0700697 if (bNotify)
698 NotifyListOrComboBoxAfterChange();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700699 return index;
700}
thestigdb1a24e2016-05-23 16:55:09 -0700701
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700702FX_BOOL CPDF_FormField::ClearOptions(FX_BOOL bNotify) {
Lei Zhang4880d1a2015-12-18 17:05:11 -0800703 if (bNotify && m_pForm->m_pFormNotify) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700704 CFX_WideString csValue;
705 int iIndex = GetSelectedIndex(0);
706 if (iIndex >= 0)
707 csValue = GetOptionLabel(iIndex);
thestigdb1a24e2016-05-23 16:55:09 -0700708 if (!NotifyListOrComboBoxBeforeChange(csValue))
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700709 return FALSE;
710 }
711
dsinclair38fd8442016-09-15 10:15:32 -0700712 m_pDict->RemoveFor("Opt");
713 m_pDict->RemoveFor("V");
714 m_pDict->RemoveFor("DV");
715 m_pDict->RemoveFor("I");
716 m_pDict->RemoveFor("TI");
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700717
thestigdb1a24e2016-05-23 16:55:09 -0700718 if (bNotify)
719 NotifyListOrComboBoxAfterChange();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700720
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700721 return TRUE;
722}
Tom Sepeza2c42ce2015-11-25 15:52:28 -0800723#endif // PDF_ENABLE_XFA
thestigdb1a24e2016-05-23 16:55:09 -0700724
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700725FX_BOOL CPDF_FormField::CheckControl(int iControlIndex,
Tom Sepezed5d7aa2016-02-02 16:02:03 -0800726 bool bChecked,
727 bool bNotify) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700728 ASSERT(GetType() == CheckBox || GetType() == RadioButton);
729 CPDF_FormControl* pControl = GetControl(iControlIndex);
dsinclair27053d82016-08-02 15:43:46 -0700730 if (!pControl)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700731 return FALSE;
dsinclair27053d82016-08-02 15:43:46 -0700732 if (!bChecked && pControl->IsChecked() == bChecked)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700733 return FALSE;
dsinclair27053d82016-08-02 15:43:46 -0700734
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700735 CFX_WideString csWExport = pControl->GetExportValue();
736 CFX_ByteString csBExport = PDF_EncodeText(csWExport);
737 int iCount = CountControls();
dsinclair27053d82016-08-02 15:43:46 -0700738 bool bUnison = IsUnison(this);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700739 for (int i = 0; i < iCount; i++) {
740 CPDF_FormControl* pCtrl = GetControl(i);
741 if (bUnison) {
742 CFX_WideString csEValue = pCtrl->GetExportValue();
743 if (csEValue == csWExport) {
dsinclair27053d82016-08-02 15:43:46 -0700744 if (pCtrl->GetOnStateName() == pControl->GetOnStateName())
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700745 pCtrl->CheckControl(bChecked);
dsinclair27053d82016-08-02 15:43:46 -0700746 else if (bChecked)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700747 pCtrl->CheckControl(FALSE);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700748 } else if (bChecked) {
749 pCtrl->CheckControl(FALSE);
750 }
751 } else {
dsinclair27053d82016-08-02 15:43:46 -0700752 if (i == iControlIndex)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700753 pCtrl->CheckControl(bChecked);
dsinclair27053d82016-08-02 15:43:46 -0700754 else if (bChecked)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700755 pCtrl->CheckControl(FALSE);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700756 }
757 }
dsinclair27053d82016-08-02 15:43:46 -0700758
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700759 CPDF_Object* pOpt = FPDF_GetFieldAttr(m_pDict, "Opt");
Dan Sinclair2b11dc12015-10-22 15:02:06 -0400760 if (!ToArray(pOpt)) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700761 if (bChecked) {
dsinclair38fd8442016-09-15 10:15:32 -0700762 m_pDict->SetNameFor("V", csBExport);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700763 } else {
764 CFX_ByteString csV;
765 CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V");
dsinclair27053d82016-08-02 15:43:46 -0700766 if (pV)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700767 csV = pV->GetString();
dsinclair27053d82016-08-02 15:43:46 -0700768 if (csV == csBExport)
dsinclair38fd8442016-09-15 10:15:32 -0700769 m_pDict->SetNameFor("V", "Off");
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700770 }
771 } else if (bChecked) {
772 CFX_ByteString csIndex;
773 csIndex.Format("%d", iControlIndex);
dsinclair38fd8442016-09-15 10:15:32 -0700774 m_pDict->SetNameFor("V", csIndex);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700775 }
thestigdb1a24e2016-05-23 16:55:09 -0700776 if (bNotify && m_pForm->m_pFormNotify)
Tom Sepezed5d7aa2016-02-02 16:02:03 -0800777 m_pForm->m_pFormNotify->AfterCheckedStatusChange(this);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700778 return TRUE;
779}
thestigdb1a24e2016-05-23 16:55:09 -0700780
tsepezc1835612016-06-08 13:30:06 -0700781CFX_WideString CPDF_FormField::GetCheckValue(FX_BOOL bDefault) const {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700782 ASSERT(GetType() == CheckBox || GetType() == RadioButton);
783 CFX_WideString csExport = L"Off";
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700784 int iCount = CountControls();
785 for (int i = 0; i < iCount; i++) {
786 CPDF_FormControl* pControl = GetControl(i);
thestigdb1a24e2016-05-23 16:55:09 -0700787 FX_BOOL bChecked =
788 bDefault ? pControl->IsDefaultChecked() : pControl->IsChecked();
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700789 if (bChecked) {
790 csExport = pControl->GetExportValue();
791 break;
792 }
793 }
794 return csExport;
795}
thestigdb1a24e2016-05-23 16:55:09 -0700796
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700797FX_BOOL CPDF_FormField::SetCheckValue(const CFX_WideString& value,
798 FX_BOOL bDefault,
799 FX_BOOL bNotify) {
800 ASSERT(GetType() == CheckBox || GetType() == RadioButton);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700801 int iCount = CountControls();
802 for (int i = 0; i < iCount; i++) {
803 CPDF_FormControl* pControl = GetControl(i);
804 CFX_WideString csExport = pControl->GetExportValue();
thestigdb1a24e2016-05-23 16:55:09 -0700805 bool val = csExport == value;
806 if (!bDefault)
807 CheckControl(GetControlIndex(pControl), val);
808 if (val)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700809 break;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700810 }
thestigdb1a24e2016-05-23 16:55:09 -0700811 if (bNotify && m_pForm->m_pFormNotify)
Tom Sepezed5d7aa2016-02-02 16:02:03 -0800812 m_pForm->m_pFormNotify->AfterCheckedStatusChange(this);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700813 return TRUE;
814}
Wei Lie1aebd42016-04-11 10:02:09 -0700815
tsepezc1835612016-06-08 13:30:06 -0700816int CPDF_FormField::GetTopVisibleIndex() const {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700817 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TI");
thestigb8bf55f2016-05-21 21:08:05 -0700818 return pObj ? pObj->GetInteger() : 0;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700819}
Wei Lie1aebd42016-04-11 10:02:09 -0700820
tsepezc1835612016-06-08 13:30:06 -0700821int CPDF_FormField::CountSelectedOptions() const {
thestigb8bf55f2016-05-21 21:08:05 -0700822 CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "I"));
823 return pArray ? pArray->GetCount() : 0;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700824}
Wei Lie1aebd42016-04-11 10:02:09 -0700825
tsepezc1835612016-06-08 13:30:06 -0700826int CPDF_FormField::GetSelectedOptionIndex(int index) const {
thestigb8bf55f2016-05-21 21:08:05 -0700827 CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "I"));
828 if (!pArray)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700829 return -1;
thestigb8bf55f2016-05-21 21:08:05 -0700830
831 int iCount = pArray->GetCount();
832 if (iCount < 0 || index >= iCount)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700833 return -1;
thestigb8bf55f2016-05-21 21:08:05 -0700834 return pArray->GetIntegerAt(index);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700835}
thestigb8bf55f2016-05-21 21:08:05 -0700836
tsepezc1835612016-06-08 13:30:06 -0700837FX_BOOL CPDF_FormField::IsOptionSelected(int iOptIndex) const {
thestigb8bf55f2016-05-21 21:08:05 -0700838 CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "I"));
839 if (!pArray)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700840 return FALSE;
thestigb8bf55f2016-05-21 21:08:05 -0700841
842 for (CPDF_Object* pObj : *pArray) {
843 if (pObj->GetInteger() == iOptIndex)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700844 return TRUE;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700845 }
846 return FALSE;
847}
thestigb8bf55f2016-05-21 21:08:05 -0700848
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700849FX_BOOL CPDF_FormField::SelectOption(int iOptIndex,
850 FX_BOOL bSelected,
851 FX_BOOL bNotify) {
dsinclair38fd8442016-09-15 10:15:32 -0700852 CPDF_Array* pArray = m_pDict->GetArrayFor("I");
Lei Zhang412e9082015-12-14 18:34:00 -0800853 if (!pArray) {
thestigdb1a24e2016-05-23 16:55:09 -0700854 if (!bSelected)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700855 return TRUE;
thestigdb1a24e2016-05-23 16:55:09 -0700856
Lei Zhang4880d1a2015-12-18 17:05:11 -0800857 pArray = new CPDF_Array;
dsinclair38fd8442016-09-15 10:15:32 -0700858 m_pDict->SetFor("I", pArray);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700859 }
thestigdb1a24e2016-05-23 16:55:09 -0700860
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700861 FX_BOOL bReturn = FALSE;
Wei Lie1aebd42016-04-11 10:02:09 -0700862 for (size_t i = 0; i < pArray->GetCount(); i++) {
Wei Li9b761132016-01-29 15:44:20 -0800863 int iFind = pArray->GetIntegerAt(i);
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700864 if (iFind == iOptIndex) {
thestigdb1a24e2016-05-23 16:55:09 -0700865 if (bSelected)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700866 return TRUE;
thestigdb1a24e2016-05-23 16:55:09 -0700867
Lei Zhang96660d62015-12-14 18:27:25 -0800868 if (bNotify && m_pForm->m_pFormNotify) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700869 CFX_WideString csValue = GetOptionLabel(iOptIndex);
thestigdb1a24e2016-05-23 16:55:09 -0700870 if (!NotifyListOrComboBoxBeforeChange(csValue))
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700871 return FALSE;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700872 }
873 pArray->RemoveAt(i);
874 bReturn = TRUE;
875 break;
thestigdb1a24e2016-05-23 16:55:09 -0700876 }
877
878 if (iFind > iOptIndex) {
879 if (!bSelected)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700880 continue;
thestigdb1a24e2016-05-23 16:55:09 -0700881
Lei Zhang96660d62015-12-14 18:27:25 -0800882 if (bNotify && m_pForm->m_pFormNotify) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700883 CFX_WideString csValue = GetOptionLabel(iOptIndex);
thestigdb1a24e2016-05-23 16:55:09 -0700884 if (!NotifyListOrComboBoxBeforeChange(csValue))
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700885 return FALSE;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700886 }
thestigdb1a24e2016-05-23 16:55:09 -0700887 pArray->InsertAt(i, new CPDF_Number(iOptIndex));
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700888 bReturn = TRUE;
889 break;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700890 }
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700891 }
892 if (!bReturn) {
thestigdb1a24e2016-05-23 16:55:09 -0700893 if (bSelected)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700894 pArray->AddInteger(iOptIndex);
thestigdb1a24e2016-05-23 16:55:09 -0700895
jaepark727da4f2016-08-08 15:45:58 -0700896 if (pArray->IsEmpty())
dsinclair38fd8442016-09-15 10:15:32 -0700897 m_pDict->RemoveFor("I");
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700898 }
thestigdb1a24e2016-05-23 16:55:09 -0700899 if (bNotify)
900 NotifyListOrComboBoxAfterChange();
901
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700902 return TRUE;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700903}
thestigdb1a24e2016-05-23 16:55:09 -0700904
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700905FX_BOOL CPDF_FormField::ClearSelectedOptions(FX_BOOL bNotify) {
Lei Zhang96660d62015-12-14 18:27:25 -0800906 if (bNotify && m_pForm->m_pFormNotify) {
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700907 CFX_WideString csValue;
908 int iIndex = GetSelectedIndex(0);
thestigdb1a24e2016-05-23 16:55:09 -0700909 if (iIndex >= 0)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700910 csValue = GetOptionLabel(iIndex);
thestigdb1a24e2016-05-23 16:55:09 -0700911
912 if (!NotifyListOrComboBoxBeforeChange(csValue))
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700913 return FALSE;
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700914 }
dsinclair38fd8442016-09-15 10:15:32 -0700915 m_pDict->RemoveFor("I");
thestigdb1a24e2016-05-23 16:55:09 -0700916 if (bNotify)
917 NotifyListOrComboBoxAfterChange();
918
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700919 return TRUE;
920}
thestigdb1a24e2016-05-23 16:55:09 -0700921
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700922void CPDF_FormField::LoadDA() {
thestigdb1a24e2016-05-23 16:55:09 -0700923 CPDF_Dictionary* pFormDict = m_pForm->m_pFormDict;
924 if (!pFormDict)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700925 return;
thestigdb1a24e2016-05-23 16:55:09 -0700926
927 CFX_ByteString DA;
928 if (CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "DA"))
929 DA = pObj->GetString();
930
931 if (DA.IsEmpty())
dsinclair38fd8442016-09-15 10:15:32 -0700932 DA = pFormDict->GetStringFor("DA");
thestigdb1a24e2016-05-23 16:55:09 -0700933
934 if (DA.IsEmpty())
935 return;
936
dsinclair38fd8442016-09-15 10:15:32 -0700937 CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR");
thestigdb1a24e2016-05-23 16:55:09 -0700938 if (!pDR)
939 return;
940
dsinclair38fd8442016-09-15 10:15:32 -0700941 CPDF_Dictionary* pFont = pDR->GetDictFor("Font");
thestigdb1a24e2016-05-23 16:55:09 -0700942 if (!pFont)
943 return;
944
tsepez4c3debb2016-04-08 12:20:38 -0700945 CPDF_SimpleParser syntax(DA.AsStringC());
Wei Li970c11e2016-02-16 14:26:22 -0800946 syntax.FindTagParamFromStart("Tf", 2);
tsepez71a452f2016-05-13 17:51:27 -0700947 CFX_ByteString font_name(syntax.GetWord());
dsinclair38fd8442016-09-15 10:15:32 -0700948 CPDF_Dictionary* pFontDict = pFont->GetDictFor(font_name);
thestigdb1a24e2016-05-23 16:55:09 -0700949 if (!pFontDict)
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700950 return;
thestigdb1a24e2016-05-23 16:55:09 -0700951
Nico Weber9d8ec5a2015-08-04 13:00:21 -0700952 m_pFont = m_pForm->m_pDocument->LoadFont(pFontDict);
953 m_FontSize = FX_atof(syntax.GetWord());
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700954}
thestigdb1a24e2016-05-23 16:55:09 -0700955
956bool CPDF_FormField::NotifyBeforeSelectionChange(const CFX_WideString& value) {
957 if (!m_pForm->m_pFormNotify)
958 return true;
959 return m_pForm->m_pFormNotify->BeforeSelectionChange(this, value) >= 0;
960}
961
962void CPDF_FormField::NotifyAfterSelectionChange() {
963 if (!m_pForm->m_pFormNotify)
964 return;
965 m_pForm->m_pFormNotify->AfterSelectionChange(this);
966}
967
968bool CPDF_FormField::NotifyBeforeValueChange(const CFX_WideString& value) {
969 if (!m_pForm->m_pFormNotify)
970 return true;
971 return m_pForm->m_pFormNotify->BeforeValueChange(this, value) >= 0;
972}
973
974void CPDF_FormField::NotifyAfterValueChange() {
975 if (!m_pForm->m_pFormNotify)
976 return;
977 m_pForm->m_pFormNotify->AfterValueChange(this);
978}
979
980bool CPDF_FormField::NotifyListOrComboBoxBeforeChange(
981 const CFX_WideString& value) {
982 switch (GetType()) {
983 case ListBox:
984 return NotifyBeforeSelectionChange(value);
985 case ComboBox:
986 return NotifyBeforeValueChange(value);
987 default:
988 return true;
989 }
990}
991
992void CPDF_FormField::NotifyListOrComboBoxAfterChange() {
993 switch (GetType()) {
994 case ListBox:
995 NotifyAfterSelectionChange();
996 break;
997 case ComboBox:
998 NotifyAfterValueChange();
999 break;
1000 default:
1001 break;
1002 }
1003}