LibreOffice Module sw (master)  1
mmlayoutpage.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <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 <i18nutil/unicode.hxx>
28 #include <unotools/tempfile.hxx>
29 #include <uitool.hxx>
30 #include <view.hxx>
31 #include <swundo.hxx>
32 #include <sfx2/docfilt.hxx>
33 #include <sfx2/fcontnr.hxx>
34 #include <svtools/unitconv.hxx>
35 #include <com/sun/star/view/XViewSettingsSupplier.hpp>
36 #include <com/sun/star/view/DocumentZoomType.hpp>
37 #include <fldmgr.hxx>
38 #include <fldbas.hxx>
39 #include <unotxdoc.hxx>
40 #include <docsh.hxx>
41 #include <doc.hxx>
42 #include <wrtsh.hxx>
43 #include <fmtsrnd.hxx>
44 #include <pagedesc.hxx>
45 #include <fmtanchr.hxx>
46 #include <fmtornt.hxx>
47 #include <fmtfsize.hxx>
48 #include <editeng/boxitem.hxx>
49 #include <osl/file.hxx>
50 #include <vcl/settings.hxx>
51 #include <unoprnms.hxx>
52 
53 #include <dbui.hrc>
54 
55 using namespace osl;
56 using namespace svt;
57 using namespace ::com::sun::star;
58 using namespace ::com::sun::star::uno;
59 using namespace ::com::sun::star::text;
60 using namespace ::com::sun::star::frame;
61 using namespace ::com::sun::star::lang;
62 using namespace ::com::sun::star::view;
63 
64 #define DEFAULT_LEFT_DISTANCE (MM50*5) // 2,5 cm
65 #define DEFAULT_TOP_DISTANCE (MM50*11) // 5,5 cm
66 #define GREETING_TOP_DISTANCE (MM50*25) //12,5 cm
67 #define DEFAULT_ADDRESS_WIDTH (MM50*15)// 7,5 cm
68 #define DEFAULT_ADDRESS_HEIGHT (MM50*7) // 3,5cm
69 
71  : vcl::OWizardPage(pPage, pWizard, "modules/swriter/ui/mmlayoutpage.ui", "MMLayoutPage")
72  , m_pExampleWrtShell(nullptr)
73  , m_pAddressBlockFormat(nullptr)
74  , m_bIsGreetingInserted(false)
75  , m_pWizard(pWizard)
76  , m_xPosition(m_xBuilder->weld_container("addresspos"))
77  , m_xAlignToBodyCB(m_xBuilder->weld_check_button("align"))
78  , m_xLeftFT(m_xBuilder->weld_label("leftft"))
79  , m_xLeftMF(m_xBuilder->weld_metric_spin_button("left", FieldUnit::CM))
80  , m_xTopMF(m_xBuilder->weld_metric_spin_button("top", FieldUnit::CM))
81  , m_xGreetingLine(m_xBuilder->weld_container("greetingspos"))
82  , m_xUpPB(m_xBuilder->weld_button("up"))
83  , m_xDownPB(m_xBuilder->weld_button("down"))
84  , m_xZoomLB(m_xBuilder->weld_combo_box("zoom"))
85 {
86  std::shared_ptr<const SfxFilter> pSfxFlt =
87  SwDocShell::Factory().GetFilterContainer()->
88  GetFilter4FilterName("writer8", SfxFilterFlags::EXPORT);
89 
90  //save the current document into a temporary file
91  {
92  //temp file needs its own block
93  //creating with extension is not supported by a static method :-(
94  OUString const sExt(
95  comphelper::string::stripStart(pSfxFlt->GetDefaultExtension(),'*'));
96  utl::TempFile aTempFile( OUString(), true, &sExt );
97  m_sExampleURL = aTempFile.GetURL();
98  aTempFile.EnableKillingFile();
99  }
100  SwView* pView = m_pWizard->GetSwView();
101  uno::Sequence< beans::PropertyValue > aValues(2);
102  beans::PropertyValue* pValues = aValues.getArray();
103  pValues[0].Name = "FilterName";
104  pValues[0].Value <<= pSfxFlt->GetFilterName();
105  // Don't save embedded data set! It would steal it from current document.
106  pValues[1].Name = "NoEmbDataSet";
107  pValues[1].Value <<= true;
108 
109  uno::Reference< frame::XStorable > xStore( pView->GetDocShell()->GetModel(), uno::UNO_QUERY);
110  xStore->storeToURL( m_sExampleURL, aValues );
111 
112  Link<SwOneExampleFrame&,void> aLink(LINK(this, SwMailMergeLayoutPage, PreviewLoadedHdl_Impl));
115 
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());
119 
120  m_xExampleContainerWIN->hide();
121 
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);
124 
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));
131 
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);
135 
136  FieldUnit eFieldUnit = ::GetDfltMetric(false);
137  ::SetFieldUnit( *m_xLeftMF, eFieldUnit );
138  ::SetFieldUnit( *m_xTopMF, eFieldUnit );
139 
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);
145 }
146 
148 {
149  File::remove( m_sExampleURL );
150 }
151 
153 {
155  bool bGreetingLine = rConfigItem.IsGreetingLine(false) && !rConfigItem.IsGreetingInserted();
156  bool bAddressBlock = rConfigItem.IsAddressBlock() && !rConfigItem.IsAddressInserted();
157 
158  m_xPosition->set_sensitive(bAddressBlock);
159  AlignToTextHdl_Impl(*m_xAlignToBodyCB);
160 
161  m_xGreetingLine->set_sensitive(bGreetingLine);
162 
163  //check if greeting and/or address frame have to be inserted/removed
164  if(!m_pExampleWrtShell) // initially there's nothing to check
165  return;
166 
167  if(!rConfigItem.IsGreetingInserted() &&
168  m_bIsGreetingInserted != bGreetingLine )
169  {
171  {
173  m_bIsGreetingInserted = false;
174  }
175  else
176  {
178  m_bIsGreetingInserted = true;
179  }
180  }
181  if(!rConfigItem.IsAddressInserted() &&
182  rConfigItem.IsAddressBlock() != ( nullptr != m_pAddressBlockFormat ))
183  {
185  {
189  m_pAddressBlockFormat = nullptr;
191  }
192  else
193  {
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)));
198  Point(nLeft, nTop),
199  m_xAlignToBodyCB->get_active(), true);
200  }
201  }
202  m_xExampleFrame->Invalidate();
203 }
204 
206 {
207  //now insert the frame and the greeting
209  if (eReason == ::vcl::WizardTypes::eTravelForward || eReason == ::vcl::WizardTypes::eFinish)
210  {
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)));
214  m_pWizard->GetSwView(),
215  rConfigItem,
216  Point(nLeft, nTop),
217  m_xAlignToBodyCB->get_active());
218  }
219  return true;
220 }
221 
223  SwMailMergeConfigItem& rConfigItem,
224  const Point& rAddressPosition,
225  bool bAlignToBody)
226 {
227  SwFrameFormat* pAddressBlockFormat = nullptr;
229  if(rConfigItem.IsAddressBlock() && !rConfigItem.IsAddressInserted())
230  {
231  //insert the frame
233  if(rAddressPosition.X() > 0 && rAddressPosition.Y() > 0)
234  aAddressPosition = rAddressPosition;
235  pAddressBlockFormat = InsertAddressFrame( pView->GetWrtShell(),
236  rConfigItem,
237  aAddressPosition, bAlignToBody, false);
238  rConfigItem.SetAddressInserted();
239  }
240  //now the greeting
241  if(rConfigItem.IsGreetingLine(false) && !rConfigItem.IsGreetingInserted())
242  {
243  InsertGreeting( pView->GetWrtShell(), rConfigItem, false);
244  rConfigItem.SetGreetingInserted();
245  }
247  return pAddressBlockFormat;
248 }
249 
251  SwWrtShell& rShell,
252  SwMailMergeConfigItem const & rConfigItem,
253  const Point& rDestination,
254  bool bAlignLeft,
255  bool bExample)
256 {
257  // insert the address block and the greeting line
258  SfxItemSet aSet(
259  rShell.GetAttrPool(),
260  svl::Items<
263  RES_BOX, RES_BOX>{} );
264  aSet.Put(SwFormatAnchor(RndStdIds::FLY_AT_PAGE, 1));
265  if(bAlignLeft)
266  aSet.Put(SwFormatHoriOrient( 0, text::HoriOrientation::NONE, text::RelOrientation::PAGE_PRINT_AREA ));
267  else
268  aSet.Put(SwFormatHoriOrient( rDestination.X(), text::HoriOrientation::NONE, text::RelOrientation::PAGE_FRAME ));
269  aSet.Put(SwFormatVertOrient( rDestination.Y(), text::VertOrientation::NONE, text::RelOrientation::PAGE_FRAME ));
271  // the example gets a border around the frame, the real document doesn't get one
272  if(!bExample)
273  aSet.Put(SvxBoxItem( RES_BOX ));
274  aSet.Put(SwFormatSurround( css::text::WrapTextMode_NONE ));
275 
276  rShell.NewFlyFrame(aSet, true );
277  SwFrameFormat* pRet = rShell.GetFlyFrameFormat();
278  OSL_ENSURE( pRet, "Fly not inserted" );
279 
280  rShell.UnSelectFrame();
281  const Sequence< OUString> aBlocks = rConfigItem.GetAddressBlocks();
282  if(bExample)
283  {
284  rShell.Insert(aBlocks[0]);
285  }
286  else
287  {
288  //the placeholders should be replaced by the appropriate fields
289  SwFieldMgr aFieldMgr(&rShell);
290  //create a database string source.command.commandtype.column
291  const SwDBData& rData = rConfigItem.GetCurrentDBData();
292  OUString sDBName(rData.sDataSource + OUStringChar(DB_DELIM)
293  + rData.sCommand + OUStringChar(DB_DELIM));
294  const OUString sDatabaseConditionPrefix(sDBName.replace(DB_DELIM, '.'));
295  sDBName += OUString::number(rData.nCommandType) + OUStringChar(DB_DELIM);
296 
297  // if only the country is in an address line the
298  // paragraph has to be hidden depending on the
299  // IsIncludeCountry()/GetExcludeCountry() settings
300 
301  bool bIncludeCountry = rConfigItem.IsIncludeCountry();
302  bool bHideEmptyParagraphs = rConfigItem.IsHideEmptyParagraphs();
303  const OUString rExcludeCountry = rConfigItem.GetExcludeCountry();
304  bool bSpecialReplacementForCountry = (!bIncludeCountry || !rExcludeCountry.isEmpty());
305 
306  const std::vector<std::pair<OUString, int>>& rHeaders = rConfigItem.GetDefaultAddressHeaders();
307  Sequence< OUString> aAssignment =
308  rConfigItem.GetColumnAssignment( rConfigItem.GetCurrentDBData() );
309  const OUString* pAssignment = aAssignment.getConstArray();
310  const OUString sCountryColumn(
311  (aAssignment.getLength() > MM_PART_COUNTRY && !aAssignment[MM_PART_COUNTRY].isEmpty())
312  ? aAssignment[MM_PART_COUNTRY]
313  : rHeaders[MM_PART_COUNTRY].first);
314 
315  OUString sHideParagraphsExpression;
316  SwAddressIterator aIter(aBlocks[0]);
317  while(aIter.HasMore())
318  {
319  SwMergeAddressItem aItem = aIter.Next();
320  if(aItem.bIsColumn)
321  {
322  OUString sConvertedColumn = aItem.sText;
323  auto nSize = std::min(static_cast<sal_uInt32>(rHeaders.size()),
324  static_cast<sal_uInt32>(aAssignment.getLength()));
325  for(sal_uInt32 nColumn = 0; nColumn < nSize; ++nColumn)
326  {
327  if (rHeaders[nColumn].first == aItem.sText &&
328  !pAssignment[nColumn].isEmpty())
329  {
330  sConvertedColumn = pAssignment[nColumn];
331  break;
332  }
333  }
334  const OUString sDB(sDBName + sConvertedColumn);
335 
336  if(!sHideParagraphsExpression.isEmpty())
337  sHideParagraphsExpression += " AND ";
338  sHideParagraphsExpression += "![" + sDatabaseConditionPrefix + sConvertedColumn + "]";
339 
340  if( bSpecialReplacementForCountry && sCountryColumn == sConvertedColumn )
341  {
342  // now insert a hidden paragraph field
343  if( !rExcludeCountry.isEmpty() )
344  {
345  const OUString sExpression("[" + sDatabaseConditionPrefix + sCountryColumn + "]");
347  sExpression + " != \"" + rExcludeCountry + "\"",
348  sExpression,
349  0, &rShell );
350  aFieldMgr.InsertField( aData );
351  }
352  else
353  {
355  aFieldMgr.InsertField( aData );
356  }
357  }
358  else
359  {
360  SwInsertField_Data aData(SwFieldTypesEnum::Database, 0, sDB, OUString(), 0, &rShell);
361  aFieldMgr.InsertField( aData );
362  }
363  }
364  else if(!aItem.bIsReturn)
365  {
366  rShell.Insert(aItem.sText);
367  }
368  else
369  {
370  if(bHideEmptyParagraphs)
371  {
372  SwInsertField_Data aData(SwFieldTypesEnum::HiddenParagraph, 0, sHideParagraphsExpression, OUString(), 0, &rShell);
373  aFieldMgr.InsertField( aData );
374  }
375  sHideParagraphsExpression.clear();
376  //now add a new paragraph
377  rShell.SplitNode();
378  }
379  }
380  if(bHideEmptyParagraphs && !sHideParagraphsExpression.isEmpty())
381  {
382  SwInsertField_Data aData(SwFieldTypesEnum::HiddenParagraph, 0, sHideParagraphsExpression, OUString(), 0, &rShell);
383  aFieldMgr.InsertField( aData );
384  }
385  }
386  return pRet;
387 }
388 
389 void SwMailMergeLayoutPage::InsertGreeting(SwWrtShell& rShell, SwMailMergeConfigItem const & rConfigItem, bool bExample)
390 {
391  //set the cursor to the desired position - if no text content is here then
392  //new paragraphs are inserted
393  const SwRect& rPageRect = rShell.GetAnyCurRect(CurRectType::Page);
394  const Point aGreetingPos( DEFAULT_LEFT_DISTANCE + rPageRect.Left(), GREETING_TOP_DISTANCE );
395 
396  const bool bRet = rShell.SetShadowCursorPos( aGreetingPos, SwFillMode::TabSpace );
397 
398  if(!bRet)
399  {
400  //there's already text at the desired position
401  //go to start of the doc, directly!
402  rShell.SttEndDoc(true);
403  //and go by paragraph until the position is reached
404  tools::Long nYPos = rShell.GetCharRect().Top();
405  while(nYPos < GREETING_TOP_DISTANCE)
406  {
407  if(!rShell.FwdPara())
408  break;
409  nYPos = rShell.GetCharRect().Top();
410  }
411  //text needs to be appended
412  while(nYPos < GREETING_TOP_DISTANCE)
413  {
414  if(!rShell.AppendTextNode())
415  break;
416  nYPos = rShell.GetCharRect().Top();
417  }
418  }
419  else
420  {
421  //we may end up inside of a paragraph if the left margin is not at DEFAULT_LEFT_DISTANCE
423  }
424  bool bSplitNode = !rShell.IsEndPara();
425  sal_Int32 nMoves = rConfigItem.GetGreetingMoves();
426  if( !bExample && 0 != nMoves )
427  {
428  if(nMoves < 0)
429  {
430  rShell.MoveParagraph( nMoves );
431  }
432  else
433  while(nMoves)
434  {
435  bool bMoved = rShell.MoveParagraph();
436  if(!bMoved)
437  {
438  //insert a new paragraph before the greeting line
439  rShell.SplitNode();
440  }
441  --nMoves;
442  }
443  }
444  //now insert the greeting text - if we have any?
445  const bool bIndividual = rConfigItem.IsIndividualGreeting(false);
446  if(bIndividual)
447  {
448  //lock expression fields - prevents hiding of the paragraph to insert into
449  rShell.LockExpFields();
450  if(bExample)
451  {
453  eGender <= SwMailMergeConfigItem::NEUTRAL; ++eGender)
454  {
456  rConfigItem.GetGreetings(static_cast<SwMailMergeConfigItem::Gender>(eGender));
457  sal_Int32 nCurrent = rConfigItem.GetCurrentGreeting(static_cast<SwMailMergeConfigItem::Gender>(eGender));
458  if( nCurrent >= 0 && nCurrent < aEntries.getLength())
459  {
460  // Greeting
461  rShell.Insert(aEntries[nCurrent]);
462  break;
463  }
464  }
465  }
466  else
467  {
468  SwFieldMgr aFieldMgr(&rShell);
469  //three paragraphs, each with an appropriate hidden paragraph field
470  //are to be inserted
471 
472  //name of the gender column
473  const OUString sGenderColumn = rConfigItem.GetAssignedColumn(MM_PART_GENDER);
474  const OUString sNameColumn = rConfigItem.GetAssignedColumn(MM_PART_LASTNAME);
475 
476  const OUString& rFemaleGenderValue = rConfigItem.GetFemaleGenderValue();
477  bool bHideEmptyParagraphs = rConfigItem.IsHideEmptyParagraphs();
478  const SwDBData& rData = rConfigItem.GetCurrentDBData();
479  const OUString sCommonBase(rData.sDataSource + "." + rData.sCommand + ".");
480  const OUString sConditionBase("[" + sCommonBase + sGenderColumn + "]");
481  const OUString sNameColumnBase("[" + sCommonBase + sNameColumn + "]");
482 
483  const OUString sDBName(rData.sDataSource + OUStringChar(DB_DELIM)
484  + rData.sCommand + OUStringChar(DB_DELIM)
485  + OUString::number(rData.nCommandType) + OUStringChar(DB_DELIM));
486 
487 // Female: [database.sGenderColumn] != "rFemaleGenderValue" && [database.NameColumn]
488 // Male: [database.sGenderColumn] == "rFemaleGenderValue" && [database.rGenderColumn]
489 // Neutral: [database.sNameColumn]
490  OSL_ENSURE(!sGenderColumn.isEmpty() && !rFemaleGenderValue.isEmpty(),
491  "gender settings not available - how to form the condition?");
492  //column used as lastname
494  eGender <= SwMailMergeConfigItem::NEUTRAL; ++eGender)
495  {
496  Sequence< OUString> aEntries = rConfigItem.GetGreetings(static_cast<SwMailMergeConfigItem::Gender>(eGender));
497  sal_Int32 nCurrent = rConfigItem.GetCurrentGreeting(static_cast<SwMailMergeConfigItem::Gender>(eGender));
498  if( nCurrent >= 0 && nCurrent < aEntries.getLength())
499  {
500  const OUString sGreeting = aEntries[nCurrent];
501  OUString sCondition;
502  OUString sHideParagraphsExpression;
503  switch(eGender)
504  {
506  sCondition = sConditionBase + " != \"" + rFemaleGenderValue
507  + "\" OR NOT " + sNameColumnBase;
508  sHideParagraphsExpression = "!" + sNameColumnBase;
509  break;
511  sCondition = sConditionBase + " == \"" + rFemaleGenderValue
512  + "\" OR NOT " + sNameColumnBase;
513  break;
515  sCondition = sNameColumnBase;
516  break;
517  }
518 
519  if(bHideEmptyParagraphs && !sHideParagraphsExpression.isEmpty())
520  {
521  OUString sComplete = "(" + sCondition + ") OR (" + sHideParagraphsExpression + ")";
522  SwInsertField_Data aData(SwFieldTypesEnum::HiddenParagraph, 0, sComplete, OUString(), 0, &rShell);
523  aFieldMgr.InsertField( aData );
524  }
525  else
526  {
527  SwInsertField_Data aData(SwFieldTypesEnum::HiddenParagraph, 0, sCondition, OUString(), 0, &rShell);
528  aFieldMgr.InsertField( aData );
529  }
530  //now the text has to be inserted
531  const std::vector<std::pair<OUString, int>>& rHeaders = rConfigItem.GetDefaultAddressHeaders();
532  Sequence< OUString> aAssignment =
533  rConfigItem.GetColumnAssignment( rConfigItem.GetCurrentDBData() );
534  const OUString* pAssignment = aAssignment.getConstArray();
535  SwAddressIterator aIter(sGreeting);
536  while(aIter.HasMore())
537  {
538  SwMergeAddressItem aItem = aIter.Next();
539  if(aItem.bIsColumn)
540  {
541  OUString sConvertedColumn = aItem.sText;
542  auto nSize = std::min(static_cast<sal_uInt32>(rHeaders.size()),
543  static_cast<sal_uInt32>(aAssignment.getLength()));
544  for(sal_uInt32 nColumn = 0; nColumn < nSize; ++nColumn)
545  {
546  if (rHeaders[nColumn].first == aItem.sText &&
547  !pAssignment[nColumn].isEmpty())
548  {
549  sConvertedColumn = pAssignment[nColumn];
550  break;
551  }
552  }
554  sDBName + sConvertedColumn,
555  OUString(), 0, &rShell);
556  aFieldMgr.InsertField( aData );
557  }
558  else
559  {
560  rShell.Insert(aItem.sText);
561  }
562  }
563  //now add a new paragraph
564  rShell.SplitNode();
565  }
566  }
567 
568  }
569  rShell.UnlockExpFields();
570  }
571  else
572  {
574  sal_Int32 nCurrent = rConfigItem.GetCurrentGreeting(SwMailMergeConfigItem::NEUTRAL);
575  // Greeting
576  rShell.Insert(( nCurrent >= 0 && nCurrent < aEntries.getLength() )
577  ? aEntries[nCurrent] : OUString());
578  }
579  // now insert a new paragraph here if necessary
580  if(bSplitNode)
581  {
582  rShell.Push();
583  rShell.SplitNode();
585  }
586  //put the cursor to the start of the paragraph
587  rShell.SttPara();
588 
589  OSL_ENSURE(nullptr == rShell.GetTableFormat(), "What to do with a table here?");
590 }
591 
593 {
594  m_xExampleContainerWIN->show();
595 
596  Reference< XModel > & xModel = m_xExampleFrame->GetModel();
597  //now the ViewOptions should be set properly
598  Reference< XViewSettingsSupplier > xSettings(xModel->getCurrentController(), UNO_QUERY);
599  m_xViewProperties = xSettings->getViewSettings();
600  auto pXDoc = comphelper::getUnoTunnelImplementation<SwXTextDocument>(xModel);
601  SwDocShell* pDocShell = pXDoc->GetDocShell();
602  m_pExampleWrtShell = pDocShell->GetWrtShell();
603  OSL_ENSURE(m_pExampleWrtShell, "No SwWrtShell found!");
604  if(!m_pExampleWrtShell)
605  return;
606 
607  SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem();
608  if(rConfigItem.IsAddressBlock())
609  {
610  m_pAddressBlockFormat = InsertAddressFrame(
611  *m_pExampleWrtShell, rConfigItem,
613  m_xAlignToBodyCB->get_active(), true);
614  }
615  if(rConfigItem.IsGreetingLine(false))
616  {
617  InsertGreeting(*m_pExampleWrtShell, rConfigItem, true);
618  m_bIsGreetingInserted = true;
619  }
620 
621  ZoomHdl_Impl(*m_xZoomLB);
622 
623  const SwFormatFrameSize& rPageSize = m_pExampleWrtShell->GetPageDesc(
624  m_pExampleWrtShell->GetCurPageDesc()).GetMaster().GetFrameSize();
625  m_xLeftMF->set_max(rPageSize.GetWidth() - DEFAULT_LEFT_DISTANCE, FieldUnit::NONE);
626  m_xTopMF->set_max(rPageSize.GetHeight() - DEFAULT_TOP_DISTANCE, FieldUnit::NONE);
627 }
628 
629 IMPL_LINK(SwMailMergeLayoutPage, ZoomHdl_Impl, weld::ComboBox&, rBox, void)
630 {
631  if (!m_pExampleWrtShell)
632  return;
633 
634  sal_Int16 eType = DocumentZoomType::BY_VALUE;
635  short nZoom = 50;
636  switch (rBox.get_active())
637  {
638  case 0 : eType = DocumentZoomType::ENTIRE_PAGE; break;
639  case 1 : nZoom = 50; break;
640  case 2 : nZoom = 75; break;
641  case 3 : nZoom = 100; break;
642  }
643  Any aZoom;
644  aZoom <<= eType;
645  m_xViewProperties->setPropertyValue(UNO_NAME_ZOOM_TYPE, aZoom);
646  aZoom <<= nZoom;
647  m_xViewProperties->setPropertyValue(UNO_NAME_ZOOM_VALUE, aZoom);
648 
649  m_xExampleFrame->Invalidate();
650 }
651 
653 {
654  if(!(m_pExampleWrtShell && m_pAddressBlockFormat))
655  return;
656 
657  tools::Long nLeft = static_cast< tools::Long >(m_xLeftMF->denormalize(m_xLeftMF->get_value(FieldUnit::TWIP)));
658  tools::Long nTop = static_cast< tools::Long >(m_xTopMF->denormalize(m_xTopMF->get_value(FieldUnit::TWIP)));
659 
660  SfxItemSet aSet(
661  m_pExampleWrtShell->GetAttrPool(),
663  if (m_xAlignToBodyCB->get_active())
664  aSet.Put(SwFormatHoriOrient( 0, text::HoriOrientation::NONE, text::RelOrientation::PAGE_PRINT_AREA ));
665  else
666  aSet.Put(SwFormatHoriOrient( nLeft, text::HoriOrientation::NONE, text::RelOrientation::PAGE_FRAME ));
667  aSet.Put(SwFormatVertOrient( nTop, text::VertOrientation::NONE, text::RelOrientation::PAGE_FRAME ));
668  m_pExampleWrtShell->GetDoc()->SetFlyFrameAttr( *m_pAddressBlockFormat, aSet );
669  m_xExampleFrame->Invalidate();
670 }
671 
672 IMPL_LINK(SwMailMergeLayoutPage, GreetingsHdl_Impl, weld::Button&, rButton, void)
673 {
674  bool bDown = &rButton == m_xDownPB.get();
675  bool bMoved = m_pExampleWrtShell->MoveParagraph( bDown ? 1 : -1 );
676  if (bMoved || bDown)
677  m_pWizard->GetConfigItem().MoveGreeting(bDown ? 1 : -1 );
678  if(!bMoved && bDown)
679  {
680  //insert a new paragraph before the greeting line
681  m_pExampleWrtShell->SplitNode();
682  }
683  m_xExampleFrame->Invalidate();
684 }
685 
686 IMPL_LINK(SwMailMergeLayoutPage, AlignToTextHdl_Impl, weld::ToggleButton&, rBox, void)
687 {
688  bool bCheck = rBox.get_active() && rBox.get_sensitive();
689  m_xLeftFT->set_sensitive(!bCheck);
690  m_xLeftMF->set_sensitive(!bCheck);
691  ChangeAddressHdl_Impl( *m_xLeftMF );
692 }
693 
694 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::unique_ptr< weld::Button > m_xUpPB
SwMergeAddressItem Next()
bool HasMore() const
bool IsHideEmptyParagraphs() const
tools::Long GetWidth() const
constexpr TypedWhichId< SwFormatSurround > RES_SURROUND(101)
bool AppendTextNode()
Definition: editsh.cxx:205
bool SttPara(bool bSelect=false)
Definition: move.cxx:356
FieldUnit
sal_Int32 nCommandType
Definition: swdbdata.hxx:32
void SplitNode(bool bAutoFormat=false)
Definition: wrtsh1.cxx:988
bool IsAddressInserted() const
#define DEFAULT_LEFT_DISTANCE
bool DelFullPara()
Remove a complete paragraph.
Definition: eddel.cxx:342
#define UNO_NAME_ZOOM_VALUE
Definition: unoprnms.hxx:421
#define EX_SHOW_DEFAULT_PAGE
Definition: unotools.hxx:33
SwMailMergeConfigItem & GetConfigItem()
#define DEFAULT_ADDRESS_WIDTH
bool SttEndDoc(bool bStt)
Definition: crsrsh.cxx:573
bool GoCurrPara(SwPaM &rPam, SwMoveFnCollection const &aPosPara)
Definition: pam.cxx:1016
const LanguageTag & GetUILanguageTag() const
signed char sal_Int8
void Left(const tools::Long nLeft)
Definition: swrect.hxx:195
constexpr TypedWhichId< SwFormatFrameSize > RES_FRM_SIZE(89)
const SwRect & GetAnyCurRect(CurRectType eType, const Point *pPt=nullptr, const css::uno::Reference< css::embed::XEmbeddedObject > &=css::uno::Reference< css::embed::XEmbeddedObject >()) const
Definition: fews.cxx:90
#define UNO_NAME_ZOOM_TYPE
Definition: unoprnms.hxx:422
OUString & GetExcludeCountry() const
long Long
OUString sDataSource
Definition: swdbdata.hxx:30
static const AllSettings & GetSettings()
std::unique_ptr< SwOneExampleFrame > m_xExampleFrame
bool Pop(SwCursorShell::PopMode=SwCursorShell::PopMode::DeleteStack)
Definition: wrtsh1.cxx:1715
SwMoveFnCollection const & fnParaStart
Definition: paminit.cxx:46
const ContentProperties & rData
SwUndoId EndUndo(SwUndoId eUndoId=SwUndoId::EMPTY, const SwRewriter *pRewriter=nullptr)
Closes parenthesis of nUndoId, not used by UI.
Definition: edws.cxx:234
#define DEFAULT_ADDRESS_HEIGHT
const SwDBData & GetCurrentDBData() const
sal_Int32 GetGreetingMoves() const
std::unique_ptr< weld::Builder > m_xBuilder
css::uno::Reference< css::frame::XModel > GetModel() const
std::unique_ptr< weld::MetricSpinButton > m_xLeftMF
Of course Writer needs its own rectangles.
Definition: swrect.hxx:35
bool InsertField(const SwInsertField_Data &rData)
Definition: fldmgr.cxx:891
Value in Var-direction gives minimum (can be exceeded but not be less).
std::unique_ptr< weld::ComboBox > m_xZoomLB
bool DelRight()
Definition: delete.cxx:292
SwWrtShell & GetWrtShell() const
Definition: view.hxx:413
Used by the UI to modify the document model.
Definition: wrtsh.hxx:91
constexpr tools::Long Width() const
bool GotoFly(const OUString &rName, FlyCntType eType=FLYCNTTYPE_ALL, bool bSelFrame=true)
Definition: move.cxx:599
#define GREETING_TOP_DISTANCE
static SwFrameFormat * InsertAddressFrame(SwWrtShell &rShell, SwMailMergeConfigItem const &rConfigItem, const Point &rDestination, bool bAlignToBody, bool bExample)
css::uno::Sequence< OUString > GetAddressBlocks() const
static SwFrameFormat * InsertAddressAndGreeting(SwView const *pView, SwMailMergeConfigItem &rConfigItem, const Point &rAddressPos, bool bAlignToBody)
#define DEFAULT_TOP_DISTANCE
const OUString & GetName() const
Definition: format.hxx:115
SwMailMergeLayoutPage(weld::Container *pPage, SwMailMergeWizard *pWizard)
static void InsertGreeting(SwWrtShell &rShell, SwMailMergeConfigItem const &rConfigItem, bool bExample)
css::uno::Sequence< OUString > GetGreetings(Gender eType) const
void Insert(SwField const &, SwPaM *pAnnotationRange=nullptr)
Definition: wrtsh2.cxx:62
bool MoveParagraph(tools::Long nOffset=1)
Definition: ednumber.cxx:441
std::unique_ptr< weld::CustomWeld > m_xExampleContainerWIN
constexpr OUStringLiteral aData
Definition: ww8scan.hxx:47
DocumentType eType
bool MovePara(SwWhichPara, SwMoveFnCollection const &)
Definition: crsrsh.cxx:695
bool IsGreetingInserted() const
const SfxItemPool & GetAttrPool() const
Definition: viewsh.hxx:612
IMPL_LINK(SwMailMergeLayoutPage, ZoomHdl_Impl, weld::ComboBox &, rBox, void)
const std::vector< std::pair< OUString, int > > & GetDefaultAddressHeaders() const
bool SetShadowCursorPos(const Point &rPt, SwFillMode eFillMode)
Definition: crstrvl.cxx:2059
Style of a layout element.
Definition: frmfmt.hxx:58
SW_DLLPUBLIC FieldUnit GetDfltMetric(bool bWeb)
Definition: uitool.cxx:726
OUString const & GetURL() const
std::unique_ptr< weld::Button > m_xDownPB
void Push()
store a copy of the current cursor on the cursor stack
Definition: crsrsh.cxx:2237
std::unique_ptr< weld::Container > m_xPosition
FlyAnchors.
Definition: fmtanchr.hxx:34
virtual ~SwMailMergeLayoutPage() override
SwUndoId StartUndo(SwUndoId eUndoId=SwUndoId::EMPTY, const SwRewriter *pRewriter=nullptr)
Undo: set up Undo parenthesis, return nUndoId of this parenthesis.
Definition: edws.cxx:223
SwWrtShell * GetWrtShell()
Access to the SwWrtShell belonging to SwView.
Definition: docsh.hxx:224
tools::Long GetHeight() const
void UnlockExpFields()
Definition: edfld.cxx:346
std::unique_ptr< weld::CheckButton > m_xAlignToBodyCB
#define DB_DELIM
Definition: swtypes.hxx:135
SwDocShell * GetDocShell()
Definition: view.cxx:1126
SwFrameFormat * GetTableFormat()
Definition: edws.cxx:183
css::uno::Sequence< OUString > GetColumnAssignment(const SwDBData &rDBData) const
Rect of current page.
sal_Int32 GetCurrentGreeting(Gender eType) const
std::unique_ptr< weld::MetricSpinButton > m_xTopMF
const PropertyValue * pValues
bool IsIndividualGreeting(bool bInEMail) const
SwMailMergeWizard * m_pWizard
const SwFrameFormat * NewFlyFrame(const SfxItemSet &rSet, bool bAnchValid=false, SwFrameFormat *pParent=nullptr)
Definition: fefly1.cxx:646
static OUString formatPercent(double dNumber, const LanguageTag &rLangTag)
constexpr tools::Long Height() const
fill with spaces and tabs
IMPL_LINK_NOARG(SwMailMergeLayoutPage, PreviewLoadedHdl_Impl, SwOneExampleFrame &, void)
OUString GetAssignedColumn(sal_uInt32 nColumn) const
virtual bool commitPage(::vcl::WizardTypes::CommitPageReason _eReason) override
void Top(const tools::Long nTop)
Definition: swrect.hxx:204
const SwRect & GetCharRect() const
Definition: crsrsh.hxx:516
bool IsGreetingLine(bool bInEMail) const
void UnSelectFrame()
Definition: select.cxx:323
OString stripStart(const OString &rIn, char c)
const OUString & GetFemaleGenderValue() const
bool IsIncludeCountry() const
constexpr TypedWhichId< SvxBoxItem > RES_BOX(106)
std::unique_ptr< weld::Container > m_xGreetingLine
virtual void Activate() override
ScXMLEditAttributeMap::Entry const aEntries[]
const SwFrameFormat * GetFlyFrameFormat() const
Get FlyFrameFormat; for UI macro linkage at Flys.
Definition: fefly1.cxx:1248
SwWrtShell * m_pExampleWrtShell
Reference< XModel > xModel
bool IsAddressBlock() const
bool IsEndPara() const
Definition: crsrsh.cxx:1113
constexpr OUStringLiteral first
bool FwdPara()
Definition: wrtsh.hxx:228
OUString sCommand
Definition: swdbdata.hxx:31
void EnableKillingFile(bool bEnable=true)
void LockExpFields()
Definition: edfld.cxx:341
Definition: view.hxx:144
constexpr TypedWhichId< SwFormatAnchor > RES_ANCHOR(104)
SwFrameFormat * m_pAddressBlockFormat