1 // Copyright 2017 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 "xfa/fxfa/cxfa_fflistbox.h"
8
9 #include <algorithm>
10 #include <utility>
11 #include <vector>
12
13 #include "xfa/fwl/cfwl_listbox.h"
14 #include "xfa/fwl/cfwl_notedriver.h"
15 #include "xfa/fwl/cfwl_widget.h"
16 #include "xfa/fxfa/cxfa_eventparam.h"
17 #include "xfa/fxfa/parser/cxfa_para.h"
18
19 namespace {
20
ToListBox(CFWL_Widget * widget)21 CFWL_ListBox* ToListBox(CFWL_Widget* widget) {
22 return static_cast<CFWL_ListBox*>(widget);
23 }
24
25 } // namespace
26
CXFA_FFListBox(CXFA_Node * pNode)27 CXFA_FFListBox::CXFA_FFListBox(CXFA_Node* pNode)
28 : CXFA_FFField(pNode), m_pOldDelegate(nullptr) {}
29
~CXFA_FFListBox()30 CXFA_FFListBox::~CXFA_FFListBox() {
31 if (!m_pNormalWidget)
32 return;
33
34 CFWL_NoteDriver* pNoteDriver =
35 m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
36 pNoteDriver->UnregisterEventTarget(m_pNormalWidget.get());
37 }
38
LoadWidget()39 bool CXFA_FFListBox::LoadWidget() {
40 auto pNew = pdfium::MakeUnique<CFWL_ListBox>(
41 GetFWLApp(), pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr);
42 CFWL_ListBox* pListBox = pNew.get();
43 pListBox->ModifyStyles(FWL_WGTSTYLE_VScroll | FWL_WGTSTYLE_NoBackground,
44 0xFFFFFFFF);
45 m_pNormalWidget = std::move(pNew);
46 m_pNormalWidget->SetLayoutItem(this);
47
48 CFWL_NoteDriver* pNoteDriver =
49 m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
50 pNoteDriver->RegisterEventTarget(m_pNormalWidget.get(),
51 m_pNormalWidget.get());
52 m_pOldDelegate = m_pNormalWidget->GetDelegate();
53 m_pNormalWidget->SetDelegate(this);
54 m_pNormalWidget->LockUpdate();
55
56 for (const auto& label : m_pNode->GetWidgetAcc()->GetChoiceListItems(false))
57 pListBox->AddString(label.AsStringView());
58
59 uint32_t dwExtendedStyle = FWL_STYLEEXT_LTB_ShowScrollBarFocus;
60 if (m_pNode->GetWidgetAcc()->IsChoiceListMultiSelect())
61 dwExtendedStyle |= FWL_STYLEEXT_LTB_MultiSelection;
62
63 dwExtendedStyle |= GetAlignment();
64 m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
65 for (int32_t selected : m_pNode->GetWidgetAcc()->GetSelectedItems())
66 pListBox->SetSelItem(pListBox->GetItem(nullptr, selected), true);
67
68 m_pNormalWidget->UnlockUpdate();
69 return CXFA_FFField::LoadWidget();
70 }
71
OnKillFocus(CXFA_FFWidget * pNewFocus)72 bool CXFA_FFListBox::OnKillFocus(CXFA_FFWidget* pNewFocus) {
73 if (!ProcessCommittedData())
74 UpdateFWLData();
75
76 CXFA_FFField::OnKillFocus(pNewFocus);
77 return true;
78 }
79
CommitData()80 bool CXFA_FFListBox::CommitData() {
81 auto* pListBox = ToListBox(m_pNormalWidget.get());
82 std::vector<int32_t> iSelArray;
83 int32_t iSels = pListBox->CountSelItems();
84 for (int32_t i = 0; i < iSels; ++i)
85 iSelArray.push_back(pListBox->GetSelIndex(i));
86
87 m_pNode->GetWidgetAcc()->SetSelectedItems(iSelArray, true, false, true);
88 return true;
89 }
90
IsDataChanged()91 bool CXFA_FFListBox::IsDataChanged() {
92 std::vector<int32_t> iSelArray = m_pNode->GetWidgetAcc()->GetSelectedItems();
93 int32_t iOldSels = pdfium::CollectionSize<int32_t>(iSelArray);
94 auto* pListBox = ToListBox(m_pNormalWidget.get());
95 int32_t iSels = pListBox->CountSelItems();
96 if (iOldSels != iSels)
97 return true;
98
99 for (int32_t i = 0; i < iSels; ++i) {
100 CFWL_ListItem* hlistItem = pListBox->GetItem(nullptr, iSelArray[i]);
101 if (!(hlistItem->GetStates() & FWL_ITEMSTATE_LTB_Selected))
102 return true;
103 }
104 return false;
105 }
106
GetAlignment()107 uint32_t CXFA_FFListBox::GetAlignment() {
108 CXFA_Para* para = m_pNode->GetParaIfExists();
109 if (!para)
110 return 0;
111
112 uint32_t dwExtendedStyle = 0;
113 switch (para->GetHorizontalAlign()) {
114 case XFA_AttributeEnum::Center:
115 dwExtendedStyle |= FWL_STYLEEXT_LTB_CenterAlign;
116 break;
117 case XFA_AttributeEnum::Justify:
118 break;
119 case XFA_AttributeEnum::JustifyAll:
120 break;
121 case XFA_AttributeEnum::Radix:
122 break;
123 case XFA_AttributeEnum::Right:
124 dwExtendedStyle |= FWL_STYLEEXT_LTB_RightAlign;
125 break;
126 default:
127 dwExtendedStyle |= FWL_STYLEEXT_LTB_LeftAlign;
128 break;
129 }
130 return dwExtendedStyle;
131 }
132
UpdateFWLData()133 bool CXFA_FFListBox::UpdateFWLData() {
134 if (!m_pNormalWidget)
135 return false;
136
137 auto* pListBox = ToListBox(m_pNormalWidget.get());
138 std::vector<int32_t> iSelArray = m_pNode->GetWidgetAcc()->GetSelectedItems();
139 std::vector<CFWL_ListItem*> selItemArray(iSelArray.size());
140 std::transform(iSelArray.begin(), iSelArray.end(), selItemArray.begin(),
141 [pListBox](int32_t val) { return pListBox->GetSelItem(val); });
142
143 pListBox->SetSelItem(pListBox->GetSelItem(-1), false);
144 for (CFWL_ListItem* pItem : selItemArray)
145 pListBox->SetSelItem(pItem, true);
146
147 m_pNormalWidget->Update();
148 return true;
149 }
150
OnSelectChanged(CFWL_Widget * pWidget)151 void CXFA_FFListBox::OnSelectChanged(CFWL_Widget* pWidget) {
152 CXFA_EventParam eParam;
153 eParam.m_eType = XFA_EVENT_Change;
154 eParam.m_pTarget = m_pNode->GetWidgetAcc();
155 eParam.m_wsPrevText = m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw);
156
157 auto* pListBox = ToListBox(m_pNormalWidget.get());
158 int32_t iSels = pListBox->CountSelItems();
159 if (iSels > 0) {
160 CFWL_ListItem* item = pListBox->GetSelItem(0);
161 eParam.m_wsNewText = item ? item->GetText() : L"";
162 }
163 m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Change, &eParam);
164 }
165
SetItemState(int32_t nIndex,bool bSelected)166 void CXFA_FFListBox::SetItemState(int32_t nIndex, bool bSelected) {
167 auto* pListBox = ToListBox(m_pNormalWidget.get());
168 pListBox->SetSelItem(pListBox->GetSelItem(nIndex), bSelected);
169 m_pNormalWidget->Update();
170 AddInvalidateRect();
171 }
172
InsertItem(const WideStringView & wsLabel,int32_t nIndex)173 void CXFA_FFListBox::InsertItem(const WideStringView& wsLabel, int32_t nIndex) {
174 WideString wsTemp(wsLabel);
175 ToListBox(m_pNormalWidget.get())->AddString(wsTemp.AsStringView());
176 m_pNormalWidget->Update();
177 AddInvalidateRect();
178 }
179
DeleteItem(int32_t nIndex)180 void CXFA_FFListBox::DeleteItem(int32_t nIndex) {
181 auto* pListBox = ToListBox(m_pNormalWidget.get());
182 if (nIndex < 0)
183 pListBox->DeleteAll();
184 else
185 pListBox->DeleteString(pListBox->GetItem(nullptr, nIndex));
186
187 pListBox->Update();
188 AddInvalidateRect();
189 }
190
OnProcessMessage(CFWL_Message * pMessage)191 void CXFA_FFListBox::OnProcessMessage(CFWL_Message* pMessage) {
192 m_pOldDelegate->OnProcessMessage(pMessage);
193 }
194
OnProcessEvent(CFWL_Event * pEvent)195 void CXFA_FFListBox::OnProcessEvent(CFWL_Event* pEvent) {
196 CXFA_FFField::OnProcessEvent(pEvent);
197 switch (pEvent->GetType()) {
198 case CFWL_Event::Type::SelectChanged:
199 OnSelectChanged(m_pNormalWidget.get());
200 break;
201 default:
202 break;
203 }
204 m_pOldDelegate->OnProcessEvent(pEvent);
205 }
206
OnDrawWidget(CXFA_Graphics * pGraphics,const CFX_Matrix & matrix)207 void CXFA_FFListBox::OnDrawWidget(CXFA_Graphics* pGraphics,
208 const CFX_Matrix& matrix) {
209 m_pOldDelegate->OnDrawWidget(pGraphics, matrix);
210 }
211
GetFormFieldType()212 FormFieldType CXFA_FFListBox::GetFormFieldType() {
213 return FormFieldType::kXFA_ListBox;
214 }
215