xfa_ffnotify.cpp revision 4d3acf4ec42bf6e838f9060103aff98fbf170794
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/app/xfa_ffnotify.h"
8
9#include "fxjs/cfxjse_value.h"
10#include "xfa/fxfa/app/cxfa_textlayout.h"
11#include "xfa/fxfa/app/xfa_ffbarcode.h"
12#include "xfa/fxfa/app/xfa_ffcheckbutton.h"
13#include "xfa/fxfa/app/xfa_ffchoicelist.h"
14#include "xfa/fxfa/app/xfa_ffdraw.h"
15#include "xfa/fxfa/app/xfa_ffexclgroup.h"
16#include "xfa/fxfa/app/xfa_fffield.h"
17#include "xfa/fxfa/app/xfa_ffimage.h"
18#include "xfa/fxfa/app/xfa_ffimageedit.h"
19#include "xfa/fxfa/app/xfa_ffpath.h"
20#include "xfa/fxfa/app/xfa_ffpushbutton.h"
21#include "xfa/fxfa/app/xfa_ffsignature.h"
22#include "xfa/fxfa/app/xfa_ffsubform.h"
23#include "xfa/fxfa/app/xfa_fftext.h"
24#include "xfa/fxfa/app/xfa_fftextedit.h"
25#include "xfa/fxfa/app/xfa_ffwidgetacc.h"
26#include "xfa/fxfa/app/xfa_fwladapter.h"
27#include "xfa/fxfa/xfa_ffapp.h"
28#include "xfa/fxfa/xfa_ffdoc.h"
29#include "xfa/fxfa/xfa_ffdocview.h"
30#include "xfa/fxfa/xfa_ffpageview.h"
31#include "xfa/fxfa/xfa_ffwidget.h"
32#include "xfa/fxfa/xfa_ffwidgethandler.h"
33
34static void XFA_FFDeleteWidgetAcc(void* pData) {
35  delete static_cast<CXFA_WidgetAcc*>(pData);
36}
37
38static XFA_MAPDATABLOCKCALLBACKINFO gs_XFADeleteWidgetAcc = {
39    XFA_FFDeleteWidgetAcc, nullptr};
40
41CXFA_FFNotify::CXFA_FFNotify(CXFA_FFDoc* pDoc) : m_pDoc(pDoc) {}
42CXFA_FFNotify::~CXFA_FFNotify() {}
43
44void CXFA_FFNotify::OnPageEvent(CXFA_ContainerLayoutItem* pSender,
45                                uint32_t dwEvent) {
46  CXFA_FFDocView* pDocView = m_pDoc->GetDocView(pSender->GetLayout());
47  if (pDocView)
48    pDocView->OnPageEvent(pSender, dwEvent);
49}
50
51void CXFA_FFNotify::OnWidgetListItemAdded(CXFA_WidgetData* pSender,
52                                          const FX_WCHAR* pLabel,
53                                          const FX_WCHAR* pValue,
54                                          int32_t iIndex) {
55  CXFA_WidgetAcc* pWidgetAcc = static_cast<CXFA_WidgetAcc*>(pSender);
56  if (pWidgetAcc->GetUIType() != XFA_Element::ChoiceList)
57    return;
58
59  CXFA_FFWidget* pWidget = nullptr;
60  while ((pWidget = pWidgetAcc->GetNextWidget(pWidget)) != nullptr) {
61    if (pWidget->IsLoaded()) {
62      if (pWidgetAcc->IsListBox()) {
63        static_cast<CXFA_FFListBox*>(pWidget)->InsertItem(pLabel, iIndex);
64      } else {
65        static_cast<CXFA_FFComboBox*>(pWidget)->InsertItem(pLabel, iIndex);
66      }
67    }
68  }
69}
70
71void CXFA_FFNotify::OnWidgetListItemRemoved(CXFA_WidgetData* pSender,
72                                            int32_t iIndex) {
73  CXFA_WidgetAcc* pWidgetAcc = static_cast<CXFA_WidgetAcc*>(pSender);
74  if (pWidgetAcc->GetUIType() != XFA_Element::ChoiceList)
75    return;
76
77  CXFA_FFWidget* pWidget = nullptr;
78  while ((pWidget = pWidgetAcc->GetNextWidget(pWidget)) != nullptr) {
79    if (pWidget->IsLoaded()) {
80      if (pWidgetAcc->IsListBox()) {
81        static_cast<CXFA_FFListBox*>(pWidget)->DeleteItem(iIndex);
82      } else {
83        static_cast<CXFA_FFComboBox*>(pWidget)->DeleteItem(iIndex);
84      }
85    }
86  }
87}
88
89CXFA_LayoutItem* CXFA_FFNotify::OnCreateLayoutItem(CXFA_Node* pNode) {
90  CXFA_LayoutProcessor* pLayout = m_pDoc->GetXFADoc()->GetDocLayout();
91  CXFA_FFDocView* pDocView = m_pDoc->GetDocView(pLayout);
92  XFA_Element eType = pNode->GetElementType();
93  if (eType == XFA_Element::PageArea)
94    return new CXFA_FFPageView(pDocView, pNode);
95  if (eType == XFA_Element::ContentArea)
96    return new CXFA_ContainerLayoutItem(pNode);
97
98  CXFA_WidgetAcc* pAcc = static_cast<CXFA_WidgetAcc*>(pNode->GetWidgetData());
99  if (!pAcc)
100    return new CXFA_ContentLayoutItem(pNode);
101
102  CXFA_FFWidget* pWidget;
103  switch (pAcc->GetUIType()) {
104    case XFA_Element::Barcode:
105      pWidget = new CXFA_FFBarcode(nullptr, pAcc);
106      break;
107    case XFA_Element::Button:
108      pWidget = new CXFA_FFPushButton(nullptr, pAcc);
109      break;
110    case XFA_Element::CheckButton:
111      pWidget = new CXFA_FFCheckButton(nullptr, pAcc);
112      break;
113    case XFA_Element::ChoiceList: {
114      if (pAcc->IsListBox()) {
115        pWidget = new CXFA_FFListBox(nullptr, pAcc);
116      } else {
117        pWidget = new CXFA_FFComboBox(nullptr, pAcc);
118      }
119    } break;
120    case XFA_Element::DateTimeEdit:
121      pWidget = new CXFA_FFDateTimeEdit(nullptr, pAcc);
122      break;
123    case XFA_Element::ImageEdit:
124      pWidget = new CXFA_FFImageEdit(nullptr, pAcc);
125      break;
126    case XFA_Element::NumericEdit:
127      pWidget = new CXFA_FFNumericEdit(nullptr, pAcc);
128      break;
129    case XFA_Element::PasswordEdit:
130      pWidget = new CXFA_FFPasswordEdit(nullptr, pAcc);
131      break;
132    case XFA_Element::Signature:
133      pWidget = new CXFA_FFSignature(nullptr, pAcc);
134      break;
135    case XFA_Element::TextEdit:
136      pWidget = new CXFA_FFTextEdit(nullptr, pAcc);
137      break;
138    case XFA_Element::Arc:
139      pWidget = new CXFA_FFArc(nullptr, pAcc);
140      break;
141    case XFA_Element::Line:
142      pWidget = new CXFA_FFLine(nullptr, pAcc);
143      break;
144    case XFA_Element::Rectangle:
145      pWidget = new CXFA_FFRectangle(nullptr, pAcc);
146      break;
147    case XFA_Element::Text:
148      pWidget = new CXFA_FFText(nullptr, pAcc);
149      break;
150    case XFA_Element::Image:
151      pWidget = new CXFA_FFImage(nullptr, pAcc);
152      break;
153    case XFA_Element::Draw:
154      pWidget = new CXFA_FFDraw(nullptr, pAcc);
155      break;
156    case XFA_Element::Subform:
157      pWidget = new CXFA_FFSubForm(nullptr, pAcc);
158      break;
159    case XFA_Element::ExclGroup:
160      pWidget = new CXFA_FFExclGroup(nullptr, pAcc);
161      break;
162    case XFA_Element::DefaultUi:
163    default:
164      pWidget = nullptr;
165      break;
166  }
167
168  if (pWidget)
169    pWidget->SetDocView(pDocView);
170  return pWidget;
171}
172
173void CXFA_FFNotify::StartFieldDrawLayout(CXFA_Node* pItem,
174                                         FX_FLOAT& fCalcWidth,
175                                         FX_FLOAT& fCalcHeight) {
176  CXFA_WidgetAcc* pAcc = static_cast<CXFA_WidgetAcc*>(pItem->GetWidgetData());
177  if (!pAcc)
178    return;
179
180  pAcc->StartWidgetLayout(fCalcWidth, fCalcHeight);
181}
182
183bool CXFA_FFNotify::FindSplitPos(CXFA_Node* pItem,
184                                 int32_t iBlockIndex,
185                                 FX_FLOAT& fCalcHeightPos) {
186  CXFA_WidgetAcc* pAcc = static_cast<CXFA_WidgetAcc*>(pItem->GetWidgetData());
187  return pAcc && pAcc->FindSplitPos(iBlockIndex, fCalcHeightPos);
188}
189
190bool CXFA_FFNotify::RunScript(CXFA_Node* pScript, CXFA_Node* pFormItem) {
191  bool bRet = false;
192  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
193  if (!pDocView) {
194    return bRet;
195  }
196  CXFA_WidgetAcc* pWidgetAcc =
197      static_cast<CXFA_WidgetAcc*>(pFormItem->GetWidgetData());
198  if (!pWidgetAcc) {
199    return bRet;
200  }
201  CXFA_EventParam EventParam;
202  EventParam.m_eType = XFA_EVENT_Unknown;
203  CFXJSE_Value* pRetValue = nullptr;
204  int32_t iRet =
205      pWidgetAcc->ExecuteScript(CXFA_Script(pScript), &EventParam, &pRetValue);
206  if (iRet == XFA_EVENTERROR_Success && pRetValue) {
207    bRet = pRetValue->ToBoolean();
208    delete pRetValue;
209  }
210  return bRet;
211}
212int32_t CXFA_FFNotify::ExecEventByDeepFirst(CXFA_Node* pFormNode,
213                                            XFA_EVENTTYPE eEventType,
214                                            bool bIsFormReady,
215                                            bool bRecursive,
216                                            CXFA_WidgetAcc* pExclude) {
217  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
218  if (!pDocView) {
219    return XFA_EVENTERROR_NotExist;
220  }
221  return pDocView->ExecEventActivityByDeepFirst(
222      pFormNode, eEventType, bIsFormReady, bRecursive,
223      pExclude ? pExclude->GetNode() : nullptr);
224}
225void CXFA_FFNotify::AddCalcValidate(CXFA_Node* pNode) {
226  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
227  if (!pDocView) {
228    return;
229  }
230  CXFA_WidgetAcc* pWidgetAcc =
231      static_cast<CXFA_WidgetAcc*>(pNode->GetWidgetData());
232  if (!pWidgetAcc) {
233    return;
234  }
235  pDocView->AddCalculateWidgetAcc(pWidgetAcc);
236  pDocView->AddValidateWidget(pWidgetAcc);
237}
238CXFA_FFDoc* CXFA_FFNotify::GetHDOC() {
239  return m_pDoc;
240}
241IXFA_DocEnvironment* CXFA_FFNotify::GetDocEnvironment() const {
242  return m_pDoc->GetDocEnvironment();
243}
244IXFA_AppProvider* CXFA_FFNotify::GetAppProvider() {
245  return m_pDoc->GetApp()->GetAppProvider();
246}
247CXFA_FFWidgetHandler* CXFA_FFNotify::GetWidgetHandler() {
248  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
249  return pDocView ? pDocView->GetWidgetHandler() : nullptr;
250}
251CXFA_FFWidget* CXFA_FFNotify::GetHWidget(CXFA_LayoutItem* pLayoutItem) {
252  return XFA_GetWidgetFromLayoutItem(pLayoutItem);
253}
254void CXFA_FFNotify::OpenDropDownList(CXFA_FFWidget* hWidget) {
255  if (hWidget->GetDataAcc()->GetUIType() != XFA_Element::ChoiceList) {
256    return;
257  }
258  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
259  pDocView->LockUpdate();
260  static_cast<CXFA_FFComboBox*>(hWidget)->OpenDropDownList();
261  pDocView->UnlockUpdate();
262  pDocView->UpdateDocView();
263}
264CFX_WideString CXFA_FFNotify::GetCurrentDateTime() {
265  CFX_Unitime dataTime;
266  dataTime.Now();
267  CFX_WideString wsDateTime;
268  wsDateTime.Format(L"%d%02d%02dT%02d%02d%02d", dataTime.GetYear(),
269                    dataTime.GetMonth(), dataTime.GetDay(), dataTime.GetHour(),
270                    dataTime.GetMinute(), dataTime.GetSecond());
271  return wsDateTime;
272}
273void CXFA_FFNotify::ResetData(CXFA_WidgetData* pWidgetData) {
274  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
275  if (!pDocView) {
276    return;
277  }
278  pDocView->ResetWidgetData(static_cast<CXFA_WidgetAcc*>(pWidgetData));
279}
280int32_t CXFA_FFNotify::GetLayoutStatus() {
281  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
282  return pDocView ? pDocView->GetLayoutStatus() : 0;
283}
284void CXFA_FFNotify::RunNodeInitialize(CXFA_Node* pNode) {
285  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
286  if (!pDocView) {
287    return;
288  }
289  pDocView->AddNewFormNode(pNode);
290}
291void CXFA_FFNotify::RunSubformIndexChange(CXFA_Node* pSubformNode) {
292  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
293  if (!pDocView) {
294    return;
295  }
296  pDocView->AddIndexChangedSubform(pSubformNode);
297}
298CXFA_Node* CXFA_FFNotify::GetFocusWidgetNode() {
299  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
300  if (!pDocView) {
301    return nullptr;
302  }
303  CXFA_WidgetAcc* pAcc = pDocView->GetFocusWidgetAcc();
304  return pAcc ? pAcc->GetNode() : nullptr;
305}
306void CXFA_FFNotify::SetFocusWidgetNode(CXFA_Node* pNode) {
307  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
308  if (!pDocView) {
309    return;
310  }
311  CXFA_WidgetAcc* pAcc =
312      pNode ? static_cast<CXFA_WidgetAcc*>(pNode->GetWidgetData()) : nullptr;
313  pDocView->SetFocusWidgetAcc(pAcc);
314}
315
316void CXFA_FFNotify::OnNodeReady(CXFA_Node* pNode) {
317  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
318  if (!pDocView)
319    return;
320
321  XFA_Element eType = pNode->GetElementType();
322  if (XFA_IsCreateWidget(eType)) {
323    CXFA_WidgetAcc* pAcc = new CXFA_WidgetAcc(pDocView, pNode);
324    pNode->SetObject(XFA_ATTRIBUTE_WidgetData, pAcc, &gs_XFADeleteWidgetAcc);
325    return;
326  }
327  switch (eType) {
328    case XFA_Element::BindItems:
329      pDocView->m_BindItems.push_back(pNode);
330      break;
331    case XFA_Element::Validate: {
332      pNode->SetFlag(XFA_NodeFlag_NeedsInitApp, false);
333    } break;
334    default:
335      break;
336  }
337}
338
339void CXFA_FFNotify::OnValueChanging(CXFA_Node* pSender, XFA_ATTRIBUTE eAttr) {
340  if (eAttr != XFA_ATTRIBUTE_Presence)
341    return;
342
343  if (pSender->GetPacketID() & XFA_XDPPACKET_Datasets)
344    return;
345
346  if (!pSender->IsFormContainer())
347    return;
348
349  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
350  if (!pDocView)
351    return;
352
353  if (pDocView->GetLayoutStatus() < XFA_DOCVIEW_LAYOUTSTATUS_End)
354    return;
355
356  CXFA_WidgetAcc* pWidgetAcc =
357      static_cast<CXFA_WidgetAcc*>(pSender->GetWidgetData());
358  if (!pWidgetAcc)
359    return;
360
361  CXFA_FFWidget* pWidget = nullptr;
362  while ((pWidget = pWidgetAcc->GetNextWidget(pWidget)) != nullptr) {
363    if (pWidget->IsLoaded())
364      pWidget->AddInvalidateRect();
365  }
366}
367
368void CXFA_FFNotify::OnValueChanged(CXFA_Node* pSender,
369                                   XFA_ATTRIBUTE eAttr,
370                                   CXFA_Node* pParentNode,
371                                   CXFA_Node* pWidgetNode) {
372  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
373  if (!pDocView)
374    return;
375
376  if (!(pSender->GetPacketID() & XFA_XDPPACKET_Form)) {
377    if (eAttr == XFA_ATTRIBUTE_Value)
378      pDocView->AddCalculateNodeNotify(pSender);
379    return;
380  }
381
382  XFA_Element eType = pParentNode->GetElementType();
383  bool bIsContainerNode = pParentNode->IsContainerNode();
384  CXFA_WidgetAcc* pWidgetAcc =
385      static_cast<CXFA_WidgetAcc*>(pWidgetNode->GetWidgetData());
386  if (!pWidgetAcc)
387    return;
388
389  bool bUpdateProperty = false;
390  pDocView->SetChangeMark();
391  switch (eType) {
392    case XFA_Element::Caption: {
393      CXFA_TextLayout* pCapOut = pWidgetAcc->GetCaptionTextLayout();
394      if (!pCapOut)
395        return;
396
397      pCapOut->Unload();
398    } break;
399    case XFA_Element::Ui:
400    case XFA_Element::Para:
401      bUpdateProperty = true;
402      break;
403    default:
404      break;
405  }
406  if (bIsContainerNode && eAttr == XFA_ATTRIBUTE_Access)
407    bUpdateProperty = true;
408
409  if (eAttr == XFA_ATTRIBUTE_Value) {
410    pDocView->AddCalculateNodeNotify(pSender);
411    if (eType == XFA_Element::Value || bIsContainerNode) {
412      if (bIsContainerNode) {
413        pWidgetAcc->UpdateUIDisplay();
414        pDocView->AddCalculateWidgetAcc(pWidgetAcc);
415        pDocView->AddValidateWidget(pWidgetAcc);
416      } else if (pWidgetNode->GetNodeItem(XFA_NODEITEM_Parent)
417                     ->GetElementType() == XFA_Element::ExclGroup) {
418        pWidgetAcc->UpdateUIDisplay();
419      }
420      return;
421    }
422  }
423  CXFA_FFWidget* pWidget = nullptr;
424  while ((pWidget = pWidgetAcc->GetNextWidget(pWidget)) != nullptr) {
425    if (!pWidget->IsLoaded())
426      continue;
427
428    if (bUpdateProperty)
429      pWidget->UpdateWidgetProperty();
430    pWidget->PerformLayout();
431    pWidget->AddInvalidateRect();
432  }
433}
434
435void CXFA_FFNotify::OnChildAdded(CXFA_Node* pSender) {
436  if (!pSender->IsFormContainer()) {
437    return;
438  }
439  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
440  if (!pDocView) {
441    return;
442  }
443  bool bLayoutReady =
444      !(pDocView->m_bInLayoutStatus) &&
445      (pDocView->GetLayoutStatus() == XFA_DOCVIEW_LAYOUTSTATUS_End);
446  if (bLayoutReady)
447    m_pDoc->GetDocEnvironment()->SetChangeMark(m_pDoc);
448}
449
450void CXFA_FFNotify::OnChildRemoved() {
451  CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
452  if (!pDocView)
453    return;
454
455  bool bLayoutReady =
456      !(pDocView->m_bInLayoutStatus) &&
457      (pDocView->GetLayoutStatus() == XFA_DOCVIEW_LAYOUTSTATUS_End);
458  if (bLayoutReady)
459    m_pDoc->GetDocEnvironment()->SetChangeMark(m_pDoc);
460}
461
462void CXFA_FFNotify::OnLayoutItemAdded(CXFA_LayoutProcessor* pLayout,
463                                      CXFA_LayoutItem* pSender,
464                                      int32_t iPageIdx,
465                                      uint32_t dwStatus) {
466  CXFA_FFDocView* pDocView = m_pDoc->GetDocView(pLayout);
467  if (!pDocView)
468    return;
469
470  CXFA_FFWidget* pWidget = XFA_GetWidgetFromLayoutItem(pSender);
471  if (!pWidget)
472    return;
473
474  CXFA_FFPageView* pNewPageView = pDocView->GetPageView(iPageIdx);
475  uint32_t dwFilter = XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable |
476                      XFA_WidgetStatus_Printable;
477  pWidget->ModifyStatus(dwStatus, dwFilter);
478  CXFA_FFPageView* pPrePageView = pWidget->GetPageView();
479  if (pPrePageView != pNewPageView ||
480      (dwStatus & (XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable)) ==
481          (XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable)) {
482    pWidget->SetPageView(pNewPageView);
483    m_pDoc->GetDocEnvironment()->WidgetPostAdd(pWidget, pWidget->GetDataAcc());
484  }
485  if (pDocView->GetLayoutStatus() != XFA_DOCVIEW_LAYOUTSTATUS_End ||
486      !(dwStatus & XFA_WidgetStatus_Visible)) {
487    return;
488  }
489  if (pWidget->IsLoaded()) {
490    CFX_RectF rtOld;
491    pWidget->GetWidgetRect(rtOld);
492    if (rtOld != pWidget->ReCacheWidgetRect())
493      pWidget->PerformLayout();
494  } else {
495    pWidget->LoadWidget();
496  }
497  pWidget->AddInvalidateRect(nullptr);
498}
499
500void CXFA_FFNotify::OnLayoutItemRemoving(CXFA_LayoutProcessor* pLayout,
501                                         CXFA_LayoutItem* pSender) {
502  CXFA_FFDocView* pDocView = m_pDoc->GetDocView(pLayout);
503  if (!pDocView)
504    return;
505
506  CXFA_FFWidget* pWidget = XFA_GetWidgetFromLayoutItem(pSender);
507  if (!pWidget)
508    return;
509
510  pDocView->DeleteLayoutItem(pWidget);
511  m_pDoc->GetDocEnvironment()->WidgetPreRemove(pWidget, pWidget->GetDataAcc());
512  pWidget->AddInvalidateRect(nullptr);
513}
514