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