/* -*- 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 #include #include 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", true))) , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("addresspreviewwin", true))) , 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) return; 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(o3tl::narrowing(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::Toggleable&, 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::Toggleable&, 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", true))) , 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.getLength()); auto it = aTemp.getArray(); *it = std::as_const(m_aAddressBlocks)[nSelect]; it = std::copy_n(std::cbegin(m_aAddressBlocks), nSelect - 1, std::next(it)); std::copy(std::next(std::cbegin(m_aAddressBlocks), nSelect + 1), std::cend(m_aAddressBlocks), it); 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()) return; const OUString sNew = xDlg->GetAddress(); if(bCustomize) { m_xPreview->ReplaceSelectedAddress(sNew); m_aAddressBlocks.getArray()[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.getArray()[nSelect] = sNew; m_xPreview->SelectAddress(o3tl::narrowing(nSelect)); } m_xDeletePB->set_sensitive(m_aAddressBlocks.getLength() > 1); } IMPL_LINK_NOARG(SwSelectAddressBlockDialog, IncludeHdl_Impl, weld::Toggleable&, 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_aSelectionChangedIdle("SwCustomizeAddressBlockDialog m_aSelectionChangedIdle") , 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", true))) , 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.subView( 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(Concat2View("<" + 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, OUString aPreview, bool bIsAddressBlock) : SfxDialogController(pParent, "modules/swriter/ui/assignfieldsdialog.ui", "AssignFieldsDialog") , m_sNone(SwResId(SW_STR_NONE)) , m_rPreviewString(std::move(aPreview)) , m_rConfigItem(rConfigItem) , m_xPreview(new SwAddressPreview(m_xBuilder->weld_scrolled_window("previewwin", true))) , 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()) { m_xEditEngine->RemoveView(m_xEditView.get()); 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::Command(const CommandEvent& rCEvt) { if (rCEvt.GetCommand() == CommandEventId::StartExtTextInput || rCEvt.GetCommand() == CommandEventId::EndExtTextInput || rCEvt.GetCommand() == CommandEventId::ExtTextInput) { return true; } return WeldEditView::Command(rCEvt); } 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 = FindCharAttrib(aSelection.nStartPos, aAttribList); if(nullptr != pAttrib) 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.getArray()[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(std::move(xRealDropTarget)) , m_pParentDialog(pParentDialog) { } }; } css::uno::Reference AddressMultiLineEdit::GetDropTarget() { if (!m_xDropTarget.is()) { auto xRealDropTarget = GetDrawingArea()->get_drop_target(); rtl::Reference pProxy = new DropTargetListener(xRealDropTarget, m_pParentDialog); xRealDropTarget->addDropTargetListener(pProxy); m_xDropTarget = 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: */ /span>Missing includeStephan Bergmann Change-Id: I094b4a1c89676426b286f72a2f510e48fed98b3b 2016-03-22tdf#93553 limit parallelism at zip save time to useful amountArmin Le Grand At ODT export time writing and zipping comtained data packages is nicely parallelized, but not limited to an upper bounds of threads to use. Together with memory consumption this makes ressource usage and runtime behaviour bad to crashing (mostly on 32bit). I have now limited the processing dependent on the number of available cores to get a good processing/ressource ratio. The result uses much less memory, is faster and runs on 32bit systems. Change-Id: I8bd516a9a0cefd644f5d7001214bc717f29770ab Reviewed-on: https://gerrit.libreoffice.org/23305 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Noel Grandin <noelgrandin@gmail.com> 2016-03-18loplugin:constantparam in packageNoel Grandin Change-Id: Ifd9bb81ff9ccfaf5093c04024d7ea93946b00e66 Reviewed-on: https://gerrit.libreoffice.org/23329 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Noel Grandin <noelgrandin@gmail.com> 2016-02-05Fix typosAndrea Gelmini Change-Id: Ice72f8d9971e15dd6ef365e64cd567b8581a92d3 Reviewed-on: https://gerrit.libreoffice.org/21797 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Ashod Nakashian <ashnakash@gmail.com> 2016-01-25InterfaceContainer2 with vector instead of SequenceNoel Grandin create an InterfaceContainer2 class to replace InterfaceContainer. It uses a std::vector instead of a Sequence for the mutable listener list, which provides far better performance. Switch all our internal use-sites to the new class. Change-Id: I6b56cfa511ded2395faa22e68fab3b2f16c3cb88 2016-01-08tdf#89236: Don't deflate encrypted document in parallelMatúš Kukan I see "warn:legacy.osl:22439:1:package/source/zipapi/ZipFile.cxx:583: Can't detect password correctness without digest!" when opening file saved with password. Obviously css::xml::crypto::XDigestContext used in ZipOutputEntry does not work properly when encrypting files in parallel, so don't do that. Change-Id: I4b354535240a4f31a6bc6855cf7f9af527634e7e Reviewed-on: https://gerrit.libreoffice.org/21238 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Matúš Kukan <matus@libreoffice.org> 2015-12-24loplugin:unusedfieldsNoel Grandin Change-Id: I979592adb978c3757a1e54615021ee424a2e02bf Reviewed-on: https://gerrit.libreoffice.org/20892 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Noel Grandin <noelgrandin@gmail.com> 2015-11-19use comphelper::containerToSequenceNoel Grandin in chart2, we remove a local equivalent of the method Change-Id: I25129a3d1ea1dd724eb9cd38a57be37a78b3d100 2015-11-15use initialiser for Sequence<OUString>Noel Grandin replaced using: git grep -lP 'Sequence.*OUString.*\(\s*1\s*\)' | xargs perl -0777 -pi -e "s/Sequence<\s*OUString\s*> (\w+)\(\s*1\s*\); .*\[0\] = (\S+);/Sequence<OUString> \1 { \2 };/g" Change-Id: I20ad0489da887a9712982531c3b127339bb8b3b9 Reviewed-on: https://gerrit.libreoffice.org/19969 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Noel Grandin <noelgrandin@gmail.com> 2015-11-15use initialiser syntax for Sequence<OUString>Noel Grandin replaced using the script: git grep -lP 'Sequence.*OUString.*\(1\)' | xargs perl -0777 -pi -e "s/Sequence< OUString > (\w+)\(1\); .*\[0\] = (\S+);/Sequence< OUString > \1 { \2 };/g" Change-Id: I23688a91562051a8eed11fc2a85599545c285c34 Reviewed-on: https://gerrit.libreoffice.org/19967 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Noel Grandin <noelgrandin@gmail.com> 2015-11-10loplugin:nullptr (automatic rewrite)Stephan Bergmann Change-Id: I1e5338558bc57afe51db57655550e9b7246f7214 2015-11-04use uno::Reference::set method instead of assignmentNoel Grandin Change-Id: I1c7240fe2e2b5eb825f028ca7502e5ba8793046b 2015-10-23com::sun::star->css in package,pyunoNoel Grandin Change-Id: I7b7b0e7fea2d1a2b9f6f5501ad5e0b8c1b4a17b9 2015-10-12Replace "SAL_OVERRIDE" with "override" in LIBO_INTERNAL_ONLY codeStephan Bergmann Change-Id: I2ea407acd763ef2d7dae2d3b8f32525523ac8274 2015-10-07clang-analyzer-deadcode.DeadStoresStephan Bergmann Change-Id: I823aab2038eb08f4061e353b5fafc12b8e60e671 2015-09-30Fix typosAndrea Gelmini Change-Id: Id27f5a357c1333dec5c24c4f5e0fdaed7a775774 Reviewed-on: https://gerrit.libreoffice.org/18963 Reviewed-by: Samuel Mehrbrodt <Samuel.Mehrbrodt@cib.de> Tested-by: Samuel Mehrbrodt <Samuel.Mehrbrodt@cib.de> 2015-09-18boost->stdCaolán McNamara Change-Id: Ie490bf2c6921f393bdeed96b1a8815996b701bf0 Reviewed-on: https://gerrit.libreoffice.org/18670 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Caolán McNamara <caolanm@redhat.com> Tested-by: Caolán McNamara <caolanm@redhat.com> 2015-08-26package: tdf#88206 replace cppu::WeakImplHelper* etc.Takeshi Abe with the variadic variants. Change-Id: If88e1d741075e86997c91dc2c59eeebe45f67c1f Reviewed-on: https://gerrit.libreoffice.org/17980 Reviewed-by: Noel Grandin <noelgrandin@gmail.com> Tested-by: Noel Grandin <noelgrandin@gmail.com> 2015-08-19Consolidate isFileUrl checksStephan Bergmann Change-Id: I1b74fdfaa09c4d0d6c296253958e83e78b546a9a 2015-08-18Simplify ZipPackage::isLocalFile checkStephan Bergmann (vnd.sun.star.wfs is long gone) Change-Id: I3e25f1728504cbad07bb97187a7bac23b33695dc 2015-08-17avoid possible leak on exceptionCaolán McNamara Change-Id: Id3c16e5fedc5e57c8daccafa25bdb2fbbd0131b0