LibreOffice Module sw (master)  1
modeltoviewhelper.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 <tools/multisel.hxx>
21 #include <doc.hxx>
22 #include <IMark.hxx>
23 #include <fldbas.hxx>
24 #include <fmtfld.hxx>
25 #include <fmtftn.hxx>
26 #include <modeltoviewhelper.hxx>
27 #include <ndtxt.hxx>
28 #include <pam.hxx>
29 #include <txatbase.hxx>
30 #include <txtfld.hxx>
31 #include <txtftn.hxx>
32 #include <scriptinfo.hxx>
33 #include <IDocumentMarkAccess.hxx>
34 #include <set>
35 #include <vector>
36 
38 {
39  sal_Int32 const m_nFieldPos;
40  OUString m_sExpand;
41  enum { NONE, FIELD, FOOTNOTE } m_eType;
42  explicit FieldResult(sal_Int32 const nPos)
43  : m_nFieldPos(nPos), m_eType(NONE)
44  { }
45 };
46 
48 {
49 public:
50  bool operator()(const FieldResult &rOne, const FieldResult &rTwo) const
51  {
52  return rOne.m_nFieldPos < rTwo.m_nFieldPos;
53  }
54 };
55 
56 typedef std::set<FieldResult, sortfieldresults> FieldResultSet;
57 
58 struct block
59 {
60  sal_Int32 const m_nStart;
61  sal_Int32 const m_nLen;
62  bool const m_bVisible;
64  block(sal_Int32 nStart, sal_Int32 nLen, bool bVisible)
65  : m_nStart(nStart), m_nLen(nLen), m_bVisible(bVisible)
66  {
67  }
68 };
69 
71 {
72  const sal_Int32 m_nPos;
73  explicit containsPos(const sal_Int32 nPos)
74  : m_nPos(nPos)
75  {
76  }
77  bool operator() (const block& rIn) const
78  {
79  return m_nPos >= rIn.m_nStart && m_nPos < rIn.m_nStart + rIn.m_nLen;
80  }
81 };
82 
84  SwRootFrame const*const pLayout, ExpandMode eMode)
85 {
86  const OUString& rNodeText = rNode.GetText();
87  m_aRetText = rNodeText;
88 
89  if (eMode == ExpandMode::PassThrough)
90  return;
91 
92  Range aRange( 0, rNodeText.isEmpty() ? 0 : rNodeText.getLength() - 1);
93  MultiSelection aHiddenMulti(aRange);
94 
95  if (eMode & ExpandMode::HideInvisible)
96  SwScriptInfo::selectHiddenTextProperty(rNode, aHiddenMulti);
97 
98  if (eMode & ExpandMode::HideDeletions)
99  SwScriptInfo::selectRedLineDeleted(rNode, aHiddenMulti);
100 
101  std::vector<block> aBlocks;
102 
103  sal_Int32 nShownStart = 0;
104  for (sal_Int32 i = 0; i < aHiddenMulti.GetRangeCount(); ++i)
105  {
106  const Range& rRange = aHiddenMulti.GetRange(i);
107  const sal_Int32 nHiddenStart = rRange.Min();
108  const sal_Int32 nHiddenEnd = rRange.Max() + 1;
109  const sal_Int32 nHiddenLen = nHiddenEnd - nHiddenStart;
110 
111  const sal_Int32 nShownEnd = nHiddenStart;
112  const sal_Int32 nShownLen = nShownEnd - nShownStart;
113 
114  if (nShownLen)
115  aBlocks.emplace_back(nShownStart, nShownLen, true);
116 
117  if (nHiddenLen)
118  aBlocks.emplace_back(nHiddenStart, nHiddenLen, false);
119 
120  nShownStart = nHiddenEnd;
121  }
122 
123  sal_Int32 nTrailingShownLen = rNodeText.getLength() - nShownStart;
124  if (nTrailingShownLen)
125  aBlocks.emplace_back(nShownStart, nTrailingShownLen, true);
126 
128  {
129  //first the normal fields, get their position in the node and what the text they expand
130  //to is
131  const SwpHints* pSwpHints2 = rNode.GetpSwpHints();
132  for ( size_t i = 0; pSwpHints2 && i < pSwpHints2->Count(); ++i )
133  {
134  const SwTextAttr* pAttr = pSwpHints2->Get(i);
135  if (pAttr->HasDummyChar())
136  {
137  const sal_Int32 nDummyCharPos = pAttr->GetStart();
138  if (aHiddenMulti.IsSelected(nDummyCharPos))
139  continue;
140  std::vector<block>::iterator aFind = std::find_if(aBlocks.begin(),
141  aBlocks.end(), containsPos(nDummyCharPos));
142  if (aFind != aBlocks.end())
143  {
144  FieldResult aFieldResult(nDummyCharPos);
145  switch (pAttr->Which())
146  {
147  case RES_TXTATR_FIELD:
149  if (eMode & ExpandMode::ExpandFields)
150  {
151  // add a ZWSP before the expanded field in replace mode
152  aFieldResult.m_sExpand = ((eMode & ExpandMode::ReplaceMode)
153  ? OUString(CHAR_ZWSP) : OUString("")) +
154  static_txtattr_cast<SwTextField const*>(pAttr)->
155  GetFormatField().GetField()->ExpandField(true, pLayout);
156  aFieldResult.m_eType = FieldResult::FIELD;
157  }
158  break;
159  case RES_TXTATR_FTN:
160  if (eMode & ExpandMode::ExpandFootnote)
161  {
162  const SwFormatFootnote& rFootnote = static_cast<SwTextFootnote const*>(pAttr)->GetFootnote();
163  const SwDoc *pDoc = rNode.GetDoc();
164  aFieldResult.m_sExpand = (eMode & ExpandMode::ReplaceMode)
165  ? OUString(CHAR_ZWSP)
166  : rFootnote.GetViewNumStr(*pDoc, pLayout);
167  aFieldResult.m_eType = FieldResult::FOOTNOTE;
168  }
169  break;
170  default:
171  break;
172  }
173  aFind->m_aAttrs.insert(aFieldResult);
174  }
175  }
176  }
177 
178  if (eMode & ExpandMode::ExpandFields)
179  {
180  //now get the dropdown formfields, get their position in the node and what the text they expand
181  //to is
182  SwPaM aPaM(rNode, 0, rNode, rNode.Len());
183  std::vector<sw::mark::IFieldmark*> aDropDowns =
185 
186  for (sw::mark::IFieldmark *pMark : aDropDowns)
187  {
188  const sal_Int32 nDummyCharPos = pMark->GetMarkPos().nContent.GetIndex()-1;
189  if (aHiddenMulti.IsSelected(nDummyCharPos))
190  continue;
191  std::vector<block>::iterator aFind = std::find_if(aBlocks.begin(), aBlocks.end(),
192  containsPos(nDummyCharPos));
193  if (aFind != aBlocks.end())
194  {
195  FieldResult aFieldResult(nDummyCharPos);
196  aFieldResult.m_sExpand = (eMode & ExpandMode::ReplaceMode)
197  ? OUString(CHAR_ZWSP)
198  : sw::mark::ExpandFieldmark(pMark);
199  aFieldResult.m_eType = FieldResult::FIELD;
200  aFind->m_aAttrs.insert(aFieldResult);
201  }
202  }
203  }
204  }
205 
206  //store the end of each range in the model and where that end of range
207  //maps to in the view
208  sal_Int32 nOffset = 0;
209  for (const auto& rBlock : aBlocks)
210  {
211  const sal_Int32 nBlockLen = rBlock.m_nLen;
212  if (!nBlockLen)
213  continue;
214  const sal_Int32 nBlockStart = rBlock.m_nStart;
215  const sal_Int32 nBlockEnd = nBlockStart + nBlockLen;
216 
217  if (!rBlock.m_bVisible)
218  {
219  sal_Int32 const modelBlockPos(nBlockEnd);
220  sal_Int32 const viewBlockPos(nBlockStart + nOffset);
221  m_aMap.emplace_back(modelBlockPos, viewBlockPos, false);
222 
223  m_aRetText = m_aRetText.replaceAt(nOffset + nBlockStart, nBlockLen, OUString());
224  nOffset -= nBlockLen;
225  }
226  else
227  {
228  for (const auto& rAttr : rBlock.m_aAttrs)
229  {
230  sal_Int32 const modelFieldPos(rAttr.m_nFieldPos);
231  sal_Int32 const viewFieldPos(rAttr.m_nFieldPos + nOffset);
232  m_aMap.emplace_back(modelFieldPos, viewFieldPos, true );
233 
234  m_aRetText = m_aRetText.replaceAt(viewFieldPos, 1, rAttr.m_sExpand);
235  nOffset += rAttr.m_sExpand.getLength() - 1;
236 
237  switch (rAttr.m_eType)
238  {
239  case FieldResult::FIELD:
240  m_FieldPositions.push_back(viewFieldPos);
241  break;
243  m_FootnotePositions.push_back(viewFieldPos);
244  break;
245  case FieldResult::NONE: /*ignore*/
246  break;
247  }
248  }
249 
250  sal_Int32 const modelEndBlock(nBlockEnd);
251  sal_Int32 const viewFieldPos(nBlockEnd + nOffset);
252  m_aMap.emplace_back(modelEndBlock, viewFieldPos, true);
253  }
254  }
255 }
256 
259 sal_Int32 ModelToViewHelper::ConvertToViewPosition( sal_Int32 nModelPos ) const
260 {
261  // Search for entry after nPos:
262  auto aIter = std::find_if(m_aMap.begin(), m_aMap.end(),
263  [nModelPos](const ConversionMapEntry& rEntry) { return rEntry.m_nModelPos >= nModelPos; });
264  if (aIter != m_aMap.end())
265  {
266  //if it's an invisible portion, map all contained positions
267  //to the anchor viewpos
268  if (!aIter->m_bVisible)
269  return aIter->m_nViewPos;
270 
271  //if it's a visible portion, then the view position is the anchor
272  //viewpos - the offset of the input modelpos from the anchor
273  //modelpos
274  const sal_Int32 nOffsetFromEnd = aIter->m_nModelPos - nModelPos;
275  return aIter->m_nViewPos - nOffsetFromEnd;
276  }
277 
278  return nModelPos;
279 }
280 
284 {
285  ModelPosition aRet;
286  aRet.mnPos = nViewPos;
287 
288  // Search for entry after nPos:
289  auto aIter = std::find_if(m_aMap.begin(), m_aMap.end(),
290  [nViewPos](const ConversionMapEntry& rEntry) { return rEntry.m_nViewPos > nViewPos; });
291 
292  // If nViewPos is in front of first field, we are finished.
293  if (aIter != m_aMap.end() && aIter != m_aMap.begin())
294  {
295  const sal_Int32 nPosModel = aIter->m_nModelPos;
296  const sal_Int32 nPosExpand = aIter->m_nViewPos;
297 
298  --aIter;
299 
300  // nPrevPosModel is the field position
301  const sal_Int32 nPrevPosModel = aIter->m_nModelPos;
302  const sal_Int32 nPrevPosExpand = aIter->m_nViewPos;
303 
304  const sal_Int32 nLengthModel = nPosModel - nPrevPosModel;
305  const sal_Int32 nLengthExpand = nPosExpand - nPrevPosExpand;
306 
307  const sal_Int32 nFieldLengthExpand = nLengthExpand - nLengthModel + 1;
308  const sal_Int32 nFieldEndExpand = nPrevPosExpand + nFieldLengthExpand;
309 
310  // Check if nPos is outside of field:
311  if ( nFieldEndExpand <= nViewPos )
312  {
313  // nPos is outside of field:
314  const sal_Int32 nDistToField = nViewPos - nFieldEndExpand + 1;
315  aRet.mnPos = nPrevPosModel + nDistToField;
316  }
317  else
318  {
319  // nViewPos is inside a field:
320  aRet.mnPos = nPrevPosModel;
321  aRet.mnSubPos = nViewPos - nPrevPosExpand;
322  aRet.mbIsField = true;
323  }
324  }
325 
326  return aRet;
327 }
328 
329 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
do not expand to content, but replace with zwsp
bool const m_bVisible
sal_Int32 const m_nStart
const OUString & GetText() const
Definition: ndtxt.hxx:211
SwpHints * GetpSwpHints()
Definition: ndtxt.hxx:219
bool operator()(const block &rIn) const
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:284
Definition: doc.hxx:185
bool HasDummyChar() const
Definition: txatbase.hxx:101
IDocumentMarkAccess * getIDocumentMarkAccess()
Definition: docbm.cxx:1552
This struct defines a position in the model string.
sal_uInt16 Which() const
Definition: txatbase.hxx:110
sal_Int32 const m_nLen
The root element of a Writer document layout.
Definition: rootfrm.hxx:79
OUString ExpandFieldmark(IFieldmark *pBM)
Definition: itrform2.cxx:847
containsPos(const sal_Int32 nPos)
FieldResultSet m_aAttrs
OUString GetViewNumStr(const SwDoc &rDoc, SwRootFrame const *pLayout, bool bInclStrings=false) const
Returns string to be displayed of footnote / endnote.
Definition: atrftn.cxx:210
sal_Int32 ConvertToViewPosition(sal_Int32 nModelPos) const
Converts a model position into a view position.
std::vector< sal_Int32 > m_FieldPositions
store positions of fields and footnotes for grammar checkers
virtual std::vector< ::sw::mark::IFieldmark * > getDropDownsFor(const SwPaM &rPaM) const =0
std::set< FieldResult, sortfieldresults > FieldResultSet
sal_Int32 GetStart() const
Definition: txatbase.hxx:82
FieldResult(sal_Int32 const nPos)
const sal_Int32 m_nPos
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
size_t Count() const
Definition: ndhints.hxx:142
SwTextAttr * Get(size_t nPos) const
Definition: ndhints.hxx:144
static void selectRedLineDeleted(const SwTextNode &rNode, MultiSelection &rHiddenMulti, bool bSelect=true)
Definition: porlay.cxx:2301
#define RES_TXTATR_FTN
Definition: hintids.hxx:152
int i
bool operator()(const FieldResult &rOne, const FieldResult &rTwo) const
sal_Int32 const m_nFieldPos
SwDoc * GetDoc()
Definition: node.hxx:702
For each expanded/hidden portion in the model string, there is an entry in the conversion map...
#define CHAR_ZWSP
Definition: swtypes.hxx:177
long Max() const
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
ExpandMode
Some helpers for converting model strings to view strings.
#define RES_TXTATR_FIELD
Definition: hintids.hxx:150
An SwTextAttr container, stores all directly formatted text portions for a text node.
Definition: ndhints.hxx:67
#define RES_TXTATR_ANNOTATION
Definition: hintids.hxx:153
std::vector< sal_Int32 > m_FootnotePositions
ModelPosition ConvertToModelPosition(sal_Int32 nViewPos) const
Converts a view position into a model position.
block(sal_Int32 nStart, sal_Int32 nLen, bool bVisible)
long Min() const
enum FieldResult::@13 m_eType
static void selectHiddenTextProperty(const SwTextNode &rNode, MultiSelection &rHiddenMulti)
Definition: porlay.cxx:2248