// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "xfa/fxfa/cxfa_fflistbox.h" #include #include #include #include "core/fxcrt/stl_util.h" #include "third_party/base/check.h" #include "v8/include/cppgc/visitor.h" #include "xfa/fwl/cfwl_listbox.h" #include "xfa/fwl/cfwl_notedriver.h" #include "xfa/fwl/cfwl_widget.h" #include "xfa/fxfa/cxfa_eventparam.h" #include "xfa/fxfa/parser/cxfa_para.h" namespace { CFWL_ListBox* ToListBox(CFWL_Widget* widget) { return static_cast(widget); } } // namespace CXFA_FFListBox::CXFA_FFListBox(CXFA_Node* pNode) : CXFA_FFDropDown(pNode) {} CXFA_FFListBox::~CXFA_FFListBox() = default; void CXFA_FFListBox::PreFinalize() { if (GetNormalWidget()) { CFWL_NoteDriver* pNoteDriver = GetNormalWidget()->GetFWLApp()->GetNoteDriver(); pNoteDriver->UnregisterEventTarget(GetNormalWidget()); } } void CXFA_FFListBox::Trace(cppgc::Visitor* visitor) const { CXFA_FFDropDown::Trace(visitor); visitor->Trace(m_pOldDelegate); } bool CXFA_FFListBox::LoadWidget() { DCHECK(!IsLoaded()); CFWL_ListBox* pListBox = cppgc::MakeGarbageCollected( GetFWLApp()->GetHeap()->GetAllocationHandle(), GetFWLApp(), CFWL_Widget::Properties(), nullptr); pListBox->ModifyStyles(FWL_STYLE_WGT_VScroll | FWL_STYLE_WGT_NoBackground, 0xFFFFFFFF); SetNormalWidget(pListBox); pListBox->SetAdapterIface(this); CFWL_NoteDriver* pNoteDriver = pListBox->GetFWLApp()->GetNoteDriver(); pNoteDriver->RegisterEventTarget(pListBox, pListBox); m_pOldDelegate = pListBox->GetDelegate(); pListBox->SetDelegate(this); { CFWL_Widget::ScopedUpdateLock update_lock(pListBox); std::vector displayables = m_pNode->GetChoiceListItems(false); std::vector settables = m_pNode->GetChoiceListItems(true); if (displayables.size() > settables.size()) displayables.resize(settables.size()); for (const auto& label : displayables) pListBox->AddString(label); uint32_t dwExtendedStyle = FWL_STYLEEXT_LTB_ShowScrollBarFocus; if (m_pNode->IsChoiceListMultiSelect()) dwExtendedStyle |= FWL_STYLEEXT_LTB_MultiSelection; dwExtendedStyle |= GetAlignment(); pListBox->ModifyStyleExts(dwExtendedStyle, 0xFFFFFFFF); for (int32_t selected : m_pNode->GetSelectedItems()) pListBox->SetSelItem(pListBox->GetItem(nullptr, selected), true); } return CXFA_FFField::LoadWidget(); } bool CXFA_FFListBox::OnKillFocus(CXFA_FFWidget* pNewFocus) { if (!ProcessCommittedData()) UpdateFWLData(); return pNewFocus && CXFA_FFField::OnKillFocus(pNewFocus); } bool CXFA_FFListBox::CommitData() { auto* pListBox = ToListBox(GetNormalWidget()); std::vector iSelArray; int32_t iSels = pListBox->CountSelItems(); for (int32_t i = 0; i < iSels; ++i) iSelArray.push_back(pListBox->GetSelIndex(i)); m_pNode->SetSelectedItems(iSelArray, true, false, true); return true; } bool CXFA_FFListBox::IsDataChanged() { std::vector iSelArray = m_pNode->GetSelectedItems(); int32_t iOldSels = fxcrt::CollectionSize(iSelArray); auto* pListBox = ToListBox(GetNormalWidget()); int32_t iSels = pListBox->CountSelItems(); if (iOldSels != iSels) return true; for (int32_t i = 0; i < iSels; ++i) { CFWL_ListBox::Item* hlistItem = pListBox->GetItem(nullptr, iSelArray[i]); if (!hlistItem->IsSelected()) return true; } return false; } uint32_t CXFA_FFListBox::GetAlignment() { CXFA_Para* para = m_pNode->GetParaIfExists(); if (!para) return 0; uint32_t dwExtendedStyle = 0; switch (para->GetHorizontalAlign()) { case XFA_AttributeValue::Center: dwExtendedStyle |= FWL_STYLEEXT_LTB_CenterAlign; break; case XFA_AttributeValue::Justify: break; case XFA_AttributeValue::JustifyAll: break; case XFA_AttributeValue::Radix: break; case XFA_AttributeValue::Right: dwExtendedStyle |= FWL_STYLEEXT_LTB_RightAlign; break; default: dwExtendedStyle |= FWL_STYLEEXT_LTB_LeftAlign; break; } return dwExtendedStyle; } bool CXFA_FFListBox::UpdateFWLData() { auto* pListBox = ToListBox(GetNormalWidget()); if (!pListBox) return false; std::vector iSelArray = m_pNode->GetSelectedItems(); std::vector selItemArray(iSelArray.size()); std::transform(iSelArray.begin(), iSelArray.end(), selItemArray.begin(), [pListBox](int32_t val) { return pListBox->GetSelItem(val); }); pListBox->SetSelItem(pListBox->GetSelItem(-1), false); for (CFWL_ListBox::Item* pItem : selItemArray) pListBox->SetSelItem(pItem, true); GetNormalWidget()->Update(); return true; } void CXFA_FFListBox::OnSelectChanged(CFWL_Widget* pWidget) { CXFA_EventParam eParam; eParam.m_eType = XFA_EVENT_Change; eParam.m_wsPrevText = m_pNode->GetValue(XFA_ValuePicture::kRaw); m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Change, &eParam); } void CXFA_FFListBox::SetItemState(int32_t nIndex, bool bSelected) { auto* pListBox = ToListBox(GetNormalWidget()); pListBox->SetSelItem(pListBox->GetSelItem(nIndex), bSelected); GetNormalWidget()->Update(); InvalidateRect(); } void CXFA_FFListBox::InsertItem(const WideString& wsLabel, int32_t nIndex) { ToListBox(GetNormalWidget())->AddString(wsLabel); GetNormalWidget()->Update(); InvalidateRect(); } void CXFA_FFListBox::DeleteItem(int32_t nIndex) { auto* pListBox = ToListBox(GetNormalWidget()); if (nIndex < 0) pListBox->DeleteAll(); else pListBox->DeleteString(pListBox->GetItem(nullptr, nIndex)); pListBox->Update(); InvalidateRect(); } void CXFA_FFListBox::OnProcessMessage(CFWL_Message* pMessage) { m_pOldDelegate->OnProcessMessage(pMessage); } void CXFA_FFListBox::OnProcessEvent(CFWL_Event* pEvent) { CXFA_FFField::OnProcessEvent(pEvent); switch (pEvent->GetType()) { case CFWL_Event::Type::SelectChanged: OnSelectChanged(GetNormalWidget()); break; default: break; } m_pOldDelegate->OnProcessEvent(pEvent); } void CXFA_FFListBox::OnDrawWidget(CFGAS_GEGraphics* pGraphics, const CFX_Matrix& matrix) { m_pOldDelegate->OnDrawWidget(pGraphics, matrix); } FormFieldType CXFA_FFListBox::GetFormFieldType() { return FormFieldType::kXFA_ListBox; }