a2f0fbd297e5f7f8c68824021238c8a1503ae2ef
[pdfium.git] / core / src / fpdfdoc / doc_formfield.cpp
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 "../../include/fpdfdoc/fpdf_doc.h"
8 CFX_WideString          GetFullName(CPDF_Dictionary* pFieldDict);
9 void                            SaveCheckedFieldStatus(CPDF_FormField* pField, CFX_ByteArray& statusArray);
10 FX_BOOL PDF_FormField_IsUnison(CPDF_FormField *pField)
11 {
12     FX_BOOL bUnison = FALSE;
13     if (pField->GetType() == CPDF_FormField::CheckBox) {
14         bUnison = TRUE;
15     } else {
16         FX_DWORD dwFlags = pField->GetFieldFlags();
17         bUnison = ((dwFlags & 0x2000000) != 0);
18     }
19     return bUnison;
20 }
21 CPDF_FormField::CPDF_FormField(CPDF_InterForm* pForm, CPDF_Dictionary* pDict)
22 {
23     m_pDict = pDict;
24     m_Type = Unknown;
25     m_pForm = pForm;
26     m_pFont = NULL;
27     m_FontSize = 0;
28     SyncFieldFlags();
29 }
30 CPDF_FormField::~CPDF_FormField()
31 {
32 }
33 void CPDF_FormField::SyncFieldFlags()
34 {
35     CFX_ByteString type_name = FPDF_GetFieldAttr(m_pDict, "FT") ? FPDF_GetFieldAttr(m_pDict, "FT")->GetString() : CFX_ByteString();
36     FX_DWORD flags = FPDF_GetFieldAttr(m_pDict, "Ff")? FPDF_GetFieldAttr(m_pDict, "Ff")->GetInteger() : 0;
37     m_Flags = 0;
38     if (flags & 1) {
39         m_Flags |= FORMFIELD_READONLY;
40     }
41     if (flags & 2) {
42         m_Flags |= FORMFIELD_REQUIRED;
43     }
44     if (flags & 4) {
45         m_Flags |= FORMFIELD_NOEXPORT;
46     }
47     if (type_name == "Btn") {
48         if (flags & 0x8000) {
49             m_Type = RadioButton;
50             if (flags & 0x4000) {
51                 m_Flags |= FORMRADIO_NOTOGGLEOFF;
52             }
53             if (flags & 0x2000000) {
54                 m_Flags |= FORMRADIO_UNISON;
55             }
56         } else if (flags & 0x10000) {
57             m_Type = PushButton;
58         } else {
59             m_Type = CheckBox;
60         }
61     } else if (type_name == "Tx") {
62         if (flags & 0x100000) {
63             m_Type = File;
64         } else if (flags & 0x2000000) {
65             m_Type = RichText;
66         } else {
67             m_Type = Text;
68             if (flags & 0x1000) {
69                 m_Flags |= FORMTEXT_MULTILINE;
70             }
71             if (flags & 0x2000) {
72                 m_Flags |= FORMTEXT_PASSWORD;
73             }
74             if (flags & 0x800000) {
75                 m_Flags |= FORMTEXT_NOSCROLL;
76             }
77             if (flags & 0x100000) {
78                 m_Flags |= FORMTEXT_COMB;
79             }
80         }
81         LoadDA();
82     } else if (type_name == "Ch") {
83         if (flags & 0x20000) {
84             m_Type = ComboBox;
85             if (flags & 0x40000) {
86                 m_Flags |= FORMCOMBO_EDIT;
87             }
88         } else {
89             m_Type = ListBox;
90             if (flags & 0x200000) {
91                 m_Flags |= FORMLIST_MULTISELECT;
92             }
93         }
94         LoadDA();
95     } else if (type_name == "Sig") {
96         m_Type = Sign;
97     }
98 }
99 CFX_WideString CPDF_FormField::GetFullName()
100 {
101     return ::GetFullName(m_pDict);
102 }
103 FX_BOOL CPDF_FormField::ResetField(FX_BOOL bNotify)
104 {
105     switch (m_Type) {
106         case CPDF_FormField::CheckBox:
107         case CPDF_FormField::RadioButton: {
108                 CFX_ByteArray statusArray;
109                 if (bNotify && m_pForm->m_pFormNotify != NULL) {
110                     SaveCheckedFieldStatus(this, statusArray);
111                 }
112                 int iCount = CountControls();
113                 if (iCount) {
114                     if (PDF_FormField_IsUnison(this)) {
115                         for(int i = 0; i < iCount; i++) {
116                             CheckControl(i, GetControl(i)->IsDefaultChecked(), FALSE);
117                         }
118                     } else {
119                         for (int i = 0; i < iCount; i ++) {
120                             CPDF_FormControl* pControl = GetControl(i);
121                             FX_BOOL bChecked = pControl->IsDefaultChecked();
122                             CheckControl(i, bChecked, FALSE);
123                         }
124                     }
125                 }
126                 if (bNotify && m_pForm->m_pFormNotify != NULL) {
127                     m_pForm->m_pFormNotify->AfterCheckedStatusChange(this, statusArray);
128                 }
129             }
130             break;
131         case CPDF_FormField::ComboBox: {
132                 CFX_WideString csValue;
133                 ClearSelection();
134                 int iIndex = GetDefaultSelectedItem();
135                 if (iIndex >= 0) {
136                     csValue = GetOptionLabel(iIndex);
137                 }
138                 if (bNotify && m_pForm->m_pFormNotify != NULL) {
139                     int iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
140                     if (iRet < 0) {
141                         return FALSE;
142                     }
143                 }
144                 SetItemSelection(iIndex, TRUE);
145                 if (bNotify && m_pForm->m_pFormNotify != NULL) {
146                     m_pForm->m_pFormNotify->AfterValueChange(this);
147                 }
148             }
149             break;
150         case CPDF_FormField::ListBox: {
151                 CFX_WideString csValue;
152                 ClearSelection();
153                 int iIndex = GetDefaultSelectedItem();
154                 if (iIndex >= 0) {
155                     csValue = GetOptionLabel(iIndex);
156                 }
157                 if (bNotify && m_pForm->m_pFormNotify != NULL) {
158                     int iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
159                     if (iRet < 0) {
160                         return FALSE;
161                     }
162                 }
163                 SetItemSelection(iIndex, TRUE);
164                 if (bNotify && m_pForm->m_pFormNotify != NULL) {
165                     m_pForm->m_pFormNotify->AfterSelectionChange(this);
166                 }
167             }
168             break;
169         case CPDF_FormField::Text:
170         case CPDF_FormField::RichText:
171         case CPDF_FormField::File:
172         default: {
173                 CPDF_Object* pDV = FPDF_GetFieldAttr(m_pDict, "DV");
174                 CFX_WideString csDValue;
175                 if (pDV != NULL) {
176                     csDValue = pDV->GetUnicodeText();
177                 }
178                 CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V");
179                 CFX_WideString csValue;
180                 if (pV != NULL) {
181                     csValue = pV->GetUnicodeText();
182                 }
183                 CPDF_Object* pRV = FPDF_GetFieldAttr(m_pDict, "RV");
184                 if (!pRV && (csDValue == csValue)) {
185                     return FALSE;
186                 }
187                 if (bNotify && m_pForm->m_pFormNotify != NULL) {
188                     int iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csDValue);
189                     if (iRet < 0) {
190                         return FALSE;
191                     }
192                 }
193                 if (pDV == NULL) {
194                     m_pDict->RemoveAt("V");
195                     m_pDict->RemoveAt("RV");
196                 } else {
197                     CPDF_Object* pClone = pDV->Clone();
198                     if (pClone == NULL) {
199                         return FALSE;
200                     }
201                     m_pDict->SetAt("V", pClone);
202                     if(pRV) {
203                         CPDF_Object* pCloneR = pDV->Clone();
204                         m_pDict->SetAt("RV", pCloneR);
205                     }
206                 }
207                 if (bNotify && m_pForm->m_pFormNotify != NULL) {
208                     m_pForm->m_pFormNotify->AfterValueChange(this);
209                 }
210                 m_pForm->m_bUpdated = TRUE;
211             }
212             break;
213     }
214     return TRUE;
215 }
216 int CPDF_FormField::GetControlIndex(const CPDF_FormControl* pControl)
217 {
218     if (pControl == NULL) {
219         return -1;
220     }
221     int iCount = m_ControlList.GetSize();
222     for (int i = 0; i < iCount; i ++) {
223         CPDF_FormControl* pFind = (CPDF_FormControl*)m_ControlList.GetAt(i);
224         if (pFind == pControl) {
225             return i;
226         }
227     }
228     return -1;
229 }
230 int CPDF_FormField::GetFieldType()
231 {
232     switch (m_Type) {
233         case PushButton:
234             return FIELDTYPE_PUSHBUTTON;
235         case CheckBox:
236             return FIELDTYPE_CHECKBOX;
237         case RadioButton:
238             return FIELDTYPE_RADIOBUTTON;
239         case ComboBox:
240             return FIELDTYPE_COMBOBOX;
241         case ListBox:
242             return FIELDTYPE_LISTBOX;
243         case Text:
244         case RichText:
245         case File:
246             return FIELDTYPE_TEXTFIELD;
247         case Sign:
248             return FIELDTYPE_SIGNATURE;
249         default:
250             break;
251     }
252     return FIELDTYPE_UNKNOWN;
253 }
254 CPDF_AAction CPDF_FormField::GetAdditionalAction()
255 {
256     CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "AA");
257     if (pObj == NULL) {
258         return NULL;
259     }
260     return pObj->GetDict();
261 }
262 CFX_WideString CPDF_FormField::GetAlternateName()
263 {
264     CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TU");
265     if (pObj == NULL) {
266         return L"";
267     }
268     return pObj->GetUnicodeText();
269 }
270 CFX_WideString CPDF_FormField::GetMappingName()
271 {
272     CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TM");
273     if (pObj == NULL) {
274         return L"";
275     }
276     return pObj->GetUnicodeText();
277 }
278 FX_DWORD CPDF_FormField::GetFieldFlags()
279 {
280     CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "Ff");
281     if (pObj == NULL) {
282         return 0;
283     }
284     return pObj->GetInteger();
285 }
286 CFX_ByteString CPDF_FormField::GetDefaultStyle()
287 {
288     CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "DS");
289     if (pObj == NULL) {
290         return "";
291     }
292     return pObj->GetString();
293 }
294 CFX_WideString CPDF_FormField::GetRichTextString()
295 {
296     CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "RV");
297     if (pObj == NULL) {
298         return L"";
299     }
300     return pObj->GetUnicodeText();
301 }
302 CFX_WideString CPDF_FormField::GetValue(FX_BOOL bDefault)
303 {
304     if (GetType() == CheckBox || GetType() == RadioButton) {
305         return GetCheckValue(bDefault);
306     }
307     CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, bDefault ? "DV" : "V");
308     if (pValue == NULL) {
309         if (!bDefault) {
310             if (m_Type == RichText) {
311                 pValue = FPDF_GetFieldAttr(m_pDict, "V");
312             }
313             if (pValue == NULL && m_Type != Text) {
314                 pValue = FPDF_GetFieldAttr(m_pDict, "DV");
315             }
316         }
317         if (pValue == NULL) {
318             return CFX_WideString();
319         }
320     }
321     switch (pValue->GetType()) {
322         case PDFOBJ_STRING:
323         case PDFOBJ_STREAM:
324             return pValue->GetUnicodeText();
325         case PDFOBJ_ARRAY:
326             pValue = ((CPDF_Array*)pValue)->GetElementValue(0);
327             if (pValue) {
328                 return pValue->GetUnicodeText();
329             }
330             break;
331     }
332     return CFX_WideString();
333 }
334 CFX_WideString CPDF_FormField::GetValue()
335 {
336     return GetValue(FALSE);
337 }
338 CFX_WideString CPDF_FormField::GetDefaultValue()
339 {
340     return GetValue(TRUE);
341 }
342 FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value, FX_BOOL bDefault, FX_BOOL bNotify)
343 {
344     switch (m_Type) {
345         case CheckBox:
346         case RadioButton: {
347                 SetCheckValue(value, bDefault, bNotify);
348                 return TRUE;
349             }
350         case File:
351         case RichText:
352         case Text:
353         case ComboBox: {
354                 CFX_WideString csValue = value;
355                 if (bNotify && m_pForm->m_pFormNotify != NULL) {
356                     int iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
357                     if (iRet < 0) {
358                         return FALSE;
359                     }
360                 }
361                 int iIndex = FindOptionValue(csValue);
362                 if (iIndex < 0) {
363                     CFX_ByteString bsEncodeText = PDF_EncodeText(csValue);
364                     m_pDict->SetAtString(bDefault ? "DV" : "V", bsEncodeText);
365                     if (m_Type == RichText && !bDefault) {
366                         m_pDict->SetAtString("RV", bsEncodeText);
367                     }
368                     m_pDict->RemoveAt("I");
369                 } else {
370                     m_pDict->SetAtString(bDefault ? "DV" : "V", PDF_EncodeText(csValue));
371                     if (bDefault) {
372                     } else {
373                         ClearSelection();
374                         SetItemSelection(iIndex, TRUE);
375                     }
376                 }
377                 if (bNotify && m_pForm->m_pFormNotify != NULL) {
378                     m_pForm->m_pFormNotify->AfterValueChange(this);
379                 }
380                 m_pForm->m_bUpdated = TRUE;
381             }
382             break;
383         case ListBox: {
384                 int iIndex = FindOptionValue(value);
385                 if (iIndex < 0) {
386                     return FALSE;
387                 }
388                 if (bDefault && iIndex == GetDefaultSelectedItem()) {
389                     return FALSE;
390                 }
391                 if (bNotify && m_pForm->m_pFormNotify != NULL) {
392                     CFX_WideString csValue = value;
393                     int iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
394                     if (iRet < 0) {
395                         return FALSE;
396                     }
397                 }
398                 if (bDefault) {
399                 } else {
400                     ClearSelection();
401                     SetItemSelection(iIndex, TRUE);
402                 }
403                 if (bNotify && m_pForm->m_pFormNotify != NULL) {
404                     m_pForm->m_pFormNotify->AfterSelectionChange(this);
405                 }
406                 m_pForm->m_bUpdated = TRUE;
407                 break;
408             }
409         default:
410             break;
411     }
412     if (CPDF_InterForm::m_bUpdateAP) {
413         UpdateAP(NULL);
414     }
415     return TRUE;
416 }
417 FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value, FX_BOOL bNotify)
418 {
419     return SetValue(value, FALSE, bNotify);
420 }
421 int CPDF_FormField::GetMaxLen()
422 {
423     CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "MaxLen");
424     if (pObj == NULL) {
425         int iCount = m_ControlList.GetSize();
426         for (int i = 0; i < iCount; i ++) {
427             CPDF_FormControl* pControl = (CPDF_FormControl*)m_ControlList.GetAt(i);
428             if (pControl == NULL) {
429                 continue;
430             }
431             CPDF_Dictionary* pWidgetDict = pControl->m_pWidgetDict;
432             if (pWidgetDict->KeyExist("MaxLen")) {
433                 return pWidgetDict->GetInteger("MaxLen");
434             }
435         }
436         return 0;
437     }
438     return pObj->GetInteger();
439 }
440 int CPDF_FormField::CountSelectedItems()
441 {
442     CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
443     if (pValue == NULL) {
444         pValue = FPDF_GetFieldAttr(m_pDict, "I");
445         if (pValue == NULL) {
446             return 0;
447         }
448     }
449     if (pValue->GetType() == PDFOBJ_STRING) {
450         if (pValue->GetString().IsEmpty()) {
451             return 0;
452         }
453         return 1;
454     }
455     if (pValue->GetType() == PDFOBJ_NUMBER) {
456         if (pValue->GetString().IsEmpty()) {
457             return 0;
458         }
459         return 1;
460     }
461     if (pValue->GetType() != PDFOBJ_ARRAY) {
462         return 0;
463     }
464     return ((CPDF_Array*)pValue)->GetCount();
465 }
466 int CPDF_FormField::GetSelectedIndex(int index)
467 {
468     CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
469     if (pValue == NULL) {
470         pValue = FPDF_GetFieldAttr(m_pDict, "I");
471         if (pValue == NULL) {
472             return -1;
473         }
474     }
475     CFX_WideString sel_value;
476     if (pValue->GetType() == PDFOBJ_STRING) {
477         if (index != 0) {
478             return -1;
479         }
480         sel_value = pValue->GetUnicodeText();
481     } else if (pValue->GetType() == PDFOBJ_NUMBER) {
482         return pValue->GetInteger();
483     } else {
484         if (pValue->GetType() != PDFOBJ_ARRAY) {
485             return -1;
486         }
487         if (index < 0) {
488             return -1;
489         }
490         CPDF_Object* elementValue = ((CPDF_Array*)pValue)->GetElementValue(index);
491         sel_value = elementValue ? elementValue->GetUnicodeText() : CFX_WideString();
492     }
493     if (index < CountSelectedOptions()) {
494         int iOptIndex = GetSelectedOptionIndex(index);
495         CFX_WideString csOpt = GetOptionValue(iOptIndex);
496         if (csOpt == sel_value) {
497             return iOptIndex;
498         }
499     }
500     int nOpts = CountOptions();
501     for (int i = 0; i < nOpts; i ++) {
502         if (sel_value == GetOptionValue(i)) {
503             return i;
504         }
505     }
506     return -1;
507 }
508 FX_BOOL CPDF_FormField::ClearSelection(FX_BOOL bNotify)
509 {
510     if (bNotify && m_pForm->m_pFormNotify != NULL) {
511         int iRet = 0;
512         CFX_WideString csValue;
513         int iIndex = GetSelectedIndex(0);
514         if (iIndex >= 0) {
515             csValue = GetOptionLabel(iIndex);
516         }
517         if (GetType() == ListBox) {
518             iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
519         }
520         if (GetType() == ComboBox) {
521             iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
522         }
523         if (iRet < 0) {
524             return FALSE;
525         }
526     }
527     m_pDict->RemoveAt("V");
528     m_pDict->RemoveAt("I");
529     if (bNotify && m_pForm->m_pFormNotify != NULL) {
530         if (GetType() == ListBox) {
531             m_pForm->m_pFormNotify->AfterSelectionChange(this);
532         }
533         if (GetType() == ComboBox) {
534             m_pForm->m_pFormNotify->AfterValueChange(this);
535         }
536     }
537     if (CPDF_InterForm::m_bUpdateAP) {
538         UpdateAP(NULL);
539     }
540     m_pForm->m_bUpdated = TRUE;
541     return TRUE;
542 }
543 FX_BOOL CPDF_FormField::IsItemSelected(int index)
544 {
545     ASSERT(GetType() == ComboBox || GetType() == ListBox);
546     if (index < 0 || index >= CountOptions()) {
547         return FALSE;
548     }
549     if (IsOptionSelected(index)) {
550         return TRUE;
551     }
552     CFX_WideString opt_value = GetOptionValue(index);
553     CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
554     if (pValue == NULL) {
555         pValue = FPDF_GetFieldAttr(m_pDict, "I");
556         if (pValue == NULL) {
557             return FALSE;
558         }
559     }
560     if (pValue->GetType() == PDFOBJ_STRING) {
561         if (pValue->GetUnicodeText() == opt_value) {
562             return TRUE;
563         }
564         return FALSE;
565     }
566     if (pValue->GetType() == PDFOBJ_NUMBER) {
567         if (pValue->GetString().IsEmpty()) {
568             return FALSE;
569         }
570         if (pValue->GetInteger() == index) {
571             return TRUE;
572         }
573         return FALSE;
574     }
575     if (pValue->GetType() != PDFOBJ_ARRAY) {
576         return FALSE;
577     }
578     CPDF_Array* pArray = (CPDF_Array*)pValue;
579     int iPos = -1;
580     for (int j = 0; j < CountSelectedOptions(); j ++) {
581         if (GetSelectedOptionIndex(j) == index) {
582             iPos = j;
583             break;
584         }
585     }
586     for (FX_DWORD i = 0; i < pArray->GetCount(); i ++)
587         if (pArray->GetElementValue(i)->GetUnicodeText() == opt_value && (int)i == iPos) {
588             return TRUE;
589         }
590     return FALSE;
591 }
592 FX_BOOL CPDF_FormField::SetItemSelection(int index, FX_BOOL bSelected, FX_BOOL bNotify)
593 {
594     ASSERT(GetType() == ComboBox || GetType() == ListBox);
595     if (index < 0 || index >= CountOptions()) {
596         return FALSE;
597     }
598     CFX_WideString opt_value = GetOptionValue(index);
599     if (bNotify && m_pForm->m_pFormNotify != NULL) {
600         int iRet = 0;
601         if (GetType() == ListBox) {
602             iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, opt_value);
603         }
604         if (GetType() == ComboBox) {
605             iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, opt_value);
606         }
607         if (iRet < 0) {
608             return FALSE;
609         }
610     }
611     if (!bSelected) {
612         CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
613         if (pValue != NULL) {
614             if (m_Type == ListBox) {
615                 SelectOption(index, FALSE);
616                 if (pValue->GetType() == PDFOBJ_STRING) {
617                     if (pValue->GetUnicodeText() == opt_value) {
618                         m_pDict->RemoveAt("V");
619                     }
620                 } else if (pValue->GetType() == PDFOBJ_ARRAY) {
621                     CPDF_Array* pArray = CPDF_Array::Create();
622                     if (pArray == NULL) {
623                         return FALSE;
624                     }
625                     int iCount = CountOptions();
626                     for (int i = 0; i < iCount; i ++) {
627                         if (i != index) {
628                             if (IsItemSelected(i)) {
629                                 opt_value = GetOptionValue(i);
630                                 pArray->AddString(PDF_EncodeText(opt_value));
631                             }
632                         }
633                     }
634                     if (pArray->GetCount() < 1) {
635                         pArray->Release();
636                     } else {
637                         m_pDict->SetAt("V", pArray);
638                     }
639                 }
640             } else if (m_Type == ComboBox) {
641                 m_pDict->RemoveAt("V");
642                 m_pDict->RemoveAt("I");
643             }
644         }
645     } else {
646         if (m_Type == ListBox) {
647             SelectOption(index, TRUE);
648             if (!(m_Flags & FORMLIST_MULTISELECT)) {
649                 m_pDict->SetAtString("V", PDF_EncodeText(opt_value, opt_value.GetLength()));
650             } else {
651                 CPDF_Array* pArray = CPDF_Array::Create();
652                 if (pArray == NULL) {
653                     return FALSE;
654                 }
655                 FX_BOOL bSelected;
656                 int iCount = CountOptions();
657                 for (int i = 0; i < iCount; i ++) {
658                     if (i != index) {
659                         bSelected = IsItemSelected(i);
660                     } else {
661                         bSelected = TRUE;
662                     }
663                     if (bSelected) {
664                         opt_value = GetOptionValue(i);
665                         pArray->AddString(PDF_EncodeText(opt_value));
666                     }
667                 }
668                 m_pDict->SetAt("V", pArray);
669             }
670         } else if (m_Type == ComboBox) {
671             m_pDict->SetAtString("V", PDF_EncodeText(opt_value, opt_value.GetLength()));
672             CPDF_Array* pI = CPDF_Array::Create();
673             if (pI == NULL) {
674                 return FALSE;
675             }
676             pI->AddInteger(index);
677             m_pDict->SetAt("I", pI);
678         }
679     }
680     if (bNotify && m_pForm->m_pFormNotify != NULL) {
681         if (GetType() == ListBox) {
682             m_pForm->m_pFormNotify->AfterSelectionChange(this);
683         }
684         if (GetType() == ComboBox) {
685             m_pForm->m_pFormNotify->AfterValueChange(this);
686         }
687     }
688     if (CPDF_InterForm::m_bUpdateAP) {
689         UpdateAP(NULL);
690     }
691     m_pForm->m_bUpdated = TRUE;
692     return TRUE;
693 }
694 FX_BOOL CPDF_FormField::IsItemDefaultSelected(int index)
695 {
696     ASSERT(GetType() == ComboBox || GetType() == ListBox);
697     if (index < 0 || index >= CountOptions()) {
698         return FALSE;
699     }
700     int iDVIndex = GetDefaultSelectedItem();
701     if (iDVIndex < 0) {
702         return FALSE;
703     }
704     return (iDVIndex == index);
705 }
706 int CPDF_FormField::GetDefaultSelectedItem()
707 {
708     ASSERT(GetType() == ComboBox || GetType() == ListBox);
709     CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "DV");
710     if (pValue == NULL) {
711         return -1;
712     }
713     CFX_WideString csDV = pValue->GetUnicodeText();
714     if (csDV.IsEmpty()) {
715         return -1;
716     }
717     int iCount = CountOptions();
718     for (int i = 0; i < iCount; i ++) {
719         if (csDV == GetOptionValue(i)) {
720             return i;
721         }
722     }
723     return -1;
724 }
725 void CPDF_FormField::UpdateAP(CPDF_FormControl* pControl)
726 {
727     if (m_Type == PushButton) {
728         return;
729     }
730     if (m_Type == RadioButton || m_Type == CheckBox) {
731         return;
732     }
733     if (!m_pForm->m_bGenerateAP) {
734         return;
735     }
736     for (int i = 0; i < CountControls(); i ++) {
737         CPDF_FormControl* pControl = GetControl(i);
738         FPDF_GenerateAP(m_pForm->m_pDocument, pControl->m_pWidgetDict);
739     }
740 }
741 int CPDF_FormField::CountOptions()
742 {
743     CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "Opt");
744     if (pValue == NULL || pValue->GetType() != PDFOBJ_ARRAY) {
745         return 0;
746     }
747     return ((CPDF_Array*)pValue)->GetCount();
748 }
749 CFX_WideString CPDF_FormField::GetOptionText(int index, int sub_index)
750 {
751     CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "Opt");
752     if (pValue == NULL || pValue->GetType() != PDFOBJ_ARRAY) {
753         return CFX_WideString();
754     }
755     CPDF_Object* pOption = ((CPDF_Array*)pValue)->GetElementValue(index);
756     if (pOption == NULL) {
757         return CFX_WideString();
758     }
759     if (pOption->GetType() == PDFOBJ_ARRAY) {
760         pOption = ((CPDF_Array*)pOption)->GetElementValue(sub_index);
761     }
762     if (pOption == NULL || pOption->GetType() != PDFOBJ_STRING) {
763         return CFX_WideString();
764     }
765     return ((CPDF_String*)pOption)->GetUnicodeText();
766 }
767 CFX_WideString CPDF_FormField::GetOptionLabel(int index)
768 {
769     return GetOptionText(index, 1);
770 }
771 CFX_WideString CPDF_FormField::GetOptionValue(int index)
772 {
773     return GetOptionText(index, 0);
774 }
775 int CPDF_FormField::FindOption(CFX_WideString csOptLabel)
776 {
777     int iCount = CountOptions();
778     for (int i = 0; i < iCount; i ++) {
779         CFX_WideString csValue = GetOptionValue(i);
780         if (csValue == csOptLabel) {
781             return i;
782         }
783     }
784     return -1;
785 }
786 int CPDF_FormField::FindOptionValue(FX_LPCWSTR csOptValue, int iStartIndex)
787 {
788     if (iStartIndex < 0) {
789         iStartIndex = 0;
790     }
791     int iCount = CountOptions();
792     for (; iStartIndex < iCount; iStartIndex ++) {
793         CFX_WideString csValue = GetOptionValue(iStartIndex);
794         if (csValue == csOptValue) {
795             return iStartIndex;
796         }
797     }
798     return -1;
799 }
800 FX_BOOL CPDF_FormField::CheckControl(int iControlIndex, FX_BOOL bChecked, FX_BOOL bNotify)
801 {
802     ASSERT(GetType() == CheckBox || GetType() == RadioButton);
803     CPDF_FormControl* pControl = GetControl(iControlIndex);
804     if (pControl == NULL) {
805         return FALSE;
806     }
807     if (!bChecked && pControl->IsChecked() == bChecked) {
808         return FALSE;
809     }
810     CFX_ByteArray statusArray;
811     if (bNotify && m_pForm->m_pFormNotify != NULL) {
812         SaveCheckedFieldStatus(this, statusArray);
813     }
814     CFX_WideString csWExport =  pControl->GetExportValue();
815     CFX_ByteString csBExport = PDF_EncodeText(csWExport);
816     int iCount = CountControls();
817     FX_BOOL bUnison = PDF_FormField_IsUnison(this);
818     for (int i = 0; i < iCount; i ++) {
819         CPDF_FormControl* pCtrl = GetControl(i);
820         if (bUnison) {
821             CFX_WideString csEValue = pCtrl->GetExportValue();
822             if (csEValue == csWExport) {
823                 if (pCtrl->GetOnStateName() == pControl->GetOnStateName()) {
824                     pCtrl->CheckControl(bChecked);
825                 } else if (bChecked) {
826                     pCtrl->CheckControl(FALSE);
827                 }
828             } else if (bChecked) {
829                 pCtrl->CheckControl(FALSE);
830             }
831         } else {
832             if (i == iControlIndex) {
833                 pCtrl->CheckControl(bChecked);
834             } else if (bChecked) {
835                 pCtrl->CheckControl(FALSE);
836             }
837         }
838     }
839     CPDF_Object* pOpt = FPDF_GetFieldAttr(m_pDict, "Opt");
840     if (pOpt == NULL || pOpt->GetType() != PDFOBJ_ARRAY) {
841         if (bChecked) {
842             m_pDict->SetAtName("V", csBExport);
843         } else {
844             CFX_ByteString csV;
845             CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V");
846             if (pV != NULL) {
847                 csV = pV->GetString();
848             }
849             if (csV == csBExport) {
850                 m_pDict->SetAtName("V", "Off");
851             }
852         }
853     } else if (bChecked) {
854         CFX_ByteString csIndex;
855         csIndex.Format("%d", iControlIndex);
856         m_pDict->SetAtName("V", csIndex);
857     }
858     if (bNotify && m_pForm->m_pFormNotify != NULL) {
859         m_pForm->m_pFormNotify->AfterCheckedStatusChange(this, statusArray);
860     }
861     m_pForm->m_bUpdated = TRUE;
862     return TRUE;
863 }
864 CFX_WideString CPDF_FormField::GetCheckValue(FX_BOOL bDefault)
865 {
866     ASSERT(GetType() == CheckBox || GetType() == RadioButton);
867     CFX_WideString csExport = L"Off";
868     FX_BOOL bChecked;
869     int iCount = CountControls();
870     for (int i = 0; i < iCount; i ++) {
871         CPDF_FormControl* pControl = GetControl(i);
872         if (bDefault) {
873             bChecked = pControl->IsDefaultChecked();
874         } else {
875             bChecked = pControl->IsChecked();
876         }
877         if (bChecked) {
878             csExport = pControl->GetExportValue();
879             break;
880         }
881     }
882     return csExport;
883 }
884 FX_BOOL CPDF_FormField::SetCheckValue(const CFX_WideString& value, FX_BOOL bDefault, FX_BOOL bNotify)
885 {
886     ASSERT(GetType() == CheckBox || GetType() == RadioButton);
887     CFX_ByteArray statusArray;
888     if (bNotify && m_pForm->m_pFormNotify != NULL) {
889         SaveCheckedFieldStatus(this, statusArray);
890     }
891     int iCount = CountControls();
892     for (int i = 0; i < iCount; i ++) {
893         CPDF_FormControl* pControl = GetControl(i);
894         CFX_WideString csExport = pControl->GetExportValue();
895         if (csExport == value) {
896             if (bDefault) {
897             } else {
898                 CheckControl(GetControlIndex(pControl), TRUE);
899             }
900             break;
901         } else {
902             if (bDefault) {
903             } else {
904                 CheckControl(GetControlIndex(pControl), FALSE);
905             }
906         }
907     }
908     if (bNotify && m_pForm->m_pFormNotify != NULL) {
909         m_pForm->m_pFormNotify->AfterCheckedStatusChange(this, statusArray);
910     }
911     m_pForm->m_bUpdated = TRUE;
912     return TRUE;
913 }
914 int CPDF_FormField::GetTopVisibleIndex()
915 {
916     CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TI");
917     if (pObj == NULL) {
918         return 0;
919     }
920     return pObj->GetInteger();
921 }
922 int CPDF_FormField::CountSelectedOptions()
923 {
924     CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "I");
925     if (pObj == NULL) {
926         return 0;
927     }
928     CPDF_Array* pArray = pObj->GetArray();
929     if (pArray == NULL) {
930         return 0;
931     }
932     return (int)pArray->GetCount();
933 }
934 int CPDF_FormField::GetSelectedOptionIndex(int index)
935 {
936     CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "I");
937     if (pObj == NULL) {
938         return -1;
939     }
940     CPDF_Array* pArray = pObj->GetArray();
941     if (pArray == NULL) {
942         return -1;
943     }
944     int iCount = (int)pArray->GetCount();
945     if (iCount > 0 && index < iCount) {
946         return pArray->GetInteger(index);
947     }
948     return -1;
949 }
950 FX_BOOL CPDF_FormField::IsOptionSelected(int iOptIndex)
951 {
952     CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "I");
953     if (pObj == NULL) {
954         return FALSE;
955     }
956     CPDF_Array* pArray = pObj->GetArray();
957     if (pArray == NULL) {
958         return FALSE;
959     }
960     int iCount = (int)pArray->GetCount();
961     for (int i = 0; i < iCount; i ++) {
962         if (pArray->GetInteger(i) == iOptIndex) {
963             return TRUE;
964         }
965     }
966     return FALSE;
967 }
968 FX_BOOL CPDF_FormField::SelectOption(int iOptIndex, FX_BOOL bSelected, FX_BOOL bNotify)
969 {
970     CPDF_Array* pArray = m_pDict->GetArray("I");
971     if (pArray == NULL) {
972         if (!bSelected) {
973             return TRUE;
974         }
975         pArray = CPDF_Array::Create();
976         if (pArray == NULL) {
977             return FALSE;
978         }
979         m_pDict->SetAt("I", pArray);
980     }
981     FX_BOOL bReturn = FALSE;
982     for (int i = 0; i < (int)pArray->GetCount(); i ++) {
983         int iFind = pArray->GetInteger(i);
984         if (iFind == iOptIndex) {
985             if (bSelected) {
986                 return TRUE;
987             }
988             if (bNotify && m_pForm->m_pFormNotify != NULL) {
989                 int iRet = 0;
990                 CFX_WideString csValue = GetOptionLabel(iOptIndex);
991                 if (GetType() == ListBox) {
992                     iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
993                 }
994                 if (GetType() == ComboBox) {
995                     iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
996                 }
997                 if (iRet < 0) {
998                     return FALSE;
999                 }
1000             }
1001             pArray->RemoveAt(i);
1002             bReturn = TRUE;
1003             break;
1004         } else if (iFind > iOptIndex) {
1005             if (!bSelected) {
1006                 continue;
1007             }
1008             if (bNotify && m_pForm->m_pFormNotify != NULL) {
1009                 int iRet = 0;
1010                 CFX_WideString csValue = GetOptionLabel(iOptIndex);
1011                 if (GetType() == ListBox) {
1012                     iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
1013                 }
1014                 if (GetType() == ComboBox) {
1015                     iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
1016                 }
1017                 if (iRet < 0) {
1018                     return FALSE;
1019                 }
1020             }
1021             CPDF_Number* pNum = CPDF_Number::Create(iOptIndex);
1022             if (pNum == NULL) {
1023                 return FALSE;
1024             }
1025             pArray->InsertAt(i, pNum);
1026             bReturn = TRUE;
1027             break;
1028         }
1029     }
1030     if (!bReturn) {
1031         if (bSelected) {
1032             pArray->AddInteger(iOptIndex);
1033         }
1034         if (pArray->GetCount() == 0) {
1035             m_pDict->RemoveAt("I");
1036         }
1037     }
1038     if (bNotify && m_pForm->m_pFormNotify != NULL) {
1039         if (GetType() == ListBox) {
1040             m_pForm->m_pFormNotify->AfterSelectionChange(this);
1041         }
1042         if (GetType() == ComboBox) {
1043             m_pForm->m_pFormNotify->AfterValueChange(this);
1044         }
1045     }
1046     m_pForm->m_bUpdated = TRUE;
1047     return TRUE;
1048 }
1049 FX_BOOL CPDF_FormField::ClearSelectedOptions(FX_BOOL bNotify)
1050 {
1051     if (bNotify && m_pForm->m_pFormNotify != NULL) {
1052         int iRet = 0;
1053         CFX_WideString csValue;
1054         int iIndex = GetSelectedIndex(0);
1055         if (iIndex >= 0) {
1056             csValue = GetOptionLabel(iIndex);
1057         }
1058         if (GetType() == ListBox) {
1059             iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
1060         }
1061         if (GetType() == ComboBox) {
1062             iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
1063         }
1064         if (iRet < 0) {
1065             return FALSE;
1066         }
1067     }
1068     m_pDict->RemoveAt("I");
1069     if (bNotify && m_pForm->m_pFormNotify != NULL) {
1070         if (GetType() == ListBox) {
1071             m_pForm->m_pFormNotify->AfterSelectionChange(this);
1072         }
1073         if (GetType() == ComboBox) {
1074             m_pForm->m_pFormNotify->AfterValueChange(this);
1075         }
1076     }
1077     m_pForm->m_bUpdated = TRUE;
1078     return TRUE;
1079 }
1080 void CPDF_FormField::LoadDA()
1081 {
1082     CFX_ByteString DA;
1083     if (CPDF_Object* pObj_t = FPDF_GetFieldAttr(m_pDict, "DA")) {
1084         DA = pObj_t->GetString();
1085     }
1086     if (DA.IsEmpty() && m_pForm->m_pFormDict) {
1087         DA = m_pForm->m_pFormDict->GetString("DA");
1088     }
1089     if (DA.IsEmpty()) {
1090         return;
1091     }
1092     CPDF_SimpleParser syntax(DA);
1093     syntax.FindTagParam("Tf", 2);
1094     CFX_ByteString font_name = syntax.GetWord();
1095     CPDF_Dictionary* pFontDict = NULL;
1096     if (m_pForm->m_pFormDict && m_pForm->m_pFormDict->GetDict("DR") &&
1097         m_pForm->m_pFormDict->GetDict("DR")->GetDict("Font") )
1098     pFontDict = m_pForm->m_pFormDict->GetDict("DR")->GetDict("Font")->GetDict(font_name);
1099
1100     if (pFontDict == NULL) {
1101         return;
1102     }
1103     m_pFont = m_pForm->m_pDocument->LoadFont(pFontDict);
1104     m_FontSize = FX_atof(syntax.GetWord());
1105 }