blob: c9a513607e31fd3b0dc7a5879bfb5584c608cad3 [file] [log] [blame]
// Copyright 2014 PDFium Authors. All rights reserved.
// 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/app/xfa_ffchoicelist.h"
#include "third_party/base/ptr_util.h"
#include "xfa/fwl/core/cfwl_app.h"
#include "xfa/fwl/core/cfwl_combobox.h"
#include "xfa/fwl/core/cfwl_edit.h"
#include "xfa/fwl/core/cfwl_evtselectchanged.h"
#include "xfa/fwl/core/cfwl_listbox.h"
#include "xfa/fwl/core/cfwl_notedriver.h"
#include "xfa/fwl/core/cfwl_widgetproperties.h"
#include "xfa/fxfa/app/xfa_fffield.h"
#include "xfa/fxfa/app/xfa_fwladapter.h"
#include "xfa/fxfa/cxfa_eventparam.h"
#include "xfa/fxfa/xfa_ffdoc.h"
#include "xfa/fxfa/xfa_ffdocview.h"
#include "xfa/fxfa/xfa_ffpageview.h"
#include "xfa/fxfa/xfa_ffwidget.h"
CXFA_FFListBox::CXFA_FFListBox(CXFA_FFPageView* pPageView,
CXFA_WidgetAcc* pDataAcc)
: CXFA_FFField(pPageView, pDataAcc), m_pOldDelegate(nullptr) {}
CXFA_FFListBox::~CXFA_FFListBox() {
if (m_pNormalWidget) {
CFWL_NoteDriver* pNoteDriver =
m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
pNoteDriver->UnregisterEventTarget(m_pNormalWidget);
}
}
bool CXFA_FFListBox::LoadWidget() {
CFWL_ListBox* pListBox = new CFWL_ListBox(
GetFWLApp(), pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr);
pListBox->ModifyStyles(FWL_WGTSTYLE_VScroll | FWL_WGTSTYLE_NoBackground,
0xFFFFFFFF);
m_pNormalWidget = (CFWL_Widget*)pListBox;
m_pNormalWidget->SetLayoutItem(this);
CFWL_NoteDriver* pNoteDriver =
m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
pNoteDriver->RegisterEventTarget(m_pNormalWidget, m_pNormalWidget);
m_pOldDelegate = m_pNormalWidget->GetDelegate();
m_pNormalWidget->SetDelegate(this);
m_pNormalWidget->LockUpdate();
CFX_WideStringArray wsLabelArray;
m_pDataAcc->GetChoiceListItems(wsLabelArray, false);
int32_t iItems = wsLabelArray.GetSize();
for (int32_t i = 0; i < iItems; i++) {
pListBox->AddString(wsLabelArray[i].AsStringC());
}
uint32_t dwExtendedStyle = FWL_STYLEEXT_LTB_ShowScrollBarFocus;
if (m_pDataAcc->GetChoiceListOpen() == XFA_ATTRIBUTEENUM_MultiSelect) {
dwExtendedStyle |= FWL_STYLEEXT_LTB_MultiSelection;
}
dwExtendedStyle |= GetAlignment();
m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
CFX_Int32Array iSelArray;
m_pDataAcc->GetSelectedItems(iSelArray);
int32_t iSelCount = iSelArray.GetSize();
for (int32_t j = 0; j < iSelCount; j++) {
CFWL_ListItem* item = pListBox->GetItem(nullptr, iSelArray[j]);
pListBox->SetSelItem(item, true);
}
m_pNormalWidget->UnlockUpdate();
return CXFA_FFField::LoadWidget();
}
bool CXFA_FFListBox::OnKillFocus(CXFA_FFWidget* pNewFocus) {
if (!ProcessCommittedData())
UpdateFWLData();
CXFA_FFField::OnKillFocus(pNewFocus);
return true;
}
bool CXFA_FFListBox::CommitData() {
CFWL_ListBox* pListBox = static_cast<CFWL_ListBox*>(m_pNormalWidget);
int32_t iSels = pListBox->CountSelItems();
CFX_Int32Array iSelArray;
for (int32_t i = 0; i < iSels; ++i)
iSelArray.Add(pListBox->GetSelIndex(i));
m_pDataAcc->SetSelectedItems(iSelArray, true, false, true);
return true;
}
bool CXFA_FFListBox::IsDataChanged() {
CFX_Int32Array iSelArray;
m_pDataAcc->GetSelectedItems(iSelArray);
int32_t iOldSels = iSelArray.GetSize();
CFWL_ListBox* pListBox = (CFWL_ListBox*)m_pNormalWidget;
int32_t iSels = pListBox->CountSelItems();
if (iOldSels != iSels)
return true;
for (int32_t i = 0; i < iSels; ++i) {
CFWL_ListItem* hlistItem = pListBox->GetItem(nullptr, iSelArray[i]);
if (!(pListBox->GetItemStates(hlistItem) & FWL_ITEMSTATE_LTB_Selected))
return true;
}
return false;
}
uint32_t CXFA_FFListBox::GetAlignment() {
uint32_t dwExtendedStyle = 0;
if (CXFA_Para para = m_pDataAcc->GetPara()) {
int32_t iHorz = para.GetHorizontalAlign();
switch (iHorz) {
case XFA_ATTRIBUTEENUM_Center:
dwExtendedStyle |= FWL_STYLEEXT_LTB_CenterAlign;
break;
case XFA_ATTRIBUTEENUM_Justify:
break;
case XFA_ATTRIBUTEENUM_JustifyAll:
break;
case XFA_ATTRIBUTEENUM_Radix:
break;
case XFA_ATTRIBUTEENUM_Right:
dwExtendedStyle |= FWL_STYLEEXT_LTB_RightAlign;
break;
default:
dwExtendedStyle |= FWL_STYLEEXT_LTB_LeftAlign;
break;
}
}
return dwExtendedStyle;
}
bool CXFA_FFListBox::UpdateFWLData() {
if (!m_pNormalWidget) {
return false;
}
CFWL_ListBox* pListBox = ((CFWL_ListBox*)m_pNormalWidget);
CFX_ArrayTemplate<CFWL_ListItem*> selItemArray;
CFX_Int32Array iSelArray;
m_pDataAcc->GetSelectedItems(iSelArray);
int32_t iSelCount = iSelArray.GetSize();
for (int32_t j = 0; j < iSelCount; j++) {
CFWL_ListItem* lpItemSel = pListBox->GetSelItem(iSelArray[j]);
selItemArray.Add(lpItemSel);
}
pListBox->SetSelItem(pListBox->GetSelItem(-1), false);
for (int32_t i = 0; i < iSelCount; i++) {
((CFWL_ListBox*)m_pNormalWidget)->SetSelItem(selItemArray[i], true);
}
m_pNormalWidget->Update();
return true;
}
void CXFA_FFListBox::OnSelectChanged(CFWL_Widget* pWidget,
const CFX_Int32Array& arrSels) {
CXFA_EventParam eParam;
eParam.m_eType = XFA_EVENT_Change;
eParam.m_pTarget = m_pDataAcc;
m_pDataAcc->GetValue(eParam.m_wsPrevText, XFA_VALUEPICTURE_Raw);
CFWL_ListBox* pListBox = (CFWL_ListBox*)m_pNormalWidget;
int32_t iSels = pListBox->CountSelItems();
if (iSels > 0) {
eParam.m_wsNewText =
pListBox->GetItemText(nullptr, pListBox->GetSelItem(0));
}
m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_Change, &eParam);
}
void CXFA_FFListBox::SetItemState(int32_t nIndex, bool bSelected) {
CFWL_ListItem* item = ((CFWL_ListBox*)m_pNormalWidget)->GetSelItem(nIndex);
((CFWL_ListBox*)m_pNormalWidget)->SetSelItem(item, bSelected);
m_pNormalWidget->Update();
AddInvalidateRect();
}
void CXFA_FFListBox::InsertItem(const CFX_WideStringC& wsLabel,
int32_t nIndex) {
CFX_WideString wsTemp(wsLabel);
((CFWL_ListBox*)m_pNormalWidget)->AddString(wsTemp.AsStringC());
m_pNormalWidget->Update();
AddInvalidateRect();
}
void CXFA_FFListBox::DeleteItem(int32_t nIndex) {
CFWL_ListBox* listBox = static_cast<CFWL_ListBox*>(m_pNormalWidget);
if (nIndex < 0)
listBox->DeleteAll();
else
listBox->DeleteString(listBox->GetItem(nullptr, nIndex));
listBox->Update();
AddInvalidateRect();
}
void CXFA_FFListBox::OnProcessMessage(CFWL_Message* pMessage) {
m_pOldDelegate->OnProcessMessage(pMessage);
}
void CXFA_FFListBox::OnProcessEvent(CFWL_Event* pEvent) {
CXFA_FFField::OnProcessEvent(pEvent);
switch (pEvent->GetClassID()) {
case CFWL_EventType::SelectChanged: {
CFX_Int32Array arrSels;
OnSelectChanged(m_pNormalWidget, arrSels);
break;
}
default:
break;
}
m_pOldDelegate->OnProcessEvent(pEvent);
}
void CXFA_FFListBox::OnDrawWidget(CFX_Graphics* pGraphics,
const CFX_Matrix* pMatrix) {
m_pOldDelegate->OnDrawWidget(pGraphics, pMatrix);
}
CXFA_FFComboBox::CXFA_FFComboBox(CXFA_FFPageView* pPageView,
CXFA_WidgetAcc* pDataAcc)
: CXFA_FFField(pPageView, pDataAcc), m_pOldDelegate(nullptr) {}
CXFA_FFComboBox::~CXFA_FFComboBox() {}
bool CXFA_FFComboBox::GetBBox(CFX_RectF& rtBox,
uint32_t dwStatus,
bool bDrawFocus) {
if (bDrawFocus)
return false;
return CXFA_FFWidget::GetBBox(rtBox, dwStatus);
}
bool CXFA_FFComboBox::PtInActiveRect(FX_FLOAT fx, FX_FLOAT fy) {
if (!m_pNormalWidget) {
return false;
}
CFX_RectF rtWidget;
((CFWL_ComboBox*)m_pNormalWidget)->GetBBox(rtWidget);
if (rtWidget.Contains(fx, fy)) {
return true;
}
return false;
}
bool CXFA_FFComboBox::LoadWidget() {
CFWL_ComboBox* pComboBox = new CFWL_ComboBox(GetFWLApp());
m_pNormalWidget = (CFWL_Widget*)pComboBox;
m_pNormalWidget->SetLayoutItem(this);
CFWL_NoteDriver* pNoteDriver =
m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
pNoteDriver->RegisterEventTarget(m_pNormalWidget, m_pNormalWidget);
m_pOldDelegate = m_pNormalWidget->GetDelegate();
m_pNormalWidget->SetDelegate(this);
m_pNormalWidget->LockUpdate();
CFX_WideStringArray wsLabelArray;
m_pDataAcc->GetChoiceListItems(wsLabelArray, false);
int32_t iItems = wsLabelArray.GetSize();
for (int32_t i = 0; i < iItems; i++) {
pComboBox->AddString(wsLabelArray[i].AsStringC());
}
CFX_Int32Array iSelArray;
m_pDataAcc->GetSelectedItems(iSelArray);
int32_t iSelCount = iSelArray.GetSize();
if (iSelCount > 0) {
pComboBox->SetCurSel(iSelArray[0]);
} else {
CFX_WideString wsText;
m_pDataAcc->GetValue(wsText, XFA_VALUEPICTURE_Raw);
pComboBox->SetEditText(wsText);
}
UpdateWidgetProperty();
m_pNormalWidget->UnlockUpdate();
return CXFA_FFField::LoadWidget();
}
void CXFA_FFComboBox::UpdateWidgetProperty() {
CFWL_ComboBox* pComboBox = (CFWL_ComboBox*)m_pNormalWidget;
if (!pComboBox) {
return;
}
uint32_t dwExtendedStyle = 0;
uint32_t dwEditStyles =
FWL_STYLEEXT_EDT_ReadOnly | FWL_STYLEEXT_EDT_LastLineHeight;
dwExtendedStyle |= UpdateUIProperty();
if (m_pDataAcc->IsChoiceListAllowTextEntry()) {
dwEditStyles &= ~FWL_STYLEEXT_EDT_ReadOnly;
dwExtendedStyle |= FWL_STYLEEXT_CMB_DropDown;
}
if (m_pDataAcc->GetAccess() != XFA_ATTRIBUTEENUM_Open ||
!m_pDataAcc->GetDoc()->GetXFADoc()->IsInteractive()) {
dwEditStyles |= FWL_STYLEEXT_EDT_ReadOnly;
dwExtendedStyle |= FWL_STYLEEXT_CMB_ReadOnly;
}
dwExtendedStyle |= GetAlignment();
m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
if (m_pDataAcc->GetHorizontalScrollPolicy() != XFA_ATTRIBUTEENUM_Off) {
dwEditStyles |= FWL_STYLEEXT_EDT_AutoHScroll;
}
pComboBox->EditModifyStylesEx(dwEditStyles, 0xFFFFFFFF);
}
bool CXFA_FFComboBox::OnRButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
if (!CXFA_FFField::OnRButtonUp(dwFlags, fx, fy))
return false;
GetDoc()->GetDocEnvironment()->PopupMenu(this, CFX_PointF(fx, fy));
return true;
}
bool CXFA_FFComboBox::OnKillFocus(CXFA_FFWidget* pNewWidget) {
bool flag = ProcessCommittedData();
if (!flag) {
UpdateFWLData();
}
CXFA_FFField::OnKillFocus(pNewWidget);
return true;
}
void CXFA_FFComboBox::OpenDropDownList() {
((CFWL_ComboBox*)m_pNormalWidget)->OpenDropDownList(true);
}
bool CXFA_FFComboBox::CommitData() {
return m_pDataAcc->SetValue(m_wsNewValue, XFA_VALUEPICTURE_Raw);
}
bool CXFA_FFComboBox::IsDataChanged() {
CFWL_ComboBox* pFWLcombobox = ((CFWL_ComboBox*)m_pNormalWidget);
CFX_WideString wsText = pFWLcombobox->GetEditText();
int32_t iCursel = pFWLcombobox->GetCurSel();
if (iCursel >= 0) {
CFX_WideString wsSel;
pFWLcombobox->GetTextByIndex(iCursel, wsSel);
if (wsSel == wsText) {
m_pDataAcc->GetChoiceListItem(wsText, iCursel, true);
}
}
CFX_WideString wsOldValue;
m_pDataAcc->GetValue(wsOldValue, XFA_VALUEPICTURE_Raw);
if (wsOldValue != wsText) {
m_wsNewValue = wsText;
return true;
}
return false;
}
void CXFA_FFComboBox::FWLEventSelChange(CXFA_EventParam* pParam) {
pParam->m_eType = XFA_EVENT_Change;
pParam->m_pTarget = m_pDataAcc;
CFWL_ComboBox* pFWLcombobox = ((CFWL_ComboBox*)m_pNormalWidget);
pParam->m_wsNewText = pFWLcombobox->GetEditText();
m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_Change, pParam);
}
uint32_t CXFA_FFComboBox::GetAlignment() {
uint32_t dwExtendedStyle = 0;
if (CXFA_Para para = m_pDataAcc->GetPara()) {
int32_t iHorz = para.GetHorizontalAlign();
switch (iHorz) {
case XFA_ATTRIBUTEENUM_Center:
dwExtendedStyle |=
FWL_STYLEEXT_CMB_EditHCenter | FWL_STYLEEXT_CMB_ListItemCenterAlign;
break;
case XFA_ATTRIBUTEENUM_Justify:
dwExtendedStyle |= FWL_STYLEEXT_CMB_EditJustified;
break;
case XFA_ATTRIBUTEENUM_JustifyAll:
break;
case XFA_ATTRIBUTEENUM_Radix:
break;
case XFA_ATTRIBUTEENUM_Right:
break;
default:
dwExtendedStyle |=
FWL_STYLEEXT_CMB_EditHNear | FWL_STYLEEXT_CMB_ListItemLeftAlign;
break;
}
int32_t iVert = para.GetVerticalAlign();
switch (iVert) {
case XFA_ATTRIBUTEENUM_Middle:
dwExtendedStyle |= FWL_STYLEEXT_CMB_EditVCenter;
break;
case XFA_ATTRIBUTEENUM_Bottom:
dwExtendedStyle |= FWL_STYLEEXT_CMB_EditVFar;
break;
default:
dwExtendedStyle |= FWL_STYLEEXT_CMB_EditVNear;
break;
}
}
return dwExtendedStyle;
}
bool CXFA_FFComboBox::UpdateFWLData() {
if (!m_pNormalWidget) {
return false;
}
CFX_Int32Array iSelArray;
m_pDataAcc->GetSelectedItems(iSelArray);
int32_t iSelCount = iSelArray.GetSize();
if (iSelCount > 0) {
((CFWL_ComboBox*)m_pNormalWidget)->SetCurSel(iSelArray[0]);
} else {
CFX_WideString wsText;
((CFWL_ComboBox*)m_pNormalWidget)->SetCurSel(-1);
m_pDataAcc->GetValue(wsText, XFA_VALUEPICTURE_Raw);
((CFWL_ComboBox*)m_pNormalWidget)->SetEditText(wsText);
}
m_pNormalWidget->Update();
return true;
}
bool CXFA_FFComboBox::CanUndo() {
return m_pDataAcc->IsChoiceListAllowTextEntry() &&
((CFWL_ComboBox*)m_pNormalWidget)->EditCanUndo();
}
bool CXFA_FFComboBox::CanRedo() {
return m_pDataAcc->IsChoiceListAllowTextEntry() &&
((CFWL_ComboBox*)m_pNormalWidget)->EditCanRedo();
}
bool CXFA_FFComboBox::Undo() {
return m_pDataAcc->IsChoiceListAllowTextEntry() &&
((CFWL_ComboBox*)m_pNormalWidget)->EditUndo();
}
bool CXFA_FFComboBox::Redo() {
return m_pDataAcc->IsChoiceListAllowTextEntry() &&
((CFWL_ComboBox*)m_pNormalWidget)->EditRedo();
}
bool CXFA_FFComboBox::CanCopy() {
return ((CFWL_ComboBox*)m_pNormalWidget)->EditCanCopy();
}
bool CXFA_FFComboBox::CanCut() {
if (m_pDataAcc->GetAccess() != XFA_ATTRIBUTEENUM_Open) {
return false;
}
return m_pDataAcc->IsChoiceListAllowTextEntry() &&
((CFWL_ComboBox*)m_pNormalWidget)->EditCanCut();
}
bool CXFA_FFComboBox::CanPaste() {
return m_pDataAcc->IsChoiceListAllowTextEntry() &&
(m_pDataAcc->GetAccess() == XFA_ATTRIBUTEENUM_Open);
}
bool CXFA_FFComboBox::CanSelectAll() {
return ((CFWL_ComboBox*)m_pNormalWidget)->EditCanSelectAll();
}
bool CXFA_FFComboBox::Copy(CFX_WideString& wsCopy) {
return ((CFWL_ComboBox*)m_pNormalWidget)->EditCopy(wsCopy);
}
bool CXFA_FFComboBox::Cut(CFX_WideString& wsCut) {
return m_pDataAcc->IsChoiceListAllowTextEntry() &&
((CFWL_ComboBox*)m_pNormalWidget)->EditCut(wsCut);
}
bool CXFA_FFComboBox::Paste(const CFX_WideString& wsPaste) {
return m_pDataAcc->IsChoiceListAllowTextEntry() &&
((CFWL_ComboBox*)m_pNormalWidget)->EditPaste(wsPaste);
}
void CXFA_FFComboBox::SelectAll() {
((CFWL_ComboBox*)m_pNormalWidget)->EditSelectAll();
}
void CXFA_FFComboBox::Delete() {
((CFWL_ComboBox*)m_pNormalWidget)->EditDelete();
}
void CXFA_FFComboBox::DeSelect() {
((CFWL_ComboBox*)m_pNormalWidget)->EditDeSelect();
}
void CXFA_FFComboBox::SetItemState(int32_t nIndex, bool bSelected) {
if (bSelected) {
((CFWL_ComboBox*)m_pNormalWidget)->SetCurSel(nIndex);
} else {
((CFWL_ComboBox*)m_pNormalWidget)->SetCurSel(-1);
}
m_pNormalWidget->Update();
AddInvalidateRect();
}
void CXFA_FFComboBox::InsertItem(const CFX_WideStringC& wsLabel,
int32_t nIndex) {
((CFWL_ComboBox*)m_pNormalWidget)->AddString(wsLabel);
m_pNormalWidget->Update();
AddInvalidateRect();
}
void CXFA_FFComboBox::DeleteItem(int32_t nIndex) {
if (nIndex < 0) {
((CFWL_ComboBox*)m_pNormalWidget)->RemoveAll();
} else {
((CFWL_ComboBox*)m_pNormalWidget)->RemoveAt(nIndex);
}
m_pNormalWidget->Update();
AddInvalidateRect();
}
void CXFA_FFComboBox::OnTextChanged(CFWL_Widget* pWidget,
const CFX_WideString& wsChanged) {
CXFA_EventParam eParam;
m_pDataAcc->GetValue(eParam.m_wsPrevText, XFA_VALUEPICTURE_Raw);
eParam.m_wsChange = wsChanged;
FWLEventSelChange(&eParam);
}
void CXFA_FFComboBox::OnSelectChanged(CFWL_Widget* pWidget, bool bLButtonUp) {
CXFA_EventParam eParam;
m_pDataAcc->GetValue(eParam.m_wsPrevText, XFA_VALUEPICTURE_Raw);
FWLEventSelChange(&eParam);
if (m_pDataAcc->GetChoiceListCommitOn() == XFA_ATTRIBUTEENUM_Select &&
bLButtonUp) {
m_pDocView->SetFocusWidgetAcc(nullptr);
}
}
void CXFA_FFComboBox::OnPreOpen(CFWL_Widget* pWidget) {
CXFA_EventParam eParam;
eParam.m_eType = XFA_EVENT_PreOpen;
eParam.m_pTarget = m_pDataAcc;
m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_PreOpen, &eParam);
}
void CXFA_FFComboBox::OnPostOpen(CFWL_Widget* pWidget) {
CXFA_EventParam eParam;
eParam.m_eType = XFA_EVENT_PostOpen;
eParam.m_pTarget = m_pDataAcc;
m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_PostOpen, &eParam);
}
void CXFA_FFComboBox::OnProcessMessage(CFWL_Message* pMessage) {
m_pOldDelegate->OnProcessMessage(pMessage);
}
void CXFA_FFComboBox::OnProcessEvent(CFWL_Event* pEvent) {
CXFA_FFField::OnProcessEvent(pEvent);
switch (pEvent->GetClassID()) {
case CFWL_EventType::SelectChanged: {
CFWL_EvtSelectChanged* postEvent =
static_cast<CFWL_EvtSelectChanged*>(pEvent);
OnSelectChanged(m_pNormalWidget, postEvent->bLButtonUp);
break;
}
case CFWL_EventType::EditChanged: {
CFX_WideString wsChanged;
OnTextChanged(m_pNormalWidget, wsChanged);
break;
}
case CFWL_EventType::PreDropDown: {
OnPreOpen(m_pNormalWidget);
break;
}
case CFWL_EventType::PostDropDown: {
OnPostOpen(m_pNormalWidget);
break;
}
default:
break;
}
m_pOldDelegate->OnProcessEvent(pEvent);
}
void CXFA_FFComboBox::OnDrawWidget(CFX_Graphics* pGraphics,
const CFX_Matrix* pMatrix) {
m_pOldDelegate->OnDrawWidget(pGraphics, pMatrix);
}