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 "fpdfsdk/pwl/cpwl_combo_box.h"
8
9 #include <algorithm>
10 #include <sstream>
11 #include <utility>
12
13 #include "core/fxge/cfx_pathdata.h"
14 #include "core/fxge/cfx_renderdevice.h"
15 #include "fpdfsdk/pwl/cpwl_edit.h"
16 #include "fpdfsdk/pwl/cpwl_edit_ctrl.h"
17 #include "fpdfsdk/pwl/cpwl_list_box.h"
18 #include "fpdfsdk/pwl/cpwl_list_impl.h"
19 #include "fpdfsdk/pwl/cpwl_wnd.h"
20 #include "public/fpdf_fwlevent.h"
21 #include "third_party/base/ptr_util.h"
22
23 namespace {
24
25 constexpr float kComboBoxDefaultFontSize = 12.0f;
26 constexpr float kComboBoxTriangleHalfLength = 3.0f;
27 constexpr int kDefaultButtonWidth = 13;
28
29 } // namespace
30
CPWL_CBListBox(const CreateParams & cp,std::unique_ptr<IPWL_SystemHandler::PerWindowData> pAttachedData)31 CPWL_CBListBox::CPWL_CBListBox(
32 const CreateParams& cp,
33 std::unique_ptr<IPWL_SystemHandler::PerWindowData> pAttachedData)
34 : CPWL_ListBox(cp, std::move(pAttachedData)) {}
35
36 CPWL_CBListBox::~CPWL_CBListBox() = default;
37
OnLButtonUp(const CFX_PointF & point,uint32_t nFlag)38 bool CPWL_CBListBox::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
39 CPWL_Wnd::OnLButtonUp(point, nFlag);
40
41 if (!m_bMouseDown)
42 return true;
43
44 ReleaseCapture();
45 m_bMouseDown = false;
46
47 if (!ClientHitTest(point))
48 return true;
49 if (CPWL_Wnd* pParent = GetParentWindow())
50 pParent->NotifyLButtonUp(this, point);
51
52 return !OnNotifySelectionChanged(false, nFlag);
53 }
54
IsMovementKey(uint16_t nChar) const55 bool CPWL_CBListBox::IsMovementKey(uint16_t nChar) const {
56 switch (nChar) {
57 case FWL_VKEY_Up:
58 case FWL_VKEY_Down:
59 case FWL_VKEY_Home:
60 case FWL_VKEY_Left:
61 case FWL_VKEY_End:
62 case FWL_VKEY_Right:
63 return true;
64 default:
65 return false;
66 }
67 }
68
OnMovementKeyDown(uint16_t nChar,uint32_t nFlag)69 bool CPWL_CBListBox::OnMovementKeyDown(uint16_t nChar, uint32_t nFlag) {
70 ASSERT(IsMovementKey(nChar));
71
72 switch (nChar) {
73 case FWL_VKEY_Up:
74 m_pList->OnVK_UP(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
75 break;
76 case FWL_VKEY_Down:
77 m_pList->OnVK_DOWN(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
78 break;
79 case FWL_VKEY_Home:
80 m_pList->OnVK_HOME(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
81 break;
82 case FWL_VKEY_Left:
83 m_pList->OnVK_LEFT(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
84 break;
85 case FWL_VKEY_End:
86 m_pList->OnVK_END(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
87 break;
88 case FWL_VKEY_Right:
89 m_pList->OnVK_RIGHT(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
90 break;
91 }
92 return OnNotifySelectionChanged(true, nFlag);
93 }
94
IsChar(uint16_t nChar,uint32_t nFlag) const95 bool CPWL_CBListBox::IsChar(uint16_t nChar, uint32_t nFlag) const {
96 return m_pList->OnChar(nChar, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
97 }
98
OnCharNotify(uint16_t nChar,uint32_t nFlag)99 bool CPWL_CBListBox::OnCharNotify(uint16_t nChar, uint32_t nFlag) {
100 if (auto* pComboBox = static_cast<CPWL_ComboBox*>(GetParentWindow()))
101 pComboBox->SetSelectText();
102
103 return OnNotifySelectionChanged(true, nFlag);
104 }
105
CPWL_CBButton(const CreateParams & cp,std::unique_ptr<IPWL_SystemHandler::PerWindowData> pAttachedData)106 CPWL_CBButton::CPWL_CBButton(
107 const CreateParams& cp,
108 std::unique_ptr<IPWL_SystemHandler::PerWindowData> pAttachedData)
109 : CPWL_Wnd(cp, std::move(pAttachedData)) {}
110
111 CPWL_CBButton::~CPWL_CBButton() = default;
112
DrawThisAppearance(CFX_RenderDevice * pDevice,const CFX_Matrix & mtUser2Device)113 void CPWL_CBButton::DrawThisAppearance(CFX_RenderDevice* pDevice,
114 const CFX_Matrix& mtUser2Device) {
115 CPWL_Wnd::DrawThisAppearance(pDevice, mtUser2Device);
116
117 CFX_FloatRect rectWnd = CPWL_Wnd::GetWindowRect();
118 if (!IsVisible() || rectWnd.IsEmpty())
119 return;
120
121 CFX_PointF ptCenter = GetCenterPoint();
122
123 static constexpr float kComboBoxTriangleQuarterLength =
124 kComboBoxTriangleHalfLength * 0.5;
125 CFX_PointF pt1(ptCenter.x - kComboBoxTriangleHalfLength,
126 ptCenter.y + kComboBoxTriangleQuarterLength);
127 CFX_PointF pt2(ptCenter.x + kComboBoxTriangleHalfLength,
128 ptCenter.y + kComboBoxTriangleQuarterLength);
129 CFX_PointF pt3(ptCenter.x, ptCenter.y - kComboBoxTriangleQuarterLength);
130
131 if (IsFloatBigger(rectWnd.right - rectWnd.left,
132 kComboBoxTriangleHalfLength * 2) &&
133 IsFloatBigger(rectWnd.top - rectWnd.bottom,
134 kComboBoxTriangleHalfLength)) {
135 CFX_PathData path;
136 path.AppendPoint(pt1, FXPT_TYPE::MoveTo, false);
137 path.AppendPoint(pt2, FXPT_TYPE::LineTo, false);
138 path.AppendPoint(pt3, FXPT_TYPE::LineTo, false);
139 path.AppendPoint(pt1, FXPT_TYPE::LineTo, false);
140
141 pDevice->DrawPath(&path, &mtUser2Device, nullptr,
142 PWL_DEFAULT_BLACKCOLOR.ToFXColor(GetTransparency()), 0,
143 FXFILL_ALTERNATE);
144 }
145 }
146
OnLButtonDown(const CFX_PointF & point,uint32_t nFlag)147 bool CPWL_CBButton::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
148 CPWL_Wnd::OnLButtonDown(point, nFlag);
149
150 SetCapture();
151 if (CPWL_Wnd* pParent = GetParentWindow())
152 pParent->NotifyLButtonDown(this, point);
153
154 return true;
155 }
156
OnLButtonUp(const CFX_PointF & point,uint32_t nFlag)157 bool CPWL_CBButton::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
158 CPWL_Wnd::OnLButtonUp(point, nFlag);
159
160 ReleaseCapture();
161 return true;
162 }
163
CPWL_ComboBox(const CreateParams & cp,std::unique_ptr<IPWL_SystemHandler::PerWindowData> pAttachedData)164 CPWL_ComboBox::CPWL_ComboBox(
165 const CreateParams& cp,
166 std::unique_ptr<IPWL_SystemHandler::PerWindowData> pAttachedData)
167 : CPWL_Wnd(cp, std::move(pAttachedData)) {
168 GetCreationParams()->dwFlags &= ~PWS_HSCROLL;
169 GetCreationParams()->dwFlags &= ~PWS_VSCROLL;
170 }
171
172 CPWL_ComboBox::~CPWL_ComboBox() = default;
173
OnDestroy()174 void CPWL_ComboBox::OnDestroy() {
175 // Until cleanup takes place in the virtual destructor for CPWL_Wnd
176 // subclasses, implement the virtual OnDestroy method that does the
177 // cleanup first, then invokes the superclass OnDestroy ... gee,
178 // like a dtor would.
179 m_pList.Release();
180 m_pButton.Release();
181 m_pEdit.Release();
182 CPWL_Wnd::OnDestroy();
183 }
184
SetFocus()185 void CPWL_ComboBox::SetFocus() {
186 if (m_pEdit)
187 m_pEdit->SetFocus();
188 }
189
KillFocus()190 void CPWL_ComboBox::KillFocus() {
191 if (!SetPopup(false))
192 return;
193
194 CPWL_Wnd::KillFocus();
195 }
196
GetSelectedText()197 WideString CPWL_ComboBox::GetSelectedText() {
198 if (m_pEdit)
199 return m_pEdit->GetSelectedText();
200
201 return WideString();
202 }
203
ReplaceSelection(const WideString & text)204 void CPWL_ComboBox::ReplaceSelection(const WideString& text) {
205 if (m_pEdit)
206 m_pEdit->ReplaceSelection(text);
207 }
208
CanUndo()209 bool CPWL_ComboBox::CanUndo() {
210 return m_pEdit && m_pEdit->CanUndo();
211 }
212
CanRedo()213 bool CPWL_ComboBox::CanRedo() {
214 return m_pEdit && m_pEdit->CanRedo();
215 }
216
Undo()217 bool CPWL_ComboBox::Undo() {
218 return m_pEdit && m_pEdit->Undo();
219 }
220
Redo()221 bool CPWL_ComboBox::Redo() {
222 return m_pEdit && m_pEdit->Redo();
223 }
224
GetText()225 WideString CPWL_ComboBox::GetText() {
226 return m_pEdit ? m_pEdit->GetText() : WideString();
227 }
228
SetText(const WideString & text)229 void CPWL_ComboBox::SetText(const WideString& text) {
230 if (m_pEdit)
231 m_pEdit->SetText(text);
232 }
233
AddString(const WideString & str)234 void CPWL_ComboBox::AddString(const WideString& str) {
235 if (m_pList)
236 m_pList->AddString(str);
237 }
238
GetSelect() const239 int32_t CPWL_ComboBox::GetSelect() const {
240 return m_nSelectItem;
241 }
242
SetSelect(int32_t nItemIndex)243 void CPWL_ComboBox::SetSelect(int32_t nItemIndex) {
244 if (m_pList)
245 m_pList->Select(nItemIndex);
246
247 m_pEdit->SetText(m_pList->GetText());
248 m_nSelectItem = nItemIndex;
249 }
250
SetEditSelection(int32_t nStartChar,int32_t nEndChar)251 void CPWL_ComboBox::SetEditSelection(int32_t nStartChar, int32_t nEndChar) {
252 if (m_pEdit)
253 m_pEdit->SetSelection(nStartChar, nEndChar);
254 }
255
GetEditSelection(int32_t & nStartChar,int32_t & nEndChar) const256 void CPWL_ComboBox::GetEditSelection(int32_t& nStartChar,
257 int32_t& nEndChar) const {
258 nStartChar = -1;
259 nEndChar = -1;
260
261 if (m_pEdit)
262 m_pEdit->GetSelection(nStartChar, nEndChar);
263 }
264
ClearSelection()265 void CPWL_ComboBox::ClearSelection() {
266 if (m_pEdit)
267 m_pEdit->ClearSelection();
268 }
269
CreateChildWnd(const CreateParams & cp)270 void CPWL_ComboBox::CreateChildWnd(const CreateParams& cp) {
271 CreateEdit(cp);
272 CreateButton(cp);
273 CreateListBox(cp);
274 }
275
CreateEdit(const CreateParams & cp)276 void CPWL_ComboBox::CreateEdit(const CreateParams& cp) {
277 if (m_pEdit)
278 return;
279
280 CreateParams ecp = cp;
281 ecp.dwFlags = PWS_VISIBLE | PWS_CHILD | PWS_BORDER | PES_CENTER |
282 PES_AUTOSCROLL | PES_UNDO;
283
284 if (HasFlag(PWS_AUTOFONTSIZE))
285 ecp.dwFlags |= PWS_AUTOFONTSIZE;
286
287 if (!HasFlag(PCBS_ALLOWCUSTOMTEXT))
288 ecp.dwFlags |= PWS_READONLY;
289
290 ecp.rcRectWnd = CFX_FloatRect();
291 ecp.dwBorderWidth = 0;
292 ecp.nBorderStyle = BorderStyle::SOLID;
293
294 auto pEdit = pdfium::MakeUnique<CPWL_Edit>(ecp, CloneAttachedData());
295 m_pEdit = pEdit.get();
296 m_pEdit->AttachFFLData(m_pFormFiller.Get());
297 AddChild(std::move(pEdit));
298 m_pEdit->Realize();
299 }
300
CreateButton(const CreateParams & cp)301 void CPWL_ComboBox::CreateButton(const CreateParams& cp) {
302 if (m_pButton)
303 return;
304
305 CreateParams bcp = cp;
306 bcp.dwFlags = PWS_VISIBLE | PWS_CHILD | PWS_BORDER | PWS_BACKGROUND;
307 bcp.sBackgroundColor = CFX_Color(CFX_Color::kRGB, 220.0f / 255.0f,
308 220.0f / 255.0f, 220.0f / 255.0f);
309 bcp.sBorderColor = PWL_DEFAULT_BLACKCOLOR;
310 bcp.dwBorderWidth = 2;
311 bcp.nBorderStyle = BorderStyle::BEVELED;
312 bcp.eCursorType = FXCT_ARROW;
313
314 auto pButton = pdfium::MakeUnique<CPWL_CBButton>(bcp, CloneAttachedData());
315 m_pButton = pButton.get();
316 AddChild(std::move(pButton));
317 m_pButton->Realize();
318 }
319
CreateListBox(const CreateParams & cp)320 void CPWL_ComboBox::CreateListBox(const CreateParams& cp) {
321 if (m_pList)
322 return;
323
324 CreateParams lcp = cp;
325 lcp.dwFlags =
326 PWS_CHILD | PWS_BORDER | PWS_BACKGROUND | PLBS_HOVERSEL | PWS_VSCROLL;
327 lcp.nBorderStyle = BorderStyle::SOLID;
328 lcp.dwBorderWidth = 1;
329 lcp.eCursorType = FXCT_ARROW;
330 lcp.rcRectWnd = CFX_FloatRect();
331
332 lcp.fFontSize =
333 (cp.dwFlags & PWS_AUTOFONTSIZE) ? kComboBoxDefaultFontSize : cp.fFontSize;
334
335 if (cp.sBorderColor.nColorType == CFX_Color::kTransparent)
336 lcp.sBorderColor = PWL_DEFAULT_BLACKCOLOR;
337
338 if (cp.sBackgroundColor.nColorType == CFX_Color::kTransparent)
339 lcp.sBackgroundColor = PWL_DEFAULT_WHITECOLOR;
340
341 auto pList = pdfium::MakeUnique<CPWL_CBListBox>(lcp, CloneAttachedData());
342 m_pList = pList.get();
343 m_pList->AttachFFLData(m_pFormFiller.Get());
344 AddChild(std::move(pList));
345 m_pList->Realize();
346 }
347
RePosChildWnd()348 bool CPWL_ComboBox::RePosChildWnd() {
349 ObservedPtr<CPWL_ComboBox> thisObserved(this);
350 const CFX_FloatRect rcClient = GetClientRect();
351 if (m_bPopup) {
352 const float fOldWindowHeight = m_rcOldWindow.Height();
353 const float fOldClientHeight = fOldWindowHeight - GetBorderWidth() * 2;
354
355 CFX_FloatRect rcList = CPWL_Wnd::GetWindowRect();
356 CFX_FloatRect rcButton = rcClient;
357 rcButton.left =
358 std::max(rcButton.right - kDefaultButtonWidth, rcClient.left);
359 CFX_FloatRect rcEdit = rcClient;
360 rcEdit.right = std::max(rcButton.left - 1.0f, rcEdit.left);
361 if (m_bBottom) {
362 rcButton.bottom = rcButton.top - fOldClientHeight;
363 rcEdit.bottom = rcEdit.top - fOldClientHeight;
364 rcList.top -= fOldWindowHeight;
365 } else {
366 rcButton.top = rcButton.bottom + fOldClientHeight;
367 rcEdit.top = rcEdit.bottom + fOldClientHeight;
368 rcList.bottom += fOldWindowHeight;
369 }
370
371 if (m_pButton) {
372 m_pButton->Move(rcButton, true, false);
373 if (!thisObserved)
374 return false;
375 }
376
377 if (m_pEdit) {
378 m_pEdit->Move(rcEdit, true, false);
379 if (!thisObserved)
380 return false;
381 }
382
383 if (m_pList) {
384 if (!m_pList->SetVisible(true) || !thisObserved)
385 return false;
386
387 if (!m_pList->Move(rcList, true, false) || !thisObserved)
388 return false;
389
390 m_pList->ScrollToListItem(m_nSelectItem);
391 if (!thisObserved)
392 return false;
393 }
394 return true;
395 }
396
397 CFX_FloatRect rcButton = rcClient;
398 rcButton.left = std::max(rcButton.right - kDefaultButtonWidth, rcClient.left);
399
400 if (m_pButton) {
401 m_pButton->Move(rcButton, true, false);
402 if (!thisObserved)
403 return false;
404 }
405
406 CFX_FloatRect rcEdit = rcClient;
407 rcEdit.right = std::max(rcButton.left - 1.0f, rcEdit.left);
408
409 if (m_pEdit) {
410 m_pEdit->Move(rcEdit, true, false);
411 if (!thisObserved)
412 return false;
413 }
414
415 if (m_pList) {
416 m_pList->SetVisible(false);
417 if (!thisObserved)
418 return false;
419 }
420
421 return true;
422 }
423
SelectAll()424 void CPWL_ComboBox::SelectAll() {
425 if (m_pEdit && HasFlag(PCBS_ALLOWCUSTOMTEXT))
426 m_pEdit->SelectAll();
427 }
428
GetFocusRect() const429 CFX_FloatRect CPWL_ComboBox::GetFocusRect() const {
430 return CFX_FloatRect();
431 }
432
SetPopup(bool bPopup)433 bool CPWL_ComboBox::SetPopup(bool bPopup) {
434 if (!m_pList)
435 return true;
436 if (bPopup == m_bPopup)
437 return true;
438 float fListHeight = m_pList->GetContentRect().Height();
439 if (!IsFloatBigger(fListHeight, 0.0f))
440 return true;
441
442 if (!bPopup) {
443 m_bPopup = bPopup;
444 return Move(m_rcOldWindow, true, true);
445 }
446
447 if (!m_pFillerNotify)
448 return true;
449
450 ObservedPtr<CPWL_ComboBox> thisObserved(this);
451 if (m_pFillerNotify->OnPopupPreOpen(GetAttachedData(), 0))
452 return !!thisObserved;
453 if (!thisObserved)
454 return false;
455
456 float fBorderWidth = m_pList->GetBorderWidth() * 2;
457 float fPopupMin = 0.0f;
458 if (m_pList->GetCount() > 3)
459 fPopupMin = m_pList->GetFirstHeight() * 3 + fBorderWidth;
460 float fPopupMax = fListHeight + fBorderWidth;
461
462 bool bBottom;
463 float fPopupRet;
464 m_pFillerNotify->QueryWherePopup(GetAttachedData(), fPopupMin, fPopupMax,
465 &bBottom, &fPopupRet);
466 if (!IsFloatBigger(fPopupRet, 0.0f))
467 return true;
468
469 m_rcOldWindow = CPWL_Wnd::GetWindowRect();
470 m_bPopup = bPopup;
471 m_bBottom = bBottom;
472
473 CFX_FloatRect rcWindow = m_rcOldWindow;
474 if (bBottom)
475 rcWindow.bottom -= fPopupRet;
476 else
477 rcWindow.top += fPopupRet;
478
479 if (!Move(rcWindow, true, true))
480 return false;
481
482 m_pFillerNotify->OnPopupPostOpen(GetAttachedData(), 0);
483 return !!thisObserved;
484 }
485
OnKeyDown(uint16_t nChar,uint32_t nFlag)486 bool CPWL_ComboBox::OnKeyDown(uint16_t nChar, uint32_t nFlag) {
487 if (!m_pList)
488 return false;
489 if (!m_pEdit)
490 return false;
491
492 m_nSelectItem = -1;
493
494 switch (nChar) {
495 case FWL_VKEY_Up:
496 if (m_pList->GetCurSel() > 0) {
497 if (m_pFillerNotify) {
498 if (m_pFillerNotify->OnPopupPreOpen(GetAttachedData(), nFlag))
499 return false;
500 if (m_pFillerNotify->OnPopupPostOpen(GetAttachedData(), nFlag))
501 return false;
502 }
503 if (m_pList->IsMovementKey(nChar)) {
504 if (m_pList->OnMovementKeyDown(nChar, nFlag))
505 return false;
506 SetSelectText();
507 }
508 }
509 return true;
510 case FWL_VKEY_Down:
511 if (m_pList->GetCurSel() < m_pList->GetCount() - 1) {
512 if (m_pFillerNotify) {
513 if (m_pFillerNotify->OnPopupPreOpen(GetAttachedData(), nFlag))
514 return false;
515 if (m_pFillerNotify->OnPopupPostOpen(GetAttachedData(), nFlag))
516 return false;
517 }
518 if (m_pList->IsMovementKey(nChar)) {
519 if (m_pList->OnMovementKeyDown(nChar, nFlag))
520 return false;
521 SetSelectText();
522 }
523 }
524 return true;
525 }
526
527 if (HasFlag(PCBS_ALLOWCUSTOMTEXT))
528 return m_pEdit->OnKeyDown(nChar, nFlag);
529
530 return false;
531 }
532
OnChar(uint16_t nChar,uint32_t nFlag)533 bool CPWL_ComboBox::OnChar(uint16_t nChar, uint32_t nFlag) {
534 if (!m_pList)
535 return false;
536
537 if (!m_pEdit)
538 return false;
539
540 m_nSelectItem = -1;
541 if (HasFlag(PCBS_ALLOWCUSTOMTEXT))
542 return m_pEdit->OnChar(nChar, nFlag);
543
544 if (m_pFillerNotify) {
545 if (m_pFillerNotify->OnPopupPreOpen(GetAttachedData(), nFlag))
546 return false;
547 if (m_pFillerNotify->OnPopupPostOpen(GetAttachedData(), nFlag))
548 return false;
549 }
550 if (!m_pList->IsChar(nChar, nFlag))
551 return false;
552 return m_pList->OnCharNotify(nChar, nFlag);
553 }
554
NotifyLButtonDown(CPWL_Wnd * child,const CFX_PointF & pos)555 void CPWL_ComboBox::NotifyLButtonDown(CPWL_Wnd* child, const CFX_PointF& pos) {
556 if (child == m_pButton) {
557 SetPopup(!m_bPopup);
558 // Note, |this| may no longer be viable at this point. If more work needs to
559 // be done, check the return value of SetPopup().
560 }
561 }
562
NotifyLButtonUp(CPWL_Wnd * child,const CFX_PointF & pos)563 void CPWL_ComboBox::NotifyLButtonUp(CPWL_Wnd* child, const CFX_PointF& pos) {
564 if (!m_pEdit || !m_pList || child != m_pList)
565 return;
566
567 SetSelectText();
568 SelectAll();
569 m_pEdit->SetFocus();
570 SetPopup(false);
571 // Note, |this| may no longer be viable at this point. If more work needs to
572 // be done, check the return value of SetPopup().
573 }
574
IsPopup() const575 bool CPWL_ComboBox::IsPopup() const {
576 return m_bPopup;
577 }
578
SetSelectText()579 void CPWL_ComboBox::SetSelectText() {
580 m_pEdit->SelectAll();
581 m_pEdit->ReplaceSelection(m_pList->GetText());
582 m_pEdit->SelectAll();
583 m_nSelectItem = m_pList->GetCurSel();
584 }
585
SetFillerNotify(IPWL_Filler_Notify * pNotify)586 void CPWL_ComboBox::SetFillerNotify(IPWL_Filler_Notify* pNotify) {
587 m_pFillerNotify = pNotify;
588
589 if (m_pEdit)
590 m_pEdit->SetFillerNotify(pNotify);
591
592 if (m_pList)
593 m_pList->SetFillerNotify(pNotify);
594 }
595