e51acf94a111a5216045773ba04e45fe918db420
[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             return pValue->GetUnicodeText();
328             break;
329     }
330     return CFX_WideString();
331 }
332 CFX_WideString CPDF_FormField::GetValue()
333 {
334     return GetValue(FALSE);
335 }
336 CFX_WideString CPDF_FormField::GetDefaultValue()
337 {
338     return GetValue(TRUE);
339 }
340 FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value, FX_BOOL bDefault, FX_BOOL bNotify)
341 {
342     switch (m_Type) {
343         case CheckBox:
344         case RadioButton: {
345                 SetCheckValue(value, bDefault, bNotify);
346                 return TRUE;
347             }
348         case File:
349         case RichText:
350         case Text:
351         case ComboBox: {
352                 CFX_WideString csValue = value;
353                 if (bNotify && m_pForm->m_pFormNotify != NULL) {
354                     int iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
355                     if (iRet < 0) {
356                         return FALSE;
357                     }
358                 }
359                 int iIndex = FindOptionValue(csValue);
360                 if (iIndex < 0) {
361                     CFX_ByteString bsEncodeText = PDF_EncodeText(csValue);
362                     m_pDict->SetAtString(bDefault ? "DV" : "V", bsEncodeText);
363                     if (m_Type == RichText && !bDefault) {
364                         m_pDict->SetAtString("RV", bsEncodeText);
365                     }
366                     m_pDict->RemoveAt("I");
367                 } else {
368                     m_pDict->SetAtString(bDefault ? "DV" : "V", PDF_EncodeText(csValue));
369                     if (bDefault) {
370                     } else {
371                         ClearSelection();
372                         SetItemSelection(iIndex, TRUE);
373                     }
374                 }
375                 if (bNotify && m_pForm->m_pFormNotify != NULL) {
376                     m_pForm->m_pFormNotify->AfterValueChange(this);
377                 }
378                 m_pForm->m_bUpdated = TRUE;
379             }
380             break;
381         case ListBox: {
382                 int iIndex = FindOptionValue(value);
383                 if (iIndex < 0) {
384                     return FALSE;
385                 }
386                 if (bDefault && iIndex == GetDefaultSelectedItem()) {
387                     return FALSE;
388                 }
389                 if (bNotify && m_pForm->m_pFormNotify != NULL) {
390                     CFX_WideString csValue = value;
391                     int iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
392                     if (iRet < 0) {
393                         return FALSE;
394                     }
395                 }
396                 if (bDefault) {
397                 } else {
398                     ClearSelection();
399                     SetItemSelection(iIndex, TRUE);
400                 }
401                 if (bNotify && m_pForm->m_pFormNotify != NULL) {
402                     m_pForm->m_pFormNotify->AfterSelectionChange(this);
403                 }
404                 m_pForm->m_bUpdated = TRUE;
405                 break;
406             }
407         default:
408             break;
409     }
410     if (CPDF_InterForm::m_bUpdateAP) {
411         UpdateAP(NULL);
412     }
413     return TRUE;
414 }
415 FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value, FX_BOOL bNotify)
416 {
417     return SetValue(value, FALSE, bNotify);
418 }
419 int CPDF_FormField::GetMaxLen()
420 {
421     CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "MaxLen");
422     if (pObj == NULL) {
423         int iCount = m_ControlList.GetSize();
424         for (int i = 0; i < iCount; i ++) {
425             CPDF_FormControl* pControl = (CPDF_FormControl*)m_ControlList.GetAt(i);
426             if (pControl == NULL) {
427                 continue;
428             }
429             CPDF_Dictionary* pWidgetDict = pControl->m_pWidgetDict;
430             if (pWidgetDict->KeyExist("MaxLen")) {
431                 return pWidgetDict->GetInteger("MaxLen");
432             }
433         }
434         return 0;
435     }
436     return pObj->GetInteger();
437 }
438 int CPDF_FormField::CountSelectedItems()
439 {
440     CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
441     if (pValue == NULL) {
442         pValue = FPDF_GetFieldAttr(m_pDict, "I");
443         if (pValue == NULL) {
444             return 0;
445         }
446     }
447     if (pValue->GetType() == PDFOBJ_STRING) {
448         if (pValue->GetString().IsEmpty()) {
449             return 0;
450         }
451         return 1;
452     }
453     if (pValue->GetType() == PDFOBJ_NUMBER) {
454         if (pValue->GetString().IsEmpty()) {
455             return 0;
456         }
457         return 1;
458     }
459     if (pValue->GetType() != PDFOBJ_ARRAY) {
460         return 0;
461     }
462     return ((CPDF_Array*)pValue)->GetCount();
463 }
464 int CPDF_FormField::GetSelectedIndex(int index)
465 {
466     CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
467     if (pValue == NULL) {
468         pValue = FPDF_GetFieldAttr(m_pDict, "I");
469         if (pValue == NULL) {
470             return -1;
471         }
472     }
473     CFX_WideString sel_value;
474     if (pValue->GetType() == PDFOBJ_STRING) {
475         if (index != 0) {
476             return -1;
477         }
478         sel_value = pValue->GetUnicodeText();
479     } else if (pValue->GetType() == PDFOBJ_NUMBER) {
480         return pValue->GetInteger();
481     } else {
482         if (pValue->GetType() != PDFOBJ_ARRAY) {
483             return -1;
484         }
485         if (index < 0) {
486             return -1;
487         }
488         CPDF_Object* elementValue = ((CPDF_Array*)pValue)->GetElementValue(index);
489         sel_value = elementValue ? elementValue->GetUnicodeText() : CFX_WideString();
490     }
491     if (index < CountSelectedOptions()) {
492         int iOptIndex = GetSelectedOptionIndex(index);
493         CFX_WideString csOpt = GetOptionValue(iOptIndex);
494         if (csOpt == sel_value) {
495             return iOptIndex;
496         }
497     }
498     int nOpts = CountOptions();
499     for (int i = 0; i < nOpts; i ++) {
500         if (sel_value == GetOptionValue(i)) {
501             return i;
502         }
503     }
504     return -1;
505 }
506 FX_BOOL CPDF_FormField::ClearSelection(FX_BOOL bNotify)
507 {
508     if (bNotify && m_pForm->m_pFormNotify != NULL) {
509         int iRet = 0;
510         CFX_WideString csValue;
511         int iIndex = GetSelectedIndex(0);
512         if (iIndex >= 0) {
513             csValue = GetOptionLabel(iIndex);
514         }
515         if (GetType() == ListBox) {
516             iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
517         }
518         if (GetType() == ComboBox) {
519             iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
520         }
521         if (iRet < 0) {
522             return FALSE;
523         }
524     }
525     m_pDict->RemoveAt("V");
526     m_pDict->RemoveAt("I");
527     if (bNotify && m_pForm->m_pFormNotify != NULL) {
528         if (GetType() == ListBox) {
529             m_pForm->m_pFormNotify->AfterSelectionChange(this);
530         }
531         if (GetType() == ComboBox) {
532             m_pForm->m_pFormNotify->AfterValueChange(this);
533         }
534     }
535     if (CPDF_InterForm::m_bUpdateAP) {
536         UpdateAP(NULL);
537     }
538     m_pForm->m_bUpdated = TRUE;
539     return TRUE;
540 }
541 FX_BOOL CPDF_FormField::IsItemSelected(int index)
542 {
543     ASSERT(GetType() == ComboBox || GetType() == ListBox);
544     if (index < 0 || index >= CountOptions()) {
545         return FALSE;
546     }
547     if (IsOptionSelected(index)) {
548         return TRUE;
549     }
550     CFX_WideString opt_value = GetOptionValue(index);
551     CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
552     if (pValue == NULL) {
553         pValue = FPDF_GetFieldAttr(m_pDict, "I");
554         if (pValue == NULL) {
555             return FALSE;
556         }
557     }
558     if (pValue->GetType() == PDFOBJ_STRING) {
559         if (pValue->GetUnicodeText() == opt_value) {
560             return TRUE;
561         }
562         return FALSE;
563     }
564     if (pValue->GetType() == PDFOBJ_NUMBER) {
565         if (pValue->GetString().IsEmpty()) {
566             return FALSE;
567         }
568         if (pValue->GetInteger() == index) {
569             return TRUE;
570         }
571         return FALSE;
572     }
573     if (pValue->GetType() != PDFOBJ_ARRAY) {
574         return FALSE;
575     }
576     CPDF_Array* pArray = (CPDF_Array*)pValue;
577     int iPos = -1;
578     for (int j = 0; j < CountSelectedOptions(); j ++) {
579         if (GetSelectedOptionIndex(j) == index) {
580             iPos = j;
581             break;
582         }
583     }
584     for (FX_DWORD i = 0; i < pArray->GetCount(); i ++)
585         if (pArray->GetElementValue(i)->GetUnicodeText() == opt_value && (int)i == iPos) {
586             return TRUE;
587         }
588     return FALSE;
589 }
590 FX_BOOL CPDF_FormField::SetItemSelection(int index, FX_BOOL bSelected, FX_BOOL bNotify)
591 {
592     ASSERT(GetType() == ComboBox || GetType() == ListBox);
593     if (index < 0 || index >= CountOptions()) {
594         return FALSE;
595     }
596     CFX_WideString opt_value = GetOptionValue(index);
597     if (bNotify && m_pForm->m_pFormNotify != NULL) {
598         int iRet = 0;
599         if (GetType() == ListBox) {
600             iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, opt_value);
601         }
602         if (GetType() == ComboBox) {
603             iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, opt_value);
604         }
605         if (iRet < 0) {
606             return FALSE;
607         }
608     }
609     if (!bSelected) {
610         CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V");
611         if (pValue != NULL) {
612             if (m_Type == ListBox) {
613                 SelectOption(index, FALSE);
614                 if (pValue->GetType() == PDFOBJ_STRING) {
615                     if (pValue->GetUnicodeText() == opt_value) {
616                         m_pDict->RemoveAt("V");
617                     }
618                 } else if (pValue->GetType() == PDFOBJ_ARRAY) {
619                     CPDF_Array* pArray = CPDF_Array::Create();
620                     if (pArray == NULL) {
621                         return FALSE;
622                     }
623                     int iCount = CountOptions();
624                     for (int i = 0; i < iCount; i ++) {
625                         if (i != index) {
626                             if (IsItemSelected(i)) {
627                                 opt_value = GetOptionValue(i);
628                                 pArray->AddString(PDF_EncodeText(opt_value));
629                             }
630                         }
631                     }
632                     if (pArray->GetCount() < 1) {
633                         pArray->Release();
634                     } else {
635                         m_pDict->SetAt("V", pArray);
636                     }
637                 }
638             } else if (m_Type == ComboBox) {
639                 m_pDict->RemoveAt("V");
640                 m_pDict->RemoveAt("I");
641             }
642         }
643     } else {
644         if (m_Type == ListBox) {
645             SelectOption(index, TRUE);
646             if (!(m_Flags & FORMLIST_MULTISELECT)) {
647                 m_pDict->SetAtString("V", PDF_EncodeText(opt_value, opt_value.GetLength()));
648             } else {
649                 CPDF_Array* pArray = CPDF_Array::Create();
650                 if (pArray == NULL) {
651                     return FALSE;
652                 }
653                 FX_BOOL bSelected;
654                 int iCount = CountOptions();
655                 for (int i = 0; i < iCount; i ++) {
656                     if (i != index) {
657                         bSelected = IsItemSelected(i);
658                     } else {
659                         bSelected = TRUE;
660                     }
661                     if (bSelected) {
662                         opt_value = GetOptionValue(i);
663                         pArray->AddString(PDF_EncodeText(opt_value));
664                     }
665                 }
666                 m_pDict->SetAt("V", pArray);
667             }
668         } else if (m_Type == ComboBox) {
669             m_pDict->SetAtString("V", PDF_EncodeText(opt_value, opt_value.GetLength()));
670             CPDF_Array* pI = CPDF_Array::Create();
671             if (pI == NULL) {
672                 return FALSE;
673             }
674             pI->AddInteger(index);
675             m_pDict->SetAt("I", pI);
676         }
677     }
678     if (bNotify && m_pForm->m_pFormNotify != NULL) {
679         if (GetType() == ListBox) {
680             m_pForm->m_pFormNotify->AfterSelectionChange(this);
681         }
682         if (GetType() == ComboBox) {
683             m_pForm->m_pFormNotify->AfterValueChange(this);
684         }
685     }
686     if (CPDF_InterForm::m_bUpdateAP) {
687         UpdateAP(NULL);
688     }
689     m_pForm->m_bUpdated = TRUE;
690     return TRUE;
691 }
692 FX_BOOL CPDF_FormField::IsItemDefaultSelected(int index)
693 {
694     ASSERT(GetType() == ComboBox || GetType() == ListBox);
695     if (index < 0 || index >= CountOptions()) {
696         return FALSE;
697     }
698     int iDVIndex = GetDefaultSelectedItem();
699     if (iDVIndex < 0) {
700         return FALSE;
701     }
702     return (iDVIndex == index);
703 }
704 int CPDF_FormField::GetDefaultSelectedItem()
705 {
706     ASSERT(GetType() == ComboBox || GetType() == ListBox);
707     CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "DV");
708     if (pValue == NULL) {
709         return -1;
710     }
711     CFX_WideString csDV = pValue->GetUnicodeText();
712     if (csDV.IsEmpty()) {
713         return -1;
714     }
715     int iCount = CountOptions();
716     for (int i = 0; i < iCount; i ++) {
717         if (csDV == GetOptionValue(i)) {
718             return i;
719         }
720     }
721     return -1;
722 }
723 void CPDF_FormField::UpdateAP(CPDF_FormControl* pControl)
724 {
725     if (m_Type == PushButton) {
726         return;
727     }
728     if (m_Type == RadioButton || m_Type == CheckBox) {
729         return;
730     }
731     if (!m_pForm->m_bGenerateAP) {
732         return;
733     }
734     for (int i = 0; i < CountControls(); i ++) {
735         CPDF_FormControl* pControl = GetControl(i);
736         FPDF_GenerateAP(m_pForm->m_pDocument, pControl->m_pWidgetDict);
737     }
738 }
739 int CPDF_FormField::CountOptions()
740 {
741     CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "Opt");
742     if (pValue == NULL || pValue->GetType() != PDFOBJ_ARRAY) {
743         return 0;
744     }
745     return ((CPDF_Array*)pValue)->GetCount();
746 }
747 CFX_WideString CPDF_FormField::GetOptionText(int index, int sub_index)
748 {
749     CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "Opt");
750     if (pValue == NULL || pValue->GetType() != PDFOBJ_ARRAY) {
751         return CFX_WideString();
752     }
753     CPDF_Object* pOption = ((CPDF_Array*)pValue)->GetElementValue(index);
754     if (pOption == NULL) {
755         return CFX_WideString();
756     }
757     if (pOption->GetType() == PDFOBJ_ARRAY) {
758         pOption = ((CPDF_Array*)pOption)->GetElementValue(sub_index);
759     }
760     if (pOption == NULL || pOption->GetType() != PDFOBJ_STRING) {
761         return CFX_WideString();
762     }
763     return ((CPDF_String*)pOption)->GetUnicodeText();
764 }
765 CFX_WideString CPDF_FormField::GetOptionLabel(int index)
766 {
767     return GetOptionText(index, 1);
768 }
769 CFX_WideString CPDF_FormField::GetOptionValue(int index)
770 {
771     return GetOptionText(index, 0);
772 }
773 int CPDF_FormField::FindOption(CFX_WideString csOptLabel)
774 {
775     int iCount = CountOptions();
776     for (int i = 0; i < iCount; i ++) {
777         CFX_WideString csValue = GetOptionValue(i);
778         if (csValue == csOptLabel) {
779             return i;
780         }
781     }
782     return -1;
783 }
784 int CPDF_FormField::FindOptionValue(FX_LPCWSTR csOptValue, int iStartIndex)
785 {
786     if (iStartIndex < 0) {
787         iStartIndex = 0;
788     }
789     int iCount = CountOptions();
790     for (; iStartIndex < iCount; iStartIndex ++) {
791         CFX_WideString csValue = GetOptionValue(iStartIndex);
792         if (csValue == csOptValue) {
793             return iStartIndex;
794         }
795     }
796     return -1;
797 }
798 FX_BOOL CPDF_FormField::CheckControl(int iControlIndex, FX_BOOL bChecked, FX_BOOL bNotify)
799 {
800     ASSERT(GetType() == CheckBox || GetType() == RadioButton);
801     CPDF_FormControl* pControl = GetControl(iControlIndex);
802     if (pControl == NULL) {
803         return FALSE;
804     }
805     if (!bChecked && pControl->IsChecked() == bChecked) {
806         return FALSE;
807     }
808     CFX_ByteArray statusArray;
809     if (bNotify && m_pForm->m_pFormNotify != NULL) {
810         SaveCheckedFieldStatus(this, statusArray);
811     }
812     CFX_WideString csWExport =  pControl->GetExportValue();
813     CFX_ByteString csBExport = PDF_EncodeText(csWExport);
814     int iCount = CountControls();
815     FX_BOOL bUnison = PDF_FormField_IsUnison(this);
816     for (int i = 0; i < iCount; i ++) {
817         CPDF_FormControl* pCtrl = GetControl(i);
818         if (bUnison) {
819             CFX_WideString csEValue = pCtrl->GetExportValue();
820             if (csEValue == csWExport) {
821                 if (pCtrl->GetOnStateName() == pControl->GetOnStateName()) {
822                     pCtrl->CheckControl(bChecked);
823                 } else if (bChecked) {
824                     pCtrl->CheckControl(FALSE);
825                 }
826             } else if (bChecked) {
827                 pCtrl->CheckControl(FALSE);
828             }
829         } else {
830             if (i == iControlIndex) {
831                 pCtrl->CheckControl(bChecked);
832             } else if (bChecked) {
833                 pCtrl->CheckControl(FALSE);
834             }
835         }
836     }
837     CPDF_Object* pOpt = FPDF_GetFieldAttr(m_pDict, "Opt");
838     if (pOpt == NULL || pOpt->GetType() != PDFOBJ_ARRAY) {
839         if (bChecked) {
840             m_pDict->SetAtName("V", csBExport);
841         } else {
842             CFX_ByteString csV;
843             CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V");
844             if (pV != NULL) {
845                 csV = pV->GetString();
846             }
847             if (csV == csBExport) {
848                 m_pDict->SetAtName("V", "Off");
849             }
850         }
851     } else if (bChecked) {
852         CFX_ByteString csIndex;
853         csIndex.Format("%d", iControlIndex);
854         m_pDict->SetAtName("V", csIndex);
855     }
856     if (bNotify && m_pForm->m_pFormNotify != NULL) {
857         m_pForm->m_pFormNotify->AfterCheckedStatusChange(this, statusArray);
858     }
859     m_pForm->m_bUpdated = TRUE;
860     return TRUE;
861 }
862 CFX_WideString CPDF_FormField::GetCheckValue(FX_BOOL bDefault)
863 {
864     ASSERT(GetType() == CheckBox || GetType() == RadioButton);
865     CFX_WideString csExport = L"Off";
866     FX_BOOL bChecked;
867     int iCount = CountControls();
868     for (int i = 0; i < iCount; i ++) {
869         CPDF_FormControl* pControl = GetControl(i);
870         if (bDefault) {
871             bChecked = pControl->IsDefaultChecked();
872         } else {
873             bChecked = pControl->IsChecked();
874         }
875         if (bChecked) {
876             csExport = pControl->GetExportValue();
877             break;
878         }
879     }
880     return csExport;
881 }
882 FX_BOOL CPDF_FormField::SetCheckValue(const CFX_WideString& value, FX_BOOL bDefault, FX_BOOL bNotify)
883 {
884     ASSERT(GetType() == CheckBox || GetType() == RadioButton);
885     CFX_ByteArray statusArray;
886     if (bNotify && m_pForm->m_pFormNotify != NULL) {
887         SaveCheckedFieldStatus(this, statusArray);
888     }
889     int iCount = CountControls();
890     for (int i = 0; i < iCount; i ++) {
891         CPDF_FormControl* pControl = GetControl(i);
892         CFX_WideString csExport = pControl->GetExportValue();
893         if (csExport == value) {
894             if (bDefault) {
895             } else {
896                 CheckControl(GetControlIndex(pControl), TRUE);
897             }
898             break;
899         } else {
900             if (bDefault) {
901             } else {
902                 CheckControl(GetControlIndex(pControl), FALSE);
903             }
904         }
905     }
906     if (bNotify && m_pForm->m_pFormNotify != NULL) {
907         m_pForm->m_pFormNotify->AfterCheckedStatusChange(this, statusArray);
908     }
909     m_pForm->m_bUpdated = TRUE;
910     return TRUE;
911 }
912 int CPDF_FormField::GetTopVisibleIndex()
913 {
914     CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TI");
915     if (pObj == NULL) {
916         return 0;
917     }
918     return pObj->GetInteger();
919 }
920 int CPDF_FormField::CountSelectedOptions()
921 {
922     CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "I");
923     if (pObj == NULL) {
924         return 0;
925     }
926     CPDF_Array* pArray = pObj->GetArray();
927     if (pArray == NULL) {
928         return 0;
929     }
930     return (int)pArray->GetCount();
931 }
932 int CPDF_FormField::GetSelectedOptionIndex(int index)
933 {
934     CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "I");
935     if (pObj == NULL) {
936         return -1;
937     }
938     CPDF_Array* pArray = pObj->GetArray();
939     if (pArray == NULL) {
940         return -1;
941     }
942     int iCount = (int)pArray->GetCount();
943     if (iCount > 0 && index < iCount) {
944         return pArray->GetInteger(index);
945     }
946     return -1;
947 }
948 FX_BOOL CPDF_FormField::IsOptionSelected(int iOptIndex)
949 {
950     CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "I");
951     if (pObj == NULL) {
952         return FALSE;
953     }
954     CPDF_Array* pArray = pObj->GetArray();
955     if (pArray == NULL) {
956         return FALSE;
957     }
958     int iCount = (int)pArray->GetCount();
959     for (int i = 0; i < iCount; i ++) {
960         if (pArray->GetInteger(i) == iOptIndex) {
961             return TRUE;
962         }
963     }
964     return FALSE;
965 }
966 FX_BOOL CPDF_FormField::SelectOption(int iOptIndex, FX_BOOL bSelected, FX_BOOL bNotify)
967 {
968     CPDF_Array* pArray = m_pDict->GetArray("I");
969     if (pArray == NULL) {
970         if (!bSelected) {
971             return TRUE;
972         }
973         pArray = CPDF_Array::Create();
974         if (pArray == NULL) {
975             return FALSE;
976         }
977         m_pDict->SetAt("I", pArray);
978     }
979     FX_BOOL bReturn = FALSE;
980     for (int i = 0; i < (int)pArray->GetCount(); i ++) {
981         int iFind = pArray->GetInteger(i);
982         if (iFind == iOptIndex) {
983             if (bSelected) {
984                 return TRUE;
985             }
986             if (bNotify && m_pForm->m_pFormNotify != NULL) {
987                 int iRet = 0;
988                 CFX_WideString csValue = GetOptionLabel(iOptIndex);
989                 if (GetType() == ListBox) {
990                     iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
991                 }
992                 if (GetType() == ComboBox) {
993                     iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
994                 }
995                 if (iRet < 0) {
996                     return FALSE;
997                 }
998             }
999             pArray->RemoveAt(i);
1000             bReturn = TRUE;
1001             break;
1002         } else if (iFind > iOptIndex) {
1003             if (!bSelected) {
1004                 continue;
1005             }
1006             if (bNotify && m_pForm->m_pFormNotify != NULL) {
1007                 int iRet = 0;
1008                 CFX_WideString csValue = GetOptionLabel(iOptIndex);
1009                 if (GetType() == ListBox) {
1010                     iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
1011                 }
1012                 if (GetType() == ComboBox) {
1013                     iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
1014                 }
1015                 if (iRet < 0) {
1016                     return FALSE;
1017                 }
1018             }
1019             CPDF_Number* pNum = CPDF_Number::Create(iOptIndex);
1020             if (pNum == NULL) {
1021                 return FALSE;
1022             }
1023             pArray->InsertAt(i, pNum);
1024             bReturn = TRUE;
1025             break;
1026         }
1027     }
1028     if (!bReturn) {
1029         if (bSelected) {
1030             pArray->AddInteger(iOptIndex);
1031         }
1032         if (pArray->GetCount() == 0) {
1033             m_pDict->RemoveAt("I");
1034         }
1035     }
1036     if (bNotify && m_pForm->m_pFormNotify != NULL) {
1037         if (GetType() == ListBox) {
1038             m_pForm->m_pFormNotify->AfterSelectionChange(this);
1039         }
1040         if (GetType() == ComboBox) {
1041             m_pForm->m_pFormNotify->AfterValueChange(this);
1042         }
1043     }
1044     m_pForm->m_bUpdated = TRUE;
1045     return TRUE;
1046 }
1047 FX_BOOL CPDF_FormField::ClearSelectedOptions(FX_BOOL bNotify)
1048 {
1049     if (bNotify && m_pForm->m_pFormNotify != NULL) {
1050         int iRet = 0;
1051         CFX_WideString csValue;
1052         int iIndex = GetSelectedIndex(0);
1053         if (iIndex >= 0) {
1054             csValue = GetOptionLabel(iIndex);
1055         }
1056         if (GetType() == ListBox) {
1057             iRet = m_pForm->m_pFormNotify->BeforeSelectionChange(this, csValue);
1058         }
1059         if (GetType() == ComboBox) {
1060             iRet = m_pForm->m_pFormNotify->BeforeValueChange(this, csValue);
1061         }
1062         if (iRet < 0) {
1063             return FALSE;
1064         }
1065     }
1066     m_pDict->RemoveAt("I");
1067     if (bNotify && m_pForm->m_pFormNotify != NULL) {
1068         if (GetType() == ListBox) {
1069             m_pForm->m_pFormNotify->AfterSelectionChange(this);
1070         }
1071         if (GetType() == ComboBox) {
1072             m_pForm->m_pFormNotify->AfterValueChange(this);
1073         }
1074     }
1075     m_pForm->m_bUpdated = TRUE;
1076     return TRUE;
1077 }
1078 void CPDF_FormField::LoadDA()
1079 {
1080     CFX_ByteString DA = FPDF_GetFieldAttr(m_pDict, "DA") ? FPDF_GetFieldAttr(m_pDict, "DA")->GetString() : CFX_ByteString();
1081     if (DA.IsEmpty()) {
1082         DA = m_pForm->m_pFormDict ? m_pForm->m_pFormDict->GetString("DA") : CFX_ByteString();
1083     }
1084     if (DA.IsEmpty()) {
1085         return;
1086     }
1087     CPDF_SimpleParser syntax(DA);
1088     syntax.FindTagParam("Tf", 2);
1089     CFX_ByteString font_name = syntax.GetWord();
1090     CPDF_Dictionary* pFontDict = NULL;
1091     if (m_pForm->m_pFormDict && m_pForm->m_pFormDict->GetDict("DR") &&
1092         m_pForm->m_pFormDict->GetDict("DR")->GetDict("Font") )
1093     pFontDict = m_pForm->m_pFormDict->GetDict("DR")->GetDict("Font")->GetDict(font_name);
1094
1095     if (pFontDict == NULL) {
1096         return;
1097     }
1098     m_pFont = m_pForm->m_pDocument->LoadFont(pFontDict);
1099     m_FontSize = FX_atof(syntax.GetWord());
1100 }