Home | History | Annotate | Download | only in fxfa
      1 // Copyright 2014 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_ffcombobox.h"
      8 
      9 #include <utility>
     10 #include <vector>
     11 
     12 #include "xfa/fwl/cfwl_combobox.h"
     13 #include "xfa/fwl/cfwl_eventselectchanged.h"
     14 #include "xfa/fwl/cfwl_notedriver.h"
     15 #include "xfa/fxfa/cxfa_eventparam.h"
     16 #include "xfa/fxfa/cxfa_ffdocview.h"
     17 #include "xfa/fxfa/parser/cxfa_para.h"
     18 
     19 namespace {
     20 
     21 CFWL_ComboBox* ToComboBox(CFWL_Widget* widget) {
     22   return static_cast<CFWL_ComboBox*>(widget);
     23 }
     24 
     25 }  // namespace
     26 
     27 CXFA_FFComboBox::CXFA_FFComboBox(CXFA_Node* pNode)
     28     : CXFA_FFField(pNode), m_pOldDelegate(nullptr) {}
     29 
     30 CXFA_FFComboBox::~CXFA_FFComboBox() {}
     31 
     32 CFX_RectF CXFA_FFComboBox::GetBBox(uint32_t dwStatus, bool bDrawFocus) {
     33   return bDrawFocus ? CFX_RectF() : CXFA_FFWidget::GetBBox(dwStatus);
     34 }
     35 
     36 bool CXFA_FFComboBox::PtInActiveRect(const CFX_PointF& point) {
     37   auto* pComboBox = ToComboBox(m_pNormalWidget.get());
     38   return pComboBox && pComboBox->GetBBox().Contains(point);
     39 }
     40 
     41 bool CXFA_FFComboBox::LoadWidget() {
     42   auto pNew = pdfium::MakeUnique<CFWL_ComboBox>(GetFWLApp());
     43   CFWL_ComboBox* pComboBox = pNew.get();
     44   m_pNormalWidget = std::move(pNew);
     45   m_pNormalWidget->SetLayoutItem(this);
     46 
     47   CFWL_NoteDriver* pNoteDriver =
     48       m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
     49   pNoteDriver->RegisterEventTarget(m_pNormalWidget.get(),
     50                                    m_pNormalWidget.get());
     51   m_pOldDelegate = m_pNormalWidget->GetDelegate();
     52   m_pNormalWidget->SetDelegate(this);
     53   m_pNormalWidget->LockUpdate();
     54 
     55   for (const auto& label : m_pNode->GetWidgetAcc()->GetChoiceListItems(false))
     56     pComboBox->AddString(label.AsStringView());
     57 
     58   std::vector<int32_t> iSelArray = m_pNode->GetWidgetAcc()->GetSelectedItems();
     59   if (iSelArray.empty()) {
     60     pComboBox->SetEditText(
     61         m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw));
     62   } else {
     63     pComboBox->SetCurSel(iSelArray.front());
     64   }
     65 
     66   UpdateWidgetProperty();
     67   m_pNormalWidget->UnlockUpdate();
     68   return CXFA_FFField::LoadWidget();
     69 }
     70 
     71 void CXFA_FFComboBox::UpdateWidgetProperty() {
     72   auto* pComboBox = ToComboBox(m_pNormalWidget.get());
     73   if (!pComboBox)
     74     return;
     75 
     76   uint32_t dwExtendedStyle = 0;
     77   uint32_t dwEditStyles = FWL_STYLEEXT_EDT_ReadOnly;
     78   dwExtendedStyle |= UpdateUIProperty();
     79   if (m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry()) {
     80     dwEditStyles &= ~FWL_STYLEEXT_EDT_ReadOnly;
     81     dwExtendedStyle |= FWL_STYLEEXT_CMB_DropDown;
     82   }
     83   if (!m_pNode->IsOpenAccess() || !GetDoc()->GetXFADoc()->IsInteractive()) {
     84     dwEditStyles |= FWL_STYLEEXT_EDT_ReadOnly;
     85     dwExtendedStyle |= FWL_STYLEEXT_CMB_ReadOnly;
     86   }
     87   dwExtendedStyle |= GetAlignment();
     88   m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
     89 
     90   if (!m_pNode->GetWidgetAcc()->IsHorizontalScrollPolicyOff())
     91     dwEditStyles |= FWL_STYLEEXT_EDT_AutoHScroll;
     92 
     93   pComboBox->EditModifyStylesEx(dwEditStyles, 0xFFFFFFFF);
     94 }
     95 
     96 bool CXFA_FFComboBox::OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
     97   if (!CXFA_FFField::OnRButtonUp(dwFlags, point))
     98     return false;
     99 
    100   GetDoc()->GetDocEnvironment()->PopupMenu(this, point);
    101   return true;
    102 }
    103 
    104 bool CXFA_FFComboBox::OnKillFocus(CXFA_FFWidget* pNewWidget) {
    105   if (!ProcessCommittedData())
    106     UpdateFWLData();
    107 
    108   CXFA_FFField::OnKillFocus(pNewWidget);
    109   return true;
    110 }
    111 
    112 void CXFA_FFComboBox::OpenDropDownList() {
    113   ToComboBox(m_pNormalWidget.get())->OpenDropDownList(true);
    114 }
    115 
    116 bool CXFA_FFComboBox::CommitData() {
    117   return m_pNode->GetWidgetAcc()->SetValue(XFA_VALUEPICTURE_Raw, m_wsNewValue);
    118 }
    119 
    120 bool CXFA_FFComboBox::IsDataChanged() {
    121   auto* pFWLcombobox = ToComboBox(m_pNormalWidget.get());
    122   WideString wsText = pFWLcombobox->GetEditText();
    123   int32_t iCursel = pFWLcombobox->GetCurSel();
    124   if (iCursel >= 0) {
    125     WideString wsSel = pFWLcombobox->GetTextByIndex(iCursel);
    126     if (wsSel == wsText)
    127       wsText = m_pNode->GetWidgetAcc()
    128                    ->GetChoiceListItem(iCursel, true)
    129                    .value_or(L"");
    130   }
    131   if (m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw) == wsText)
    132     return false;
    133 
    134   m_wsNewValue = wsText;
    135   return true;
    136 }
    137 
    138 void CXFA_FFComboBox::FWLEventSelChange(CXFA_EventParam* pParam) {
    139   pParam->m_eType = XFA_EVENT_Change;
    140   pParam->m_pTarget = m_pNode->GetWidgetAcc();
    141   pParam->m_wsNewText = ToComboBox(m_pNormalWidget.get())->GetEditText();
    142   m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Change, pParam);
    143 }
    144 
    145 uint32_t CXFA_FFComboBox::GetAlignment() {
    146   CXFA_Para* para = m_pNode->GetParaIfExists();
    147   if (!para)
    148     return 0;
    149 
    150   uint32_t dwExtendedStyle = 0;
    151   switch (para->GetHorizontalAlign()) {
    152     case XFA_AttributeEnum::Center:
    153       dwExtendedStyle |=
    154           FWL_STYLEEXT_CMB_EditHCenter | FWL_STYLEEXT_CMB_ListItemCenterAlign;
    155       break;
    156     case XFA_AttributeEnum::Justify:
    157       dwExtendedStyle |= FWL_STYLEEXT_CMB_EditJustified;
    158       break;
    159     case XFA_AttributeEnum::JustifyAll:
    160       break;
    161     case XFA_AttributeEnum::Radix:
    162       break;
    163     case XFA_AttributeEnum::Right:
    164       break;
    165     default:
    166       dwExtendedStyle |=
    167           FWL_STYLEEXT_CMB_EditHNear | FWL_STYLEEXT_CMB_ListItemLeftAlign;
    168       break;
    169   }
    170 
    171   switch (para->GetVerticalAlign()) {
    172     case XFA_AttributeEnum::Middle:
    173       dwExtendedStyle |= FWL_STYLEEXT_CMB_EditVCenter;
    174       break;
    175     case XFA_AttributeEnum::Bottom:
    176       dwExtendedStyle |= FWL_STYLEEXT_CMB_EditVFar;
    177       break;
    178     default:
    179       dwExtendedStyle |= FWL_STYLEEXT_CMB_EditVNear;
    180       break;
    181   }
    182   return dwExtendedStyle;
    183 }
    184 
    185 bool CXFA_FFComboBox::UpdateFWLData() {
    186   auto* pComboBox = ToComboBox(m_pNormalWidget.get());
    187   if (!pComboBox)
    188     return false;
    189 
    190   std::vector<int32_t> iSelArray = m_pNode->GetWidgetAcc()->GetSelectedItems();
    191   if (!iSelArray.empty()) {
    192     pComboBox->SetCurSel(iSelArray.front());
    193   } else {
    194     pComboBox->SetCurSel(-1);
    195     pComboBox->SetEditText(
    196         m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw));
    197   }
    198   pComboBox->Update();
    199   return true;
    200 }
    201 
    202 bool CXFA_FFComboBox::CanUndo() {
    203   return m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
    204          ToComboBox(m_pNormalWidget.get())->EditCanUndo();
    205 }
    206 
    207 bool CXFA_FFComboBox::CanRedo() {
    208   return m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
    209          ToComboBox(m_pNormalWidget.get())->EditCanRedo();
    210 }
    211 
    212 bool CXFA_FFComboBox::Undo() {
    213   return m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
    214          ToComboBox(m_pNormalWidget.get())->EditUndo();
    215 }
    216 
    217 bool CXFA_FFComboBox::Redo() {
    218   return m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
    219          ToComboBox(m_pNormalWidget.get())->EditRedo();
    220 }
    221 
    222 bool CXFA_FFComboBox::CanCopy() {
    223   return ToComboBox(m_pNormalWidget.get())->EditCanCopy();
    224 }
    225 
    226 bool CXFA_FFComboBox::CanCut() {
    227   return m_pNode->IsOpenAccess() &&
    228          m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
    229          ToComboBox(m_pNormalWidget.get())->EditCanCut();
    230 }
    231 
    232 bool CXFA_FFComboBox::CanPaste() {
    233   return m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
    234          m_pNode->IsOpenAccess();
    235 }
    236 
    237 bool CXFA_FFComboBox::CanSelectAll() {
    238   return ToComboBox(m_pNormalWidget.get())->EditCanSelectAll();
    239 }
    240 
    241 Optional<WideString> CXFA_FFComboBox::Copy() {
    242   return ToComboBox(m_pNormalWidget.get())->EditCopy();
    243 }
    244 
    245 Optional<WideString> CXFA_FFComboBox::Cut() {
    246   if (!m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry())
    247     return {};
    248 
    249   return ToComboBox(m_pNormalWidget.get())->EditCut();
    250 }
    251 
    252 bool CXFA_FFComboBox::Paste(const WideString& wsPaste) {
    253   return m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
    254          ToComboBox(m_pNormalWidget.get())->EditPaste(wsPaste);
    255 }
    256 
    257 void CXFA_FFComboBox::SelectAll() {
    258   ToComboBox(m_pNormalWidget.get())->EditSelectAll();
    259 }
    260 
    261 void CXFA_FFComboBox::Delete() {
    262   ToComboBox(m_pNormalWidget.get())->EditDelete();
    263 }
    264 
    265 void CXFA_FFComboBox::DeSelect() {
    266   ToComboBox(m_pNormalWidget.get())->EditDeSelect();
    267 }
    268 
    269 FormFieldType CXFA_FFComboBox::GetFormFieldType() {
    270   return FormFieldType::kXFA_ComboBox;
    271 }
    272 
    273 void CXFA_FFComboBox::SetItemState(int32_t nIndex, bool bSelected) {
    274   ToComboBox(m_pNormalWidget.get())->SetCurSel(bSelected ? nIndex : -1);
    275   m_pNormalWidget->Update();
    276   AddInvalidateRect();
    277 }
    278 
    279 void CXFA_FFComboBox::InsertItem(const WideStringView& wsLabel,
    280                                  int32_t nIndex) {
    281   ToComboBox(m_pNormalWidget.get())->AddString(wsLabel);
    282   m_pNormalWidget->Update();
    283   AddInvalidateRect();
    284 }
    285 
    286 void CXFA_FFComboBox::DeleteItem(int32_t nIndex) {
    287   if (nIndex < 0)
    288     ToComboBox(m_pNormalWidget.get())->RemoveAll();
    289   else
    290     ToComboBox(m_pNormalWidget.get())->RemoveAt(nIndex);
    291 
    292   m_pNormalWidget->Update();
    293   AddInvalidateRect();
    294 }
    295 
    296 void CXFA_FFComboBox::OnTextChanged(CFWL_Widget* pWidget,
    297                                     const WideString& wsChanged) {
    298   CXFA_EventParam eParam;
    299   eParam.m_wsPrevText = m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw);
    300   eParam.m_wsChange = wsChanged;
    301   FWLEventSelChange(&eParam);
    302 }
    303 
    304 void CXFA_FFComboBox::OnSelectChanged(CFWL_Widget* pWidget, bool bLButtonUp) {
    305   CXFA_EventParam eParam;
    306   eParam.m_wsPrevText = m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw);
    307   FWLEventSelChange(&eParam);
    308   if (m_pNode->GetWidgetAcc()->IsChoiceListCommitOnSelect() && bLButtonUp)
    309     m_pDocView->SetFocusWidgetAcc(nullptr);
    310 }
    311 
    312 void CXFA_FFComboBox::OnPreOpen(CFWL_Widget* pWidget) {
    313   CXFA_EventParam eParam;
    314   eParam.m_eType = XFA_EVENT_PreOpen;
    315   eParam.m_pTarget = m_pNode->GetWidgetAcc();
    316   m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::PreOpen, &eParam);
    317 }
    318 
    319 void CXFA_FFComboBox::OnPostOpen(CFWL_Widget* pWidget) {
    320   CXFA_EventParam eParam;
    321   eParam.m_eType = XFA_EVENT_PostOpen;
    322   eParam.m_pTarget = m_pNode->GetWidgetAcc();
    323   m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::PostOpen, &eParam);
    324 }
    325 
    326 void CXFA_FFComboBox::OnProcessMessage(CFWL_Message* pMessage) {
    327   m_pOldDelegate->OnProcessMessage(pMessage);
    328 }
    329 
    330 void CXFA_FFComboBox::OnProcessEvent(CFWL_Event* pEvent) {
    331   CXFA_FFField::OnProcessEvent(pEvent);
    332   switch (pEvent->GetType()) {
    333     case CFWL_Event::Type::SelectChanged: {
    334       auto* postEvent = static_cast<CFWL_EventSelectChanged*>(pEvent);
    335       OnSelectChanged(m_pNormalWidget.get(), postEvent->bLButtonUp);
    336       break;
    337     }
    338     case CFWL_Event::Type::EditChanged: {
    339       WideString wsChanged;
    340       OnTextChanged(m_pNormalWidget.get(), wsChanged);
    341       break;
    342     }
    343     case CFWL_Event::Type::PreDropDown: {
    344       OnPreOpen(m_pNormalWidget.get());
    345       break;
    346     }
    347     case CFWL_Event::Type::PostDropDown: {
    348       OnPostOpen(m_pNormalWidget.get());
    349       break;
    350     }
    351     default:
    352       break;
    353   }
    354   m_pOldDelegate->OnProcessEvent(pEvent);
    355 }
    356 
    357 void CXFA_FFComboBox::OnDrawWidget(CXFA_Graphics* pGraphics,
    358                                    const CFX_Matrix& matrix) {
    359   m_pOldDelegate->OnDrawWidget(pGraphics, matrix);
    360 }
    361