1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <swtypes.hxx>
21 #include "mmlayoutpage.hxx"
22 #include <mailmergewizard.hxx>
23 #include <mmconfigitem.hxx>
24 #include <mailmergehelper.hxx>
25 #include <unotools.hxx>
26 #include <comphelper/string.hxx>
27 #include <comphelper/propertyvalue.hxx>
28 #include <comphelper/servicehelper.hxx>
29 #include <i18nutil/unicode.hxx>
30 #include <unotools/tempfile.hxx>
34 #include <sfx2/docfilt.hxx>
35 #include <sfx2/fcontnr.hxx>
36 #include <svtools/unitconv.hxx>
37 #include <com/sun/star/view/XViewSettingsSupplier.hpp>
38 #include <com/sun/star/view/DocumentZoomType.hpp>
41 #include <unotxdoc.hxx>
45 #include <fmtsrnd.hxx>
46 #include <pagedesc.hxx>
47 #include <fmtanchr.hxx>
48 #include <fmtornt.hxx>
49 #include <fmtfsize.hxx>
50 #include <editeng/boxitem.hxx>
51 #include <osl/diagnose.h>
52 #include <osl/file.hxx>
53 #include <vcl/settings.hxx>
54 #include <unoprnms.hxx>
59 using namespace ::com::sun::star
;
60 using namespace ::com::sun::star::uno
;
61 using namespace ::com::sun::star::text
;
62 using namespace ::com::sun::star::frame
;
63 using namespace ::com::sun::star::view
;
65 constexpr tools::Long DEFAULT_LEFT_DISTANCE
= o3tl::toTwips(25, o3tl::Length::mm
); // 2,5 cm
66 constexpr tools::Long DEFAULT_TOP_DISTANCE
= o3tl::toTwips(55, o3tl::Length::mm
); // 5,5 cm
67 constexpr tools::Long GREETING_TOP_DISTANCE
= o3tl::toTwips(125, o3tl::Length::mm
); //12,5 cm
68 constexpr tools::Long DEFAULT_ADDRESS_WIDTH
= o3tl::toTwips(75, o3tl::Length::mm
); // 7,5 cm
69 constexpr tools::Long DEFAULT_ADDRESS_HEIGHT
= o3tl::toTwips(35, o3tl::Length::mm
); // 3,5cm
71 SwMailMergeLayoutPage::SwMailMergeLayoutPage(weld::Container
* pPage
, SwMailMergeWizard
* pWizard
)
72 : vcl::OWizardPage(pPage
, pWizard
, u
"modules/swriter/ui/mmlayoutpage.ui"_ustr
, u
"MMLayoutPage"_ustr
)
73 , m_pExampleWrtShell(nullptr)
74 , m_pAddressBlockFormat(nullptr)
75 , m_bIsGreetingInserted(false)
77 , m_xPosition(m_xBuilder
->weld_container(u
"addresspos"_ustr
))
78 , m_xAlignToBodyCB(m_xBuilder
->weld_check_button(u
"align"_ustr
))
79 , m_xLeftFT(m_xBuilder
->weld_label(u
"leftft"_ustr
))
80 , m_xLeftMF(m_xBuilder
->weld_metric_spin_button(u
"left"_ustr
, FieldUnit::CM
))
81 , m_xTopMF(m_xBuilder
->weld_metric_spin_button(u
"top"_ustr
, FieldUnit::CM
))
82 , m_xGreetingLine(m_xBuilder
->weld_container(u
"greetingspos"_ustr
))
83 , m_xUpPB(m_xBuilder
->weld_button(u
"up"_ustr
))
84 , m_xDownPB(m_xBuilder
->weld_button(u
"down"_ustr
))
85 , m_xZoomLB(m_xBuilder
->weld_combo_box(u
"zoom"_ustr
))
87 std::shared_ptr
<const SfxFilter
> pSfxFlt
=
88 SwDocShell::Factory().GetFilterContainer()->
89 GetFilter4FilterName(u
"writer8"_ustr
, SfxFilterFlags::EXPORT
);
91 //save the current document into a temporary file
93 //temp file needs its own block
94 //creating with extension is not supported by a static method :-(
96 comphelper::string::stripStart(pSfxFlt
->GetDefaultExtension(),'*'));
97 utl::TempFileNamed
aTempFile( u
"", true, sExt
);
98 aTempFile
.EnableKillingFile();
99 m_sExampleURL
= aTempFile
.GetURL();
101 SwView
* pView
= m_pWizard
->GetSwView();
102 // Don't save embedded data set! It would steal it from current document.
103 uno::Sequence
< beans::PropertyValue
> aValues
=
105 comphelper::makePropertyValue(u
"FilterName"_ustr
, pSfxFlt
->GetFilterName()),
106 comphelper::makePropertyValue(u
"NoEmbDataSet"_ustr
, true)
109 uno::Reference
< frame::XStorable
> xStore( pView
->GetDocShell()->GetModel(), uno::UNO_QUERY
);
110 xStore
->storeToURL( m_sExampleURL
, aValues
);
112 Link
<SwOneExampleFrame
&,void> aLink(LINK(this, SwMailMergeLayoutPage
, PreviewLoadedHdl_Impl
));
113 m_xExampleFrame
.reset(new SwOneExampleFrame(EX_SHOW_DEFAULT_PAGE
, &aLink
, &m_sExampleURL
));
114 m_xExampleContainerWIN
.reset(new weld::CustomWeld(*m_xBuilder
, u
"example"_ustr
, *m_xExampleFrame
));
116 Size aSize
= m_xExampleFrame
->GetDrawingArea()->get_ref_device().LogicToPixel(
117 Size(124, 159), MapMode(MapUnit::MapAppFont
));
118 m_xExampleFrame
->set_size_request(aSize
.Width(), aSize
.Height());
120 m_xExampleContainerWIN
->hide();
122 m_xLeftMF
->set_value(m_xLeftMF
->normalize(DEFAULT_LEFT_DISTANCE
), FieldUnit::TWIP
);
123 m_xTopMF
->set_value(m_xTopMF
->normalize(DEFAULT_TOP_DISTANCE
), FieldUnit::TWIP
);
125 const LanguageTag
& rLang
= Application::GetSettings().GetUILanguageTag();
126 m_xZoomLB
->append_text(unicode::formatPercent(50, rLang
));
127 m_xZoomLB
->append_text(unicode::formatPercent(75, rLang
));
128 m_xZoomLB
->append_text(unicode::formatPercent(100, rLang
));
129 m_xZoomLB
->set_active(0); //page size
130 m_xZoomLB
->connect_changed(LINK(this, SwMailMergeLayoutPage
, ZoomHdl_Impl
));
132 Link
<weld::MetricSpinButton
&,void> aFrameHdl
= LINK(this, SwMailMergeLayoutPage
, ChangeAddressHdl_Impl
);
133 m_xLeftMF
->connect_value_changed(aFrameHdl
);
134 m_xTopMF
->connect_value_changed(aFrameHdl
);
136 FieldUnit eFieldUnit
= ::GetDfltMetric(false);
137 ::SetFieldUnit( *m_xLeftMF
, eFieldUnit
);
138 ::SetFieldUnit( *m_xTopMF
, eFieldUnit
);
140 Link
<weld::Button
&,void> aUpDownHdl
= LINK(this, SwMailMergeLayoutPage
, GreetingsHdl_Impl
);
141 m_xUpPB
->connect_clicked(aUpDownHdl
);
142 m_xDownPB
->connect_clicked(aUpDownHdl
);
143 m_xAlignToBodyCB
->connect_toggled(LINK(this, SwMailMergeLayoutPage
, AlignToTextHdl_Impl
));
144 m_xAlignToBodyCB
->set_active(true);
147 SwMailMergeLayoutPage::~SwMailMergeLayoutPage()
149 File::remove( m_sExampleURL
);
152 void SwMailMergeLayoutPage::Activate()
154 SwMailMergeConfigItem
& rConfigItem
= m_pWizard
->GetConfigItem();
155 bool bGreetingLine
= rConfigItem
.IsGreetingLine(false) && !rConfigItem
.IsGreetingInserted();
156 bool bAddressBlock
= rConfigItem
.IsAddressBlock() && !rConfigItem
.IsAddressInserted();
158 m_xPosition
->set_sensitive(bAddressBlock
);
159 AlignToTextHdl_Impl(*m_xAlignToBodyCB
);
161 m_xGreetingLine
->set_sensitive(bGreetingLine
);
163 //check if greeting and/or address frame have to be inserted/removed
164 if(!m_pExampleWrtShell
) // initially there's nothing to check
167 if(!rConfigItem
.IsGreetingInserted() &&
168 m_bIsGreetingInserted
!= bGreetingLine
)
170 if( m_bIsGreetingInserted
)
172 m_pExampleWrtShell
->DelFullPara();
173 m_bIsGreetingInserted
= false;
177 InsertGreeting(*m_pExampleWrtShell
, m_pWizard
->GetConfigItem(), true);
178 m_bIsGreetingInserted
= true;
181 if(!rConfigItem
.IsAddressInserted() &&
182 rConfigItem
.IsAddressBlock() != ( nullptr != m_pAddressBlockFormat
))
184 if( m_pAddressBlockFormat
)
186 m_pExampleWrtShell
->Push();
187 m_pExampleWrtShell
->GotoFly( m_pAddressBlockFormat
->GetName() );
188 m_pExampleWrtShell
->DelRight();
189 m_pAddressBlockFormat
= nullptr;
190 m_pExampleWrtShell
->Pop(SwCursorShell::PopMode::DeleteCurrent
);
194 tools::Long nLeft
= static_cast< tools::Long
>(m_xLeftMF
->denormalize(m_xLeftMF
->get_value(FieldUnit::TWIP
)));
195 tools::Long nTop
= static_cast< tools::Long
>(m_xTopMF
->denormalize(m_xTopMF
->get_value(FieldUnit::TWIP
)));
196 m_pAddressBlockFormat
= InsertAddressFrame(
197 *m_pExampleWrtShell
, m_pWizard
->GetConfigItem(),
199 m_xAlignToBodyCB
->get_active(), true);
202 m_xExampleFrame
->Invalidate();
205 bool SwMailMergeLayoutPage::commitPage(::vcl::WizardTypes::CommitPageReason eReason
)
207 //now insert the frame and the greeting
208 SwMailMergeConfigItem
& rConfigItem
= m_pWizard
->GetConfigItem();
209 if (eReason
== ::vcl::WizardTypes::eTravelForward
|| eReason
== ::vcl::WizardTypes::eFinish
)
211 tools::Long nLeft
= static_cast< tools::Long
>(m_xLeftMF
->denormalize(m_xLeftMF
->get_value(FieldUnit::TWIP
)));
212 tools::Long nTop
= static_cast< tools::Long
>(m_xTopMF
->denormalize(m_xTopMF
->get_value(FieldUnit::TWIP
)));
213 InsertAddressAndGreeting(
214 m_pWizard
->GetSwView(),
217 m_xAlignToBodyCB
->get_active());
222 SwFrameFormat
* SwMailMergeLayoutPage::InsertAddressAndGreeting(SwView
const * pView
,
223 SwMailMergeConfigItem
& rConfigItem
,
224 const Point
& rAddressPosition
,
227 SwFrameFormat
* pAddressBlockFormat
= nullptr;
228 pView
->GetWrtShell().StartUndo(SwUndoId::INSERT
);
229 if(rConfigItem
.IsAddressBlock() && !rConfigItem
.IsAddressInserted())
232 Point
aAddressPosition(DEFAULT_LEFT_DISTANCE
, DEFAULT_TOP_DISTANCE
);
233 if(rAddressPosition
.X() > 0 && rAddressPosition
.Y() > 0)
234 aAddressPosition
= rAddressPosition
;
235 pAddressBlockFormat
= InsertAddressFrame( pView
->GetWrtShell(),
237 aAddressPosition
, bAlignToBody
, false);
238 rConfigItem
.SetAddressInserted();
241 if(rConfigItem
.IsGreetingLine(false) && !rConfigItem
.IsGreetingInserted())
243 InsertGreeting( pView
->GetWrtShell(), rConfigItem
, false);
244 rConfigItem
.SetGreetingInserted();
246 pView
->GetWrtShell().EndUndo(SwUndoId::INSERT
);
247 return pAddressBlockFormat
;
250 SwFrameFormat
* SwMailMergeLayoutPage::InsertAddressFrame(
252 SwMailMergeConfigItem
const & rConfigItem
,
253 const Point
& rDestination
,
257 // insert the address block and the greeting line
259 RES_FRM_SIZE
, RES_FRM_SIZE
,
260 RES_SURROUND
, RES_ANCHOR
,
261 RES_BOX
, RES_BOX
> aSet( rShell
.GetAttrPool() );
262 aSet
.Put(SwFormatAnchor(RndStdIds::FLY_AT_PAGE
, 1));
264 aSet
.Put(SwFormatHoriOrient( 0, text::HoriOrientation::NONE
, text::RelOrientation::PAGE_PRINT_AREA
));
266 aSet
.Put(SwFormatHoriOrient( rDestination
.X(), text::HoriOrientation::NONE
, text::RelOrientation::PAGE_FRAME
));
267 aSet
.Put(SwFormatVertOrient( rDestination
.Y(), text::VertOrientation::NONE
, text::RelOrientation::PAGE_FRAME
));
268 aSet
.Put(SwFormatFrameSize( SwFrameSize::Minimum
, DEFAULT_ADDRESS_WIDTH
, DEFAULT_ADDRESS_HEIGHT
));
269 // the example gets a border around the frame, the real document doesn't get one
271 aSet
.Put(SvxBoxItem( RES_BOX
));
272 aSet
.Put(SwFormatSurround( css::text::WrapTextMode_NONE
));
274 rShell
.NewFlyFrame(aSet
, true );
275 SwFrameFormat
* pRet
= rShell
.GetFlyFrameFormat();
276 OSL_ENSURE( pRet
, "Fly not inserted" );
278 rShell
.UnSelectFrame();
279 const Sequence
< OUString
> aBlocks
= rConfigItem
.GetAddressBlocks();
282 rShell
.Insert(aBlocks
[0]);
286 //the placeholders should be replaced by the appropriate fields
287 SwFieldMgr
aFieldMgr(&rShell
);
288 //create a database string source.command.commandtype.column
289 const SwDBData
& rData
= rConfigItem
.GetCurrentDBData();
290 OUString
sDBName(rData
.sDataSource
+ OUStringChar(DB_DELIM
)
291 + rData
.sCommand
+ OUStringChar(DB_DELIM
));
292 const OUString
sDatabaseConditionPrefix(sDBName
.replace(DB_DELIM
, '.'));
293 sDBName
+= OUString::number(rData
.nCommandType
) + OUStringChar(DB_DELIM
);
295 // if only the country is in an address line the
296 // paragraph has to be hidden depending on the
297 // IsIncludeCountry()/GetExcludeCountry() settings
299 bool bIncludeCountry
= rConfigItem
.IsIncludeCountry();
300 bool bHideEmptyParagraphs
= rConfigItem
.IsHideEmptyParagraphs();
301 const OUString
& rExcludeCountry
= rConfigItem
.GetExcludeCountry();
302 bool bSpecialReplacementForCountry
= (!bIncludeCountry
|| !rExcludeCountry
.isEmpty());
304 const std::vector
<std::pair
<OUString
, int>>& rHeaders
= rConfigItem
.GetDefaultAddressHeaders();
305 Sequence
< OUString
> aAssignment
=
306 rConfigItem
.GetColumnAssignment( rConfigItem
.GetCurrentDBData() );
307 const OUString
* pAssignment
= aAssignment
.getConstArray();
308 const OUString
sCountryColumn(
309 (aAssignment
.getLength() > MM_PART_COUNTRY
&& !aAssignment
[MM_PART_COUNTRY
].isEmpty())
310 ? aAssignment
[MM_PART_COUNTRY
]
311 : rHeaders
[MM_PART_COUNTRY
].first
);
313 OUString sHideParagraphsExpression
;
314 SwAddressIterator
aIter(aBlocks
[0]);
315 while(aIter
.HasMore())
317 SwMergeAddressItem aItem
= aIter
.Next();
320 OUString sConvertedColumn
= aItem
.sText
;
321 auto nSize
= std::min(static_cast<sal_uInt32
>(rHeaders
.size()),
322 static_cast<sal_uInt32
>(aAssignment
.getLength()));
323 for(sal_uInt32 nColumn
= 0; nColumn
< nSize
; ++nColumn
)
325 if (rHeaders
[nColumn
].first
== aItem
.sText
&&
326 !pAssignment
[nColumn
].isEmpty())
328 sConvertedColumn
= pAssignment
[nColumn
];
332 const OUString
sDB(sDBName
+ sConvertedColumn
);
334 if(!sHideParagraphsExpression
.isEmpty())
335 sHideParagraphsExpression
+= " AND ";
336 sHideParagraphsExpression
+= "![" + sDatabaseConditionPrefix
+ sConvertedColumn
+ "]";
338 if( bSpecialReplacementForCountry
&& sCountryColumn
== sConvertedColumn
)
340 // now insert a hidden paragraph field
341 if( !rExcludeCountry
.isEmpty() )
343 const OUString
sExpression("[" + sDatabaseConditionPrefix
+ sCountryColumn
+ "]");
344 SwInsertField_Data
aData(SwFieldTypesEnum::ConditionalText
, 0,
345 sExpression
+ " != \"" + rExcludeCountry
+ "\"",
348 aFieldMgr
.InsertField( aData
);
352 SwInsertField_Data
aData(SwFieldTypesEnum::HiddenParagraph
, 0, u
""_ustr
, u
""_ustr
, 0, &rShell
);
353 aFieldMgr
.InsertField( aData
);
358 SwInsertField_Data
aData(SwFieldTypesEnum::Database
, 0, sDB
, OUString(), 0, &rShell
);
359 aFieldMgr
.InsertField( aData
);
362 else if(!aItem
.bIsReturn
)
364 rShell
.Insert(aItem
.sText
);
368 if(bHideEmptyParagraphs
)
370 SwInsertField_Data
aData(SwFieldTypesEnum::HiddenParagraph
, 0, sHideParagraphsExpression
, OUString(), 0, &rShell
);
371 aFieldMgr
.InsertField( aData
);
373 sHideParagraphsExpression
.clear();
374 //now add a new paragraph
378 if(bHideEmptyParagraphs
&& !sHideParagraphsExpression
.isEmpty())
380 SwInsertField_Data
aData(SwFieldTypesEnum::HiddenParagraph
, 0, sHideParagraphsExpression
, OUString(), 0, &rShell
);
381 aFieldMgr
.InsertField( aData
);
387 void SwMailMergeLayoutPage::InsertGreeting(SwWrtShell
& rShell
, SwMailMergeConfigItem
const & rConfigItem
, bool bExample
)
389 //set the cursor to the desired position - if no text content is here then
390 //new paragraphs are inserted
391 const SwRect
& rPageRect
= rShell
.GetAnyCurRect(CurRectType::Page
);
392 const Point
aGreetingPos( DEFAULT_LEFT_DISTANCE
+ rPageRect
.Left(), GREETING_TOP_DISTANCE
);
394 const bool bRet
= rShell
.SetShadowCursorPos( aGreetingPos
, SwFillMode::TabSpace
);
398 //there's already text at the desired position
399 //go to start of the doc, directly!
400 rShell
.SttEndDoc(true);
401 //and go by paragraph until the position is reached
402 tools::Long nYPos
= rShell
.GetCharRect().Top();
403 while(nYPos
< GREETING_TOP_DISTANCE
)
405 if(!rShell
.FwdPara())
407 nYPos
= rShell
.GetCharRect().Top();
409 //text needs to be appended
410 while(nYPos
< GREETING_TOP_DISTANCE
)
412 if(!rShell
.AppendTextNode())
414 nYPos
= rShell
.GetCharRect().Top();
419 //we may end up inside of a paragraph if the left margin is not at DEFAULT_LEFT_DISTANCE
420 rShell
.MovePara(GoCurrPara
, fnParaStart
);
422 bool bSplitNode
= !rShell
.IsEndPara();
423 SwNodeOffset
nMoves(rConfigItem
.GetGreetingMoves());
424 if( !bExample
&& SwNodeOffset(0) != nMoves
)
426 if(nMoves
< SwNodeOffset(0))
428 rShell
.MoveParagraph( nMoves
);
433 bool bMoved
= rShell
.MoveParagraph();
436 //insert a new paragraph before the greeting line
442 //now insert the greeting text - if we have any?
443 const bool bIndividual
= rConfigItem
.IsIndividualGreeting(false);
446 //lock expression fields - prevents hiding of the paragraph to insert into
447 rShell
.LockExpFields();
450 for(sal_Int8 eGender
= SwMailMergeConfigItem::FEMALE
;
451 eGender
<= SwMailMergeConfigItem::NEUTRAL
; ++eGender
)
453 Sequence
< OUString
> aEntries
=
454 rConfigItem
.GetGreetings(static_cast<SwMailMergeConfigItem::Gender
>(eGender
));
455 sal_Int32 nCurrent
= rConfigItem
.GetCurrentGreeting(static_cast<SwMailMergeConfigItem::Gender
>(eGender
));
456 if( nCurrent
>= 0 && nCurrent
< aEntries
.getLength())
459 rShell
.Insert(aEntries
[nCurrent
]);
466 SwFieldMgr
aFieldMgr(&rShell
);
467 //three paragraphs, each with an appropriate hidden paragraph field
470 //name of the gender column
471 const OUString sGenderColumn
= rConfigItem
.GetAssignedColumn(MM_PART_GENDER
);
472 const OUString sNameColumn
= rConfigItem
.GetAssignedColumn(MM_PART_LASTNAME
);
474 const OUString
& rFemaleGenderValue
= rConfigItem
.GetFemaleGenderValue();
475 bool bHideEmptyParagraphs
= rConfigItem
.IsHideEmptyParagraphs();
476 const SwDBData
& rData
= rConfigItem
.GetCurrentDBData();
477 const OUString
sCommonBase(rData
.sDataSource
+ "." + rData
.sCommand
+ ".");
478 const OUString
sConditionBase("[" + sCommonBase
+ sGenderColumn
+ "]");
479 const OUString
sNameColumnBase("[" + sCommonBase
+ sNameColumn
+ "]");
481 const OUString
sDBName(rData
.sDataSource
+ OUStringChar(DB_DELIM
)
482 + rData
.sCommand
+ OUStringChar(DB_DELIM
)
483 + OUString::number(rData
.nCommandType
) + OUStringChar(DB_DELIM
));
485 // Female: [database.sGenderColumn] != "rFemaleGenderValue" && [database.NameColumn]
486 // Male: [database.sGenderColumn] == "rFemaleGenderValue" && [database.rGenderColumn]
487 // Neutral: [database.sNameColumn]
488 OSL_ENSURE(!sGenderColumn
.isEmpty() && !rFemaleGenderValue
.isEmpty(),
489 "gender settings not available - how to form the condition?");
490 //column used as lastname
491 for(sal_Int8 eGender
= SwMailMergeConfigItem::FEMALE
;
492 eGender
<= SwMailMergeConfigItem::NEUTRAL
; ++eGender
)
494 Sequence
< OUString
> aEntries
= rConfigItem
.GetGreetings(static_cast<SwMailMergeConfigItem::Gender
>(eGender
));
495 sal_Int32 nCurrent
= rConfigItem
.GetCurrentGreeting(static_cast<SwMailMergeConfigItem::Gender
>(eGender
));
496 if( nCurrent
>= 0 && nCurrent
< aEntries
.getLength())
498 const OUString
& sGreeting
= aEntries
[nCurrent
];
500 OUString sHideParagraphsExpression
;
503 case SwMailMergeConfigItem::FEMALE
:
504 sCondition
= sConditionBase
+ " != \"" + rFemaleGenderValue
505 + "\" OR NOT " + sNameColumnBase
;
506 sHideParagraphsExpression
= "!" + sNameColumnBase
;
508 case SwMailMergeConfigItem::MALE
:
509 sCondition
= sConditionBase
+ " == \"" + rFemaleGenderValue
510 + "\" OR NOT " + sNameColumnBase
;
512 case SwMailMergeConfigItem::NEUTRAL
:
513 sCondition
= sNameColumnBase
;
517 if(bHideEmptyParagraphs
&& !sHideParagraphsExpression
.isEmpty())
519 OUString sComplete
= "(" + sCondition
+ ") OR (" + sHideParagraphsExpression
+ ")";
520 SwInsertField_Data
aData(SwFieldTypesEnum::HiddenParagraph
, 0, sComplete
, OUString(), 0, &rShell
);
521 aFieldMgr
.InsertField( aData
);
525 SwInsertField_Data
aData(SwFieldTypesEnum::HiddenParagraph
, 0, sCondition
, OUString(), 0, &rShell
);
526 aFieldMgr
.InsertField( aData
);
528 //now the text has to be inserted
529 const std::vector
<std::pair
<OUString
, int>>& rHeaders
= rConfigItem
.GetDefaultAddressHeaders();
530 Sequence
< OUString
> aAssignment
=
531 rConfigItem
.GetColumnAssignment( rConfigItem
.GetCurrentDBData() );
532 const OUString
* pAssignment
= aAssignment
.getConstArray();
533 SwAddressIterator
aIter(sGreeting
);
534 while(aIter
.HasMore())
536 SwMergeAddressItem aItem
= aIter
.Next();
539 OUString sConvertedColumn
= aItem
.sText
;
540 auto nSize
= std::min(static_cast<sal_uInt32
>(rHeaders
.size()),
541 static_cast<sal_uInt32
>(aAssignment
.getLength()));
542 for(sal_uInt32 nColumn
= 0; nColumn
< nSize
; ++nColumn
)
544 if (rHeaders
[nColumn
].first
== aItem
.sText
&&
545 !pAssignment
[nColumn
].isEmpty())
547 sConvertedColumn
= pAssignment
[nColumn
];
551 SwInsertField_Data
aData(SwFieldTypesEnum::Database
, 0,
552 sDBName
+ sConvertedColumn
,
553 OUString(), 0, &rShell
);
554 aFieldMgr
.InsertField( aData
);
558 rShell
.Insert(aItem
.sText
);
561 //now add a new paragraph
567 rShell
.UnlockExpFields();
571 Sequence
< OUString
> aEntries
= rConfigItem
.GetGreetings(SwMailMergeConfigItem::NEUTRAL
);
572 sal_Int32 nCurrent
= rConfigItem
.GetCurrentGreeting(SwMailMergeConfigItem::NEUTRAL
);
574 rShell
.Insert(( nCurrent
>= 0 && nCurrent
< aEntries
.getLength() )
575 ? aEntries
[nCurrent
] : OUString());
577 // now insert a new paragraph here if necessary
582 rShell
.Pop(SwCursorShell::PopMode::DeleteCurrent
);
584 //put the cursor to the start of the paragraph
587 OSL_ENSURE(nullptr == rShell
.GetTableFormat(), "What to do with a table here?");
590 IMPL_LINK_NOARG(SwMailMergeLayoutPage
, PreviewLoadedHdl_Impl
, SwOneExampleFrame
&, void)
592 m_xExampleContainerWIN
->show();
594 rtl::Reference
< SwXTextDocument
> & xModel
= m_xExampleFrame
->GetModel();
595 //now the ViewOptions should be set properly
596 Reference
< XViewSettingsSupplier
> xSettings(xModel
->getCurrentController(), UNO_QUERY
);
597 m_xViewProperties
= xSettings
->getViewSettings();
598 SwDocShell
* pDocShell
= xModel
->GetDocShell();
599 m_pExampleWrtShell
= pDocShell
->GetWrtShell();
600 OSL_ENSURE(m_pExampleWrtShell
, "No SwWrtShell found!");
601 if(!m_pExampleWrtShell
)
604 SwMailMergeConfigItem
& rConfigItem
= m_pWizard
->GetConfigItem();
605 if(rConfigItem
.IsAddressBlock())
607 m_pAddressBlockFormat
= InsertAddressFrame(
608 *m_pExampleWrtShell
, rConfigItem
,
609 Point(DEFAULT_LEFT_DISTANCE
, DEFAULT_TOP_DISTANCE
),
610 m_xAlignToBodyCB
->get_active(), true);
612 if(rConfigItem
.IsGreetingLine(false))
614 InsertGreeting(*m_pExampleWrtShell
, rConfigItem
, true);
615 m_bIsGreetingInserted
= true;
618 ZoomHdl_Impl(*m_xZoomLB
);
620 const SwFormatFrameSize
& rPageSize
= m_pExampleWrtShell
->GetPageDesc(
621 m_pExampleWrtShell
->GetCurPageDesc()).GetMaster().GetFrameSize();
622 m_xLeftMF
->set_max(rPageSize
.GetWidth() - DEFAULT_LEFT_DISTANCE
, FieldUnit::NONE
);
623 m_xTopMF
->set_max(rPageSize
.GetHeight() - DEFAULT_TOP_DISTANCE
, FieldUnit::NONE
);
626 IMPL_LINK(SwMailMergeLayoutPage
, ZoomHdl_Impl
, weld::ComboBox
&, rBox
, void)
628 if (!m_pExampleWrtShell
)
631 sal_Int16 eType
= DocumentZoomType::BY_VALUE
;
633 switch (rBox
.get_active())
635 case 0 : eType
= DocumentZoomType::ENTIRE_PAGE
; break;
636 case 1 : nZoom
= 50; break;
637 case 2 : nZoom
= 75; break;
638 case 3 : nZoom
= 100; break;
642 m_xViewProperties
->setPropertyValue(UNO_NAME_ZOOM_TYPE
, aZoom
);
644 m_xViewProperties
->setPropertyValue(UNO_NAME_ZOOM_VALUE
, aZoom
);
646 m_xExampleFrame
->Invalidate();
649 IMPL_LINK_NOARG(SwMailMergeLayoutPage
, ChangeAddressHdl_Impl
, weld::MetricSpinButton
&, void)
651 if(!(m_pExampleWrtShell
&& m_pAddressBlockFormat
))
654 tools::Long nLeft
= static_cast< tools::Long
>(m_xLeftMF
->denormalize(m_xLeftMF
->get_value(FieldUnit::TWIP
)));
655 tools::Long nTop
= static_cast< tools::Long
>(m_xTopMF
->denormalize(m_xTopMF
->get_value(FieldUnit::TWIP
)));
657 SfxItemSetFixed
<RES_VERT_ORIENT
, RES_ANCHOR
> aSet(
658 m_pExampleWrtShell
->GetAttrPool());
659 if (m_xAlignToBodyCB
->get_active())
660 aSet
.Put(SwFormatHoriOrient( 0, text::HoriOrientation::NONE
, text::RelOrientation::PAGE_PRINT_AREA
));
662 aSet
.Put(SwFormatHoriOrient( nLeft
, text::HoriOrientation::NONE
, text::RelOrientation::PAGE_FRAME
));
663 aSet
.Put(SwFormatVertOrient( nTop
, text::VertOrientation::NONE
, text::RelOrientation::PAGE_FRAME
));
664 m_pExampleWrtShell
->GetDoc()->SetFlyFrameAttr( *m_pAddressBlockFormat
, aSet
);
665 m_xExampleFrame
->Invalidate();
668 IMPL_LINK(SwMailMergeLayoutPage
, GreetingsHdl_Impl
, weld::Button
&, rButton
, void)
670 bool bDown
= &rButton
== m_xDownPB
.get();
671 bool bMoved
= m_pExampleWrtShell
->MoveParagraph( SwNodeOffset(bDown
? 1 : -1) );
673 m_pWizard
->GetConfigItem().MoveGreeting(bDown
? 1 : -1 );
676 //insert a new paragraph before the greeting line
677 m_pExampleWrtShell
->SplitNode();
679 m_xExampleFrame
->Invalidate();
682 IMPL_LINK(SwMailMergeLayoutPage
, AlignToTextHdl_Impl
, weld::Toggleable
&, rBox
, void)
684 bool bCheck
= rBox
.get_active() && rBox
.get_sensitive();
685 m_xLeftFT
->set_sensitive(!bCheck
);
686 m_xLeftMF
->set_sensitive(!bCheck
);
687 ChangeAddressHdl_Impl( *m_xLeftMF
);
690 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */