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 21 CFWL_ListBox* ToListBox(CFWL_Widget* widget) { 22 return static_cast<CFWL_ListBox*>(widget); 23 } 24 25 } // namespace 26 27 CXFA_FFListBox::CXFA_FFListBox(CXFA_Node* pNode) 28 : CXFA_FFField(pNode), m_pOldDelegate(nullptr) {} 29 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 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 72 bool CXFA_FFListBox::OnKillFocus(CXFA_FFWidget* pNewFocus) { 73 if (!ProcessCommittedData()) 74 UpdateFWLData(); 75 76 CXFA_FFField::OnKillFocus(pNewFocus); 77 return true; 78 } 79 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 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 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 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 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 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 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 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 191 void CXFA_FFListBox::OnProcessMessage(CFWL_Message* pMessage) { 192 m_pOldDelegate->OnProcessMessage(pMessage); 193 } 194 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 207 void CXFA_FFListBox::OnDrawWidget(CXFA_Graphics* pGraphics, 208 const CFX_Matrix& matrix) { 209 m_pOldDelegate->OnDrawWidget(pGraphics, matrix); 210 } 211 212 FormFieldType CXFA_FFListBox::GetFormFieldType() { 213 return FormFieldType::kXFA_ListBox; 214 } 215