nss: upgrade to release 3.73
[LibreOffice.git] / sw / source / ui / dbui / mmaddressblockpage.cxx
blob876f5e5bf27d9f037e98ed8d225924e73c7b6daf
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
42 #include <vector>
43 #include <strings.hrc>
44 #include <mmaddressblockpage.hrc>
45 #include <helpids.h>
47 using namespace svt;
48 using namespace ::com::sun::star;
49 using namespace ::com::sun::star::container;
50 using namespace ::com::sun::star::sdb;
51 using namespace ::com::sun::star::sdbc;
52 using namespace ::com::sun::star::sdbcx;
54 SwMailMergeAddressBlockPage::SwMailMergeAddressBlockPage(weld::Container* pPage, SwMailMergeWizard* pWizard)
55 : vcl::OWizardPage(pPage, pWizard, "modules/swriter/ui/mmaddressblockpage.ui", "MMAddressBlockPage")
56 , m_pWizard(pWizard)
57 , m_xAddressListPB(m_xBuilder->weld_button("addresslist"))
58 , m_xCurrentAddressFI(m_xBuilder->weld_label("currentaddress"))
59 , m_xStep2(m_xBuilder->weld_container("step2"))
60 , m_xStep3(m_xBuilder->weld_container("step3"))
61 , m_xStep4(m_xBuilder->weld_container("step4"))
62 , m_xSettingsFI(m_xBuilder->weld_label("settingsft"))
63 , m_xAddressCB(m_xBuilder->weld_check_button("address"))
64 , m_xSettingsPB(m_xBuilder->weld_button("settings"))
65 , m_xHideEmptyParagraphsCB(m_xBuilder->weld_check_button("hideempty"))
66 , m_xAssignPB(m_xBuilder->weld_button("assign"))
67 , m_xDocumentIndexFI(m_xBuilder->weld_label("documentindex"))
68 , m_xPrevSetIB(m_xBuilder->weld_button("prev"))
69 , m_xNextSetIB(m_xBuilder->weld_button("next"))
70 , m_xDifferentlist(m_xBuilder->weld_button("differentlist"))
71 , m_xSettings(new SwAddressPreview(m_xBuilder->weld_scrolled_window("settingspreviewwin", true)))
72 , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("addresspreviewwin", true)))
73 , m_xSettingsWIN(new weld::CustomWeld(*m_xBuilder, "settingspreview", *m_xSettings))
74 , m_xPreviewWIN(new weld::CustomWeld(*m_xBuilder, "addresspreview", *m_xPreview))
76 m_xSettingsWIN->set_size_request(m_xDifferentlist->get_approximate_digit_width() * 40,
77 m_xDifferentlist->get_text_height() * 6);
78 m_xPreviewWIN->set_size_request(m_xDifferentlist->get_approximate_digit_width() * 44,
79 m_xDifferentlist->get_text_height() * 6);
80 m_sChangeAddress = m_xDifferentlist->get_label();
81 m_sDocument = m_xDocumentIndexFI->get_label();
83 m_sCurrentAddress = m_xCurrentAddressFI->get_label();
84 m_xAddressListPB->connect_clicked(LINK(this, SwMailMergeAddressBlockPage, AddressListHdl_Impl));
85 m_xSettingsPB->connect_clicked(LINK(this, SwMailMergeAddressBlockPage, SettingsHdl_Impl));
86 m_xAssignPB->connect_clicked(LINK(this, SwMailMergeAddressBlockPage, AssignHdl_Impl ));
87 m_xAddressCB->connect_toggled(LINK(this, SwMailMergeAddressBlockPage, AddressBlockHdl_Impl));
88 m_xSettings->SetSelectHdl(LINK(this, SwMailMergeAddressBlockPage, AddressBlockSelectHdl_Impl));
89 m_xHideEmptyParagraphsCB->connect_toggled(LINK(this, SwMailMergeAddressBlockPage, HideParagraphsHdl_Impl));
91 Link<weld::Button&,void> aLink = LINK(this, SwMailMergeAddressBlockPage, InsertDataHdl_Impl);
92 m_xPrevSetIB->connect_clicked(aLink);
93 m_xNextSetIB->connect_clicked(aLink);
95 // lock in preferred size including current address line
96 Size aSize1(m_xContainer->get_preferred_size());
98 OUString sOrigLabel = m_xAddressListPB->get_label();
99 m_xAddressListPB->set_label(m_sChangeAddress);
100 Size aSize2(m_xContainer->get_preferred_size());
101 m_xAddressListPB->set_label(sOrigLabel);
103 m_xCurrentAddressFI->hide();
105 m_xContainer->set_size_request(std::max(aSize1.Width(), aSize2.Width()),
106 std::max(aSize1.Height(), aSize2.Height()));
109 SwMailMergeAddressBlockPage::~SwMailMergeAddressBlockPage()
111 m_xPreviewWIN.reset();
112 m_xSettingsWIN.reset();
113 m_xPreview.reset();
114 m_xSettings.reset();
117 bool SwMailMergeAddressBlockPage::canAdvance() const
119 return m_pWizard->GetConfigItem().GetResultSet().is();
122 void SwMailMergeAddressBlockPage::Activate()
124 SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem();
125 bool bIsLetter = rConfigItem.IsOutputToLetter();
127 //no address block is created for e-Mail
128 m_xStep2->set_visible(bIsLetter);
129 m_xStep3->set_visible(bIsLetter);
130 m_xStep4->set_visible(bIsLetter);
132 if (!bIsLetter)
133 return;
135 m_xHideEmptyParagraphsCB->set_active( rConfigItem.IsHideEmptyParagraphs() );
136 m_xDocumentIndexFI->set_label(m_sDocument.replaceFirst("%1", "1"));
138 m_xSettings->Clear();
139 const uno::Sequence< OUString> aBlocks =
140 m_pWizard->GetConfigItem().GetAddressBlocks();
141 for(const auto& rAddress : aBlocks)
142 m_xSettings->AddAddress(rAddress);
143 m_xSettings->SelectAddress(static_cast<sal_uInt16>(rConfigItem.GetCurrentAddressBlockIndex()));
144 m_xAddressCB->set_active(rConfigItem.IsAddressBlock());
145 AddressBlockHdl_Impl(*m_xAddressCB);
146 m_xSettings->SetLayout(1, 2);
147 InsertDataHdl(nullptr);
150 bool SwMailMergeAddressBlockPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason )
152 return ::vcl::WizardTypes::eTravelForward != _eReason || m_pWizard->GetConfigItem().GetResultSet().is();
155 IMPL_LINK_NOARG(SwMailMergeAddressBlockPage, AddressListHdl_Impl, weld::Button&, void)
159 SwAddressListDialog aAddrDialog(this);
160 if (RET_OK == aAddrDialog.run())
162 SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem();
163 rConfigItem.SetCurrentConnection(
164 aAddrDialog.GetSource(),
165 aAddrDialog.GetConnection(),
166 aAddrDialog.GetColumnsSupplier(),
167 aAddrDialog.GetDBData());
168 OUString sFilter = aAddrDialog.GetFilter();
169 rConfigItem.SetFilter( sFilter );
170 InsertDataHdl(nullptr);
171 GetWizard()->UpdateRoadmap();
172 GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE));
175 catch (const uno::Exception& e)
177 TOOLS_WARN_EXCEPTION("sw", "");
178 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_pWizard->getDialog(),
179 VclMessageType::Warning, VclButtonsType::Ok, e.Message));
180 xBox->run();
184 IMPL_LINK_NOARG(SwMailMergeAddressBlockPage, SettingsHdl_Impl, weld::Button&, void)
186 SwSelectAddressBlockDialog aDlg(m_pWizard->getDialog(), m_pWizard->GetConfigItem());
187 SwMailMergeConfigItem& rConfig = m_pWizard->GetConfigItem();
188 aDlg.SetAddressBlocks(rConfig.GetAddressBlocks(), m_xSettings->GetSelectedAddress());
189 aDlg.SetSettings(rConfig.IsIncludeCountry(), rConfig.GetExcludeCountry());
190 if (aDlg.run() == RET_OK)
192 //the dialog provides the selected address at the first position!
193 const uno::Sequence< OUString> aBlocks = aDlg.GetAddressBlocks();
194 rConfig.SetAddressBlocks(aBlocks);
195 m_xSettings->Clear();
196 for(const auto& rAddress : aBlocks)
197 m_xSettings->AddAddress(rAddress);
198 m_xSettings->SelectAddress(0);
199 m_xSettings->Invalidate(); // #i40408
200 rConfig.SetCountrySettings(aDlg.IsIncludeCountry(), aDlg.GetCountry());
201 InsertDataHdl(nullptr);
203 GetWizard()->UpdateRoadmap();
204 GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE));
207 IMPL_LINK_NOARG(SwMailMergeAddressBlockPage, AssignHdl_Impl, weld::Button&, void)
209 SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem();
210 const sal_uInt16 nSel = m_xSettings->GetSelectedAddress();
211 const uno::Sequence< OUString> aBlocks = rConfigItem.GetAddressBlocks();
212 SwAssignFieldsDialog aDlg(m_pWizard->getDialog(), m_pWizard->GetConfigItem(), aBlocks[nSel], true);
213 if(RET_OK == aDlg.run())
215 //preview update
216 InsertDataHdl(nullptr);
217 GetWizard()->UpdateRoadmap();
218 GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE));
222 void SwMailMergeAddressBlockPage::EnableAddressBlock(bool bAll, bool bSelective)
224 m_xSettingsFI->set_sensitive(bAll);
225 m_xAddressCB->set_sensitive(bAll);
226 bSelective &= bAll;
227 m_xHideEmptyParagraphsCB->set_sensitive(bSelective);
228 m_xSettingsWIN->set_sensitive(bSelective);
229 m_xSettingsPB->set_sensitive(bSelective);
230 m_xStep3->set_sensitive(bSelective);
231 m_xStep4->set_sensitive(bSelective);
234 IMPL_LINK(SwMailMergeAddressBlockPage, AddressBlockHdl_Impl, weld::ToggleButton&, rBox, void)
236 EnableAddressBlock(rBox.get_sensitive(), rBox.get_active());
237 SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem();
238 rConfigItem.SetAddressBlock(m_xAddressCB->get_active());
239 m_pWizard->UpdateRoadmap();
240 GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE));
243 IMPL_LINK_NOARG(SwMailMergeAddressBlockPage, AddressBlockSelectHdl_Impl, LinkParamNone*, void)
245 const sal_uInt16 nSel = m_xSettings->GetSelectedAddress();
246 const uno::Sequence< OUString> aBlocks =
247 m_pWizard->GetConfigItem().GetAddressBlocks();
248 m_xPreview->SetAddress(SwAddressPreview::FillData(aBlocks[nSel],
249 m_pWizard->GetConfigItem()));
250 m_pWizard->GetConfigItem().SetCurrentAddressBlockIndex( nSel );
251 GetWizard()->UpdateRoadmap();
252 GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE));
255 IMPL_LINK(SwMailMergeAddressBlockPage, HideParagraphsHdl_Impl, weld::ToggleButton&, rBox, void)
257 SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem();
258 rConfigItem.SetHideEmptyParagraphs(rBox.get_active());
261 void SwMailMergeAddressBlockPage::InsertDataHdl(const weld::Button* pButton)
263 //if no pButton is given, the first set has to be pre-set
264 SwMailMergeConfigItem& rConfig = m_pWizard->GetConfigItem();
265 std::unique_ptr<weld::WaitObject> xWaitObj(new weld::WaitObject(m_pWizard->getDialog()));
266 if(!pButton)
268 rConfig.GetResultSet();
270 else
272 bool bNext = pButton == m_xNextSetIB.get();
273 sal_Int32 nPos = rConfig.GetResultSetPosition();
274 rConfig.MoveResultSet( bNext ? ++nPos : --nPos);
276 xWaitObj.reset();
277 sal_Int32 nPos = rConfig.GetResultSetPosition();
278 bool bEnable = true;
279 if(nPos < 1)
281 bEnable = false;
282 nPos = 1;
284 else
286 //if output type is letter
287 if (m_xSettings->IsVisible())
289 //Fill data into preview
290 const sal_uInt16 nSel = m_xSettings->GetSelectedAddress();
291 const uno::Sequence< OUString> aBlocks =
292 m_pWizard->GetConfigItem().GetAddressBlocks();
293 m_xPreview->SetAddress(SwAddressPreview::FillData(aBlocks[nSel], rConfig));
296 m_xPrevSetIB->set_sensitive(bEnable);
297 m_xDocumentIndexFI->set_label(m_sDocument.replaceFirst("%1", OUString::number(nPos)));
299 GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE));
300 bool bHasResultSet = rConfig.GetResultSet().is();
301 m_xCurrentAddressFI->set_visible(bHasResultSet);
302 if(bHasResultSet)
304 m_xCurrentAddressFI->set_label(m_sCurrentAddress.replaceFirst("%1", rConfig.GetCurrentDBData().sDataSource));
305 m_xAddressListPB->set_label(m_sChangeAddress);
307 EnableAddressBlock(bHasResultSet, m_xAddressCB->get_active());
310 IMPL_LINK(SwMailMergeAddressBlockPage, InsertDataHdl_Impl, weld::Button&, rButton, void)
312 InsertDataHdl(&rButton);
315 SwSelectAddressBlockDialog::SwSelectAddressBlockDialog(weld::Window* pParent, SwMailMergeConfigItem& rConfig)
316 : SfxDialogController(pParent, "modules/swriter/ui/selectblockdialog.ui", "SelectBlockDialog")
317 , m_rConfig(rConfig)
318 , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("previewwin", true)))
319 , m_xNewPB(m_xBuilder->weld_button("new"))
320 , m_xCustomizePB(m_xBuilder->weld_button("edit"))
321 , m_xDeletePB(m_xBuilder->weld_button("delete"))
322 , m_xNeverRB(m_xBuilder->weld_radio_button("never"))
323 , m_xAlwaysRB(m_xBuilder->weld_radio_button("always"))
324 , m_xDependentRB(m_xBuilder->weld_radio_button("dependent"))
325 , m_xCountryED(m_xBuilder->weld_entry("country"))
326 , m_xPreviewWin(new weld::CustomWeld(*m_xBuilder, "preview", *m_xPreview))
328 m_xPreviewWin->set_size_request(m_xCountryED->get_approximate_digit_width() * 45,
329 m_xCountryED->get_text_height() * 12);
331 Link<weld::Button&,void> aCustomizeHdl = LINK(this, SwSelectAddressBlockDialog, NewCustomizeHdl_Impl);
332 m_xNewPB->connect_clicked(aCustomizeHdl);
333 m_xCustomizePB->connect_clicked(aCustomizeHdl);
335 m_xDeletePB->connect_clicked(LINK(this, SwSelectAddressBlockDialog, DeleteHdl_Impl));
337 Link<weld::ToggleButton&,void> aLk = LINK(this, SwSelectAddressBlockDialog, IncludeHdl_Impl);
338 m_xNeverRB->connect_toggled(aLk);
339 m_xAlwaysRB->connect_toggled(aLk);
340 m_xDependentRB->connect_toggled(aLk);
341 m_xPreview->SetLayout(2, 2);
342 m_xPreview->EnableScrollBar();
345 SwSelectAddressBlockDialog::~SwSelectAddressBlockDialog()
349 void SwSelectAddressBlockDialog::SetAddressBlocks(const uno::Sequence< OUString>& rBlocks,
350 sal_uInt16 nSelectedAddress)
352 m_aAddressBlocks = rBlocks;
353 for (const auto& rAddressBlock : std::as_const(m_aAddressBlocks))
354 m_xPreview->AddAddress(rAddressBlock);
355 m_xPreview->SelectAddress(nSelectedAddress);
358 // return the address blocks and put the selected one to the first position
359 const uno::Sequence< OUString >& SwSelectAddressBlockDialog::GetAddressBlocks()
361 //put the selected block to the first position
362 const sal_Int32 nSelect = static_cast<sal_Int32>(m_xPreview->GetSelectedAddress());
363 if(nSelect)
365 uno::Sequence< OUString >aTemp = m_aAddressBlocks;
366 aTemp[0] = m_aAddressBlocks[nSelect];
367 std::copy(m_aAddressBlocks.begin(), std::next(m_aAddressBlocks.begin(), nSelect), std::next(aTemp.begin()));
368 std::copy(std::next(m_aAddressBlocks.begin(), nSelect + 1), m_aAddressBlocks.end(), std::next(aTemp.begin(), nSelect + 1));
369 m_aAddressBlocks = aTemp;
371 return m_aAddressBlocks;
374 void SwSelectAddressBlockDialog::SetSettings(
375 bool bIsCountry, const OUString& rCountry)
377 weld::RadioButton *pActive = m_xNeverRB.get();
378 if(bIsCountry)
380 pActive = !rCountry.isEmpty() ? m_xDependentRB.get() : m_xAlwaysRB.get();
381 m_xCountryED->set_text(rCountry);
383 pActive->set_active(true);
384 IncludeHdl_Impl(*pActive);
385 m_xDeletePB->set_sensitive(m_aAddressBlocks.getLength() > 1);
388 OUString SwSelectAddressBlockDialog::GetCountry() const
390 if (m_xDependentRB->get_active())
391 return m_xCountryED->get_text();
392 return OUString();
395 IMPL_LINK(SwSelectAddressBlockDialog, DeleteHdl_Impl, weld::Button&, rButton, void)
397 if (m_aAddressBlocks.getLength())
399 const sal_Int32 nSelected = static_cast<sal_Int32>(m_xPreview->GetSelectedAddress());
400 comphelper::removeElementAt(m_aAddressBlocks, nSelected);
401 if (m_aAddressBlocks.getLength() <= 1)
402 rButton.set_sensitive(false);
403 m_xPreview->RemoveSelectedAddress();
407 IMPL_LINK(SwSelectAddressBlockDialog, NewCustomizeHdl_Impl, weld::Button&, rButton, void)
409 bool bCustomize = &rButton == m_xCustomizePB.get();
410 SwCustomizeAddressBlockDialog::DialogType nType = bCustomize ?
411 SwCustomizeAddressBlockDialog::ADDRESSBLOCK_EDIT :
412 SwCustomizeAddressBlockDialog::ADDRESSBLOCK_NEW;
413 std::unique_ptr<SwCustomizeAddressBlockDialog> xDlg(new SwCustomizeAddressBlockDialog(&rButton,
414 m_rConfig, nType));
415 if(bCustomize)
417 xDlg->SetAddress(m_aAddressBlocks[m_xPreview->GetSelectedAddress()]);
419 if (RET_OK != xDlg->run())
420 return;
422 const OUString sNew = xDlg->GetAddress();
423 if(bCustomize)
425 m_xPreview->ReplaceSelectedAddress(sNew);
426 m_aAddressBlocks[m_xPreview->GetSelectedAddress()] = sNew;
428 else
430 m_xPreview->AddAddress(sNew);
431 m_aAddressBlocks.realloc(m_aAddressBlocks.getLength() + 1);
432 const sal_Int32 nSelect = m_aAddressBlocks.getLength() - 1;
433 m_aAddressBlocks[nSelect] = sNew;
434 m_xPreview->SelectAddress(static_cast<sal_uInt16>(nSelect));
436 m_xDeletePB->set_sensitive(m_aAddressBlocks.getLength() > 1);
439 IMPL_LINK_NOARG(SwSelectAddressBlockDialog, IncludeHdl_Impl, weld::ToggleButton&, void)
441 m_xCountryED->set_sensitive(m_xDependentRB->get_active());
444 #define USER_DATA_SALUTATION -1
445 #define USER_DATA_PUNCTUATION -2
446 #define USER_DATA_TEXT -3
447 #define USER_DATA_NONE -4
449 IMPL_LINK(SwCustomizeAddressBlockDialog, TextFilterHdl, OUString&, rTest, bool)
451 rTest = m_aTextFilter.filter(rTest);
452 return true;
455 SwCustomizeAddressBlockDialog::SwCustomizeAddressBlockDialog(
456 weld::Widget* pParent, SwMailMergeConfigItem& rConfig, DialogType eType)
457 : SfxDialogController(pParent, "modules/swriter/ui/addressblockdialog.ui",
458 "AddressBlockDialog")
459 , m_aTextFilter("<>")
460 , m_rConfigItem(rConfig)
461 , m_eType(eType)
462 , m_xAddressElementsFT(m_xBuilder->weld_label("addressesft"))
463 , m_xAddressElementsLB(m_xBuilder->weld_tree_view("addresses"))
464 , m_xInsertFieldIB(m_xBuilder->weld_button("toaddr"))
465 , m_xRemoveFieldIB(m_xBuilder->weld_button("fromaddr"))
466 , m_xDragFT(m_xBuilder->weld_label("addressdestft"))
467 , m_xUpIB(m_xBuilder->weld_button("up"))
468 , m_xLeftIB(m_xBuilder->weld_button("left"))
469 , m_xRightIB(m_xBuilder->weld_button("right"))
470 , m_xDownIB(m_xBuilder->weld_button("down"))
471 , m_xFieldFT(m_xBuilder->weld_label("customft"))
472 , m_xFieldCB(m_xBuilder->weld_combo_box("custom"))
473 , m_xOK(m_xBuilder->weld_button("ok"))
474 , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("previewwin", true)))
475 , m_xPreviewWIN(new weld::CustomWeld(*m_xBuilder, "addrpreview", *m_xPreview))
476 , m_xDragED(new AddressMultiLineEdit(this))
477 , m_xDragWIN(new weld::CustomWeld(*m_xBuilder, "addressdest", *m_xDragED))
479 m_aSelectionChangedIdle.SetInvokeHandler( LINK( this, SwCustomizeAddressBlockDialog, SelectionChangedIdleHdl ) );
481 Size aSize(m_xDragED->GetDrawingArea()->get_size_request());
482 m_xPreview->set_size_request(aSize.Width(), aSize.Height());
484 m_xFieldCB->connect_entry_insert_text(LINK(this, SwCustomizeAddressBlockDialog, TextFilterHdl));
485 m_xAddressElementsLB->set_size_request(-1, m_xAddressElementsLB->get_height_rows(16));
487 if( eType >= GREETING_FEMALE )
489 m_xFieldFT->show();
490 m_xFieldCB->show();
491 m_xAddressElementsLB->append(OUString::number(USER_DATA_SALUTATION), SwResId(ST_SALUTATION));
492 m_xAddressElementsLB->append(OUString::number(USER_DATA_PUNCTUATION), SwResId(ST_PUNCTUATION));
493 m_xAddressElementsLB->append(OUString::number(USER_DATA_TEXT), SwResId(ST_TEXT));
494 for (size_t i = 0; i < SAL_N_ELEMENTS(RA_SALUTATION); ++i)
495 m_aSalutations.push_back(SwResId(RA_SALUTATION[i]));
496 for (size_t i = 0; i < SAL_N_ELEMENTS(RA_PUNCTUATION); ++i)
497 m_aPunctuations.push_back(SwResId(RA_PUNCTUATION[i]));
498 m_xDragED->SetText(" ");
499 m_xDialog->set_title(SwResId(eType == GREETING_MALE ? ST_TITLE_MALE : ST_TITLE_FEMALE));
500 m_xAddressElementsFT->set_label(SwResId(ST_SALUTATIONELEMENTS));
501 m_xInsertFieldIB->set_tooltip_text(SwResId(ST_INSERTSALUTATIONFIELD));
502 m_xRemoveFieldIB->set_tooltip_text(SwResId(ST_REMOVESALUTATIONFIELD));
503 m_xDragFT->set_label(SwResId(ST_DRAGSALUTATION));
505 else
507 if (eType == ADDRESSBLOCK_EDIT)
508 m_xDialog->set_title(SwResId(ST_TITLE_EDIT));
509 m_xDragED->SetText("\n\n\n\n\n");
510 /* Set custom HIDs for swriter/01/mm_newaddblo.xhp */
511 m_xAddressElementsLB->set_help_id( HID_MM_ADDBLOCK_ELEMENTS );
512 m_xInsertFieldIB->set_help_id( HID_MM_ADDBLOCK_INSERT );
513 m_xRemoveFieldIB->set_help_id( HID_MM_ADDBLOCK_REMOVE );
514 m_xDragWIN->set_help_id( HID_MM_ADDBLOCK_DRAG );
515 m_xPreviewWIN->set_help_id( HID_MM_ADDBLOCK_PREVIEW );
516 m_xRightIB->set_help_id( HID_MM_ADDBLOCK_MOVEBUTTONS );
517 m_xLeftIB->set_help_id( HID_MM_ADDBLOCK_MOVEBUTTONS );
518 m_xDownIB->set_help_id( HID_MM_ADDBLOCK_MOVEBUTTONS );
519 m_xUpIB->set_help_id( HID_MM_ADDBLOCK_MOVEBUTTONS );
522 const std::vector<std::pair<OUString, int>>& rHeaders = m_rConfigItem.GetDefaultAddressHeaders();
523 for (size_t i = 0; i < rHeaders.size(); ++i)
524 m_xAddressElementsLB->append(OUString::number(i), rHeaders[i].first);
525 m_xOK->connect_clicked(LINK(this, SwCustomizeAddressBlockDialog, OKHdl_Impl));
526 m_xAddressElementsLB->connect_changed(LINK(this, SwCustomizeAddressBlockDialog, ListBoxSelectHdl_Impl));
527 if (m_xAddressElementsLB->n_children())
528 m_xAddressElementsLB->select(0);
529 m_xDragED->SetModifyHdl(LINK(this, SwCustomizeAddressBlockDialog, EditModifyHdl_Impl));
530 m_xDragED->SetSelectionChangedHdl( LINK( this, SwCustomizeAddressBlockDialog, SelectionChangedHdl_Impl));
531 m_xFieldCB->connect_changed(LINK(this, SwCustomizeAddressBlockDialog, FieldChangeComboBoxHdl_Impl));
532 Link<weld::Button&,void> aImgButtonHdl = LINK(this, SwCustomizeAddressBlockDialog, ImageButtonHdl_Impl);
533 m_xInsertFieldIB->connect_clicked(aImgButtonHdl);
534 m_xRemoveFieldIB->connect_clicked(aImgButtonHdl);
535 m_xUpIB->connect_clicked(aImgButtonHdl);
536 m_xLeftIB->connect_clicked(aImgButtonHdl);
537 m_xRightIB->connect_clicked(aImgButtonHdl);
538 m_xDownIB->connect_clicked(aImgButtonHdl);
539 UpdateImageButtons_Impl();
542 bool SwCustomizeAddressBlockDialog::SetCursorLogicPosition(const Point& rPosition)
544 return m_xDragED->SetCursorLogicPosition(rPosition);
547 void SwCustomizeAddressBlockDialog::UpdateFields()
549 m_xDragED->UpdateFields();
552 SwCustomizeAddressBlockDialog::~SwCustomizeAddressBlockDialog()
554 m_xDragED->EndDropTarget();
557 IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog, OKHdl_Impl, weld::Button&, void)
559 m_xDialog->response(RET_OK);
562 IMPL_LINK(SwCustomizeAddressBlockDialog, ListBoxSelectHdl_Impl, weld::TreeView&, rBox, void)
564 sal_Int32 nUserData = rBox.get_selected_id().toInt32();
565 // Check if the selected entry is already in the address and then forbid inserting
566 m_xInsertFieldIB->set_sensitive(nUserData >= 0 || !HasItem(nUserData));
569 IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog, EditModifyHdl_Impl, AddressMultiLineEdit&, void)
571 m_xPreview->SetAddress(SwAddressPreview::FillData(GetAddress(), m_rConfigItem));
572 UpdateImageButtons_Impl();
575 IMPL_LINK(SwCustomizeAddressBlockDialog, ImageButtonHdl_Impl, weld::Button&, rButton, void)
577 if (m_xInsertFieldIB.get() == &rButton)
579 int nEntry = m_xAddressElementsLB->get_selected_index();
580 if (nEntry != -1)
582 m_xDragED->InsertNewEntry("<" + m_xAddressElementsLB->get_text(nEntry) + ">");
585 else if (m_xRemoveFieldIB.get() == &rButton)
587 m_xDragED->RemoveCurrentEntry();
589 else
591 MoveItemFlags nMove = MoveItemFlags::Down;
592 if (m_xUpIB.get() == &rButton)
593 nMove = MoveItemFlags::Up;
594 else if (m_xLeftIB.get() == &rButton)
595 nMove = MoveItemFlags::Left;
596 else if (m_xRightIB.get() == &rButton)
597 nMove = MoveItemFlags::Right;
598 m_xDragED->MoveCurrentItem(nMove);
600 UpdateImageButtons_Impl();
603 sal_Int32 SwCustomizeAddressBlockDialog::GetSelectedItem_Impl() const
605 sal_Int32 nRet = USER_DATA_NONE;
606 const OUString sSelected = m_xDragED->GetCurrentItem();
607 if(!sSelected.isEmpty())
609 for (int i = 0, nEntryCount = m_xAddressElementsLB->n_children(); i < nEntryCount; ++i)
611 const OUString sEntry = m_xAddressElementsLB->get_text(i);
612 if( sEntry == sSelected.subView( 1, sSelected.getLength() - 2 ) )
614 nRet = m_xAddressElementsLB->get_id(i).toInt32();
615 break;
619 return nRet;
622 bool SwCustomizeAddressBlockDialog::HasItem(sal_Int32 nUserData)
624 //get the entry from the ListBox
625 OUString sEntry;
626 for (int i = 0, nEntryCount = m_xAddressElementsLB->n_children(); i < nEntryCount; ++i)
628 if (m_xAddressElementsLB->get_id(i).toInt32() == nUserData)
630 sEntry = m_xAddressElementsLB->get_text(i);
631 break;
634 //search for this entry in the content
635 return m_xDragED->GetText().indexOf(OUString("<" + sEntry + ">")) >= 0;
638 IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog, SelectionChangedIdleHdl, Timer*, void)
640 // called in case the selection of the edit field changes.
641 // determine selection - if it's one of the editable fields then
642 // enable the related ComboBox and fill it
644 // don't trigger outself again
645 m_xDragED->SetSelectionChangedHdl(Link<bool, void>());
647 sal_Int32 nSelected = GetSelectedItem_Impl();
648 if (USER_DATA_NONE != nSelected)
649 m_xDragED->SelectCurrentItem();
651 if(m_xFieldCB->get_visible() && (USER_DATA_NONE != nSelected) && (nSelected < 0))
653 //search in ListBox if it's one of the first entries
654 OUString sSelect;
655 std::vector<OUString>* pVector = nullptr;
656 switch(nSelected) {
657 case USER_DATA_SALUTATION:
658 sSelect = m_sCurrentSalutation;
659 pVector = &m_aSalutations;
660 break;
661 case USER_DATA_PUNCTUATION:
662 sSelect = m_sCurrentPunctuation;
663 pVector = &m_aPunctuations;
664 break;
665 case USER_DATA_TEXT:
666 sSelect = m_sCurrentText;
667 break;
669 m_xFieldCB->clear();
670 if(pVector) {
671 for (const auto& rItem : *pVector)
672 m_xFieldCB->append_text(rItem);
674 m_xFieldCB->set_entry_text(sSelect);
675 m_xFieldCB->set_sensitive(true);
676 m_xFieldFT->set_sensitive(true);
678 else
680 m_xFieldCB->set_sensitive(false);
681 m_xFieldFT->set_sensitive(false);
684 UpdateImageButtons_Impl();
685 m_xDragED->SetSelectionChangedHdl( LINK( this, SwCustomizeAddressBlockDialog, SelectionChangedHdl_Impl));
688 IMPL_LINK(SwCustomizeAddressBlockDialog, SelectionChangedHdl_Impl, bool, bIdle, void)
690 if (bIdle)
691 m_aSelectionChangedIdle.Start();
692 else
694 m_aSelectionChangedIdle.Stop();
695 SelectionChangedIdleHdl(nullptr);
699 IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog, FieldChangeComboBoxHdl_Impl, weld::ComboBox&, void)
701 //changing the field content changes the related members, too
702 sal_Int32 nSelected = GetSelectedItem_Impl();
703 const OUString sContent = m_xFieldCB->get_active_text();
704 switch(nSelected) {
705 case USER_DATA_SALUTATION:
706 m_sCurrentSalutation = sContent;
707 break;
708 case USER_DATA_PUNCTUATION:
709 m_sCurrentPunctuation = sContent;
710 break;
711 case USER_DATA_TEXT:
712 m_sCurrentText = sContent;
713 break;
715 UpdateImageButtons_Impl();
716 m_xPreview->SetAddress(GetAddress());
717 EditModifyHdl_Impl(*m_xDragED);
720 void SwCustomizeAddressBlockDialog::UpdateImageButtons_Impl()
722 MoveItemFlags nMove = m_xDragED->IsCurrentItemMoveable();
723 m_xUpIB->set_sensitive( bool(nMove & MoveItemFlags::Up) );
724 m_xLeftIB->set_sensitive( bool(nMove & MoveItemFlags::Left) );
725 m_xRightIB->set_sensitive( bool(nMove & MoveItemFlags::Right) );
726 m_xDownIB->set_sensitive( bool(nMove & MoveItemFlags::Down) );
727 m_xRemoveFieldIB->set_sensitive(m_xDragED->HasCurrentItem());
728 int nEntry = m_xAddressElementsLB->get_selected_index();
729 m_xInsertFieldIB->set_sensitive( nEntry != -1 &&
730 (m_xAddressElementsLB->get_id(nEntry).toInt32() >= 0 || !m_xFieldCB->get_active_text().isEmpty()));
733 void SwCustomizeAddressBlockDialog::SetAddress(const OUString& rAddress)
735 m_xDragED->SetText(rAddress);
736 UpdateImageButtons_Impl();
737 EditModifyHdl_Impl(*m_xDragED);
740 OUString SwCustomizeAddressBlockDialog::GetAddress() const
742 OUString sAddress(m_xDragED->GetAddress());
743 //remove placeholders by the actual content
744 if (m_xFieldFT->get_visible())
746 for (int i = 0, nEntryCount = m_xAddressElementsLB->n_children(); i < nEntryCount; ++i)
748 const OUString sEntry = "<" + m_xAddressElementsLB->get_text(i) + ">";
749 sal_Int32 nUserData = m_xAddressElementsLB->get_id(i).toInt32();
750 switch(nUserData)
752 case USER_DATA_SALUTATION:
753 sAddress = sAddress.replaceFirst(sEntry, m_sCurrentSalutation);
754 break;
755 case USER_DATA_PUNCTUATION:
756 sAddress = sAddress.replaceFirst(sEntry, m_sCurrentPunctuation);
757 break;
758 case USER_DATA_TEXT:
759 sAddress = sAddress.replaceFirst(sEntry, m_sCurrentText);
760 break;
764 return sAddress;
767 namespace {
769 struct SwAssignFragment
771 std::unique_ptr<weld::Builder> m_xBuilder;
772 std::unique_ptr<weld::Label> m_xLabel;
773 std::unique_ptr<weld::ComboBox> m_xComboBox;
774 std::unique_ptr<weld::Label> m_xPreview;
776 SwAssignFragment(weld::Container* pGrid, int nLine)
777 : m_xBuilder(Application::CreateBuilder(pGrid, "modules/swriter/ui/assignfragment.ui"))
778 , m_xLabel(m_xBuilder->weld_label("label"))
779 , m_xComboBox(m_xBuilder->weld_combo_box("combobox"))
780 , m_xPreview(m_xBuilder->weld_label("preview"))
782 m_xLabel->set_grid_left_attach(0);
783 m_xLabel->set_grid_top_attach(nLine);
785 m_xComboBox->set_grid_left_attach(1);
786 m_xComboBox->set_grid_top_attach(nLine);
788 m_xPreview->set_grid_left_attach(2);
789 m_xPreview->set_grid_top_attach(nLine);
795 class SwAssignFieldsControl
797 friend class SwAssignFieldsDialog;
798 std::unique_ptr<weld::ScrolledWindow> m_xVScroll;
799 std::unique_ptr<weld::Container> m_xGrid;
801 std::vector<SwAssignFragment> m_aFields;
803 SwMailMergeConfigItem* m_rConfigItem;
805 Link<LinkParamNone*,void> m_aModifyHdl;
807 DECL_LINK(MatchHdl_Impl, weld::ComboBox&, void);
808 DECL_LINK(GotFocusHdl_Impl, weld::Widget&, void);
810 void MakeVisible(const tools::Rectangle & rRect);
811 public:
812 SwAssignFieldsControl(std::unique_ptr<weld::ScrolledWindow> xWindow,
813 std::unique_ptr<weld::Container> xGrid);
815 void Init(SwAssignFieldsDialog* pDialog, SwMailMergeConfigItem& rConfigItem);
816 void SetModifyHdl(const Link<LinkParamNone*,void>& rModifyHdl)
818 m_aModifyHdl = rModifyHdl;
819 m_aModifyHdl.Call(nullptr);
823 SwAssignFieldsControl::SwAssignFieldsControl(std::unique_ptr<weld::ScrolledWindow> xWindow,
824 std::unique_ptr<weld::Container> xGrid)
825 : m_xVScroll(std::move(xWindow))
826 , m_xGrid(std::move(xGrid))
827 , m_rConfigItem(nullptr)
831 void SwAssignFieldsControl::Init(SwAssignFieldsDialog* pDialog, SwMailMergeConfigItem& rConfigItem)
833 m_rConfigItem = &rConfigItem;
835 //get the name of the default headers
836 const std::vector<std::pair<OUString, int>>& rHeaders = rConfigItem.GetDefaultAddressHeaders();
837 //get the actual data
838 uno::Reference< XColumnsSupplier > xColsSupp( rConfigItem.GetResultSet(), uno::UNO_QUERY);
839 //get the name of the actual columns
840 uno::Reference <XNameAccess> xColAccess = xColsSupp.is() ? xColsSupp->getColumns() : nullptr;
841 uno::Sequence< OUString > aFields;
842 if(xColAccess.is())
843 aFields = xColAccess->getElementNames();
845 //get the current assignment list
846 //each position in this sequence matches the position in the header array rHeaders
847 //if no assignment is available an empty sequence will be returned
848 uno::Sequence< OUString> aAssignments = rConfigItem.GetColumnAssignment( rConfigItem.GetCurrentDBData() );
849 Link<weld::ComboBox&,void> aMatchHdl = LINK(this, SwAssignFieldsControl, MatchHdl_Impl);
850 Link<weld::Widget&,void> aFocusHdl = LINK(this, SwAssignFieldsControl, GotFocusHdl_Impl);
852 int nLabelWidth(0), nComboBoxWidth(0), nPreviewWidth(0);
854 //fill the controls
855 for (size_t i = 0; i < rHeaders.size(); ++i)
857 m_aFields.emplace_back(m_xGrid.get(), i);
859 const OUString rHeader = rHeaders[i].first;
860 weld::ComboBox& rNewLB = *m_aFields.back().m_xComboBox;
861 rNewLB.append_text(SwResId(SW_STR_NONE));
862 rNewLB.set_active(0);
864 for (const OUString& rField : std::as_const(aFields))
865 rNewLB.append_text(rField);
866 //select the ListBox
867 //if there is an assignment
868 if(o3tl::make_unsigned(aAssignments.getLength()) > i && !aAssignments[i].isEmpty())
869 rNewLB.set_active_text(aAssignments[i]);
870 else //otherwise the current column name may match one of the db columns
871 rNewLB.set_active_text(rHeader);
873 weld::Label& rNewText = *m_aFields.back().m_xLabel;
874 rNewText.set_label("<" + rHeader + ">");
876 weld::Label& rNewPreview = *m_aFields.back().m_xPreview;
877 //then the preview can be filled accordingly
878 if (xColAccess.is() && rNewLB.get_active() > 0 &&
879 xColAccess->hasByName(rNewLB.get_active_text()))
881 uno::Any aCol = xColAccess->getByName(rNewLB.get_active_text());
882 uno::Reference< XColumn > xColumn;
883 aCol >>= xColumn;
884 if(xColumn.is())
888 rNewPreview.set_label(xColumn->getString());
890 catch (const SQLException&)
896 if (i == 0)
898 auto nLineHeight = m_xGrid->get_preferred_size().Height();
899 m_xVScroll->set_size_request(m_xVScroll->get_approximate_digit_width() * 65,
900 nLineHeight * 6);
901 nComboBoxWidth = rNewLB.get_preferred_size().Width();
904 nLabelWidth = std::max<int>(nLabelWidth, rNewText.get_preferred_size().Width());
905 nPreviewWidth = std::max<int>(nPreviewWidth, rNewPreview.get_preferred_size().Width());
907 rNewLB.connect_changed(aMatchHdl);
908 rNewLB.connect_focus_in(aFocusHdl);
909 rNewText.show();
910 rNewLB.show();
911 rNewPreview.show();
913 pDialog->ConnectSizeGroups(nLabelWidth, nComboBoxWidth, nPreviewWidth);
916 void SwAssignFieldsControl::MakeVisible(const tools::Rectangle & rRect)
918 //determine range of visible positions
919 auto nMinVisiblePos = m_xVScroll->vadjustment_get_value();
920 auto nMaxVisiblePos = nMinVisiblePos + m_xVScroll->vadjustment_get_page_size();
921 if (rRect.Top() < nMinVisiblePos || rRect.Bottom() > nMaxVisiblePos)
922 m_xVScroll->vadjustment_set_value(rRect.Top());
925 IMPL_LINK(SwAssignFieldsControl, MatchHdl_Impl, weld::ComboBox&, rBox, void)
927 const OUString sColumn = rBox.get_active_text();
928 uno::Reference< XColumnsSupplier > xColsSupp( m_rConfigItem->GetResultSet(), uno::UNO_QUERY);
929 uno::Reference <XNameAccess> xColAccess = xColsSupp.is() ? xColsSupp->getColumns() : nullptr;
930 OUString sPreview;
931 if(xColAccess.is() && xColAccess->hasByName(sColumn))
933 uno::Any aCol = xColAccess->getByName(sColumn);
934 uno::Reference< XColumn > xColumn;
935 aCol >>= xColumn;
936 if(xColumn.is())
940 sPreview = xColumn->getString();
942 catch (const sdbc::SQLException&)
947 auto aLBIter = std::find_if(m_aFields.begin(), m_aFields.end(), [&rBox](const SwAssignFragment& rFragment){
948 return &rBox == rFragment.m_xComboBox.get(); });
949 if (aLBIter != m_aFields.end())
951 auto nIndex = static_cast<sal_Int32>(std::distance(m_aFields.begin(), aLBIter));
952 m_aFields[nIndex].m_xPreview->set_label(sPreview);
954 m_aModifyHdl.Call(nullptr);
957 IMPL_LINK(SwAssignFieldsControl, GotFocusHdl_Impl, weld::Widget&, rBox, void)
959 int x, y, width, height;
960 rBox.get_extents_relative_to(*m_xGrid, x, y, width, height);
961 // the container has a border of 3 in the .ui
962 tools::Rectangle aRect(Point(x - 3, y - 3), Size(width + 6, height + 6));
963 MakeVisible(aRect);
966 SwAssignFieldsDialog::SwAssignFieldsDialog(
967 weld::Window* pParent, SwMailMergeConfigItem& rConfigItem,
968 const OUString& rPreview,
969 bool bIsAddressBlock)
970 : SfxDialogController(pParent, "modules/swriter/ui/assignfieldsdialog.ui", "AssignFieldsDialog")
971 , m_sNone(SwResId(SW_STR_NONE))
972 , m_rPreviewString(rPreview)
973 , m_rConfigItem(rConfigItem)
974 , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("previewwin", true)))
975 , m_xMatchingFI(m_xBuilder->weld_label("MATCHING_LABEL"))
976 , m_xAddressTitle(m_xBuilder->weld_label("addresselem"))
977 , m_xMatchTitle(m_xBuilder->weld_label("matchelem"))
978 , m_xPreviewTitle(m_xBuilder->weld_label("previewelem"))
979 , m_xPreviewFI(m_xBuilder->weld_label("PREVIEW_LABEL"))
980 , m_xOK(m_xBuilder->weld_button("ok"))
981 , m_xPreviewWin(new weld::CustomWeld(*m_xBuilder, "PREVIEW", *m_xPreview))
982 , m_xFieldsControl(new SwAssignFieldsControl(m_xBuilder->weld_scrolled_window("scroll"),
983 m_xBuilder->weld_container("FIELDS")))
985 m_xPreviewWin->set_size_request(m_xMatchingFI->get_approximate_digit_width() * 45,
986 m_xMatchingFI->get_text_height() * 5);
987 m_xFieldsControl->Init(this, rConfigItem);
989 const OUString sMatchesTo( SwResId(ST_MATCHESTO) );
990 if (!bIsAddressBlock)
992 m_xPreviewFI->set_label(SwResId(ST_SALUTATIONPREVIEW));
993 m_xMatchingFI->set_label(SwResId(ST_SALUTATIONMATCHING));
994 m_xAddressTitle->set_label(SwResId(ST_SALUTATIONELEMENT));
997 m_xFieldsControl->SetModifyHdl(LINK(this, SwAssignFieldsDialog, AssignmentModifyHdl_Impl ));
998 m_xMatchingFI->set_label(m_xMatchingFI->get_label().replaceAll("%1", sMatchesTo));
999 m_xOK->connect_clicked(LINK(this, SwAssignFieldsDialog, OkHdl_Impl));
1002 SwAssignFieldsDialog::~SwAssignFieldsDialog()
1006 uno::Sequence< OUString > SwAssignFieldsDialog::CreateAssignments()
1008 uno::Sequence< OUString > aAssignments(
1009 m_rConfigItem.GetDefaultAddressHeaders().size());
1010 OUString* pAssignments = aAssignments.getArray();
1011 sal_Int32 nIndex = 0;
1012 for (const auto& rLBItem : m_xFieldsControl->m_aFields)
1014 const OUString sSelect = rLBItem.m_xComboBox->get_active_text();
1015 pAssignments[nIndex] = (m_sNone != sSelect) ? sSelect : OUString();
1016 ++nIndex;
1018 return aAssignments;
1021 IMPL_LINK_NOARG(SwAssignFieldsDialog, OkHdl_Impl, weld::Button&, void)
1023 m_rConfigItem.SetColumnAssignment(
1024 m_rConfigItem.GetCurrentDBData(),
1025 CreateAssignments() );
1026 m_xDialog->response(RET_OK);
1029 IMPL_LINK_NOARG(SwAssignFieldsDialog, AssignmentModifyHdl_Impl, LinkParamNone*, void)
1031 uno::Sequence< OUString > aAssignments = CreateAssignments();
1032 const OUString sPreview = SwAddressPreview::FillData(
1033 m_rPreviewString, m_rConfigItem, &aAssignments);
1034 m_xPreview->SetAddress(sPreview);
1037 void SwAssignFieldsDialog::ConnectSizeGroups(int nLabelWidth, int nComboBoxWidth, int nPreviewWidth)
1039 m_xAddressTitle->set_size_request(nLabelWidth, -1);
1040 m_xMatchTitle->set_size_request(nComboBoxWidth, -1);
1041 m_xPreviewTitle->set_size_request(nPreviewWidth, -1);
1044 namespace
1046 const EECharAttrib* FindCharAttrib(int nStartPosition, std::vector<EECharAttrib>& rAttribList)
1048 for (auto it = rAttribList.rbegin(); it != rAttribList.rend(); ++it)
1050 const auto& rTextAtr = *it;
1051 if (rTextAtr.pAttr->Which() != EE_CHAR_GRABBAG)
1052 continue;
1053 if (rTextAtr.nStart <= nStartPosition && rTextAtr.nEnd >= nStartPosition)
1055 return &rTextAtr;
1059 return nullptr;
1063 AddressMultiLineEdit::AddressMultiLineEdit(SwCustomizeAddressBlockDialog *pParent)
1064 : m_pParentDialog(pParent)
1068 void AddressMultiLineEdit::EndDropTarget()
1070 if (m_xDropTarget.is())
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();
1079 AddressMultiLineEdit::~AddressMultiLineEdit()
1081 assert(!m_xDropTarget.is());
1084 void AddressMultiLineEdit::SetDrawingArea(weld::DrawingArea* pDrawingArea)
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);
1091 bool AddressMultiLineEdit::KeyInput(const KeyEvent& rKEvt)
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);
1100 bool AddressMultiLineEdit::MouseButtonDown(const MouseEvent& rMEvt)
1102 if (rMEvt.GetClicks() >= 2)
1103 return true; // handled
1104 return WeldEditView::MouseButtonDown(rMEvt);
1107 OUString AddressMultiLineEdit::GetText() const
1109 return m_xEditEngine->GetText();
1112 void AddressMultiLineEdit::SetText( const OUString& rStr )
1114 m_xEditEngine->SetText(rStr);
1115 //set attributes to all address tokens
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)
1122 sal_Int32 nIndex = 0;
1123 const OUString sPara = m_xEditEngine->GetText( nPara );
1124 if (!sPara.isEmpty() && !sPara.endsWith(" "))
1126 ESelection aPaM(nPara, sPara.getLength(), nPara, sPara.getLength());
1127 m_xEditEngine->QuickInsertText(" ", aPaM);
1129 for(;;)
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));
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)
1151 sal_Int32 nLastLen = m_xEditEngine->GetText(nParaCount - 1).getLength();
1152 if(nLastLen)
1154 int nPara = nParaCount ? nParaCount - 1 : 0;
1155 ESelection aPaM(nPara, nLastLen, nPara, nLastLen);
1156 m_xEditEngine->QuickInsertText("\n \n ", aPaM);
1160 m_xEditView->SetSelection(ESelection(0, 0, 0, 0));
1163 // Insert the new entry in front of the entry at the beginning of the selection
1164 void AddressMultiLineEdit::InsertNewEntry( const OUString& rStr )
1166 // insert new entry after current selected one.
1167 ESelection aSelection = m_xEditView->GetSelection();
1168 const sal_uInt32 nPara = aSelection.nStartPara;
1170 std::vector<EECharAttrib> aAttribList;
1171 m_xEditEngine->GetCharAttribs(nPara, aAttribList);
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 );
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);
1189 void AddressMultiLineEdit::InsertNewEntryAtPosition( const OUString& rStr, sal_uLong nPara, sal_uInt16 nIndex )
1191 ESelection aInsertPos(nPara, nIndex, nPara, nIndex);
1192 m_xEditEngine->QuickInsertText(rStr, aInsertPos);
1194 //restore the attributes
1195 SetText( GetAddress() );
1197 //select the newly inserted/moved element
1198 m_xEditView->SetSelection(aInsertPos);
1199 m_aSelectionLink.Call(false);
1202 void AddressMultiLineEdit::RemoveCurrentEntry()
1204 ESelection aSelection = m_xEditView->GetSelection();
1206 std::vector<EECharAttrib> aAttribList;
1207 m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList);
1209 const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList);
1210 if(pBeginAttrib &&
1211 (pBeginAttrib->nStart <= aSelection.nStartPos
1212 && pBeginAttrib->nEnd >= aSelection.nEndPos))
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);
1223 void AddressMultiLineEdit::MoveCurrentItem(MoveItemFlags nMove)
1225 ESelection aSelection = m_xEditView->GetSelection();
1227 std::vector<EECharAttrib> aAttribList;
1228 m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList);
1230 const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList);
1231 if(!pBeginAttrib ||
1232 pBeginAttrib->nStart > aSelection.nStartPos ||
1233 pBeginAttrib->nEnd < aSelection.nEndPos)
1234 return;
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)
1246 case MoveItemFlags::Left :
1247 if(nIndex)
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 )
1255 nSearchIndex = sPara.lastIndexOf( '<', nIndex );
1256 if( nSearchIndex != -1 )
1257 nIndex = nSearchIndex;
1260 break;
1261 case MoveItemFlags::Right:
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)
1268 nIndex = pEndAttrib->nEnd;
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;
1282 //add a new paragraph if there is none yet
1283 if (nPara >= m_xEditEngine->GetParagraphCount())
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);
1290 InsertNewEntryAtPosition( sCurrentItem, nPara, nIndex );
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);
1302 MoveItemFlags AddressMultiLineEdit::IsCurrentItemMoveable() const
1304 MoveItemFlags nRet = MoveItemFlags::NONE;
1305 ESelection aSelection = m_xEditView->GetSelection();
1307 std::vector<EECharAttrib> aAttribList;
1308 m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList);
1310 const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList);
1311 if (pBeginAttrib &&
1312 (pBeginAttrib->nStart <= aSelection.nStartPos
1313 && pBeginAttrib->nEnd >= aSelection.nEndPos))
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;
1322 return nRet;
1325 bool AddressMultiLineEdit::HasCurrentItem() const
1327 ESelection aSelection = m_xEditView->GetSelection();
1329 std::vector<EECharAttrib> aAttribList;
1330 m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList);
1332 const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList);
1333 return (pBeginAttrib &&
1334 (pBeginAttrib->nStart <= aSelection.nStartPos
1335 && pBeginAttrib->nEnd >= aSelection.nEndPos));
1338 OUString AddressMultiLineEdit::GetCurrentItem() const
1340 ESelection aSelection = m_xEditView->GetSelection();
1342 std::vector<EECharAttrib> aAttribList;
1343 m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList);
1345 const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList);
1346 if (pBeginAttrib &&
1347 (pBeginAttrib->nStart <= aSelection.nStartPos
1348 && pBeginAttrib->nEnd >= aSelection.nEndPos))
1350 const sal_uInt32 nPara = aSelection.nStartPara;
1351 ESelection aEntrySel(nPara, pBeginAttrib->nStart, nPara, pBeginAttrib->nEnd);
1352 return m_xEditEngine->GetText( aEntrySel );
1354 return OUString();
1357 void AddressMultiLineEdit::SelectCurrentItem()
1359 ESelection aSelection = m_xEditView->GetSelection();
1361 std::vector<EECharAttrib> aAttribList;
1362 m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList);
1364 const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList);
1365 if (pBeginAttrib &&
1366 (pBeginAttrib->nStart <= aSelection.nStartPos
1367 && pBeginAttrib->nEnd >= aSelection.nEndPos))
1369 const sal_uInt32 nPara = aSelection.nStartPara;
1370 ESelection aEntrySel(nPara, pBeginAttrib->nStart, nPara, pBeginAttrib->nEnd);
1371 m_xEditView->SetSelection(aEntrySel);
1372 Invalidate();
1376 OUString AddressMultiLineEdit::GetAddress() const
1378 OUString sRet;
1379 const sal_uInt32 nParaCount = m_xEditEngine->GetParagraphCount();
1380 for(sal_uInt32 nPara = nParaCount; nPara; --nPara)
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())
1386 sRet = sPara + sRet;
1387 //insert the para break
1388 if(nPara > 1)
1389 sRet = "\n" + sRet;
1392 return sRet;
1395 void AddressMultiLineEdit::UpdateFields()
1397 ESelection aSelection = m_xEditView->GetSelection();
1399 //restore the attributes
1400 SetText( GetAddress() );
1402 //reselect the element
1403 m_xEditView->SetSelection(aSelection);
1404 m_aSelectionLink.Call(false);
1407 void AddressMultiLineEdit::EditViewSelectionChange()
1409 WeldEditView::EditViewSelectionChange();
1410 m_aSelectionLink.Call(true);
1413 namespace
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 >
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;
1425 // XEventListener
1426 virtual void SAL_CALL disposing( const css::lang::EventObject& ) override
1428 m_xRealDropTarget.clear();
1429 m_aListeners.clear();
1432 // XDropTargetListener
1433 virtual void SAL_CALL drop( const css::datatransfer::dnd::DropTargetDropEvent& dtde ) override
1435 SolarMutexGuard aGuard;
1437 auto aReplacement(dtde);
1439 Point aMousePos(dtde.LocationX, dtde.LocationY);
1440 bool bAllowed = m_pParentDialog->SetCursorLogicPosition(aMousePos);
1441 if (bAllowed)
1443 if (weld::TreeView* pTree = m_pParentDialog->get_drag_source())
1445 int nEntry = pTree->get_selected_index();
1446 if (nEntry != -1)
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))
1452 rtl::Reference<TransferDataContainer> xContainer = new TransferDataContainer;
1453 xContainer->CopyString( "<" + pTree->get_text(nEntry) + ">" );
1455 // replace what the treeview is offering with what ImpEditView::drop wants
1456 aReplacement.Transferable = xContainer.get();
1462 std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners);
1463 for (auto const& listener : aListeners)
1464 listener->drop(aReplacement);
1466 if (bAllowed)
1467 m_pParentDialog->UpdateFields();
1470 virtual void SAL_CALL dragEnter( const css::datatransfer::dnd::DropTargetDragEnterEvent& dtdee ) override
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]);
1477 std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners);
1478 for (auto const& listener : aListeners)
1479 listener->dragEnter(aReplacement);
1482 virtual void SAL_CALL dragExit( const css::datatransfer::dnd::DropTargetEvent& dte ) override
1484 std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners);
1485 for (auto const& listener : aListeners)
1486 listener->dragExit( dte );
1489 virtual void SAL_CALL dragOver( const css::datatransfer::dnd::DropTargetDragEvent& dtde ) override
1491 std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners);
1492 for (auto const& listener : aListeners)
1493 listener->dragOver( dtde );
1496 virtual void SAL_CALL dropActionChanged( const css::datatransfer::dnd::DropTargetDragEvent& dtde ) override
1498 std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners);
1499 for (auto const& listener : aListeners)
1500 listener->dropActionChanged( dtde );
1503 // XDropTarget
1504 virtual void SAL_CALL addDropTargetListener(const css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>& xListener) override
1506 m_aListeners.push_back(xListener);
1509 virtual void SAL_CALL removeDropTargetListener(const css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>& xListener) override
1511 m_aListeners.erase(std::remove(m_aListeners.begin(), m_aListeners.end(), xListener), m_aListeners.end());
1514 virtual sal_Bool SAL_CALL isActive() override
1516 return m_xRealDropTarget->isActive();
1519 virtual void SAL_CALL setActive(sal_Bool active) override
1521 m_xRealDropTarget->setActive(active);
1524 virtual sal_Int8 SAL_CALL getDefaultActions() override
1526 return m_xRealDropTarget->getDefaultActions();
1529 virtual void SAL_CALL setDefaultActions(sal_Int8 actions) override
1531 m_xRealDropTarget->setDefaultActions(actions);
1534 public:
1535 DropTargetListener(css::uno::Reference<css::datatransfer::dnd::XDropTarget> xRealDropTarget,
1536 SwCustomizeAddressBlockDialog* pParentDialog)
1537 : m_xRealDropTarget(xRealDropTarget)
1538 , m_pParentDialog(pParentDialog)
1544 css::uno::Reference<css::datatransfer::dnd::XDropTarget> AddressMultiLineEdit::GetDropTarget()
1546 if (!m_xDropTarget.is())
1548 auto xRealDropTarget = GetDrawingArea()->get_drop_target();
1549 DropTargetListener* pProxy = new DropTargetListener(xRealDropTarget, m_pParentDialog);
1550 uno::Reference<css::datatransfer::dnd::XDropTargetListener> xListener(pProxy);
1551 xRealDropTarget->addDropTargetListener(xListener);
1552 m_xDropTarget = uno::Reference<css::datatransfer::dnd::XDropTarget>(pProxy);
1554 return m_xDropTarget;
1557 bool AddressMultiLineEdit::SetCursorLogicPosition(const Point& rPosition)
1559 Point aMousePos = EditViewOutputDevice().PixelToLogic(rPosition);
1560 m_xEditView->SetCursorLogicPosition(aMousePos, false, true);
1562 ESelection aSelection = m_xEditView->GetSelection();
1563 std::vector<EECharAttrib> aAttribList;
1564 m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList);
1565 return FindCharAttrib(aSelection.nStartPos, aAttribList) == nullptr;
1568 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */