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