/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include "mmaddressblockpage.hxx" #include #include #include "addresslistdialog.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace svt; using namespace ::com::sun::star; using namespace ::com::sun::star::container; using namespace ::com::sun::star::sdb; using namespace ::com::sun::star::sdbc; using namespace ::com::sun::star::sdbcx; SwMailMergeAddressBlockPage::SwMailMergeAddressBlockPage(weld::Container* pPage, SwMailMergeWizard* pWizard) : vcl::OWizardPage(pPage, pWizard, "modules/swriter/ui/mmaddressblockpage.ui", "MMAddressBlockPage") , m_pWizard(pWizard) , m_xAddressListPB(m_xBuilder->weld_button("addresslist")) , m_xCurrentAddressFI(m_xBuilder->weld_label("currentaddress")) , m_xStep2(m_xBuilder->weld_container("step2")) , m_xStep3(m_xBuilder->weld_container("step3")) , m_xStep4(m_xBuilder->weld_container("step4")) , m_xSettingsFI(m_xBuilder->weld_label("settingsft")) , m_xAddressCB(m_xBuilder->weld_check_button("address")) , m_xSettingsPB(m_xBuilder->weld_button("settings")) , m_xHideEmptyParagraphsCB(m_xBuilder->weld_check_button("hideempty")) , m_xAssignPB(m_xBuilder->weld_button("assign")) , m_xDocumentIndexFI(m_xBuilder->weld_label("documentindex")) , m_xPrevSetIB(m_xBuilder->weld_button("prev")) , m_xNextSetIB(m_xBuilder->weld_button("next")) , m_xDifferentlist(m_xBuilder->weld_button("differentlist")) , m_xSettings(new SwAddressPreview(m_xBuilder->weld_scrolled_window("settingspreviewwin"))) , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("addresspreviewwin"))) , m_xSettingsWIN(new weld::CustomWeld(*m_xBuilder, "settingspreview", *m_xSettings)) , m_xPreviewWIN(new weld::CustomWeld(*m_xBuilder, "addresspreview", *m_xPreview)) { m_xSettingsWIN->set_size_request(m_xDifferentlist->get_approximate_digit_width() * 40, m_xDifferentlist->get_text_height() * 6); m_xPreviewWIN->set_size_request(m_xDifferentlist->get_approximate_digit_width() * 44, m_xDifferentlist->get_text_height() * 6); m_sChangeAddress = m_xDifferentlist->get_label(); m_sDocument = m_xDocumentIndexFI->get_label(); m_sCurrentAddress = m_xCurrentAddressFI->get_label(); m_xAddressListPB->connect_clicked(LINK(this, SwMailMergeAddressBlockPage, AddressListHdl_Impl)); m_xSettingsPB->connect_clicked(LINK(this, SwMailMergeAddressBlockPage, SettingsHdl_Impl)); m_xAssignPB->connect_clicked(LINK(this, SwMailMergeAddressBlockPage, AssignHdl_Impl )); m_xAddressCB->connect_toggled(LINK(this, SwMailMergeAddressBlockPage, AddressBlockHdl_Impl)); m_xSettings->SetSelectHdl(LINK(this, SwMailMergeAddressBlockPage, AddressBlockSelectHdl_Impl)); m_xHideEmptyParagraphsCB->connect_toggled(LINK(this, SwMailMergeAddressBlockPage, HideParagraphsHdl_Impl)); Link aLink = LINK(this, SwMailMergeAddressBlockPage, InsertDataHdl_Impl); m_xPrevSetIB->connect_clicked(aLink); m_xNextSetIB->connect_clicked(aLink); // lock in preferred size including current address line Size aSize1(m_xContainer->get_preferred_size()); OUString sOrigLabel = m_xAddressListPB->get_label(); m_xAddressListPB->set_label(m_sChangeAddress); Size aSize2(m_xContainer->get_preferred_size()); m_xAddressListPB->set_label(sOrigLabel); m_xCurrentAddressFI->hide(); m_xContainer->set_size_request(std::max(aSize1.Width(), aSize2.Width()), std::max(aSize1.Height(), aSize2.Height())); } SwMailMergeAddressBlockPage::~SwMailMergeAddressBlockPage() { m_xPreviewWIN.reset(); m_xSettingsWIN.reset(); m_xPreview.reset(); m_xSettings.reset(); } bool SwMailMergeAddressBlockPage::canAdvance() const { return m_pWizard->GetConfigItem().GetResultSet().is(); } void SwMailMergeAddressBlockPage::Activate() { SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem(); bool bIsLetter = rConfigItem.IsOutputToLetter(); //no address block is created for e-Mail m_xStep2->set_visible(bIsLetter); m_xStep3->set_visible(bIsLetter); m_xStep4->set_visible(bIsLetter); if (bIsLetter) { m_xHideEmptyParagraphsCB->set_active( rConfigItem.IsHideEmptyParagraphs() ); m_xDocumentIndexFI->set_label(m_sDocument.replaceFirst("%1", "1")); m_xSettings->Clear(); const uno::Sequence< OUString> aBlocks = m_pWizard->GetConfigItem().GetAddressBlocks(); for(const auto& rAddress : aBlocks) m_xSettings->AddAddress(rAddress); m_xSettings->SelectAddress(static_cast(rConfigItem.GetCurrentAddressBlockIndex())); m_xAddressCB->set_active(rConfigItem.IsAddressBlock()); AddressBlockHdl_Impl(*m_xAddressCB); m_xSettings->SetLayout(1, 2); InsertDataHdl(nullptr); } } bool SwMailMergeAddressBlockPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) { return ::vcl::WizardTypes::eTravelForward != _eReason || m_pWizard->GetConfigItem().GetResultSet().is(); } IMPL_LINK_NOARG(SwMailMergeAddressBlockPage, AddressListHdl_Impl, weld::Button&, void) { try { SwAddressListDialog aAddrDialog(this); if (RET_OK == aAddrDialog.run()) { SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem(); rConfigItem.SetCurrentConnection( aAddrDialog.GetSource(), aAddrDialog.GetConnection(), aAddrDialog.GetColumnsSupplier(), aAddrDialog.GetDBData()); OUString sFilter = aAddrDialog.GetFilter(); rConfigItem.SetFilter( sFilter ); InsertDataHdl(nullptr); GetWizard()->UpdateRoadmap(); GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE)); } } catch (const uno::Exception& e) { TOOLS_WARN_EXCEPTION("sw", ""); std::unique_ptr xBox(Application::CreateMessageDialog(m_pWizard->getDialog(), VclMessageType::Warning, VclButtonsType::Ok, e.Message)); xBox->run(); } } IMPL_LINK_NOARG(SwMailMergeAddressBlockPage, SettingsHdl_Impl, weld::Button&, void) { SwSelectAddressBlockDialog aDlg(m_pWizard->getDialog(), m_pWizard->GetConfigItem()); SwMailMergeConfigItem& rConfig = m_pWizard->GetConfigItem(); aDlg.SetAddressBlocks(rConfig.GetAddressBlocks(), m_xSettings->GetSelectedAddress()); aDlg.SetSettings(rConfig.IsIncludeCountry(), rConfig.GetExcludeCountry()); if (aDlg.run() == RET_OK) { //the dialog provides the selected address at the first position! const uno::Sequence< OUString> aBlocks = aDlg.GetAddressBlocks(); rConfig.SetAddressBlocks(aBlocks); m_xSettings->Clear(); for(const auto& rAddress : aBlocks) m_xSettings->AddAddress(rAddress); m_xSettings->SelectAddress(0); m_xSettings->Invalidate(); // #i40408 rConfig.SetCountrySettings(aDlg.IsIncludeCountry(), aDlg.GetCountry()); InsertDataHdl(nullptr); } GetWizard()->UpdateRoadmap(); GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE)); } IMPL_LINK_NOARG(SwMailMergeAddressBlockPage, AssignHdl_Impl, weld::Button&, void) { SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem(); const sal_uInt16 nSel = m_xSettings->GetSelectedAddress(); const uno::Sequence< OUString> aBlocks = rConfigItem.GetAddressBlocks(); SwAssignFieldsDialog aDlg(m_pWizard->getDialog(), m_pWizard->GetConfigItem(), aBlocks[nSel], true); if(RET_OK == aDlg.run()) { //preview update InsertDataHdl(nullptr); GetWizard()->UpdateRoadmap(); GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE)); } } void SwMailMergeAddressBlockPage::EnableAddressBlock(bool bAll, bool bSelective) { m_xSettingsFI->set_sensitive(bAll); m_xAddressCB->set_sensitive(bAll); bSelective &= bAll; m_xHideEmptyParagraphsCB->set_sensitive(bSelective); m_xSettingsWIN->set_sensitive(bSelective); m_xSettingsPB->set_sensitive(bSelective); m_xStep3->set_sensitive(bSelective); m_xStep4->set_sensitive(bSelective); } IMPL_LINK(SwMailMergeAddressBlockPage, AddressBlockHdl_Impl, weld::ToggleButton&, rBox, void) { EnableAddressBlock(rBox.get_sensitive(), rBox.get_active()); SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem(); rConfigItem.SetAddressBlock(m_xAddressCB->get_active()); m_pWizard->UpdateRoadmap(); GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE)); } IMPL_LINK_NOARG(SwMailMergeAddressBlockPage, AddressBlockSelectHdl_Impl, LinkParamNone*, void) { const sal_uInt16 nSel = m_xSettings->GetSelectedAddress(); const uno::Sequence< OUString> aBlocks = m_pWizard->GetConfigItem().GetAddressBlocks(); m_xPreview->SetAddress(SwAddressPreview::FillData(aBlocks[nSel], m_pWizard->GetConfigItem())); m_pWizard->GetConfigItem().SetCurrentAddressBlockIndex( nSel ); GetWizard()->UpdateRoadmap(); GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE)); } IMPL_LINK(SwMailMergeAddressBlockPage, HideParagraphsHdl_Impl, weld::ToggleButton&, rBox, void) { SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem(); rConfigItem.SetHideEmptyParagraphs(rBox.get_active()); } void SwMailMergeAddressBlockPage::InsertDataHdl(const weld::Button* pButton) { //if no pButton is given, the first set has to be pre-set SwMailMergeConfigItem& rConfig = m_pWizard->GetConfigItem(); std::unique_ptr xWaitObj(new weld::WaitObject(m_pWizard->getDialog())); if(!pButton) { rConfig.GetResultSet(); } else { bool bNext = pButton == m_xNextSetIB.get(); sal_Int32 nPos = rConfig.GetResultSetPosition(); rConfig.MoveResultSet( bNext ? ++nPos : --nPos); } xWaitObj.reset(); sal_Int32 nPos = rConfig.GetResultSetPosition(); bool bEnable = true; if(nPos < 1) { bEnable = false; nPos = 1; } else { //if output type is letter if (m_xSettings->IsVisible()) { //Fill data into preview const sal_uInt16 nSel = m_xSettings->GetSelectedAddress(); const uno::Sequence< OUString> aBlocks = m_pWizard->GetConfigItem().GetAddressBlocks(); m_xPreview->SetAddress(SwAddressPreview::FillData(aBlocks[nSel], rConfig)); } } m_xPrevSetIB->set_sensitive(bEnable); m_xDocumentIndexFI->set_label(m_sDocument.replaceFirst("%1", OUString::number(nPos))); GetWizard()->enableButtons(WizardButtonFlags::NEXT, GetWizard()->isStateEnabled(MM_GREETINGSPAGE)); bool bHasResultSet = rConfig.GetResultSet().is(); m_xCurrentAddressFI->set_visible(bHasResultSet); if(bHasResultSet) { m_xCurrentAddressFI->set_label(m_sCurrentAddress.replaceFirst("%1", rConfig.GetCurrentDBData().sDataSource)); m_xAddressListPB->set_label(m_sChangeAddress); } EnableAddressBlock(bHasResultSet, m_xAddressCB->get_active()); } IMPL_LINK(SwMailMergeAddressBlockPage, InsertDataHdl_Impl, weld::Button&, rButton, void) { InsertDataHdl(&rButton); } SwSelectAddressBlockDialog::SwSelectAddressBlockDialog(weld::Window* pParent, SwMailMergeConfigItem& rConfig) : SfxDialogController(pParent, "modules/swriter/ui/selectblockdialog.ui", "SelectBlockDialog") , m_rConfig(rConfig) , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("previewwin"))) , m_xNewPB(m_xBuilder->weld_button("new")) , m_xCustomizePB(m_xBuilder->weld_button("edit")) , m_xDeletePB(m_xBuilder->weld_button("delete")) , m_xNeverRB(m_xBuilder->weld_radio_button("never")) , m_xAlwaysRB(m_xBuilder->weld_radio_button("always")) , m_xDependentRB(m_xBuilder->weld_radio_button("dependent")) , m_xCountryED(m_xBuilder->weld_entry("country")) , m_xPreviewWin(new weld::CustomWeld(*m_xBuilder, "preview", *m_xPreview)) { m_xPreviewWin->set_size_request(m_xCountryED->get_approximate_digit_width() * 45, m_xCountryED->get_text_height() * 12); Link aCustomizeHdl = LINK(this, SwSelectAddressBlockDialog, NewCustomizeHdl_Impl); m_xNewPB->connect_clicked(aCustomizeHdl); m_xCustomizePB->connect_clicked(aCustomizeHdl); m_xDeletePB->connect_clicked(LINK(this, SwSelectAddressBlockDialog, DeleteHdl_Impl)); Link aLk = LINK(this, SwSelectAddressBlockDialog, IncludeHdl_Impl); m_xNeverRB->connect_toggled(aLk); m_xAlwaysRB->connect_toggled(aLk); m_xDependentRB->connect_toggled(aLk); m_xPreview->SetLayout(2, 2); m_xPreview->EnableScrollBar(); } SwSelectAddressBlockDialog::~SwSelectAddressBlockDialog() { } void SwSelectAddressBlockDialog::SetAddressBlocks(const uno::Sequence< OUString>& rBlocks, sal_uInt16 nSelectedAddress) { m_aAddressBlocks = rBlocks; for (const auto& rAddressBlock : std::as_const(m_aAddressBlocks)) m_xPreview->AddAddress(rAddressBlock); m_xPreview->SelectAddress(nSelectedAddress); } // return the address blocks and put the selected one to the first position const uno::Sequence< OUString >& SwSelectAddressBlockDialog::GetAddressBlocks() { //put the selected block to the first position const sal_Int32 nSelect = static_cast(m_xPreview->GetSelectedAddress()); if(nSelect) { uno::Sequence< OUString >aTemp = m_aAddressBlocks; aTemp[0] = m_aAddressBlocks[nSelect]; std::copy(m_aAddressBlocks.begin(), std::next(m_aAddressBlocks.begin(), nSelect), std::next(aTemp.begin())); std::copy(std::next(m_aAddressBlocks.begin(), nSelect + 1), m_aAddressBlocks.end(), std::next(aTemp.begin(), nSelect + 1)); m_aAddressBlocks = aTemp; } return m_aAddressBlocks; } void SwSelectAddressBlockDialog::SetSettings( bool bIsCountry, const OUString& rCountry) { weld::RadioButton *pActive = m_xNeverRB.get(); if(bIsCountry) { pActive = !rCountry.isEmpty() ? m_xDependentRB.get() : m_xAlwaysRB.get(); m_xCountryED->set_text(rCountry); } pActive->set_active(true); IncludeHdl_Impl(*pActive); m_xDeletePB->set_sensitive(m_aAddressBlocks.getLength() > 1); } OUString SwSelectAddressBlockDialog::GetCountry() const { if (m_xDependentRB->get_active()) return m_xCountryED->get_text(); return OUString(); } IMPL_LINK(SwSelectAddressBlockDialog, DeleteHdl_Impl, weld::Button&, rButton, void) { if (m_aAddressBlocks.getLength()) { const sal_Int32 nSelected = static_cast(m_xPreview->GetSelectedAddress()); comphelper::removeElementAt(m_aAddressBlocks, nSelected); if (m_aAddressBlocks.getLength() <= 1) rButton.set_sensitive(false); m_xPreview->RemoveSelectedAddress(); } } IMPL_LINK(SwSelectAddressBlockDialog, NewCustomizeHdl_Impl, weld::Button&, rButton, void) { bool bCustomize = &rButton == m_xCustomizePB.get(); SwCustomizeAddressBlockDialog::DialogType nType = bCustomize ? SwCustomizeAddressBlockDialog::ADDRESSBLOCK_EDIT : SwCustomizeAddressBlockDialog::ADDRESSBLOCK_NEW; std::unique_ptr xDlg(new SwCustomizeAddressBlockDialog(&rButton, m_rConfig, nType)); if(bCustomize) { xDlg->SetAddress(m_aAddressBlocks[m_xPreview->GetSelectedAddress()]); } if (RET_OK == xDlg->run()) { const OUString sNew = xDlg->GetAddress(); if(bCustomize) { m_xPreview->ReplaceSelectedAddress(sNew); m_aAddressBlocks[m_xPreview->GetSelectedAddress()] = sNew; } else { m_xPreview->AddAddress(sNew); m_aAddressBlocks.realloc(m_aAddressBlocks.getLength() + 1); const sal_Int32 nSelect = m_aAddressBlocks.getLength() - 1; m_aAddressBlocks[nSelect] = sNew; m_xPreview->SelectAddress(static_cast(nSelect)); } m_xDeletePB->set_sensitive(m_aAddressBlocks.getLength() > 1); } } IMPL_LINK_NOARG(SwSelectAddressBlockDialog, IncludeHdl_Impl, weld::ToggleButton&, void) { m_xCountryED->set_sensitive(m_xDependentRB->get_active()); } #define USER_DATA_SALUTATION -1 #define USER_DATA_PUNCTUATION -2 #define USER_DATA_TEXT -3 #define USER_DATA_NONE -4 IMPL_LINK(SwCustomizeAddressBlockDialog, TextFilterHdl, OUString&, rTest, bool) { rTest = m_aTextFilter.filter(rTest); return true; } SwCustomizeAddressBlockDialog::SwCustomizeAddressBlockDialog( weld::Widget* pParent, SwMailMergeConfigItem& rConfig, DialogType eType) : SfxDialogController(pParent, "modules/swriter/ui/addressblockdialog.ui", "AddressBlockDialog") , m_aTextFilter("<>") , m_rConfigItem(rConfig) , m_eType(eType) , m_xAddressElementsFT(m_xBuilder->weld_label("addressesft")) , m_xAddressElementsLB(m_xBuilder->weld_tree_view("addresses")) , m_xInsertFieldIB(m_xBuilder->weld_button("toaddr")) , m_xRemoveFieldIB(m_xBuilder->weld_button("fromaddr")) , m_xDragFT(m_xBuilder->weld_label("addressdestft")) , m_xUpIB(m_xBuilder->weld_button("up")) , m_xLeftIB(m_xBuilder->weld_button("left")) , m_xRightIB(m_xBuilder->weld_button("right")) , m_xDownIB(m_xBuilder->weld_button("down")) , m_xFieldFT(m_xBuilder->weld_label("customft")) , m_xFieldCB(m_xBuilder->weld_combo_box("custom")) , m_xOK(m_xBuilder->weld_button("ok")) , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("previewwin"))) , m_xPreviewWIN(new weld::CustomWeld(*m_xBuilder, "addrpreview", *m_xPreview)) , m_xDragED(new AddressMultiLineEdit(this)) , m_xDragWIN(new weld::CustomWeld(*m_xBuilder, "addressdest", *m_xDragED)) { m_aSelectionChangedIdle.SetInvokeHandler( LINK( this, SwCustomizeAddressBlockDialog, SelectionChangedIdleHdl ) ); Size aSize(m_xDragED->GetDrawingArea()->get_size_request()); m_xPreview->set_size_request(aSize.Width(), aSize.Height()); m_xFieldCB->connect_entry_insert_text(LINK(this, SwCustomizeAddressBlockDialog, TextFilterHdl)); m_xAddressElementsLB->set_size_request(-1, m_xAddressElementsLB->get_height_rows(16)); if( eType >= GREETING_FEMALE ) { m_xFieldFT->show(); m_xFieldCB->show(); m_xAddressElementsLB->append(OUString::number(USER_DATA_SALUTATION), SwResId(ST_SALUTATION)); m_xAddressElementsLB->append(OUString::number(USER_DATA_PUNCTUATION), SwResId(ST_PUNCTUATION)); m_xAddressElementsLB->append(OUString::number(USER_DATA_TEXT), SwResId(ST_TEXT)); for (size_t i = 0; i < SAL_N_ELEMENTS(RA_SALUTATION); ++i) m_aSalutations.push_back(SwResId(RA_SALUTATION[i])); for (size_t i = 0; i < SAL_N_ELEMENTS(RA_PUNCTUATION); ++i) m_aPunctuations.push_back(SwResId(RA_PUNCTUATION[i])); m_xDragED->SetText(" "); m_xDialog->set_title(SwResId(eType == GREETING_MALE ? ST_TITLE_MALE : ST_TITLE_FEMALE)); m_xAddressElementsFT->set_label(SwResId(ST_SALUTATIONELEMENTS)); m_xInsertFieldIB->set_tooltip_text(SwResId(ST_INSERTSALUTATIONFIELD)); m_xRemoveFieldIB->set_tooltip_text(SwResId(ST_REMOVESALUTATIONFIELD)); m_xDragFT->set_label(SwResId(ST_DRAGSALUTATION)); } else { if (eType == ADDRESSBLOCK_EDIT) m_xDialog->set_title(SwResId(ST_TITLE_EDIT)); m_xDragED->SetText("\n\n\n\n\n"); /* Set custom HIDs for swriter/01/mm_newaddblo.xhp */ m_xAddressElementsLB->set_help_id( HID_MM_ADDBLOCK_ELEMENTS ); m_xInsertFieldIB->set_help_id( HID_MM_ADDBLOCK_INSERT ); m_xRemoveFieldIB->set_help_id( HID_MM_ADDBLOCK_REMOVE ); m_xDragWIN->set_help_id( HID_MM_ADDBLOCK_DRAG ); m_xPreviewWIN->set_help_id( HID_MM_ADDBLOCK_PREVIEW ); m_xRightIB->set_help_id( HID_MM_ADDBLOCK_MOVEBUTTONS ); m_xLeftIB->set_help_id( HID_MM_ADDBLOCK_MOVEBUTTONS ); m_xDownIB->set_help_id( HID_MM_ADDBLOCK_MOVEBUTTONS ); m_xUpIB->set_help_id( HID_MM_ADDBLOCK_MOVEBUTTONS ); } const std::vector>& rHeaders = m_rConfigItem.GetDefaultAddressHeaders(); for (size_t i = 0; i < rHeaders.size(); ++i) m_xAddressElementsLB->append(OUString::number(i), rHeaders[i].first); m_xOK->connect_clicked(LINK(this, SwCustomizeAddressBlockDialog, OKHdl_Impl)); m_xAddressElementsLB->connect_changed(LINK(this, SwCustomizeAddressBlockDialog, ListBoxSelectHdl_Impl)); if (m_xAddressElementsLB->n_children()) m_xAddressElementsLB->select(0); m_xDragED->SetModifyHdl(LINK(this, SwCustomizeAddressBlockDialog, EditModifyHdl_Impl)); m_xDragED->SetSelectionChangedHdl( LINK( this, SwCustomizeAddressBlockDialog, SelectionChangedHdl_Impl)); m_xFieldCB->connect_changed(LINK(this, SwCustomizeAddressBlockDialog, FieldChangeComboBoxHdl_Impl)); Link aImgButtonHdl = LINK(this, SwCustomizeAddressBlockDialog, ImageButtonHdl_Impl); m_xInsertFieldIB->connect_clicked(aImgButtonHdl); m_xRemoveFieldIB->connect_clicked(aImgButtonHdl); m_xUpIB->connect_clicked(aImgButtonHdl); m_xLeftIB->connect_clicked(aImgButtonHdl); m_xRightIB->connect_clicked(aImgButtonHdl); m_xDownIB->connect_clicked(aImgButtonHdl); UpdateImageButtons_Impl(); } bool SwCustomizeAddressBlockDialog::SetCursorLogicPosition(const Point& rPosition) { return m_xDragED->SetCursorLogicPosition(rPosition); } void SwCustomizeAddressBlockDialog::UpdateFields() { m_xDragED->UpdateFields(); } SwCustomizeAddressBlockDialog::~SwCustomizeAddressBlockDialog() { m_xDragED->EndDropTarget(); } IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog, OKHdl_Impl, weld::Button&, void) { m_xDialog->response(RET_OK); } IMPL_LINK(SwCustomizeAddressBlockDialog, ListBoxSelectHdl_Impl, weld::TreeView&, rBox, void) { sal_Int32 nUserData = rBox.get_selected_id().toInt32(); // Check if the selected entry is already in the address and then forbid inserting m_xInsertFieldIB->set_sensitive(nUserData >= 0 || !HasItem(nUserData)); } IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog, EditModifyHdl_Impl, AddressMultiLineEdit&, void) { m_xPreview->SetAddress(SwAddressPreview::FillData(GetAddress(), m_rConfigItem)); UpdateImageButtons_Impl(); } IMPL_LINK(SwCustomizeAddressBlockDialog, ImageButtonHdl_Impl, weld::Button&, rButton, void) { if (m_xInsertFieldIB.get() == &rButton) { int nEntry = m_xAddressElementsLB->get_selected_index(); if (nEntry != -1) { m_xDragED->InsertNewEntry("<" + m_xAddressElementsLB->get_text(nEntry) + ">"); } } else if (m_xRemoveFieldIB.get() == &rButton) { m_xDragED->RemoveCurrentEntry(); } else { MoveItemFlags nMove = MoveItemFlags::Down; if (m_xUpIB.get() == &rButton) nMove = MoveItemFlags::Up; else if (m_xLeftIB.get() == &rButton) nMove = MoveItemFlags::Left; else if (m_xRightIB.get() == &rButton) nMove = MoveItemFlags::Right; m_xDragED->MoveCurrentItem(nMove); } UpdateImageButtons_Impl(); } sal_Int32 SwCustomizeAddressBlockDialog::GetSelectedItem_Impl() const { sal_Int32 nRet = USER_DATA_NONE; const OUString sSelected = m_xDragED->GetCurrentItem(); if(!sSelected.isEmpty()) { for (int i = 0, nEntryCount = m_xAddressElementsLB->n_children(); i < nEntryCount; ++i) { const OUString sEntry = m_xAddressElementsLB->get_text(i); if( sEntry == sSelected.copy( 1, sSelected.getLength() - 2 ) ) { nRet = m_xAddressElementsLB->get_id(i).toInt32(); break; } } } return nRet; } bool SwCustomizeAddressBlockDialog::HasItem(sal_Int32 nUserData) { //get the entry from the ListBox OUString sEntry; for (int i = 0, nEntryCount = m_xAddressElementsLB->n_children(); i < nEntryCount; ++i) { if (m_xAddressElementsLB->get_id(i).toInt32() == nUserData) { sEntry = m_xAddressElementsLB->get_text(i); break; } } //search for this entry in the content return m_xDragED->GetText().indexOf("<" + sEntry + ">") >= 0; } IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog, SelectionChangedIdleHdl, Timer*, void) { // called in case the selection of the edit field changes. // determine selection - if it's one of the editable fields then // enable the related ComboBox and fill it // don't trigger outself again m_xDragED->SetSelectionChangedHdl(Link()); sal_Int32 nSelected = GetSelectedItem_Impl(); if (USER_DATA_NONE != nSelected) m_xDragED->SelectCurrentItem(); if(m_xFieldCB->get_visible() && (USER_DATA_NONE != nSelected) && (nSelected < 0)) { //search in ListBox if it's one of the first entries OUString sSelect; std::vector* pVector = nullptr; switch(nSelected) { case USER_DATA_SALUTATION: sSelect = m_sCurrentSalutation; pVector = &m_aSalutations; break; case USER_DATA_PUNCTUATION: sSelect = m_sCurrentPunctuation; pVector = &m_aPunctuations; break; case USER_DATA_TEXT: sSelect = m_sCurrentText; break; } m_xFieldCB->clear(); if(pVector) { for (const auto& rItem : *pVector) m_xFieldCB->append_text(rItem); } m_xFieldCB->set_entry_text(sSelect); m_xFieldCB->set_sensitive(true); m_xFieldFT->set_sensitive(true); } else { m_xFieldCB->set_sensitive(false); m_xFieldFT->set_sensitive(false); } UpdateImageButtons_Impl(); m_xDragED->SetSelectionChangedHdl( LINK( this, SwCustomizeAddressBlockDialog, SelectionChangedHdl_Impl)); } IMPL_LINK(SwCustomizeAddressBlockDialog, SelectionChangedHdl_Impl, bool, bIdle, void) { if (bIdle) m_aSelectionChangedIdle.Start(); else { m_aSelectionChangedIdle.Stop(); SelectionChangedIdleHdl(nullptr); } } IMPL_LINK_NOARG(SwCustomizeAddressBlockDialog, FieldChangeComboBoxHdl_Impl, weld::ComboBox&, void) { //changing the field content changes the related members, too sal_Int32 nSelected = GetSelectedItem_Impl(); const OUString sContent = m_xFieldCB->get_active_text(); switch(nSelected) { case USER_DATA_SALUTATION: m_sCurrentSalutation = sContent; break; case USER_DATA_PUNCTUATION: m_sCurrentPunctuation = sContent; break; case USER_DATA_TEXT: m_sCurrentText = sContent; break; } UpdateImageButtons_Impl(); m_xPreview->SetAddress(GetAddress()); EditModifyHdl_Impl(*m_xDragED); } void SwCustomizeAddressBlockDialog::UpdateImageButtons_Impl() { MoveItemFlags nMove = m_xDragED->IsCurrentItemMoveable(); m_xUpIB->set_sensitive( bool(nMove & MoveItemFlags::Up) ); m_xLeftIB->set_sensitive( bool(nMove & MoveItemFlags::Left) ); m_xRightIB->set_sensitive( bool(nMove & MoveItemFlags::Right) ); m_xDownIB->set_sensitive( bool(nMove & MoveItemFlags::Down) ); m_xRemoveFieldIB->set_sensitive(m_xDragED->HasCurrentItem()); int nEntry = m_xAddressElementsLB->get_selected_index(); m_xInsertFieldIB->set_sensitive( nEntry != -1 && (m_xAddressElementsLB->get_id(nEntry).toInt32() >= 0 || !m_xFieldCB->get_active_text().isEmpty())); } void SwCustomizeAddressBlockDialog::SetAddress(const OUString& rAddress) { m_xDragED->SetText(rAddress); UpdateImageButtons_Impl(); EditModifyHdl_Impl(*m_xDragED); } OUString SwCustomizeAddressBlockDialog::GetAddress() const { OUString sAddress(m_xDragED->GetAddress()); //remove placeholders by the actual content if (m_xFieldFT->get_visible()) { for (int i = 0, nEntryCount = m_xAddressElementsLB->n_children(); i < nEntryCount; ++i) { const OUString sEntry = "<" + m_xAddressElementsLB->get_text(i) + ">"; sal_Int32 nUserData = m_xAddressElementsLB->get_id(i).toInt32(); switch(nUserData) { case USER_DATA_SALUTATION: sAddress = sAddress.replaceFirst(sEntry, m_sCurrentSalutation); break; case USER_DATA_PUNCTUATION: sAddress = sAddress.replaceFirst(sEntry, m_sCurrentPunctuation); break; case USER_DATA_TEXT: sAddress = sAddress.replaceFirst(sEntry, m_sCurrentText); break; } } } return sAddress; } namespace { struct SwAssignFragment { std::unique_ptr m_xBuilder; std::unique_ptr m_xLabel; std::unique_ptr m_xComboBox; std::unique_ptr m_xPreview; SwAssignFragment(weld::Container* pGrid, int nLine) : m_xBuilder(Application::CreateBuilder(pGrid, "modules/swriter/ui/assignfragment.ui")) , m_xLabel(m_xBuilder->weld_label("label")) , m_xComboBox(m_xBuilder->weld_combo_box("combobox")) , m_xPreview(m_xBuilder->weld_label("preview")) { m_xLabel->set_grid_left_attach(0); m_xLabel->set_grid_top_attach(nLine); m_xComboBox->set_grid_left_attach(1); m_xComboBox->set_grid_top_attach(nLine); m_xPreview->set_grid_left_attach(2); m_xPreview->set_grid_top_attach(nLine); } }; } class SwAssignFieldsControl { friend class SwAssignFieldsDialog; std::unique_ptr m_xVScroll; std::unique_ptr m_xGrid; std::vector m_aFields; SwMailMergeConfigItem* m_rConfigItem; Link m_aModifyHdl; DECL_LINK(MatchHdl_Impl, weld::ComboBox&, void); DECL_LINK(GotFocusHdl_Impl, weld::Widget&, void); void MakeVisible(const tools::Rectangle & rRect); public: SwAssignFieldsControl(std::unique_ptr xWindow, std::unique_ptr xGrid); void Init(SwAssignFieldsDialog* pDialog, SwMailMergeConfigItem& rConfigItem); void SetModifyHdl(const Link& rModifyHdl) { m_aModifyHdl = rModifyHdl; m_aModifyHdl.Call(nullptr); } }; SwAssignFieldsControl::SwAssignFieldsControl(std::unique_ptr xWindow, std::unique_ptr xGrid) : m_xVScroll(std::move(xWindow)) , m_xGrid(std::move(xGrid)) , m_rConfigItem(nullptr) { } void SwAssignFieldsControl::Init(SwAssignFieldsDialog* pDialog, SwMailMergeConfigItem& rConfigItem) { m_rConfigItem = &rConfigItem; //get the name of the default headers const std::vector>& rHeaders = rConfigItem.GetDefaultAddressHeaders(); //get the actual data uno::Reference< XColumnsSupplier > xColsSupp( rConfigItem.GetResultSet(), uno::UNO_QUERY); //get the name of the actual columns uno::Reference xColAccess = xColsSupp.is() ? xColsSupp->getColumns() : nullptr; uno::Sequence< OUString > aFields; if(xColAccess.is()) aFields = xColAccess->getElementNames(); //get the current assignment list //each position in this sequence matches the position in the header array rHeaders //if no assignment is available an empty sequence will be returned uno::Sequence< OUString> aAssignments = rConfigItem.GetColumnAssignment( rConfigItem.GetCurrentDBData() ); Link aMatchHdl = LINK(this, SwAssignFieldsControl, MatchHdl_Impl); Link aFocusHdl = LINK(this, SwAssignFieldsControl, GotFocusHdl_Impl); int nLabelWidth(0), nComboBoxWidth(0), nPreviewWidth(0); //fill the controls for (size_t i = 0; i < rHeaders.size(); ++i) { m_aFields.emplace_back(m_xGrid.get(), i); const OUString rHeader = rHeaders[i].first; weld::ComboBox& rNewLB = *m_aFields.back().m_xComboBox; rNewLB.append_text(SwResId(SW_STR_NONE)); rNewLB.set_active(0); for (const OUString& rField : std::as_const(aFields)) rNewLB.append_text(rField); //select the ListBox //if there is an assignment if(o3tl::make_unsigned(aAssignments.getLength()) > i && !aAssignments[i].isEmpty()) rNewLB.set_active_text(aAssignments[i]); else //otherwise the current column name may match one of the db columns rNewLB.set_active_text(rHeader); weld::Label& rNewText = *m_aFields.back().m_xLabel; rNewText.set_label("<" + rHeader + ">"); weld::Label& rNewPreview = *m_aFields.back().m_xPreview; //then the preview can be filled accordingly if (xColAccess.is() && rNewLB.get_active() > 0 && xColAccess->hasByName(rNewLB.get_active_text())) { uno::Any aCol = xColAccess->getByName(rNewLB.get_active_text()); uno::Reference< XColumn > xColumn; aCol >>= xColumn; if(xColumn.is()) { try { rNewPreview.set_label(xColumn->getString()); } catch (const SQLException&) { } } } if (i == 0) { auto nLineHeight = m_xGrid->get_preferred_size().Height(); m_xVScroll->set_size_request(m_xVScroll->get_approximate_digit_width() * 65, nLineHeight * 6); nComboBoxWidth = rNewLB.get_preferred_size().Width(); } nLabelWidth = std::max(nLabelWidth, rNewText.get_preferred_size().Width()); nPreviewWidth = std::max(nPreviewWidth, rNewPreview.get_preferred_size().Width()); rNewLB.connect_changed(aMatchHdl); rNewLB.connect_focus_in(aFocusHdl); rNewText.show(); rNewLB.show(); rNewPreview.show(); } pDialog->ConnectSizeGroups(nLabelWidth, nComboBoxWidth, nPreviewWidth); } void SwAssignFieldsControl::MakeVisible(const tools::Rectangle & rRect) { //determine range of visible positions auto nMinVisiblePos = m_xVScroll->vadjustment_get_value(); auto nMaxVisiblePos = nMinVisiblePos + m_xVScroll->vadjustment_get_page_size(); if (rRect.Top() < nMinVisiblePos || rRect.Bottom() > nMaxVisiblePos) m_xVScroll->vadjustment_set_value(rRect.Top()); } IMPL_LINK(SwAssignFieldsControl, MatchHdl_Impl, weld::ComboBox&, rBox, void) { const OUString sColumn = rBox.get_active_text(); uno::Reference< XColumnsSupplier > xColsSupp( m_rConfigItem->GetResultSet(), uno::UNO_QUERY); uno::Reference xColAccess = xColsSupp.is() ? xColsSupp->getColumns() : nullptr; OUString sPreview; if(xColAccess.is() && xColAccess->hasByName(sColumn)) { uno::Any aCol = xColAccess->getByName(sColumn); uno::Reference< XColumn > xColumn; aCol >>= xColumn; if(xColumn.is()) { try { sPreview = xColumn->getString(); } catch (const sdbc::SQLException&) { } } } auto aLBIter = std::find_if(m_aFields.begin(), m_aFields.end(), [&rBox](const SwAssignFragment& rFragment){ return &rBox == rFragment.m_xComboBox.get(); }); if (aLBIter != m_aFields.end()) { auto nIndex = static_cast(std::distance(m_aFields.begin(), aLBIter)); m_aFields[nIndex].m_xPreview->set_label(sPreview); } m_aModifyHdl.Call(nullptr); } IMPL_LINK(SwAssignFieldsControl, GotFocusHdl_Impl, weld::Widget&, rBox, void) { int x, y, width, height; rBox.get_extents_relative_to(*m_xGrid, x, y, width, height); // the container has a border of 3 in the .ui tools::Rectangle aRect(Point(x - 3, y - 3), Size(width + 6, height + 6)); MakeVisible(aRect); } SwAssignFieldsDialog::SwAssignFieldsDialog( weld::Window* pParent, SwMailMergeConfigItem& rConfigItem, const OUString& rPreview, bool bIsAddressBlock) : SfxDialogController(pParent, "modules/swriter/ui/assignfieldsdialog.ui", "AssignFieldsDialog") , m_sNone(SwResId(SW_STR_NONE)) , m_rPreviewString(rPreview) , m_rConfigItem(rConfigItem) , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("previewwin"))) , m_xMatchingFI(m_xBuilder->weld_label("MATCHING_LABEL")) , m_xAddressTitle(m_xBuilder->weld_label("addresselem")) , m_xMatchTitle(m_xBuilder->weld_label("matchelem")) , m_xPreviewTitle(m_xBuilder->weld_label("previewelem")) , m_xPreviewFI(m_xBuilder->weld_label("PREVIEW_LABEL")) , m_xOK(m_xBuilder->weld_button("ok")) , m_xPreviewWin(new weld::CustomWeld(*m_xBuilder, "PREVIEW", *m_xPreview)) , m_xFieldsControl(new SwAssignFieldsControl(m_xBuilder->weld_scrolled_window("scroll"), m_xBuilder->weld_container("FIELDS"))) { m_xPreviewWin->set_size_request(m_xMatchingFI->get_approximate_digit_width() * 45, m_xMatchingFI->get_text_height() * 5); m_xFieldsControl->Init(this, rConfigItem); const OUString sMatchesTo( SwResId(ST_MATCHESTO) ); if (!bIsAddressBlock) { m_xPreviewFI->set_label(SwResId(ST_SALUTATIONPREVIEW)); m_xMatchingFI->set_label(SwResId(ST_SALUTATIONMATCHING)); m_xAddressTitle->set_label(SwResId(ST_SALUTATIONELEMENT)); } m_xFieldsControl->SetModifyHdl(LINK(this, SwAssignFieldsDialog, AssignmentModifyHdl_Impl )); m_xMatchingFI->set_label(m_xMatchingFI->get_label().replaceAll("%1", sMatchesTo)); m_xOK->connect_clicked(LINK(this, SwAssignFieldsDialog, OkHdl_Impl)); } SwAssignFieldsDialog::~SwAssignFieldsDialog() { } uno::Sequence< OUString > SwAssignFieldsDialog::CreateAssignments() { uno::Sequence< OUString > aAssignments( m_rConfigItem.GetDefaultAddressHeaders().size()); OUString* pAssignments = aAssignments.getArray(); sal_Int32 nIndex = 0; for (const auto& rLBItem : m_xFieldsControl->m_aFields) { const OUString sSelect = rLBItem.m_xComboBox->get_active_text(); pAssignments[nIndex] = (m_sNone != sSelect) ? sSelect : OUString(); ++nIndex; } return aAssignments; } IMPL_LINK_NOARG(SwAssignFieldsDialog, OkHdl_Impl, weld::Button&, void) { m_rConfigItem.SetColumnAssignment( m_rConfigItem.GetCurrentDBData(), CreateAssignments() ); m_xDialog->response(RET_OK); } IMPL_LINK_NOARG(SwAssignFieldsDialog, AssignmentModifyHdl_Impl, LinkParamNone*, void) { uno::Sequence< OUString > aAssignments = CreateAssignments(); const OUString sPreview = SwAddressPreview::FillData( m_rPreviewString, m_rConfigItem, &aAssignments); m_xPreview->SetAddress(sPreview); } void SwAssignFieldsDialog::ConnectSizeGroups(int nLabelWidth, int nComboBoxWidth, int nPreviewWidth) { m_xAddressTitle->set_size_request(nLabelWidth, -1); m_xMatchTitle->set_size_request(nComboBoxWidth, -1); m_xPreviewTitle->set_size_request(nPreviewWidth, -1); } namespace { const EECharAttrib* FindCharAttrib(int nStartPosition, std::vector& rAttribList) { for (auto it = rAttribList.rbegin(); it != rAttribList.rend(); ++it) { const auto& rTextAtr = *it; if (rTextAtr.pAttr->Which() != EE_CHAR_GRABBAG) continue; if (rTextAtr.nStart <= nStartPosition && rTextAtr.nEnd >= nStartPosition) { return &rTextAtr; } } return nullptr; } } AddressMultiLineEdit::AddressMultiLineEdit(SwCustomizeAddressBlockDialog *pParent) : m_pParentDialog(pParent) { } void AddressMultiLineEdit::EndDropTarget() { if (m_xDropTarget.is()) { auto xRealDropTarget = GetDrawingArea()->get_drop_target(); uno::Reference xListener(m_xDropTarget, uno::UNO_QUERY); xRealDropTarget->removeDropTargetListener(xListener); m_xDropTarget.clear(); } } AddressMultiLineEdit::~AddressMultiLineEdit() { assert(!m_xDropTarget.is()); } void AddressMultiLineEdit::SetDrawingArea(weld::DrawingArea* pDrawingArea) { Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(160, 60), MapMode(MapUnit::MapAppFont))); pDrawingArea->set_size_request(aSize.Width(), aSize.Height()); WeldEditView::SetDrawingArea(pDrawingArea); } bool AddressMultiLineEdit::KeyInput(const KeyEvent& rKEvt) { if (rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE) return false; // we want default esc behaviour if (rKEvt.GetCharCode()) return true; // handled return WeldEditView::KeyInput(rKEvt); } bool AddressMultiLineEdit::MouseButtonDown(const MouseEvent& rMEvt) { if (rMEvt.GetClicks() >= 2) return true; // handled return WeldEditView::MouseButtonDown(rMEvt); } OUString AddressMultiLineEdit::GetText() const { return m_xEditEngine->GetText(); } void AddressMultiLineEdit::SetText( const OUString& rStr ) { m_xEditEngine->SetText(rStr); //set attributes to all address tokens sal_Int32 nSequence(0); SfxGrabBagItem aProtectAttr(EE_CHAR_GRABBAG); const sal_uInt32 nParaCount = m_xEditEngine->GetParagraphCount(); for(sal_uInt32 nPara = 0; nPara < nParaCount; ++nPara) { sal_Int32 nIndex = 0; const OUString sPara = m_xEditEngine->GetText( nPara ); if (!sPara.isEmpty() && !sPara.endsWith(" ")) { ESelection aPaM(nPara, sPara.getLength(), nPara, sPara.getLength()); m_xEditEngine->QuickInsertText(" ", aPaM); } for(;;) { const sal_Int32 nStart = sPara.indexOf( '<', nIndex ); if (nStart < 0) break; const sal_Int32 nEnd = sPara.indexOf( '>', nStart ); if (nEnd < 0) break; nIndex = nEnd; SfxItemSet aSet(m_xEditEngine->GetEmptyItemSet()); // make each one different, so they are not collapsed together // as one attribute aProtectAttr.GetGrabBag()["Index"] <<= nSequence++; aSet.Put(aProtectAttr); m_xEditEngine->QuickSetAttribs(aSet, ESelection(nPara, nStart, nPara, nEnd + 1)); } } // add two empty paragraphs at the end if(m_pParentDialog->m_eType == SwCustomizeAddressBlockDialog::ADDRESSBLOCK_NEW || m_pParentDialog->m_eType == SwCustomizeAddressBlockDialog::ADDRESSBLOCK_EDIT) { sal_Int32 nLastLen = m_xEditEngine->GetText(nParaCount - 1).getLength(); if(nLastLen) { int nPara = nParaCount ? nParaCount - 1 : 0; ESelection aPaM(nPara, nLastLen, nPara, nLastLen); m_xEditEngine->QuickInsertText("\n \n ", aPaM); } } m_xEditView->SetSelection(ESelection(0, 0, 0, 0)); } // Insert the new entry in front of the entry at the beginning of the selection void AddressMultiLineEdit::InsertNewEntry( const OUString& rStr ) { // insert new entry after current selected one. ESelection aSelection = m_xEditView->GetSelection(); const sal_uInt32 nPara = aSelection.nStartPara; std::vector aAttribList; m_xEditEngine->GetCharAttribs(nPara, aAttribList); sal_Int32 nIndex = aSelection.nEndPara; const EECharAttrib* pAttrib; if(nullptr != (pAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList))) nIndex = pAttrib->nEnd; InsertNewEntryAtPosition( rStr, nPara, nIndex ); // select the new entry m_xEditEngine->GetCharAttribs(nPara, aAttribList); pAttrib = FindCharAttrib(nIndex, aAttribList); const sal_Int32 nEnd = pAttrib ? pAttrib->nEnd : nIndex; ESelection aEntrySel(nPara, nIndex, nPara, nEnd); m_xEditView->SetSelection(aEntrySel); Invalidate(); m_aModifyLink.Call(*this); } void AddressMultiLineEdit::InsertNewEntryAtPosition( const OUString& rStr, sal_uLong nPara, sal_uInt16 nIndex ) { ESelection aInsertPos(nPara, nIndex, nPara, nIndex); m_xEditEngine->QuickInsertText(rStr, aInsertPos); //restore the attributes SetText( GetAddress() ); //select the newly inserted/moved element m_xEditView->SetSelection(aInsertPos); m_aSelectionLink.Call(false); } void AddressMultiLineEdit::RemoveCurrentEntry() { ESelection aSelection = m_xEditView->GetSelection(); std::vector aAttribList; m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList); const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList); if(pBeginAttrib && (pBeginAttrib->nStart <= aSelection.nStartPos && pBeginAttrib->nEnd >= aSelection.nEndPos)) { const sal_uInt32 nPara = aSelection.nStartPara; ESelection aEntrySel(nPara, pBeginAttrib->nStart, nPara, pBeginAttrib->nEnd); m_xEditEngine->QuickInsertText(OUString(), aEntrySel); //restore the attributes SetText( GetAddress() ); m_aModifyLink.Call(*this); } } void AddressMultiLineEdit::MoveCurrentItem(MoveItemFlags nMove) { ESelection aSelection = m_xEditView->GetSelection(); std::vector aAttribList; m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList); const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList); if(!pBeginAttrib || !(pBeginAttrib->nStart <= aSelection.nStartPos && pBeginAttrib->nEnd >= aSelection.nEndPos)) return; //current item has been found sal_Int32 nPara = aSelection.nStartPara; sal_Int32 nIndex = pBeginAttrib->nStart; ESelection aEntrySel(nPara, pBeginAttrib->nStart, nPara, pBeginAttrib->nEnd); const OUString sCurrentItem = m_xEditEngine->GetText(aEntrySel); m_xEditEngine->RemoveAttribs(aEntrySel, false, EE_CHAR_GRABBAG); m_xEditEngine->QuickInsertText(OUString(), aEntrySel); m_xEditEngine->GetCharAttribs(nPara, aAttribList); switch (nMove) { case MoveItemFlags::Left : if(nIndex) { //go left to find a predecessor or simple text --nIndex; const OUString sPara = m_xEditEngine->GetText( nPara ); sal_Int32 nSearchIndex = sPara.lastIndexOf( '>', nIndex+1 ); if( nSearchIndex != -1 && nSearchIndex == nIndex ) { nSearchIndex = sPara.lastIndexOf( '<', nIndex ); if( nSearchIndex != -1 ) nIndex = nSearchIndex; } } break; case MoveItemFlags::Right: { //go right to find a successor or simple text ++nIndex; const EECharAttrib* pEndAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList); if(pEndAttrib && pEndAttrib->nEnd >= nIndex) { nIndex = pEndAttrib->nEnd; } } break; case MoveItemFlags::Up : --nPara; nIndex = 0; break; case MoveItemFlags::Down : ++nPara; nIndex = 0; break; default: break; } //add a new paragraph if there is none yet if (nPara >= m_xEditEngine->GetParagraphCount()) { auto nInsPara = nPara - 1; auto nInsPos = m_xEditEngine->GetTextLen( nPara - 1 ); ESelection aTemp(nInsPara, nInsPos, nInsPara, nInsPos); m_xEditEngine->QuickInsertText("\n", aTemp); } InsertNewEntryAtPosition( sCurrentItem, nPara, nIndex ); // select the new entry [#i40817] m_xEditEngine->GetCharAttribs(nPara, aAttribList); const EECharAttrib* pAttrib = FindCharAttrib(nIndex, aAttribList); if (pAttrib) aEntrySel = ESelection(nPara, nIndex, nPara, pAttrib->nEnd); m_xEditView->SetSelection(aEntrySel); Invalidate(); m_aModifyLink.Call(*this); } MoveItemFlags AddressMultiLineEdit::IsCurrentItemMoveable() const { MoveItemFlags nRet = MoveItemFlags::NONE; ESelection aSelection = m_xEditView->GetSelection(); std::vector aAttribList; m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList); const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList); if (pBeginAttrib && (pBeginAttrib->nStart <= aSelection.nStartPos && pBeginAttrib->nEnd >= aSelection.nEndPos)) { if (pBeginAttrib->nStart) nRet |= MoveItemFlags::Left; //if there is an entry it can always be move to the right and down nRet |= MoveItemFlags::Right | MoveItemFlags::Down; if (aSelection.nStartPara > 0) nRet |= MoveItemFlags::Up; } return nRet; } bool AddressMultiLineEdit::HasCurrentItem() const { ESelection aSelection = m_xEditView->GetSelection(); std::vector aAttribList; m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList); const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList); return (pBeginAttrib && (pBeginAttrib->nStart <= aSelection.nStartPos && pBeginAttrib->nEnd >= aSelection.nEndPos)); } OUString AddressMultiLineEdit::GetCurrentItem() const { ESelection aSelection = m_xEditView->GetSelection(); std::vector aAttribList; m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList); const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList); if (pBeginAttrib && (pBeginAttrib->nStart <= aSelection.nStartPos && pBeginAttrib->nEnd >= aSelection.nEndPos)) { const sal_uInt32 nPara = aSelection.nStartPara; ESelection aEntrySel(nPara, pBeginAttrib->nStart, nPara, pBeginAttrib->nEnd); return m_xEditEngine->GetText( aEntrySel ); } return OUString(); } void AddressMultiLineEdit::SelectCurrentItem() { ESelection aSelection = m_xEditView->GetSelection(); std::vector aAttribList; m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList); const EECharAttrib* pBeginAttrib = FindCharAttrib(aSelection.nStartPos, aAttribList); if (pBeginAttrib && (pBeginAttrib->nStart <= aSelection.nStartPos && pBeginAttrib->nEnd >= aSelection.nEndPos)) { const sal_uInt32 nPara = aSelection.nStartPara; ESelection aEntrySel(nPara, pBeginAttrib->nStart, nPara, pBeginAttrib->nEnd); m_xEditView->SetSelection(aEntrySel); Invalidate(); } } OUString AddressMultiLineEdit::GetAddress() const { OUString sRet; const sal_uInt32 nParaCount = m_xEditEngine->GetParagraphCount(); for(sal_uInt32 nPara = nParaCount; nPara; --nPara) { const OUString sPara = comphelper::string::stripEnd(m_xEditEngine->GetText(nPara - 1), ' '); //don't add empty trailing paragraphs if(!sRet.isEmpty() || !sPara.isEmpty()) { sRet = sPara + sRet; //insert the para break if(nPara > 1) sRet = "\n" + sRet; } } return sRet; } void AddressMultiLineEdit::UpdateFields() { ESelection aSelection = m_xEditView->GetSelection(); //restore the attributes SetText( GetAddress() ); //reselect the element m_xEditView->SetSelection(aSelection); m_aSelectionLink.Call(false); } void AddressMultiLineEdit::EditViewSelectionChange() { WeldEditView::EditViewSelectionChange(); m_aSelectionLink.Call(true); } namespace { // sit between the tree as drag source and the editview as drop target and translate // the tree dnd data to the simple string the editview wants class DropTargetListener : public cppu::WeakImplHelper< css::datatransfer::dnd::XDropTargetListener, css::datatransfer::dnd::XDropTarget > { private: css::uno::Reference m_xRealDropTarget; std::vector> m_aListeners; SwCustomizeAddressBlockDialog* m_pParentDialog; // XEventListener virtual void SAL_CALL disposing( const css::lang::EventObject& ) override { m_xRealDropTarget.clear(); m_aListeners.clear(); } // XDropTargetListener virtual void SAL_CALL drop( const css::datatransfer::dnd::DropTargetDropEvent& dtde ) override { SolarMutexGuard aGuard; auto aReplacement(dtde); Point aMousePos(dtde.LocationX, dtde.LocationY); bool bAllowed = m_pParentDialog->SetCursorLogicPosition(aMousePos); if (bAllowed) { if (weld::TreeView* pTree = m_pParentDialog->get_drag_source()) { int nEntry = pTree->get_selected_index(); if (nEntry != -1) { sal_Int32 nUserData = pTree->get_id(nEntry).toInt32(); //special entries can only be once in the address / greeting if (nUserData >= 0 || !m_pParentDialog->HasItem(nUserData)) { rtl::Reference xContainer = new TransferDataContainer; xContainer->CopyString( "<" + pTree->get_text(nEntry) + ">" ); // replace what the treeview is offering with what ImpEditView::drop wants aReplacement.Transferable = xContainer.get(); } } } } std::vector> aListeners(m_aListeners); for (auto const& listener : aListeners) listener->drop(aReplacement); if (bAllowed) m_pParentDialog->UpdateFields(); } virtual void SAL_CALL dragEnter( const css::datatransfer::dnd::DropTargetDragEnterEvent& dtdee ) override { auto aReplacement(dtdee); // replace what the treeview is offering with what ImpEditView::dragEnter wants aReplacement.SupportedDataFlavors.realloc(1); SotExchange::GetFormatDataFlavor(SotClipboardFormatId::STRING, aReplacement.SupportedDataFlavors[0]); std::vector> aListeners(m_aListeners); for (auto const& listener : aListeners) listener->dragEnter(aReplacement); } virtual void SAL_CALL dragExit( const css::datatransfer::dnd::DropTargetEvent& dte ) override { std::vector> aListeners(m_aListeners); for (auto const& listener : aListeners) listener->dragExit( dte ); } virtual void SAL_CALL dragOver( const css::datatransfer::dnd::DropTargetDragEvent& dtde ) override { std::vector> aListeners(m_aListeners); for (auto const& listener : aListeners) listener->dragOver( dtde ); } virtual void SAL_CALL dropActionChanged( const css::datatransfer::dnd::DropTargetDragEvent& dtde ) override { std::vector> aListeners(m_aListeners); for (auto const& listener : aListeners) listener->dropActionChanged( dtde ); } // XDropTarget virtual void SAL_CALL addDropTargetListener(const css::uno::Reference& xListener) override { m_aListeners.push_back(xListener); } virtual void SAL_CALL removeDropTargetListener(const css::uno::Reference& xListener) override { m_aListeners.erase(std::remove(m_aListeners.begin(), m_aListeners.end(), xListener), m_aListeners.end()); } virtual sal_Bool SAL_CALL isActive() override { return m_xRealDropTarget->isActive(); } virtual void SAL_CALL setActive(sal_Bool active) override { m_xRealDropTarget->setActive(active); } virtual sal_Int8 SAL_CALL getDefaultActions() override { return m_xRealDropTarget->getDefaultActions(); } virtual void SAL_CALL setDefaultActions(sal_Int8 actions) override { m_xRealDropTarget->setDefaultActions(actions); } public: DropTargetListener(css::uno::Reference xRealDropTarget, SwCustomizeAddressBlockDialog* pParentDialog) : m_xRealDropTarget(xRealDropTarget) , m_pParentDialog(pParentDialog) { } }; } css::uno::Reference AddressMultiLineEdit::GetDropTarget() { if (!m_xDropTarget.is()) { auto xRealDropTarget = GetDrawingArea()->get_drop_target(); DropTargetListener* pProxy = new DropTargetListener(xRealDropTarget, m_pParentDialog); uno::Reference xListener(pProxy); xRealDropTarget->addDropTargetListener(xListener); m_xDropTarget = uno::Reference(pProxy); } return m_xDropTarget; } bool AddressMultiLineEdit::SetCursorLogicPosition(const Point& rPosition) { Point aMousePos = EditViewOutputDevice().PixelToLogic(rPosition); m_xEditView->SetCursorLogicPosition(aMousePos, false, true); ESelection aSelection = m_xEditView->GetSelection(); std::vector aAttribList; m_xEditEngine->GetCharAttribs(aSelection.nStartPara, aAttribList); return FindCharAttrib(aSelection.nStartPos, aAttribList) == nullptr; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */