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