1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include "mmaddressblockpage.hxx"
21 #include <mailmergewizard.hxx>
22 #include <swtypes.hxx>
23 #include "addresslistdialog.hxx"
24 #include <editeng/eeitem.hxx>
25 #include <o3tl/safeint.hxx>
26 #include <svl/grabbagitem.hxx>
27 #include <svl/itemset.hxx>
28 #include <vcl/event.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/weld.hxx>
31 #include <vcl/transfer.hxx>
32 #include <mmconfigitem.hxx>
33 #include <com/sun/star/container/XNameAccess.hpp>
34 #include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
35 #include <com/sun/star/sdbc/SQLException.hpp>
36 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
37 #include <com/sun/star/sdb/XColumn.hpp>
38 #include <comphelper/sequence.hxx>
39 #include <comphelper/string.hxx>
40 #include <tools/diagnose_ex.h>
41 
42 #include <vector>
43 #include <strings.hrc>
44 #include <mmaddressblockpage.hrc>
45 #include <helpids.h>
46 
47 using namespace ::com::sun::star;
48 using namespace ::com::sun::star::container;
49 using namespace ::com::sun::star::sdb;
50 using namespace ::com::sun::star::sdbc;
51 using namespace ::com::sun::star::sdbcx;
52 
SwMailMergeAddressBlockPage(weld::Container * pPage,SwMailMergeWizard * pWizard)53 SwMailMergeAddressBlockPage::SwMailMergeAddressBlockPage(weld::Container* pPage, SwMailMergeWizard* pWizard)
54     : vcl::OWizardPage(pPage, pWizard, "modules/swriter/ui/mmaddressblockpage.ui", "MMAddressBlockPage")
55     , m_pWizard(pWizard)
56     , m_xAddressListPB(m_xBuilder->weld_button("addresslist"))
57     , m_xCurrentAddressFI(m_xBuilder->weld_label("currentaddress"))
58     , m_xStep2(m_xBuilder->weld_container("step2"))
59     , m_xStep3(m_xBuilder->weld_container("step3"))
60     , m_xStep4(m_xBuilder->weld_container("step4"))
61     , m_xSettingsFI(m_xBuilder->weld_label("settingsft"))
62     , m_xAddressCB(m_xBuilder->weld_check_button("address"))
63     , m_xSettingsPB(m_xBuilder->weld_button("settings"))
64     , m_xHideEmptyParagraphsCB(m_xBuilder->weld_check_button("hideempty"))
65     , m_xAssignPB(m_xBuilder->weld_button("assign"))
66     , m_xDocumentIndexFI(m_xBuilder->weld_label("documentindex"))
67     , m_xPrevSetIB(m_xBuilder->weld_button("prev"))
68     , m_xNextSetIB(m_xBuilder->weld_button("next"))
69     , m_xDifferentlist(m_xBuilder->weld_button("differentlist"))
70     , m_xSettings(new SwAddressPreview(m_xBuilder->weld_scrolled_window("settingspreviewwin", true)))
71     , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("addresspreviewwin", true)))
72     , m_xSettingsWIN(new weld::CustomWeld(*m_xBuilder, "settingspreview", *m_xSettings))
73     , m_xPreviewWIN(new weld::CustomWeld(*m_xBuilder, "addresspreview", *m_xPreview))
74 {
75     m_xSettingsWIN->set_size_request(m_xDifferentlist->get_approximate_digit_width() * 40,
76                                      m_xDifferentlist->get_text_height() * 6);
77     m_xPreviewWIN->set_size_request(m_xDifferentlist->get_approximate_digit_width() * 44,
78                                     m_xDifferentlist->get_text_height() * 6);
79     m_sChangeAddress = m_xDifferentlist->get_label();
80     m_sDocument = m_xDocumentIndexFI->get_label();
81 
82     m_sCurrentAddress = m_xCurrentAddressFI->get_label();
83     m_xAddressListPB->connect_clicked(LINK(this, SwMailMergeAddressBlockPage, AddressListHdl_Impl));
84     m_xSettingsPB->connect_clicked(LINK(this, SwMailMergeAddressBlockPage, SettingsHdl_Impl));
85     m_xAssignPB->connect_clicked(LINK(this, SwMailMergeAddressBlockPage, AssignHdl_Impl ));
86     m_xAddressCB->connect_toggled(LINK(this, SwMailMergeAddressBlockPage, AddressBlockHdl_Impl));
87     m_xSettings->SetSelectHdl(LINK(this, SwMailMergeAddressBlockPage, AddressBlockSelectHdl_Impl));
88     m_xHideEmptyParagraphsCB->connect_toggled(LINK(this, SwMailMergeAddressBlockPage, HideParagraphsHdl_Impl));
89 
90     Link<weld::Button&,void> aLink = LINK(this, SwMailMergeAddressBlockPage, InsertDataHdl_Impl);
91     m_xPrevSetIB->connect_clicked(aLink);
92     m_xNextSetIB->connect_clicked(aLink);
93 
94     // lock in preferred size including current address line
95     Size aSize1(m_xContainer->get_preferred_size());
96 
97     OUString sOrigLabel = m_xAddressListPB->get_label();
98     m_xAddressListPB->set_label(m_sChangeAddress);
99     Size aSize2(m_xContainer->get_preferred_size());
100     m_xAddressListPB->set_label(sOrigLabel);
101 
102     m_xCurrentAddressFI->hide();
103 
104     m_xContainer->set_size_request(std::max(aSize1.Width(), aSize2.Width()),
105                                    std::max(aSize1.Height(), aSize2.Height()));
106 }
107 
~SwMailMergeAddressBlockPage()108 SwMailMergeAddressBlockPage::~SwMailMergeAddressBlockPage()
109 {
110     m_xPreviewWIN.reset();
111     m_xSettingsWIN.reset();
112     m_xPreview.reset();
113     m_xSettings.reset();
114 }
115 
canAdvance() const116 bool SwMailMergeAddressBlockPage::canAdvance() const
117 {
118     return m_pWizard->GetConfigItem().GetResultSet().is();
119 }
120 
Activate()121 void SwMailMergeAddressBlockPage::Activate()
122 {
123     SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem();
124     bool bIsLetter = rConfigItem.IsOutputToLetter();
125 
126     //no address block is created for e-Mail
127     m_xStep2->set_visible(bIsLetter);
128     m_xStep3->set_visible(bIsLetter);
129     m_xStep4->set_visible(bIsLetter);
130 
131     if (!bIsLetter)
132         return;
133 
134     m_xHideEmptyParagraphsCB->set_active( rConfigItem.IsHideEmptyParagraphs() );
135     m_xDocumentIndexFI->set_label(m_sDocument.replaceFirst("%1", "1"));
136 
137     m_xSettings->Clear();
138     const uno::Sequence< OUString> aBlocks =
139                 m_pWizard->GetConfigItem().GetAddressBlocks();
140     for(const auto& rAddress : aBlocks)
141         m_xSettings->AddAddress(rAddress);
142     m_xSettings->SelectAddress(o3tl::narrowing<sal_uInt16>(rConfigItem.GetCurrentAddressBlockIndex()));
143     m_xAddressCB->set_active(rConfigItem.IsAddressBlock());
144     AddressBlockHdl_Impl(*m_xAddressCB);
145     m_xSettings->SetLayout(1, 2);
146     InsertDataHdl(nullptr);
147 }
148 
commitPage(::vcl::WizardTypes::CommitPageReason _eReason)149 bool SwMailMergeAddressBlockPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason )
150 {
151     return ::vcl::WizardTypes::eTravelForward != _eReason || m_pWizard->GetConfigItem().GetResultSet().is();
152 }
153 
IMPL_LINK_NOARG(SwMailMergeAddressBlockPage,AddressListHdl_Impl,weld::Button &,void)154 IMPL_LINK_NOARG(SwMailMergeAddressBlockPage, AddressListHdl_Impl, weld::Button&, void)
155 {
156     try
157     {
158         SwAddressListDialog aAddrDialog(this);
159         if (RET_OK == aAddrDialog.run())
160         {
161             SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem();
162             rConfigItem.SetCurrentConnection(
163                             aAddrDialog.GetSource(),
164                             aAddrDialog.GetConnection(),
165                             aAddrDialog.GetColumnsSupplier(),
166                             aAddrDialog.GetDBData());
167             OUString sFilter = aAddrDialog.GetFilter();
168             rConfigItem.SetFilter( sFilter );
169             InsertDataHdl(nullptr);
170             GetWizard()->UpdateRoadmap();
171             GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE));
172         }
173     }
174     catch (const uno::Exception& e)
175     {
176         TOOLS_WARN_EXCEPTION("sw", "");
177         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_pWizard->getDialog(),
178                                                   VclMessageType::Warning, VclButtonsType::Ok, e.Message));
179         xBox->run();
180     }
181 }
182 
IMPL_LINK_NOARG(SwMailMergeAddressBlockPage,SettingsHdl_Impl,weld::Button &,void)183 IMPL_LINK_NOARG(SwMailMergeAddressBlockPage, SettingsHdl_Impl, weld::Button&, void)
184 {
185     SwSelectAddressBlockDialog aDlg(m_pWizard->getDialog(), m_pWizard->GetConfigItem());
186     SwMailMergeConfigItem& rConfig = m_pWizard->GetConfigItem();
187     aDlg.SetAddressBlocks(rConfig.GetAddressBlocks(), m_xSettings->GetSelectedAddress());
188     aDlg.SetSettings(rConfig.IsIncludeCountry(), rConfig.GetExcludeCountry());
189     if (aDlg.run() == RET_OK)
190     {
191         //the dialog provides the selected address at the first position!
192         const uno::Sequence< OUString> aBlocks = aDlg.GetAddressBlocks();
193         rConfig.SetAddressBlocks(aBlocks);
194         m_xSettings->Clear();
195         for(const auto& rAddress : aBlocks)
196             m_xSettings->AddAddress(rAddress);
197         m_xSettings->SelectAddress(0);
198         m_xSettings->Invalidate();    // #i40408
199         rConfig.SetCountrySettings(aDlg.IsIncludeCountry(), aDlg.GetCountry());
200         InsertDataHdl(nullptr);
201     }
202     GetWizard()->UpdateRoadmap();
203     GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE));
204 }
205 
IMPL_LINK_NOARG(SwMailMergeAddressBlockPage,AssignHdl_Impl,weld::Button &,void)206 IMPL_LINK_NOARG(SwMailMergeAddressBlockPage, AssignHdl_Impl, weld::Button&, void)
207 {
208     SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem();
209     const sal_uInt16 nSel = m_xSettings->GetSelectedAddress();
210     const uno::Sequence< OUString> aBlocks = rConfigItem.GetAddressBlocks();
211     SwAssignFieldsDialog aDlg(m_pWizard->getDialog(), m_pWizard->GetConfigItem(), aBlocks[nSel], true);
212     if(RET_OK == aDlg.run())
213     {
214         //preview update
215         InsertDataHdl(nullptr);
216         GetWizard()->UpdateRoadmap();
217         GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE));
218     }
219 }
220 
EnableAddressBlock(bool bAll,bool bSelective)221 void SwMailMergeAddressBlockPage::EnableAddressBlock(bool bAll, bool bSelective)
222 {
223     m_xSettingsFI->set_sensitive(bAll);
224     m_xAddressCB->set_sensitive(bAll);
225     bSelective &= bAll;
226     m_xHideEmptyParagraphsCB->set_sensitive(bSelective);
227     m_xSettingsWIN->set_sensitive(bSelective);
228     m_xSettingsPB->set_sensitive(bSelective);
229     m_xStep3->set_sensitive(bSelective);
230     m_xStep4->set_sensitive(bSelective);
231 }
232 
IMPL_LINK(SwMailMergeAddressBlockPage,AddressBlockHdl_Impl,weld::Toggleable &,rBox,void)233 IMPL_LINK(SwMailMergeAddressBlockPage, AddressBlockHdl_Impl, weld::Toggleable&, rBox, void)
234 {
235     EnableAddressBlock(rBox.get_sensitive(), rBox.get_active());
236     SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem();
237     rConfigItem.SetAddressBlock(m_xAddressCB->get_active());
238     m_pWizard->UpdateRoadmap();
239     GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE));
240 }
241 
IMPL_LINK_NOARG(SwMailMergeAddressBlockPage,AddressBlockSelectHdl_Impl,LinkParamNone *,void)242 IMPL_LINK_NOARG(SwMailMergeAddressBlockPage, AddressBlockSelectHdl_Impl, LinkParamNone*, void)
243 {
244     const sal_uInt16 nSel = m_xSettings->GetSelectedAddress();
245     const uno::Sequence< OUString> aBlocks =
246                 m_pWizard->GetConfigItem().GetAddressBlocks();
247     m_xPreview->SetAddress(SwAddressPreview::FillData(aBlocks[nSel],
248                                                          m_pWizard->GetConfigItem()));
249     m_pWizard->GetConfigItem().SetCurrentAddressBlockIndex( nSel );
250     GetWizard()->UpdateRoadmap();
251     GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE));
252 }
253 
IMPL_LINK(SwMailMergeAddressBlockPage,HideParagraphsHdl_Impl,weld::Toggleable &,rBox,void)254 IMPL_LINK(SwMailMergeAddressBlockPage, HideParagraphsHdl_Impl, weld::Toggleable&, rBox, void)
255 {
256     SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem();
257     rConfigItem.SetHideEmptyParagraphs(rBox.get_active());
258 }
259 
InsertDataHdl(const weld::Button * pButton)260 void SwMailMergeAddressBlockPage::InsertDataHdl(const weld::Button* pButton)
261 {
262     //if no pButton is given, the first set has to be pre-set
263     SwMailMergeConfigItem& rConfig = m_pWizard->GetConfigItem();
264     std::unique_ptr<weld::WaitObject> xWaitObj(new weld::WaitObject(m_pWizard->getDialog()));
265     if(!pButton)
266     {
267         rConfig.GetResultSet();
268     }
269     else
270     {
271         bool bNext = pButton == m_xNextSetIB.get();
272         sal_Int32 nPos = rConfig.GetResultSetPosition();
273         rConfig.MoveResultSet( bNext ? ++nPos : --nPos);
274     }
275     xWaitObj.reset();
276     sal_Int32 nPos = rConfig.GetResultSetPosition();
277     bool bEnable = true;
278     if(nPos < 1)
279     {
280         bEnable = false;
281         nPos = 1;
282     }
283     else
284     {
285         //if output type is letter
286         if (m_xSettings->IsVisible())
287         {
288             //Fill data into preview
289             const sal_uInt16 nSel = m_xSettings->GetSelectedAddress();
290             const uno::Sequence< OUString> aBlocks =
291                         m_pWizard->GetConfigItem().GetAddressBlocks();
292             m_xPreview->SetAddress(SwAddressPreview::FillData(aBlocks[nSel], rConfig));
293         }
294     }
295     m_xPrevSetIB->set_sensitive(bEnable);
296     m_xDocumentIndexFI->set_label(m_sDocument.replaceFirst("%1", OUString::number(nPos)));
297 
298     GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE));
299     bool bHasResultSet = rConfig.GetResultSet().is();
300     m_xCurrentAddressFI->set_visible(bHasResultSet);
301     if(bHasResultSet)
302     {
303         m_xCurrentAddressFI->set_label(m_sCurrentAddress.replaceFirst("%1", rConfig.GetCurrentDBData().sDataSource));
304         m_xAddressListPB->set_label(m_sChangeAddress);
305     }
306     EnableAddressBlock(bHasResultSet, m_xAddressCB->get_active());
307 }
308 
IMPL_LINK(SwMailMergeAddressBlockPage,InsertDataHdl_Impl,weld::Button &,rButton,void)309 IMPL_LINK(SwMailMergeAddressBlockPage, InsertDataHdl_Impl, weld::Button&, rButton, void)
310 {
311     InsertDataHdl(&rButton);
312 }
313 
SwSelectAddressBlockDialog(weld::Window * pParent,SwMailMergeConfigItem & rConfig)314 SwSelectAddressBlockDialog::SwSelectAddressBlockDialog(weld::Window* pParent, SwMailMergeConfigItem& rConfig)
315     : SfxDialogController(pParent, "modules/swriter/ui/selectblockdialog.ui", "SelectBlockDialog")
316     , m_rConfig(rConfig)
317     , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("previewwin", true)))
318     , m_xNewPB(m_xBuilder->weld_button("new"))
319     , m_xCustomizePB(m_xBuilder->weld_button("edit"))
320     , m_xDeletePB(m_xBuilder->weld_button("delete"))
321     , m_xNeverRB(m_xBuilder->weld_radio_button("never"))
322     , m_xAlwaysRB(m_xBuilder->weld_radio_button("always"))
323     , m_xDependentRB(m_xBuilder->weld_radio_button("dependent"))
324     , m_xCountryED(m_xBuilder->weld_entry("country"))
325     , m_xPreviewWin(new weld::CustomWeld(*m_xBuilder, "preview", *m_xPreview))
326 {
327     m_xPreviewWin->set_size_request(m_xCountryED->get_approximate_digit_width() * 45,
328                                     m_xCountryED->get_text_height() * 12);
329 
330     Link<weld::Button&,void> aCustomizeHdl = LINK(this, SwSelectAddressBlockDialog, NewCustomizeHdl_Impl);
331     m_xNewPB->connect_clicked(aCustomizeHdl);
332     m_xCustomizePB->connect_clicked(aCustomizeHdl);
333 
334     m_xDeletePB->connect_clicked(LINK(this, SwSelectAddressBlockDialog, DeleteHdl_Impl));
335 
336     Link<weld::Toggleable&,void> aLk = LINK(this, SwSelectAddressBlockDialog, IncludeHdl_Impl);
337     m_xNeverRB->connect_toggled(aLk);
338     m_xAlwaysRB->connect_toggled(aLk);
339     m_xDependentRB->connect_toggled(aLk);
340     m_xPreview->SetLayout(2, 2);
341     m_xPreview->EnableScrollBar();
342 }
343 
~SwSelectAddressBlockDialog()344 SwSelectAddressBlockDialog::~SwSelectAddressBlockDialog()
345 {
346 }
347 
SetAddressBlocks(const uno::Sequence<OUString> & rBlocks,sal_uInt16 nSelectedAddress)348 void SwSelectAddressBlockDialog::SetAddressBlocks(const uno::Sequence< OUString>& rBlocks,
349         sal_uInt16 nSelectedAddress)
350 {
351     m_aAddressBlocks = rBlocks;
352     for (const auto& rAddressBlock : std::as_const(m_aAddressBlocks))
353         m_xPreview->AddAddress(rAddressBlock);
354     m_xPreview->SelectAddress(nSelectedAddress);
355 }
356 
357 // return the address blocks and put the selected one to the first position
GetAddressBlocks()358 const uno::Sequence< OUString >&    SwSelectAddressBlockDialog::GetAddressBlocks()
359 {
360     //put the selected block to the first position
361     const sal_Int32 nSelect = static_cast<sal_Int32>(m_xPreview->GetSelectedAddress());
362     if(nSelect)
363     {
364         uno::Sequence< OUString >aTemp = m_aAddressBlocks;
365         aTemp[0] = m_aAddressBlocks[nSelect];
366         std::copy(m_aAddressBlocks.begin(), std::next(m_aAddressBlocks.begin(), nSelect), std::next(aTemp.begin()));
367         std::copy(std::next(m_aAddressBlocks.begin(), nSelect + 1), m_aAddressBlocks.end(), std::next(aTemp.begin(), nSelect + 1));
368         m_aAddressBlocks = aTemp;
369     }
370     return m_aAddressBlocks;
371 }
372 
SetSettings(bool bIsCountry,const OUString & rCountry)373 void SwSelectAddressBlockDialog::SetSettings(
374         bool bIsCountry, const OUString& rCountry)
375 {
376     weld::RadioButton *pActive = m_xNeverRB.get();
377     if(bIsCountry)
378     {
379         pActive = !rCountry.isEmpty() ? m_xDependentRB.get() : m_xAlwaysRB.get();
380         m_xCountryED->set_text(rCountry);
381     }
382     pActive->set_active(true);
383     IncludeHdl_Impl(*pActive);
384     m_xDeletePB->set_sensitive(m_aAddressBlocks.getLength() > 1);
385 }
386 
GetCountry() const387 OUString SwSelectAddressBlockDialog::GetCountry() const
388 {
389     if (m_xDependentRB->get_active())
390         return m_xCountryED->get_text();
391     return OUString();
392 }
393 
IMPL_LINK(SwSelectAddressBlockDialog,DeleteHdl_Impl,weld::Button &,rButton,void)394 IMPL_LINK(SwSelectAddressBlockDialog, DeleteHdl_Impl, weld::Button&, rButton, void)
395 {
396     if (m_aAddressBlocks.getLength())
397     {
398         const sal_Int32 nSelected = static_cast<sal_Int32>(m_xPreview->GetSelectedAddress());
399         comphelper::removeElementAt(m_aAddressBlocks, nSelected);
400         if (m_aAddressBlocks.getLength() <= 1)
401             rButton.set_sensitive(false);
402         m_xPreview->RemoveSelectedAddress();
403     }
404 }
405 
IMPL_LINK(SwSelectAddressBlockDialog,NewCustomizeHdl_Impl,weld::Button &,rButton,void)406 IMPL_LINK(SwSelectAddressBlockDialog, NewCustomizeHdl_Impl, weld::Button&, rButton, void)
407 {
408     bool bCustomize = &rButton == m_xCustomizePB.get();
409     SwCustomizeAddressBlockDialog::DialogType nType = bCustomize ?
410         SwCustomizeAddressBlockDialog::ADDRESSBLOCK_EDIT :
411         SwCustomizeAddressBlockDialog::ADDRESSBLOCK_NEW;
412     std::unique_ptr<SwCustomizeAddressBlockDialog> xDlg(new SwCustomizeAddressBlockDialog(&rButton,
413             m_rConfig, nType));
414     if(bCustomize)
415     {
416         xDlg->SetAddress(m_aAddressBlocks[m_xPreview->GetSelectedAddress()]);
417     }
418     if (RET_OK != xDlg->run())
419         return;
420 
421     const OUString sNew = xDlg->GetAddress();
422     if(bCustomize)
423     {
424         m_xPreview->ReplaceSelectedAddress(sNew);
425         m_aAddressBlocks[m_xPreview->GetSelectedAddress()] = sNew;
426     }
427     else
428     {
429         m_xPreview->AddAddress(sNew);
430         m_aAddressBlocks.realloc(m_aAddressBlocks.getLength() + 1);
431         const sal_Int32 nSelect = m_aAddressBlocks.getLength() - 1;
432         m_aAddressBlocks[nSelect] = sNew;
433         m_xPreview->SelectAddress(o3tl::narrowing<sal_uInt16>(nSelect));
434     }
435     m_xDeletePB->set_sensitive(m_aAddressBlocks.getLength() > 1);
436 }
437 
IMPL_LINK_NOARG(SwSelectAddressBlockDialog,IncludeHdl_Impl,weld::Toggleable &,void)438 IMPL_LINK_NOARG(SwSelectAddressBlockDialog, IncludeHdl_Impl, weld::Toggleable&,  void)
439 {
440     m_xCountryED->set_sensitive(m_xDependentRB->get_active());
441 }
442 
443 #define USER_DATA_SALUTATION        -1
444 #define USER_DATA_PUNCTUATION       -2
445 #define USER_DATA_TEXT              -3
446 #define USER_DATA_NONE              -4
447 
IMPL_LINK(SwCustomizeAddressBlockDialog,TextFilterHdl,OUString &,rTest,bool)448 IMPL_LINK(SwCustomizeAddressBlockDialog, TextFilterHdl, OUString&, rTest, bool)
449 {
450     rTest = m_aTextFilter.filter(rTest);
451     return true;
452 }
453 
SwCustomizeAddressBlockDialog(weld::Widget * pParent,SwMailMergeConfigItem & rConfig,DialogType eType)454 SwCustomizeAddressBlockDialog::SwCustomizeAddressBlockDialog(
455         weld::Widget* pParent, SwMailMergeConfigItem& rConfig, DialogType eType)
456     : SfxDialogController(pParent, "modules/swriter/ui/addressblockdialog.ui",
457                           "AddressBlockDialog")
458     , m_aTextFilter("<>")
459     , m_rConfigItem(rConfig)
460     , m_eType(eType)
461     , m_xAddressElementsFT(m_xBuilder->weld_label("addressesft"))
462     , m_xAddressElementsLB(m_xBuilder->weld_tree_view("addresses"))
463     , m_xInsertFieldIB(m_xBuilder->weld_button("toaddr"))
464     , m_xRemoveFieldIB(m_xBuilder->weld_button("fromaddr"))
465     , m_xDragFT(m_xBuilder->weld_label("addressdestft"))
466     , m_xUpIB(m_xBuilder->weld_button("up"))
467     , m_xLeftIB(m_xBuilder->weld_button("left"))
468     , m_xRightIB(m_xBuilder->weld_button("right"))
469     , m_xDownIB(m_xBuilder->weld_button("down"))
470     , m_xFieldFT(m_xBuilder->weld_label("customft"))
471     , m_xFieldCB(m_xBuilder->weld_combo_box("custom"))
472     , m_xOK(m_xBuilder->weld_button("ok"))
473     , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("previewwin", true)))
474     , m_xPreviewWIN(new weld::CustomWeld(*m_xBuilder, "addrpreview", *m_xPreview))
475     , m_xDragED(new AddressMultiLineEdit(this))
476     , m_xDragWIN(new weld::CustomWeld(*m_xBuilder, "addressdest", *m_xDragED))
477 {
478     m_aSelectionChangedIdle.SetInvokeHandler( LINK( this, SwCustomizeAddressBlockDialog, SelectionChangedIdleHdl ) );
479 
480     Size aSize(m_xDragED->GetDrawingArea()->get_size_request());
481     m_xPreview->set_size_request(aSize.Width(), aSize.Height());
482 
483     m_xFieldCB->connect_entry_insert_text(LINK(this, SwCustomizeAddressBlockDialog, TextFilterHdl));
484     m_xAddressElementsLB->set_size_request(-1, m_xAddressElementsLB->get_height_rows(16));
485 
486     if( eType >= GREETING_FEMALE )
487     {
488         m_xFieldFT->show();
489         m_xFieldCB->show();
490         m_xAddressElementsLB->append(OUString::number(USER_DATA_SALUTATION), SwResId(ST_SALUTATION));
491         m_xAddressElementsLB->append(OUString::number(USER_DATA_PUNCTUATION), SwResId(ST_PUNCTUATION));
492         m_xAddressElementsLB->append(OUString::number(USER_DATA_TEXT), SwResId(ST_TEXT));
493         for (size_t i = 0; i < SAL_N_ELEMENTS(RA_SALUTATION); ++i)
494             m_aSalutations.push_back(SwResId(RA_SALUTATION[i]));
495         for (size_t i = 0; i < SAL_N_ELEMENTS(RA_PUNCTUATION); ++i)
496             m_aPunctuations.push_back(SwResId(RA_PUNCTUATION[i]));
497         m_xDragED->SetText("            ");
498         m_xDialog->set_title(SwResId(eType == GREETING_MALE ? ST_TITLE_MALE : ST_TITLE_FEMALE));
499         m_xAddressElementsFT->set_label(SwResId(ST_SALUTATIONELEMENTS));
500         m_xInsertFieldIB->set_tooltip_text(SwResId(ST_INSERTSALUTATIONFIELD));
501         m_xRemoveFieldIB->set_tooltip_text(SwResId(ST_REMOVESALUTATIONFIELD));
502         m_xDragFT->set_label(SwResId(ST_DRAGSALUTATION));
503     }
504     else
505     {
506         if (eType == ADDRESSBLOCK_EDIT)
507             m_xDialog->set_title(SwResId(ST_TITLE_EDIT));
508         m_xDragED->SetText("\n\n\n\n\n");
509         /* Set custom HIDs for swriter/01/mm_newaddblo.xhp */
510         m_xAddressElementsLB->set_help_id( HID_MM_ADDBLOCK_ELEMENTS );
511         m_xInsertFieldIB->set_help_id( HID_MM_ADDBLOCK_INSERT );
512         m_xRemoveFieldIB->set_help_id( HID_MM_ADDBLOCK_REMOVE );
513         m_xDragWIN->set_help_id( HID_MM_ADDBLOCK_DRAG );
514         m_xPreviewWIN->set_help_id( HID_MM_ADDBLOCK_PREVIEW );
515         m_xRightIB->set_help_id( HID_MM_ADDBLOCK_MOVEBUTTONS );
516         m_xLeftIB->set_help_id( HID_MM_ADDBLOCK_MOVEBUTTONS );
517         m_xDownIB->set_help_id( HID_MM_ADDBLOCK_MOVEBUTTONS );
518         m_xUpIB->set_help_id( HID_MM_ADDBLOCK_MOVEBUTTONS );
519     }
520 
521     const std::vector<std::pair<OUString, int>>& rHeaders = m_rConfigItem.GetDefaultAddressHeaders();
522     for (size_t i = 0; i < rHeaders.size(); ++i)
523         m_xAddressElementsLB->append(OUString::number(i), rHeaders[i].first);
524     m_xOK->connect_clicked(LINK(this, SwCustomizeAddressBlockDialog, OKHdl_Impl));
525     m_xAddressElementsLB->connect_changed(LINK(this, SwCustomizeAddressBlockDialog, ListBoxSelectHdl_Impl));
526     if (m_xAddressElementsLB->n_children())
527         m_xAddressElementsLB->select(0);
528     m_xDragED->SetModifyHdl(LINK(this, SwCustomizeAddressBlockDialog, EditModifyHdl_Impl));
529     m_xDragED->SetSelectionChangedHdl( LINK( this, SwCustomizeAddressBlockDialog, SelectionChangedHdl_Impl));
530     m_xFieldCB->connect_changed(LINK(this, SwCustomizeAddressBlockDialog, FieldChangeComboBoxHdl_Impl));
531     Link<weld::Button&,void> aImgButtonHdl = LINK(this, SwCustomizeAddressBlockDialog, ImageButtonHdl_Impl);
532     m_xInsertFieldIB->connect_clicked(aImgButtonHdl);
533     m_xRemoveFieldIB->connect_clicked(aImgButtonHdl);
534     m_xUpIB->connect_clicked(aImgButtonHdl);
535     m_xLeftIB->connect_clicked(aImgButtonHdl);
536     m_xRightIB->connect_clicked(aImgButtonHdl);
537     m_xDownIB->connect_clicked(aImgButtonHdl);
538     UpdateImageButtons_Impl();
539 }
540 
SetCursorLogicPosition(const Point & rPosition)541 bool SwCustomizeAddressBlockDialog::SetCursorLogicPosition(const Point& rPosition)
542 {
543     return m_xDragED->SetCursorLogicPosition(rPosition);
544 }
545 
UpdateFields()546 void SwCustomizeAddressBlockDialog::UpdateFields()
547 {
548     m_xDragED->UpdateFields();
549 }
550 
~SwCustomizeAddressBlockDialog()551 SwCustomizeAddressBlockDialog::~SwCustomizeAddressBlockDialog()
552 {
553     m_xDragED->EndDropTarget();
554 }
555 
IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog,OKHdl_Impl,weld::Button &,void)556 IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog, OKHdl_Impl, weld::Button&, void)
557 {
558     m_xDialog->response(RET_OK);
559 }
560 
IMPL_LINK(SwCustomizeAddressBlockDialog,ListBoxSelectHdl_Impl,weld::TreeView &,rBox,void)561 IMPL_LINK(SwCustomizeAddressBlockDialog, ListBoxSelectHdl_Impl, weld::TreeView&, rBox, void)
562 {
563     sal_Int32 nUserData = rBox.get_selected_id().toInt32();
564     // Check if the selected entry is already in the address and then forbid inserting
565     m_xInsertFieldIB->set_sensitive(nUserData >= 0 || !HasItem(nUserData));
566 }
567 
IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog,EditModifyHdl_Impl,AddressMultiLineEdit &,void)568 IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog, EditModifyHdl_Impl, AddressMultiLineEdit&, void)
569 {
570     m_xPreview->SetAddress(SwAddressPreview::FillData(GetAddress(), m_rConfigItem));
571     UpdateImageButtons_Impl();
572 }
573 
IMPL_LINK(SwCustomizeAddressBlockDialog,ImageButtonHdl_Impl,weld::Button &,rButton,void)574 IMPL_LINK(SwCustomizeAddressBlockDialog, ImageButtonHdl_Impl, weld::Button&, rButton, void)
575 {
576     if (m_xInsertFieldIB.get() == &rButton)
577     {
578         int nEntry = m_xAddressElementsLB->get_selected_index();
579         if (nEntry != -1)
580         {
581             m_xDragED->InsertNewEntry("<" + m_xAddressElementsLB->get_text(nEntry) + ">");
582         }
583     }
584     else if (m_xRemoveFieldIB.get() == &rButton)
585     {
586         m_xDragED->RemoveCurrentEntry();
587     }
588     else
589     {
590         MoveItemFlags nMove = MoveItemFlags::Down;
591         if (m_xUpIB.get() == &rButton)
592             nMove = MoveItemFlags::Up;
593         else if (m_xLeftIB.get() == &rButton)
594             nMove = MoveItemFlags::Left;
595         else if (m_xRightIB.get() == &rButton)
596             nMove = MoveItemFlags::Right;
597         m_xDragED->MoveCurrentItem(nMove);
598     }
599     UpdateImageButtons_Impl();
600 }
601 
GetSelectedItem_Impl() const602 sal_Int32 SwCustomizeAddressBlockDialog::GetSelectedItem_Impl() const
603 {
604     sal_Int32 nRet = USER_DATA_NONE;
605     const OUString sSelected = m_xDragED->GetCurrentItem();
606     if(!sSelected.isEmpty())
607     {
608         for (int i = 0, nEntryCount = m_xAddressElementsLB->n_children(); i < nEntryCount; ++i)
609         {
610             const OUString sEntry = m_xAddressElementsLB->get_text(i);
611             if( sEntry == sSelected.subView( 1, sSelected.getLength() - 2 ) )
612             {
613                 nRet = m_xAddressElementsLB->get_id(i).toInt32();
614                 break;
615             }
616         }
617     }
618     return nRet;
619 }
620 
HasItem(sal_Int32 nUserData)621 bool SwCustomizeAddressBlockDialog::HasItem(sal_Int32 nUserData)
622 {
623     //get the entry from the ListBox
624     OUString sEntry;
625     for (int i = 0, nEntryCount = m_xAddressElementsLB->n_children(); i < nEntryCount; ++i)
626     {
627         if (m_xAddressElementsLB->get_id(i).toInt32() == nUserData)
628         {
629             sEntry = m_xAddressElementsLB->get_text(i);
630             break;
631         }
632     }
633     //search for this entry in the content
634     return m_xDragED->GetText().indexOf(OUString("<" + sEntry + ">")) >= 0;
635 }
636 
IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog,SelectionChangedIdleHdl,Timer *,void)637 IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog, SelectionChangedIdleHdl, Timer*, void)
638 {
639     // called in case the selection of the edit field changes.
640     // determine selection - if it's one of the editable fields then
641     // enable the related ComboBox and fill it
642 
643     // don't trigger outself again
644     m_xDragED->SetSelectionChangedHdl(Link<bool, void>());
645 
646     sal_Int32 nSelected = GetSelectedItem_Impl();
647     if (USER_DATA_NONE != nSelected)
648         m_xDragED->SelectCurrentItem();
649 
650     if(m_xFieldCB->get_visible() && (USER_DATA_NONE != nSelected) && (nSelected < 0))
651     {
652         //search in ListBox if it's one of the first entries
653         OUString sSelect;
654         std::vector<OUString>* pVector = nullptr;
655         switch(nSelected) {
656             case USER_DATA_SALUTATION:
657                 sSelect =  m_sCurrentSalutation;
658                 pVector = &m_aSalutations;
659                 break;
660             case USER_DATA_PUNCTUATION:
661                 sSelect =  m_sCurrentPunctuation;
662                 pVector = &m_aPunctuations;
663                 break;
664             case USER_DATA_TEXT:
665                 sSelect =  m_sCurrentText;
666                 break;
667         }
668         m_xFieldCB->clear();
669         if(pVector) {
670             for (const auto& rItem : *pVector)
671                 m_xFieldCB->append_text(rItem);
672         }
673         m_xFieldCB->set_entry_text(sSelect);
674         m_xFieldCB->set_sensitive(true);
675         m_xFieldFT->set_sensitive(true);
676     }
677     else
678     {
679         m_xFieldCB->set_sensitive(false);
680         m_xFieldFT->set_sensitive(false);
681     }
682 
683     UpdateImageButtons_Impl();
684     m_xDragED->SetSelectionChangedHdl( LINK( this, SwCustomizeAddressBlockDialog, SelectionChangedHdl_Impl));
685 }
686 
IMPL_LINK(SwCustomizeAddressBlockDialog,SelectionChangedHdl_Impl,bool,bIdle,void)687 IMPL_LINK(SwCustomizeAddressBlockDialog, SelectionChangedHdl_Impl, bool, bIdle, void)
688 {
689     if (bIdle)
690         m_aSelectionChangedIdle.Start();
691     else
692     {
693         m_aSelectionChangedIdle.Stop();
694         SelectionChangedIdleHdl(nullptr);
695     }
696 }
697 
IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog,FieldChangeComboBoxHdl_Impl,weld::ComboBox &,void)698 IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog, FieldChangeComboBoxHdl_Impl, weld::ComboBox&, void)
699 {
700     //changing the field content changes the related members, too
701     sal_Int32 nSelected = GetSelectedItem_Impl();
702     const OUString sContent = m_xFieldCB->get_active_text();
703     switch(nSelected) {
704         case USER_DATA_SALUTATION:
705             m_sCurrentSalutation = sContent;
706             break;
707         case USER_DATA_PUNCTUATION:
708             m_sCurrentPunctuation = sContent;
709             break;
710         case USER_DATA_TEXT:
711             m_sCurrentText = sContent;
712             break;
713     }
714     UpdateImageButtons_Impl();
715     m_xPreview->SetAddress(GetAddress());
716     EditModifyHdl_Impl(*m_xDragED);
717 }
718 
UpdateImageButtons_Impl()719 void SwCustomizeAddressBlockDialog::UpdateImageButtons_Impl()
720 {
721     MoveItemFlags nMove = m_xDragED->IsCurrentItemMoveable();
722     m_xUpIB->set_sensitive( bool(nMove & MoveItemFlags::Up) );
723     m_xLeftIB->set_sensitive( bool(nMove & MoveItemFlags::Left) );
724     m_xRightIB->set_sensitive( bool(nMove & MoveItemFlags::Right) );
725     m_xDownIB->set_sensitive( bool(nMove & MoveItemFlags::Down) );
726     m_xRemoveFieldIB->set_sensitive(m_xDragED->HasCurrentItem());
727     int nEntry = m_xAddressElementsLB->get_selected_index();
728     m_xInsertFieldIB->set_sensitive( nEntry != -1 &&
729             (m_xAddressElementsLB->get_id(nEntry).toInt32() >= 0 || !m_xFieldCB->get_active_text().isEmpty()));
730 }
731 
SetAddress(const OUString & rAddress)732 void SwCustomizeAddressBlockDialog::SetAddress(const OUString& rAddress)
733 {
734     m_xDragED->SetText(rAddress);
735     UpdateImageButtons_Impl();
736     EditModifyHdl_Impl(*m_xDragED);
737 }
738 
GetAddress() const739 OUString SwCustomizeAddressBlockDialog::GetAddress() const
740 {
741     OUString sAddress(m_xDragED->GetAddress());
742     //remove placeholders by the actual content
743     if (m_xFieldFT->get_visible())
744     {
745         for (int i = 0, nEntryCount = m_xAddressElementsLB->n_children(); i < nEntryCount; ++i)
746         {
747             const OUString sEntry = "<" + m_xAddressElementsLB->get_text(i) + ">";
748             sal_Int32 nUserData = m_xAddressElementsLB->get_id(i).toInt32();
749             switch(nUserData)
750             {
751                 case USER_DATA_SALUTATION:
752                     sAddress = sAddress.replaceFirst(sEntry, m_sCurrentSalutation);
753                     break;
754                 case USER_DATA_PUNCTUATION:
755                     sAddress = sAddress.replaceFirst(sEntry, m_sCurrentPunctuation);
756                     break;
757                 case USER_DATA_TEXT:
758                     sAddress = sAddress.replaceFirst(sEntry, m_sCurrentText);
759                     break;
760             }
761         }
762     }
763     return sAddress;
764 }
765 
766 namespace {
767 
768 struct SwAssignFragment
769 {
770     std::unique_ptr<weld::Builder> m_xBuilder;
771     std::unique_ptr<weld::Label> m_xLabel;
772     std::unique_ptr<weld::ComboBox> m_xComboBox;
773     std::unique_ptr<weld::Label> m_xPreview;
774 
SwAssignFragment__anon9171a1ef0111::SwAssignFragment775     SwAssignFragment(weld::Container* pGrid, int nLine)
776         : m_xBuilder(Application::CreateBuilder(pGrid, "modules/swriter/ui/assignfragment.ui"))
777         , m_xLabel(m_xBuilder->weld_label("label"))
778         , m_xComboBox(m_xBuilder->weld_combo_box("combobox"))
779         , m_xPreview(m_xBuilder->weld_label("preview"))
780     {
781         m_xLabel->set_grid_left_attach(0);
782         m_xLabel->set_grid_top_attach(nLine);
783 
784         m_xComboBox->set_grid_left_attach(1);
785         m_xComboBox->set_grid_top_attach(nLine);
786 
787         m_xPreview->set_grid_left_attach(2);
788         m_xPreview->set_grid_top_attach(nLine);
789     }
790 };
791 
792 }
793 
794 class SwAssignFieldsControl
795 {
796     friend class SwAssignFieldsDialog;
797     std::unique_ptr<weld::ScrolledWindow> m_xVScroll;
798     std::unique_ptr<weld::Container> m_xGrid;
799 
800     std::vector<SwAssignFragment> m_aFields;
801 
802     SwMailMergeConfigItem* m_rConfigItem;
803 
804     Link<LinkParamNone*,void>   m_aModifyHdl;
805 
806     DECL_LINK(MatchHdl_Impl, weld::ComboBox&, void);
807     DECL_LINK(GotFocusHdl_Impl, weld::Widget&, void);
808 
809     void MakeVisible(const tools::Rectangle & rRect);
810 public:
811     SwAssignFieldsControl(std::unique_ptr<weld::ScrolledWindow> xWindow,
812                           std::unique_ptr<weld::Container> xGrid);
813 
814     void Init(SwAssignFieldsDialog* pDialog, SwMailMergeConfigItem& rConfigItem);
SetModifyHdl(const Link<LinkParamNone *,void> & rModifyHdl)815     void SetModifyHdl(const Link<LinkParamNone*,void>& rModifyHdl)
816     {
817         m_aModifyHdl = rModifyHdl;
818         m_aModifyHdl.Call(nullptr);
819     }
820 };
821 
SwAssignFieldsControl(std::unique_ptr<weld::ScrolledWindow> xWindow,std::unique_ptr<weld::Container> xGrid)822 SwAssignFieldsControl::SwAssignFieldsControl(std::unique_ptr<weld::ScrolledWindow> xWindow,
823                                              std::unique_ptr<weld::Container> xGrid)
824     : m_xVScroll(std::move(xWindow))
825     , m_xGrid(std::move(xGrid))
826     , m_rConfigItem(nullptr)
827 {
828 }
829 
Init(SwAssignFieldsDialog * pDialog,SwMailMergeConfigItem & rConfigItem)830 void SwAssignFieldsControl::Init(SwAssignFieldsDialog* pDialog, SwMailMergeConfigItem& rConfigItem)
831 {
832     m_rConfigItem = &rConfigItem;
833 
834     //get the name of the default headers
835     const std::vector<std::pair<OUString, int>>& rHeaders = rConfigItem.GetDefaultAddressHeaders();
836     //get the actual data
837     uno::Reference< XColumnsSupplier > xColsSupp( rConfigItem.GetResultSet(), uno::UNO_QUERY);
838     //get the name of the actual columns
839     uno::Reference <XNameAccess> xColAccess = xColsSupp.is() ? xColsSupp->getColumns() : nullptr;
840     uno::Sequence< OUString > aFields;
841     if(xColAccess.is())
842         aFields = xColAccess->getElementNames();
843 
844     //get the current assignment list
845     //each position in this sequence matches the position in the header array rHeaders
846     //if no assignment is available an empty sequence will be returned
847     uno::Sequence< OUString> aAssignments = rConfigItem.GetColumnAssignment( rConfigItem.GetCurrentDBData() );
848     Link<weld::ComboBox&,void> aMatchHdl = LINK(this, SwAssignFieldsControl, MatchHdl_Impl);
849     Link<weld::Widget&,void> aFocusHdl = LINK(this, SwAssignFieldsControl, GotFocusHdl_Impl);
850 
851     int nLabelWidth(0), nComboBoxWidth(0), nPreviewWidth(0);
852 
853     //fill the controls
854     for (size_t i = 0; i < rHeaders.size(); ++i)
855     {
856         m_aFields.emplace_back(m_xGrid.get(), i);
857 
858         const OUString rHeader = rHeaders[i].first;
859         weld::ComboBox& rNewLB = *m_aFields.back().m_xComboBox;
860         rNewLB.append_text(SwResId(SW_STR_NONE));
861         rNewLB.set_active(0);
862 
863         for (const OUString& rField : std::as_const(aFields))
864             rNewLB.append_text(rField);
865         //select the ListBox
866         //if there is an assignment
867         if(o3tl::make_unsigned(aAssignments.getLength()) > i && !aAssignments[i].isEmpty())
868             rNewLB.set_active_text(aAssignments[i]);
869         else //otherwise the current column name may match one of the db columns
870             rNewLB.set_active_text(rHeader);
871 
872         weld::Label& rNewText = *m_aFields.back().m_xLabel;
873         rNewText.set_label("<" + rHeader + ">");
874 
875         weld::Label& rNewPreview = *m_aFields.back().m_xPreview;
876         //then the preview can be filled accordingly
877         if (xColAccess.is() && rNewLB.get_active() > 0 &&
878             xColAccess->hasByName(rNewLB.get_active_text()))
879         {
880             uno::Any aCol = xColAccess->getByName(rNewLB.get_active_text());
881             uno::Reference< XColumn > xColumn;
882             aCol >>= xColumn;
883             if(xColumn.is())
884             {
885                 try
886                 {
887                     rNewPreview.set_label(xColumn->getString());
888                 }
889                 catch (const SQLException&)
890                 {
891                 }
892             }
893         }
894 
895         if (i == 0)
896         {
897             auto nLineHeight = m_xGrid->get_preferred_size().Height();
898             m_xVScroll->set_size_request(m_xVScroll->get_approximate_digit_width() * 65,
899                                          nLineHeight * 6);
900             nComboBoxWidth = rNewLB.get_preferred_size().Width();
901         }
902 
903         nLabelWidth = std::max<int>(nLabelWidth, rNewText.get_preferred_size().Width());
904         nPreviewWidth = std::max<int>(nPreviewWidth, rNewPreview.get_preferred_size().Width());
905 
906         rNewLB.connect_changed(aMatchHdl);
907         rNewLB.connect_focus_in(aFocusHdl);
908         rNewText.show();
909         rNewLB.show();
910         rNewPreview.show();
911     }
912     pDialog->ConnectSizeGroups(nLabelWidth, nComboBoxWidth, nPreviewWidth);
913 }
914 
MakeVisible(const tools::Rectangle & rRect)915 void SwAssignFieldsControl::MakeVisible(const tools::Rectangle & rRect)
916 {
917     //determine range of visible positions
918     auto nMinVisiblePos = m_xVScroll->vadjustment_get_value();
919     auto nMaxVisiblePos = nMinVisiblePos + m_xVScroll->vadjustment_get_page_size();
920     if (rRect.Top() < nMinVisiblePos || rRect.Bottom() > nMaxVisiblePos)
921         m_xVScroll->vadjustment_set_value(rRect.Top());
922 }
923 
IMPL_LINK(SwAssignFieldsControl,MatchHdl_Impl,weld::ComboBox &,rBox,void)924 IMPL_LINK(SwAssignFieldsControl, MatchHdl_Impl, weld::ComboBox&, rBox, void)
925 {
926     const OUString sColumn = rBox.get_active_text();
927     uno::Reference< XColumnsSupplier > xColsSupp( m_rConfigItem->GetResultSet(), uno::UNO_QUERY);
928     uno::Reference <XNameAccess> xColAccess = xColsSupp.is() ? xColsSupp->getColumns() : nullptr;
929     OUString sPreview;
930     if(xColAccess.is() && xColAccess->hasByName(sColumn))
931     {
932         uno::Any aCol = xColAccess->getByName(sColumn);
933         uno::Reference< XColumn > xColumn;
934         aCol >>= xColumn;
935         if(xColumn.is())
936         {
937             try
938             {
939                 sPreview = xColumn->getString();
940             }
941             catch (const sdbc::SQLException&)
942             {
943             }
944         }
945     }
946     auto aLBIter = std::find_if(m_aFields.begin(), m_aFields.end(), [&rBox](const SwAssignFragment& rFragment){
947                                                                      return &rBox == rFragment.m_xComboBox.get(); });
948     if (aLBIter != m_aFields.end())
949     {
950         auto nIndex = static_cast<sal_Int32>(std::distance(m_aFields.begin(), aLBIter));
951         m_aFields[nIndex].m_xPreview->set_label(sPreview);
952     }
953     m_aModifyHdl.Call(nullptr);
954 }
955 
IMPL_LINK(SwAssignFieldsControl,GotFocusHdl_Impl,weld::Widget &,rBox,void)956 IMPL_LINK(SwAssignFieldsControl, GotFocusHdl_Impl, weld::Widget&, rBox, void)
957 {
958     int x, y, width, height;
959     rBox.get_extents_relative_to(*m_xGrid, x, y, width, height);
960     // the container has a border of 3 in the .ui
961     tools::Rectangle aRect(Point(x - 3, y - 3), Size(width + 6, height + 6));
962     MakeVisible(aRect);
963 }
964 
SwAssignFieldsDialog(weld::Window * pParent,SwMailMergeConfigItem & rConfigItem,const OUString & rPreview,bool bIsAddressBlock)965 SwAssignFieldsDialog::SwAssignFieldsDialog(
966         weld::Window* pParent, SwMailMergeConfigItem& rConfigItem,
967         const OUString& rPreview,
968         bool bIsAddressBlock)
969     : SfxDialogController(pParent, "modules/swriter/ui/assignfieldsdialog.ui", "AssignFieldsDialog")
970     , m_sNone(SwResId(SW_STR_NONE))
971     , m_rPreviewString(rPreview)
972     , m_rConfigItem(rConfigItem)
973     , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("previewwin", true)))
974     , m_xMatchingFI(m_xBuilder->weld_label("MATCHING_LABEL"))
975     , m_xAddressTitle(m_xBuilder->weld_label("addresselem"))
976     , m_xMatchTitle(m_xBuilder->weld_label("matchelem"))
977     , m_xPreviewTitle(m_xBuilder->weld_label("previewelem"))
978     , m_xPreviewFI(m_xBuilder->weld_label("PREVIEW_LABEL"))
979     , m_xOK(m_xBuilder->weld_button("ok"))
980     , m_xPreviewWin(new weld::CustomWeld(*m_xBuilder, "PREVIEW", *m_xPreview))
981     , m_xFieldsControl(new SwAssignFieldsControl(m_xBuilder->weld_scrolled_window("scroll"),
982                                                  m_xBuilder->weld_container("FIELDS")))
983 {
984     m_xPreviewWin->set_size_request(m_xMatchingFI->get_approximate_digit_width() * 45,
985                                     m_xMatchingFI->get_text_height() * 5);
986     m_xFieldsControl->Init(this, rConfigItem);
987 
988     const OUString sMatchesTo( SwResId(ST_MATCHESTO) );
989     if (!bIsAddressBlock)
990     {
991         m_xPreviewFI->set_label(SwResId(ST_SALUTATIONPREVIEW));
992         m_xMatchingFI->set_label(SwResId(ST_SALUTATIONMATCHING));
993         m_xAddressTitle->set_label(SwResId(ST_SALUTATIONELEMENT));
994     }
995 
996     m_xFieldsControl->SetModifyHdl(LINK(this, SwAssignFieldsDialog, AssignmentModifyHdl_Impl ));
997     m_xMatchingFI->set_label(m_xMatchingFI->get_label().replaceAll("%1", sMatchesTo));
998     m_xOK->connect_clicked(LINK(this, SwAssignFieldsDialog, OkHdl_Impl));
999 }
1000 
~SwAssignFieldsDialog()1001 SwAssignFieldsDialog::~SwAssignFieldsDialog()
1002 {
1003 }
1004 
CreateAssignments()1005 uno::Sequence< OUString > SwAssignFieldsDialog::CreateAssignments()
1006 {
1007     uno::Sequence< OUString > aAssignments(
1008             m_rConfigItem.GetDefaultAddressHeaders().size());
1009     OUString* pAssignments = aAssignments.getArray();
1010     sal_Int32 nIndex = 0;
1011     for (const auto& rLBItem : m_xFieldsControl->m_aFields)
1012     {
1013         const OUString sSelect = rLBItem.m_xComboBox->get_active_text();
1014         pAssignments[nIndex] = (m_sNone != sSelect) ? sSelect : OUString();
1015         ++nIndex;
1016     }
1017     return aAssignments;
1018 }
1019 
IMPL_LINK_NOARG(SwAssignFieldsDialog,OkHdl_Impl,weld::Button &,void)1020 IMPL_LINK_NOARG(SwAssignFieldsDialog, OkHdl_Impl, weld::Button&, void)
1021 {
1022     m_rConfigItem.SetColumnAssignment(
1023                             m_rConfigItem.GetCurrentDBData(),
1024                             CreateAssignments() );
1025     m_xDialog->response(RET_OK);
1026 }
1027 
IMPL_LINK_NOARG(SwAssignFieldsDialog,AssignmentModifyHdl_Impl,LinkParamNone *,void)1028 IMPL_LINK_NOARG(SwAssignFieldsDialog, AssignmentModifyHdl_Impl, LinkParamNone*, void)
1029 {
1030     uno::Sequence< OUString > aAssignments = CreateAssignments();
1031     const OUString sPreview = SwAddressPreview::FillData(
1032             m_rPreviewString, m_rConfigItem, &aAssignments);
1033     m_xPreview->SetAddress(sPreview);
1034 }
1035 
ConnectSizeGroups(int nLabelWidth,int nComboBoxWidth,int nPreviewWidth)1036 void SwAssignFieldsDialog::ConnectSizeGroups(int nLabelWidth, int nComboBoxWidth, int nPreviewWidth)
1037 {
1038     m_xAddressTitle->set_size_request(nLabelWidth, -1);
1039     m_xMatchTitle->set_size_request(nComboBoxWidth, -1);
1040     m_xPreviewTitle->set_size_request(nPreviewWidth, -1);
1041 }
1042 
1043 namespace
1044 {
FindCharAttrib(int nStartPosition,std::vector<EECharAttrib> & rAttribList)1045     const EECharAttrib* FindCharAttrib(int nStartPosition, std::vector<EECharAttrib>& rAttribList)
1046     {
1047         for (auto it = rAttribList.rbegin(); it != rAttribList.rend(); ++it)
1048         {
1049             const auto& rTextAtr = *it;
1050             if (rTextAtr.pAttr->Which() != EE_CHAR_GRABBAG)
1051                 continue;
1052             if (rTextAtr.nStart <= nStartPosition && rTextAtr.nEnd >= nStartPosition)
1053             {
1054                 return &rTextAtr;
1055             }
1056         }
1057 
1058         return nullptr;
1059     }
1060 }
1061 
AddressMultiLineEdit(SwCustomizeAddressBlockDialog * pParent)1062 AddressMultiLineEdit::AddressMultiLineEdit(SwCustomizeAddressBlockDialog *pParent)
1063     : m_pParentDialog(pParent)
1064 {
1065 }
1066 
EndDropTarget()1067 void AddressMultiLineEdit::EndDropTarget()
1068 {
1069     if (m_xDropTarget.is())
1070     {
1071         m_xEditEngine->RemoveView(m_xEditView.get());
1072         auto xRealDropTarget = GetDrawingArea()->get_drop_target();
1073         uno::Reference<css::datatransfer::dnd::XDropTargetListener> xListener(m_xDropTarget, uno::UNO_QUERY);
1074         xRealDropTarget->removeDropTargetListener(xListener);
1075         m_xDropTarget.clear();
1076     }
1077 }
1078 
~AddressMultiLineEdit()1079 AddressMultiLineEdit::~AddressMultiLineEdit()
1080 {
1081     assert(!m_xDropTarget.is());
1082 }
1083 
SetDrawingArea(weld::DrawingArea * pDrawingArea)1084 void AddressMultiLineEdit::SetDrawingArea(weld::DrawingArea* pDrawingArea)
1085 {
1086     Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(160, 60), MapMode(MapUnit::MapAppFont)));
1087     pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
1088     WeldEditView::SetDrawingArea(pDrawingArea);
1089 }
1090 
KeyInput(const KeyEvent & rKEvt)1091 bool AddressMultiLineEdit::KeyInput(const KeyEvent& rKEvt)
1092 {
1093     if (rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE)
1094         return false; // we want default esc behaviour
1095     if (rKEvt.GetCharCode())
1096         return true; // handled
1097     return WeldEditView::KeyInput(rKEvt);
1098 }
1099 
MouseButtonDown(const MouseEvent & rMEvt)1100 bool AddressMultiLineEdit::MouseButtonDown(const MouseEvent& rMEvt)
1101 {
1102     if (rMEvt.GetClicks() >= 2)
1103         return true; // handled
1104     return WeldEditView::MouseButtonDown(rMEvt);
1105 }
1106 
GetText() const1107 OUString AddressMultiLineEdit::GetText() const
1108 {
1109     return m_xEditEngine->GetText();
1110 }
1111 
SetText(const OUString & rStr)1112 void AddressMultiLineEdit::SetText( const OUString& rStr )
1113 {
1114     m_xEditEngine->SetText(rStr);
1115     //set attributes to all address tokens
1116 
1117     sal_Int32 nSequence(0);
1118     SfxGrabBagItem aProtectAttr(EE_CHAR_GRABBAG);
1119     const sal_uInt32 nParaCount = m_xEditEngine->GetParagraphCount();
1120     for(sal_uInt32 nPara = 0; nPara < nParaCount; ++nPara)
1121     {
1122         sal_Int32 nIndex = 0;
1123         const OUString sPara = m_xEditEngine->GetText( nPara );
1124         if (!sPara.isEmpty() && !sPara.endsWith(" "))
1125         {
1126             ESelection aPaM(nPara, sPara.getLength(), nPara, sPara.getLength());
1127             m_xEditEngine->QuickInsertText(" ", aPaM);
1128         }
1129         for(;;)
1130         {
1131             const sal_Int32 nStart = sPara.indexOf( '<', nIndex );
1132             if (nStart < 0)
1133                 break;
1134             const sal_Int32 nEnd = sPara.indexOf( '>', nStart );
1135             if (nEnd < 0)
1136                 break;
1137             nIndex = nEnd;
1138             SfxItemSet aSet(m_xEditEngine->GetEmptyItemSet());
1139             // make each one different, so they are not collapsed together
1140             // as one attribute
1141             aProtectAttr.GetGrabBag()["Index"] <<= nSequence++;
1142             aSet.Put(aProtectAttr);
1143             m_xEditEngine->QuickSetAttribs(aSet, ESelection(nPara, nStart, nPara, nEnd + 1));
1144         }
1145 
1146     }
1147     // add two empty paragraphs at the end
1148     if(m_pParentDialog->m_eType == SwCustomizeAddressBlockDialog::ADDRESSBLOCK_NEW ||
1149             m_pParentDialog->m_eType == SwCustomizeAddressBlockDialog::ADDRESSBLOCK_EDIT)
1150     {
1151         sal_Int32 nLastLen = m_xEditEngine->GetText(nParaCount - 1).getLength();
1152         if(nLastLen)
1153         {
1154             int nPara = nParaCount ? nParaCount - 1 : 0;
1155             ESelection aPaM(nPara, nLastLen, nPara, nLastLen);
1156             m_xEditEngine->QuickInsertText("\n \n ", aPaM);
1157         }
1158     }
1159 
1160     m_xEditView->SetSelection(ESelection(0, 0, 0, 0));
1161 }
1162 
1163 // Insert the new entry in front of the entry at the beginning of the selection
InsertNewEntry(const OUString & rStr)1164 void AddressMultiLineEdit::InsertNewEntry( const OUString& rStr )
1165 {
1166     // insert new entry after current selected one.
1167     ESelection aSelection = m_xEditView->GetSelection();
1168     const sal_uInt32 nPara = aSelection.nStartPara;
1169 
1170     std::vector<EECharAttrib> aAttribList;
1171     m_xEditEngine->GetCharAttribs(nPara, aAttribList);
1172 
1173     sal_Int32 nIndex = aSelection.nEndPara;
1174     const EECharAttrib* pAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList);
1175     if(nullptr != pAttrib)
1176         nIndex = pAttrib->nEnd;
1177     InsertNewEntryAtPosition( rStr, nPara, nIndex );
1178 
1179     // select the new entry
1180     m_xEditEngine->GetCharAttribs(nPara, aAttribList);
1181     pAttrib = FindCharAttrib(nIndex, aAttribList);
1182     const sal_Int32 nEnd = pAttrib ? pAttrib->nEnd : nIndex;
1183     ESelection aEntrySel(nPara, nIndex, nPara, nEnd);
1184     m_xEditView->SetSelection(aEntrySel);
1185     Invalidate();
1186     m_aModifyLink.Call(*this);
1187 }
1188 
InsertNewEntryAtPosition(const OUString & rStr,sal_uLong nPara,sal_uInt16 nIndex)1189 void AddressMultiLineEdit::InsertNewEntryAtPosition( const OUString& rStr, sal_uLong nPara, sal_uInt16 nIndex )
1190 {
1191     ESelection aInsertPos(nPara, nIndex, nPara, nIndex);
1192     m_xEditEngine->QuickInsertText(rStr, aInsertPos);
1193 
1194     //restore the attributes
1195     SetText( GetAddress() );
1196 
1197     //select the newly inserted/moved element
1198     m_xEditView->SetSelection(aInsertPos);
1199     m_aSelectionLink.Call(false);
1200 }
1201 
RemoveCurrentEntry()1202 void AddressMultiLineEdit::RemoveCurrentEntry()
1203 {
1204     ESelection aSelection = m_xEditView->GetSelection();
1205 
1206     std::vector<EECharAttrib> aAttribList;
1207     m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList);
1208 
1209     const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList);
1210     if(pBeginAttrib &&
1211             (pBeginAttrib->nStart <= aSelection.nStartPos
1212                             && pBeginAttrib->nEnd >= aSelection.nEndPos))
1213     {
1214         const sal_uInt32 nPara = aSelection.nStartPara;
1215         ESelection aEntrySel(nPara, pBeginAttrib->nStart, nPara, pBeginAttrib->nEnd);
1216         m_xEditEngine->QuickInsertText(OUString(), aEntrySel);
1217         //restore the attributes
1218         SetText( GetAddress() );
1219         m_aModifyLink.Call(*this);
1220     }
1221 }
1222 
MoveCurrentItem(MoveItemFlags nMove)1223 void AddressMultiLineEdit::MoveCurrentItem(MoveItemFlags nMove)
1224 {
1225     ESelection aSelection = m_xEditView->GetSelection();
1226 
1227     std::vector<EECharAttrib> aAttribList;
1228     m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList);
1229 
1230     const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList);
1231     if(!pBeginAttrib ||
1232          pBeginAttrib->nStart > aSelection.nStartPos ||
1233          pBeginAttrib->nEnd < aSelection.nEndPos)
1234         return;
1235 
1236     //current item has been found
1237     sal_Int32 nPara = aSelection.nStartPara;
1238     sal_Int32 nIndex = pBeginAttrib->nStart;
1239     ESelection aEntrySel(nPara, pBeginAttrib->nStart, nPara, pBeginAttrib->nEnd);
1240     const OUString sCurrentItem = m_xEditEngine->GetText(aEntrySel);
1241     m_xEditEngine->RemoveAttribs(aEntrySel, false, EE_CHAR_GRABBAG);
1242     m_xEditEngine->QuickInsertText(OUString(), aEntrySel);
1243     m_xEditEngine->GetCharAttribs(nPara, aAttribList);
1244     switch (nMove)
1245     {
1246         case MoveItemFlags::Left :
1247             if(nIndex)
1248             {
1249                 //go left to find a predecessor or simple text
1250                 --nIndex;
1251                 const OUString sPara = m_xEditEngine->GetText( nPara );
1252                 sal_Int32 nSearchIndex = sPara.lastIndexOf( '>', nIndex+1 );
1253                 if( nSearchIndex != -1 && nSearchIndex == nIndex )
1254                 {
1255                     nSearchIndex = sPara.lastIndexOf( '<', nIndex );
1256                     if( nSearchIndex != -1 )
1257                         nIndex = nSearchIndex;
1258                 }
1259             }
1260         break;
1261         case MoveItemFlags::Right:
1262         {
1263             //go right to find a successor or simple text
1264             ++nIndex;
1265             const EECharAttrib* pEndAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList);
1266             if(pEndAttrib && pEndAttrib->nEnd >= nIndex)
1267             {
1268                 nIndex = pEndAttrib->nEnd;
1269             }
1270         }
1271         break;
1272         case MoveItemFlags::Up   :
1273             --nPara;
1274             nIndex = 0;
1275         break;
1276         case MoveItemFlags::Down :
1277             ++nPara;
1278             nIndex = 0;
1279         break;
1280         default: break;
1281     }
1282     //add a new paragraph if there is none yet
1283     if (nPara >= m_xEditEngine->GetParagraphCount())
1284     {
1285         auto nInsPara = nPara - 1;
1286         auto nInsPos = m_xEditEngine->GetTextLen( nPara - 1 );
1287         ESelection aTemp(nInsPara, nInsPos, nInsPara, nInsPos);
1288         m_xEditEngine->QuickInsertText("\n", aTemp);
1289     }
1290     InsertNewEntryAtPosition( sCurrentItem, nPara, nIndex );
1291 
1292     // select the new entry [#i40817]
1293     m_xEditEngine->GetCharAttribs(nPara, aAttribList);
1294     const EECharAttrib* pAttrib = FindCharAttrib(nIndex, aAttribList);
1295     if (pAttrib)
1296         aEntrySel = ESelection(nPara, nIndex, nPara, pAttrib->nEnd);
1297     m_xEditView->SetSelection(aEntrySel);
1298     Invalidate();
1299     m_aModifyLink.Call(*this);
1300 }
1301 
IsCurrentItemMoveable() const1302 MoveItemFlags AddressMultiLineEdit::IsCurrentItemMoveable() const
1303 {
1304     MoveItemFlags nRet = MoveItemFlags::NONE;
1305     ESelection aSelection = m_xEditView->GetSelection();
1306 
1307     std::vector<EECharAttrib> aAttribList;
1308     m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList);
1309 
1310     const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList);
1311     if (pBeginAttrib &&
1312             (pBeginAttrib->nStart <= aSelection.nStartPos
1313                             && pBeginAttrib->nEnd >= aSelection.nEndPos))
1314     {
1315         if (pBeginAttrib->nStart)
1316             nRet |= MoveItemFlags::Left;
1317         //if there is an entry it can always be move to the right and down
1318         nRet |= MoveItemFlags::Right | MoveItemFlags::Down;
1319         if (aSelection.nStartPara > 0)
1320             nRet |= MoveItemFlags::Up;
1321     }
1322     return nRet;
1323 }
1324 
HasCurrentItem() const1325 bool AddressMultiLineEdit::HasCurrentItem() const
1326 {
1327     ESelection aSelection = m_xEditView->GetSelection();
1328 
1329     std::vector<EECharAttrib> aAttribList;
1330     m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList);
1331 
1332     const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList);
1333     return (pBeginAttrib &&
1334             (pBeginAttrib->nStart <= aSelection.nStartPos
1335                             && pBeginAttrib->nEnd >= aSelection.nEndPos));
1336 }
1337 
GetCurrentItem() const1338 OUString AddressMultiLineEdit::GetCurrentItem() const
1339 {
1340     ESelection aSelection = m_xEditView->GetSelection();
1341 
1342     std::vector<EECharAttrib> aAttribList;
1343     m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList);
1344 
1345     const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList);
1346     if (pBeginAttrib &&
1347             (pBeginAttrib->nStart <= aSelection.nStartPos
1348                             && pBeginAttrib->nEnd >= aSelection.nEndPos))
1349     {
1350         const sal_uInt32 nPara = aSelection.nStartPara;
1351         ESelection aEntrySel(nPara, pBeginAttrib->nStart, nPara, pBeginAttrib->nEnd);
1352         return m_xEditEngine->GetText( aEntrySel );
1353     }
1354     return OUString();
1355 }
1356 
SelectCurrentItem()1357 void AddressMultiLineEdit::SelectCurrentItem()
1358 {
1359     ESelection aSelection = m_xEditView->GetSelection();
1360 
1361     std::vector<EECharAttrib> aAttribList;
1362     m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList);
1363 
1364     const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList);
1365     if (pBeginAttrib &&
1366             (pBeginAttrib->nStart <= aSelection.nStartPos
1367                             && pBeginAttrib->nEnd >= aSelection.nEndPos))
1368     {
1369         const sal_uInt32 nPara = aSelection.nStartPara;
1370         ESelection aEntrySel(nPara, pBeginAttrib->nStart, nPara, pBeginAttrib->nEnd);
1371         m_xEditView->SetSelection(aEntrySel);
1372         Invalidate();
1373     }
1374 }
1375 
GetAddress() const1376 OUString AddressMultiLineEdit::GetAddress() const
1377 {
1378     OUString sRet;
1379     const sal_uInt32 nParaCount = m_xEditEngine->GetParagraphCount();
1380     for(sal_uInt32 nPara = nParaCount; nPara; --nPara)
1381     {
1382         const OUString sPara = comphelper::string::stripEnd(m_xEditEngine->GetText(nPara - 1), ' ');
1383         //don't add empty trailing paragraphs
1384         if(!sRet.isEmpty() || !sPara.isEmpty())
1385         {
1386             sRet = sPara + sRet;
1387             //insert the para break
1388             if(nPara > 1)
1389                 sRet = "\n" + sRet;
1390         }
1391     }
1392     return sRet;
1393 }
1394 
UpdateFields()1395 void AddressMultiLineEdit::UpdateFields()
1396 {
1397     ESelection aSelection = m_xEditView->GetSelection();
1398 
1399     //restore the attributes
1400     SetText( GetAddress() );
1401 
1402     //reselect the element
1403     m_xEditView->SetSelection(aSelection);
1404     m_aSelectionLink.Call(false);
1405 }
1406 
EditViewSelectionChange()1407 void AddressMultiLineEdit::EditViewSelectionChange()
1408 {
1409     WeldEditView::EditViewSelectionChange();
1410     m_aSelectionLink.Call(true);
1411 }
1412 
1413 namespace
1414 {
1415     // sit between the tree as drag source and the editview as drop target and translate
1416     // the tree dnd data to the simple string the editview wants
1417     class DropTargetListener : public cppu::WeakImplHelper< css::datatransfer::dnd::XDropTargetListener,
1418                                                             css::datatransfer::dnd::XDropTarget >
1419     {
1420     private:
1421         css::uno::Reference<css::datatransfer::dnd::XDropTarget> m_xRealDropTarget;
1422         std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> m_aListeners;
1423         SwCustomizeAddressBlockDialog* m_pParentDialog;
1424 
1425         // XEventListener
disposing(const css::lang::EventObject &)1426         virtual void SAL_CALL disposing( const css::lang::EventObject& ) override
1427         {
1428             m_xRealDropTarget.clear();
1429             m_aListeners.clear();
1430         }
1431 
1432         // XDropTargetListener
drop(const css::datatransfer::dnd::DropTargetDropEvent & dtde)1433         virtual void SAL_CALL drop( const css::datatransfer::dnd::DropTargetDropEvent& dtde ) override
1434         {
1435             SolarMutexGuard aGuard;
1436 
1437             auto aReplacement(dtde);
1438 
1439             Point aMousePos(dtde.LocationX, dtde.LocationY);
1440             bool bAllowed = m_pParentDialog->SetCursorLogicPosition(aMousePos);
1441             if (bAllowed)
1442             {
1443                 if (weld::TreeView* pTree = m_pParentDialog->get_drag_source())
1444                 {
1445                     int nEntry = pTree->get_selected_index();
1446                     if (nEntry != -1)
1447                     {
1448                         sal_Int32 nUserData = pTree->get_id(nEntry).toInt32();
1449                         //special entries can only be once in the address / greeting
1450                         if (nUserData >= 0 || !m_pParentDialog->HasItem(nUserData))
1451                         {
1452                             rtl::Reference<TransferDataContainer> xContainer = new TransferDataContainer;
1453                             xContainer->CopyString( "<" + pTree->get_text(nEntry) + ">" );
1454 
1455                             // replace what the treeview is offering with what ImpEditView::drop wants
1456                             aReplacement.Transferable = xContainer.get();
1457                         }
1458                     }
1459                 }
1460             }
1461 
1462             std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners);
1463             for (auto const& listener : aListeners)
1464                 listener->drop(aReplacement);
1465 
1466             if (bAllowed)
1467                 m_pParentDialog->UpdateFields();
1468         }
1469 
dragEnter(const css::datatransfer::dnd::DropTargetDragEnterEvent & dtdee)1470         virtual void SAL_CALL dragEnter( const css::datatransfer::dnd::DropTargetDragEnterEvent& dtdee ) override
1471         {
1472             auto aReplacement(dtdee);
1473             // replace what the treeview is offering with what ImpEditView::dragEnter wants
1474             aReplacement.SupportedDataFlavors.realloc(1);
1475             SotExchange::GetFormatDataFlavor(SotClipboardFormatId::STRING, aReplacement.SupportedDataFlavors[0]);
1476 
1477             std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners);
1478             for (auto const& listener : aListeners)
1479                 listener->dragEnter(aReplacement);
1480         }
1481 
dragExit(const css::datatransfer::dnd::DropTargetEvent & dte)1482         virtual void SAL_CALL dragExit( const css::datatransfer::dnd::DropTargetEvent& dte ) override
1483         {
1484             std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners);
1485             for (auto const& listener : aListeners)
1486                 listener->dragExit( dte );
1487         }
1488 
dragOver(const css::datatransfer::dnd::DropTargetDragEvent & dtde)1489         virtual void SAL_CALL dragOver( const css::datatransfer::dnd::DropTargetDragEvent& dtde ) override
1490         {
1491             std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners);
1492             for (auto const& listener : aListeners)
1493                 listener->dragOver( dtde );
1494         }
1495 
dropActionChanged(const css::datatransfer::dnd::DropTargetDragEvent & dtde)1496         virtual void SAL_CALL dropActionChanged( const css::datatransfer::dnd::DropTargetDragEvent& dtde ) override
1497         {
1498             std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners);
1499             for (auto const& listener : aListeners)
1500                 listener->dropActionChanged( dtde );
1501         }
1502 
1503         // XDropTarget
addDropTargetListener(const css::uno::Reference<css::datatransfer::dnd::XDropTargetListener> & xListener)1504         virtual void SAL_CALL addDropTargetListener(const css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>& xListener) override
1505         {
1506             m_aListeners.push_back(xListener);
1507         }
1508 
removeDropTargetListener(const css::uno::Reference<css::datatransfer::dnd::XDropTargetListener> & xListener)1509         virtual void SAL_CALL removeDropTargetListener(const css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>& xListener) override
1510         {
1511             m_aListeners.erase(std::remove(m_aListeners.begin(), m_aListeners.end(), xListener), m_aListeners.end());
1512         }
1513 
isActive()1514         virtual sal_Bool SAL_CALL isActive() override
1515         {
1516             return m_xRealDropTarget->isActive();
1517         }
1518 
setActive(sal_Bool active)1519         virtual void SAL_CALL setActive(sal_Bool active) override
1520         {
1521             m_xRealDropTarget->setActive(active);
1522         }
1523 
getDefaultActions()1524         virtual sal_Int8 SAL_CALL getDefaultActions() override
1525         {
1526             return m_xRealDropTarget->getDefaultActions();
1527         }
1528 
setDefaultActions(sal_Int8 actions)1529         virtual void SAL_CALL setDefaultActions(sal_Int8 actions) override
1530         {
1531             m_xRealDropTarget->setDefaultActions(actions);
1532         }
1533 
1534     public:
DropTargetListener(css::uno::Reference<css::datatransfer::dnd::XDropTarget> xRealDropTarget,SwCustomizeAddressBlockDialog * pParentDialog)1535         DropTargetListener(css::uno::Reference<css::datatransfer::dnd::XDropTarget> xRealDropTarget,
1536                            SwCustomizeAddressBlockDialog* pParentDialog)
1537             : m_xRealDropTarget(xRealDropTarget)
1538             , m_pParentDialog(pParentDialog)
1539         {
1540         }
1541     };
1542 }
1543 
GetDropTarget()1544 css::uno::Reference<css::datatransfer::dnd::XDropTarget> AddressMultiLineEdit::GetDropTarget()
1545 {
1546     if (!m_xDropTarget.is())
1547     {
1548         auto xRealDropTarget = GetDrawingArea()->get_drop_target();
1549         rtl::Reference<DropTargetListener> pProxy = new DropTargetListener(xRealDropTarget, m_pParentDialog);
1550         xRealDropTarget->addDropTargetListener(pProxy);
1551         m_xDropTarget = pProxy;
1552     }
1553     return m_xDropTarget;
1554 }
1555 
SetCursorLogicPosition(const Point & rPosition)1556 bool AddressMultiLineEdit::SetCursorLogicPosition(const Point& rPosition)
1557 {
1558     Point aMousePos = EditViewOutputDevice().PixelToLogic(rPosition);
1559     m_xEditView->SetCursorLogicPosition(aMousePos, false, true);
1560 
1561     ESelection aSelection = m_xEditView->GetSelection();
1562     std::vector<EECharAttrib> aAttribList;
1563     m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList);
1564     return FindCharAttrib(aSelection.nStartPos, aAttribList) == nullptr;
1565 }
1566 
1567 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1568