LibreOffice Module sw (master)  1
bookmrk.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 <memory>
21 #include <bookmrk.hxx>
22 #include <IDocumentUndoRedo.hxx>
24 #include <IDocumentState.hxx>
25 #include <doc.hxx>
26 #include <ndtxt.hxx>
27 #include <pam.hxx>
28 #include <swserv.hxx>
29 #include <sfx2/linkmgr.hxx>
30 #include <UndoBookmark.hxx>
31 #include <unobookmark.hxx>
32 #include <xmloff/odffields.hxx>
33 #include <libxml/xmlwriter.h>
34 #include <comphelper/random.hxx>
36 #include <sal/log.hxx>
37 #include <svl/zforlist.hxx>
38 #include <edtwin.hxx>
39 #include <DateFormFieldButton.hxx>
42 
43 using namespace ::sw::mark;
44 using namespace ::com::sun::star;
45 using namespace ::com::sun::star::uno;
46 
47 namespace sw { namespace mark
48 {
49 
51  {
52  SwPosition const& rStartPos(rMark.GetMarkStart());
53  SwPosition const& rEndPos(rMark.GetMarkEnd());
54  SwNodes const& rNodes(rStartPos.nNode.GetNodes());
55  sal_uLong const nStartNode(rStartPos.nNode.GetIndex());
56  sal_uLong const nEndNode(rEndPos.nNode.GetIndex());
57  int nFields(0);
58  o3tl::optional<SwPosition> ret;
59  for (sal_uLong n = nEndNode; nStartNode <= n; --n)
60  {
61  SwNode *const pNode(rNodes[n]);
62  if (pNode->IsTextNode())
63  {
64  SwTextNode & rTextNode(*pNode->GetTextNode());
65  sal_Int32 const nStart(n == nStartNode
66  ? rStartPos.nContent.GetIndex() + 1
67  : 0);
68  sal_Int32 const nEnd(n == nEndNode
69  // subtract 1 to ignore the end char
70  ? rEndPos.nContent.GetIndex() - 1
71  : rTextNode.Len());
72  for (sal_Int32 i = nEnd; nStart < i; --i)
73  {
74  const sal_Unicode c(rTextNode.GetText()[i - 1]);
75  switch (c)
76  {
78  --nFields;
79  assert(0 <= nFields);
80  break;
82  ++nFields;
83  // fields in field result could happen by manual
84  // editing, although the field update deletes them
85  break;
87  if (nFields == 0)
88  {
89  assert(!ret); // one per field
90  ret = SwPosition(rTextNode, i - 1);
91 #ifndef DBG_UTIL
92  return *ret;
93 #endif
94  }
95  break;
96  }
97  }
98  }
99  else if (pNode->IsEndNode())
100  {
101  assert(nStartNode <= pNode->StartOfSectionIndex());
102  // fieldmark cannot overlap node section
103  n = pNode->StartOfSectionIndex();
104  }
105  else
106  {
107  assert(pNode->IsNoTextNode());
108  }
109  }
110  assert(ret); // must have found it
111  return *ret;
112  }
113 } } // namespace sw::mark
114 
115 namespace
116 {
117  void lcl_FixPosition(SwPosition& rPos)
118  {
119  // make sure the position has 1) the proper node, and 2) a proper index
120  SwTextNode* pTextNode = rPos.nNode.GetNode().GetTextNode();
121  if(pTextNode == nullptr && rPos.nContent.GetIndex() > 0)
122  {
123  SAL_INFO(
124  "sw.core",
125  "illegal position: " << rPos.nContent.GetIndex()
126  << " without proper TextNode");
127  rPos.nContent.Assign(nullptr, 0);
128  }
129  else if(pTextNode != nullptr && rPos.nContent.GetIndex() > pTextNode->Len())
130  {
131  SAL_INFO(
132  "sw.core",
133  "illegal position: " << rPos.nContent.GetIndex()
134  << " is beyond " << pTextNode->Len());
135  rPos.nContent.Assign(pTextNode, pTextNode->Len());
136  }
137  }
138 
139  void lcl_AssertFieldMarksSet(Fieldmark const * const pField,
140  const sal_Unicode aStartMark,
141  const sal_Unicode aEndMark)
142  {
143  if (aEndMark != CH_TXT_ATR_FORMELEMENT)
144  {
145  SwPosition const& rStart(pField->GetMarkStart());
146  assert(rStart.nNode.GetNode().GetTextNode()->GetText()[rStart.nContent.GetIndex()] == aStartMark); (void) rStart; (void) aStartMark;
147  SwPosition const sepPos(sw::mark::FindFieldSep(*pField));
148  assert(sepPos.nNode.GetNode().GetTextNode()->GetText()[sepPos.nContent.GetIndex()] == CH_TXT_ATR_FIELDSEP); (void) sepPos;
149  }
150  SwPosition const& rEnd(pField->GetMarkEnd());
151  assert(rEnd.nNode.GetNode().GetTextNode()->GetText()[rEnd.nContent.GetIndex() - 1] == aEndMark); (void) rEnd;
152  }
153 
154  void lcl_SetFieldMarks(Fieldmark* const pField,
155  SwDoc* const io_pDoc,
156  const sal_Unicode aStartMark,
157  const sal_Unicode aEndMark,
158  SwPosition const*const pSepPos)
159  {
161  OUString startChar(aStartMark);
162  if (aEndMark != CH_TXT_ATR_FORMELEMENT
163  && pField->GetMarkStart() == pField->GetMarkEnd())
164  {
165  // do only 1 InsertString call - to expand existing bookmarks at the
166  // position over the whole field instead of just aStartMark
167  startChar += OUStringChar(CH_TXT_ATR_FIELDSEP) + OUStringChar(aEndMark);
168  }
169 
170  SwPosition start = pField->GetMarkStart();
171  if (aEndMark != CH_TXT_ATR_FORMELEMENT)
172  {
173  SwPaM aStartPaM(start);
174  io_pDoc->getIDocumentContentOperations().InsertString(aStartPaM, startChar);
175  start.nContent -= startChar.getLength(); // restore, it was moved by InsertString
176  // do not manipulate via reference directly but call SetMarkStartPos
177  // which works even if start and end pos were the same
178  pField->SetMarkStartPos( start );
179  SwPosition& rEnd = pField->GetMarkEnd(); // note: retrieve after
180  // setting start, because if start==end it can go stale, see SetMarkPos()
181  assert(pSepPos == nullptr || (start < *pSepPos && *pSepPos <= rEnd));
182  if (startChar.getLength() == 1)
183  {
184  *aStartPaM.GetPoint() = pSepPos ? *pSepPos : rEnd;
185  io_pDoc->getIDocumentContentOperations().InsertString(aStartPaM, OUString(CH_TXT_ATR_FIELDSEP));
186  if (!pSepPos || rEnd < *pSepPos)
187  { // rEnd is not moved automatically if it's same as insert pos
188  ++rEnd.nContent;
189  }
190  }
191  assert(pSepPos == nullptr || (start < *pSepPos && *pSepPos <= rEnd));
192  }
193  else
194  {
195  assert(pSepPos == nullptr);
196  }
197 
198  SwPosition& rEnd = pField->GetMarkEnd();
199  if (aEndMark && startChar.getLength() == 1)
200  {
201  SwPaM aEndPaM(rEnd);
202  io_pDoc->getIDocumentContentOperations().InsertString(aEndPaM, OUString(aEndMark));
203  ++rEnd.nContent;
204  }
205  lcl_AssertFieldMarksSet(pField, aStartMark, aEndMark);
206 
208  };
209 
210  void lcl_RemoveFieldMarks(Fieldmark const * const pField,
211  SwDoc* const io_pDoc,
212  const sal_Unicode aStartMark,
213  const sal_Unicode aEndMark)
214  {
216 
217  const SwPosition& rStart = pField->GetMarkStart();
218  SwTextNode const*const pStartTextNode = rStart.nNode.GetNode().GetTextNode();
219  assert(pStartTextNode);
220  if (aEndMark != CH_TXT_ATR_FORMELEMENT)
221  {
222  (void) pStartTextNode;
223  // check this before start / end because of the +1 / -1 ...
224  SwPosition const sepPos(sw::mark::FindFieldSep(*pField));
225  io_pDoc->GetDocumentContentOperationsManager().DeleteDummyChar(rStart, aStartMark);
227  }
228 
229  const SwPosition& rEnd = pField->GetMarkEnd();
230  SwTextNode *const pEndTextNode = rEnd.nNode.GetNode().GetTextNode();
231  assert(pEndTextNode);
232  const sal_Int32 nEndPos = (rEnd == rStart)
233  ? rEnd.nContent.GetIndex()
234  : rEnd.nContent.GetIndex() - 1;
235  assert(pEndTextNode->GetText()[nEndPos] == aEndMark);
236  SwPosition const aEnd(*pEndTextNode, nEndPos);
237  io_pDoc->GetDocumentContentOperationsManager().DeleteDummyChar(aEnd, aEndMark);
238 
240  };
241 }
242 
243 namespace sw { namespace mark
244 {
246  const OUString& rName)
247  : m_pPos1(new SwPosition(*(aPaM.GetPoint())))
248  , m_aName(rName)
249  {
250  m_pPos1->nContent.SetMark(this);
251  lcl_FixPosition(*m_pPos1);
252  if (aPaM.HasMark() && (*aPaM.GetMark() != *aPaM.GetPoint()))
253  {
255  lcl_FixPosition(*m_pPos2);
256  }
257  }
258 
259  // For fieldmarks, the CH_TXT_ATR_FIELDSTART and CH_TXT_ATR_FIELDEND
260  // themselves are part of the covered range. This is guaranteed by
261  // TextFieldmark::InitDoc/lcl_AssureFieldMarksSet.
262  bool MarkBase::IsCoveringPosition(const SwPosition& rPos) const
263  {
264  return GetMarkStart() <= rPos && rPos < GetMarkEnd();
265  }
266 
267  void MarkBase::SetMarkPos(const SwPosition& rNewPos)
268  {
269  std::make_unique<SwPosition>(rNewPos).swap(m_pPos1);
270  m_pPos1->nContent.SetMark(this);
271  }
272 
274  {
275  std::make_unique<SwPosition>(rNewPos).swap(m_pPos2);
276  m_pPos2->nContent.SetMark(this);
277  }
278 
279  OUString MarkBase::ToString( ) const
280  {
281  return "Mark: ( Name, [ Node1, Index1 ] ): ( " + m_aName + ", [ "
282  + OUString::number( GetMarkPos().nNode.GetIndex( ) ) + ", "
283  + OUString::number( GetMarkPos().nContent.GetIndex( ) ) + " ] )";
284  }
285 
287  {
288  xmlTextWriterStartElement(pWriter, BAD_CAST("MarkBase"));
289  xmlTextWriterWriteAttribute(pWriter, BAD_CAST("name"), BAD_CAST(m_aName.toUtf8().getStr()));
290  xmlTextWriterStartElement(pWriter, BAD_CAST("markPos"));
291  GetMarkPos().dumpAsXml(pWriter);
292  xmlTextWriterEndElement(pWriter);
293  if (IsExpanded())
294  {
295  xmlTextWriterStartElement(pWriter, BAD_CAST("otherMarkPos"));
296  GetOtherMarkPos().dumpAsXml(pWriter);
297  xmlTextWriterEndElement(pWriter);
298  }
299  xmlTextWriterEndElement(pWriter);
300  }
301 
303  { }
304 
305  OUString MarkBase::GenerateNewName(const OUString& rPrefix)
306  {
307  static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != nullptr);
308 
309  if (bHack)
310  {
311  static sal_Int64 nIdCounter = SAL_CONST_INT64(6000000000);
312  return rPrefix + OUString::number(nIdCounter++);
313  }
314  else
315  {
316  static OUString sUniquePostfix;
317  static sal_Int32 nCount = SAL_MAX_INT32;
318  if(nCount == SAL_MAX_INT32)
319  {
320  unsigned int const n(comphelper::rng::uniform_uint_distribution(0,
321  std::numeric_limits<unsigned int>::max()));
322  sUniquePostfix = "_" + OUString::number(n);
323  nCount = 0;
324  }
325  // putting the counter in front of the random parts will speed up string comparisons
326  return rPrefix + OUString::number(nCount++) + sUniquePostfix;
327  }
328  }
329 
330  void MarkBase::Modify( const SfxPoolItem *pOld, const SfxPoolItem *pNew )
331  {
332  NotifyClients(pOld, pNew);
333  if (pOld && (RES_REMOVE_UNO_OBJECT == pOld->Which()))
334  { // invalidate cached uno object
335  SetXBookmark(uno::Reference<text::XTextContent>(nullptr));
336  }
337  }
338 
340  : MarkBase(rPaM, MarkBase::GenerateNewName("__NavigatorReminder__"))
341  { }
342 
343  UnoMark::UnoMark(const SwPaM& aPaM)
344  : MarkBase(aPaM, MarkBase::GenerateNewName("__UnoMark__"))
345  { }
346 
348  : MarkBase(aPaM, MarkBase::GenerateNewName("__DdeLink__"))
349  { }
350 
352  {
353  m_aRefObj = pObj;
354  }
355 
357  {
358  if(m_aRefObj.is())
360  }
361 
363  {
364  if( m_aRefObj.is() )
365  {
366  if(m_aRefObj->HasDataLinks())
367  {
369  p->SendDataChanged();
370  }
372  }
373  }
374 
376  const vcl::KeyCode& rCode,
377  const OUString& rName)
378  : DdeBookmark(aPaM)
379  , ::sfx2::Metadatable()
380  , m_aCode(rCode)
381  , m_bHidden(false)
382  {
383  m_aName = rName;
384  }
385 
386  void Bookmark::InitDoc(SwDoc* const io_pDoc,
387  sw::mark::InsertMode const, SwPosition const*const)
388  {
389  if (io_pDoc->GetIDocumentUndoRedo().DoesUndo())
390  {
391  io_pDoc->GetIDocumentUndoRedo().AppendUndo(
392  std::make_unique<SwUndoInsBookmark>(*this));
393  }
394  io_pDoc->getIDocumentState().SetModified();
395  }
396 
397  void Bookmark::DeregisterFromDoc(SwDoc* const io_pDoc)
398  {
400 
401  if (io_pDoc->GetIDocumentUndoRedo().DoesUndo())
402  {
403  io_pDoc->GetIDocumentUndoRedo().AppendUndo(
404  std::make_unique<SwUndoDeleteBookmark>(*this));
405  }
406  io_pDoc->getIDocumentState().SetModified();
407  }
408 
410  {
411  SwDoc *const pDoc( GetMarkPos().GetDoc() );
412  assert(pDoc);
413  return pDoc->GetXmlIdRegistry();
414  }
415 
417  {
418  SwDoc *const pDoc( GetMarkPos().GetDoc() );
419  assert(pDoc);
420  return pDoc->IsClipBoard();
421  }
422 
423  bool Bookmark::IsInUndo() const
424  {
425  return false;
426  }
427 
429  {
430  SwDoc *const pDoc( GetMarkPos().GetDoc() );
431  assert(pDoc);
432  return !pDoc->IsInHeaderFooter( GetMarkPos().nNode );
433  }
434 
435  uno::Reference< rdf::XMetadatable > Bookmark::MakeUnoObject()
436  {
437  SwDoc *const pDoc( GetMarkPos().GetDoc() );
438  assert(pDoc);
439  const uno::Reference< rdf::XMetadatable> xMeta(
440  SwXBookmark::CreateXBookmark(*pDoc, this), uno::UNO_QUERY);
441  return xMeta;
442  }
443 
445  : MarkBase(rPaM, MarkBase::GenerateNewName("__Fieldmark__"))
446  {
447  if(!IsExpanded())
449  }
450 
451  void Fieldmark::SetMarkStartPos( const SwPosition& rNewStartPos )
452  {
453  if ( GetMarkPos( ) <= GetOtherMarkPos( ) )
454  return SetMarkPos( rNewStartPos );
455  else
456  return SetOtherMarkPos( rNewStartPos );
457  }
458 
459  void Fieldmark::SetMarkEndPos( const SwPosition& rNewEndPos )
460  {
461  if ( GetMarkPos( ) <= GetOtherMarkPos( ) )
462  return SetOtherMarkPos( rNewEndPos );
463  else
464  return SetMarkPos( rNewEndPos );
465  }
466 
467  OUString Fieldmark::ToString( ) const
468  {
469  return "Fieldmark: ( Name, Type, [ Nd1, Id1 ], [ Nd2, Id2 ] ): ( " + m_aName + ", "
470  + m_aFieldname + ", [ " + OUString::number( GetMarkPos().nNode.GetIndex( ) )
471  + ", " + OUString::number( GetMarkPos( ).nContent.GetIndex( ) ) + " ], ["
472  + OUString::number( GetOtherMarkPos().nNode.GetIndex( ) ) + ", "
473  + OUString::number( GetOtherMarkPos( ).nContent.GetIndex( ) ) + " ] ) ";
474  }
475 
477  {
478  // TODO: Does exist a better solution to trigger a format of the
479  // fieldmark portion? If yes, please use it.
480  SwPaM aPaM( GetMarkPos(), GetOtherMarkPos() );
481  aPaM.InvalidatePaM();
482  }
483 
485  {
486  xmlTextWriterStartElement(pWriter, BAD_CAST("Fieldmark"));
487  xmlTextWriterWriteAttribute(pWriter, BAD_CAST("fieldname"), BAD_CAST(m_aFieldname.toUtf8().getStr()));
488  xmlTextWriterWriteAttribute(pWriter, BAD_CAST("fieldHelptext"), BAD_CAST(m_aFieldHelptext.toUtf8().getStr()));
489  MarkBase::dumpAsXml(pWriter);
490  xmlTextWriterStartElement(pWriter, BAD_CAST("parameters"));
491  for (auto& rParam : m_vParams)
492  {
493  xmlTextWriterStartElement(pWriter, BAD_CAST("parameter"));
494  xmlTextWriterWriteAttribute(pWriter, BAD_CAST("name"), BAD_CAST(rParam.first.toUtf8().getStr()));
495  xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(comphelper::anyToString(rParam.second).toUtf8().getStr()));
496  xmlTextWriterEndElement(pWriter);
497  }
498  xmlTextWriterEndElement(pWriter);
499  xmlTextWriterEndElement(pWriter);
500  }
501 
502  TextFieldmark::TextFieldmark(const SwPaM& rPaM, const OUString& rName)
503  : Fieldmark(rPaM)
504  {
505  if ( !rName.isEmpty() )
506  m_aName = rName;
507  }
508 
509  void TextFieldmark::InitDoc(SwDoc* const io_pDoc,
510  sw::mark::InsertMode const eMode, SwPosition const*const pSepPos)
511  {
512  if (eMode == sw::mark::InsertMode::New)
513  {
514  lcl_SetFieldMarks(this, io_pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND, pSepPos);
515  }
516  else
517  {
518  lcl_AssertFieldMarksSet(this, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND);
519  }
520  }
521 
523  {
524  IDocumentUndoRedo & rIDUR(pDoc->GetIDocumentUndoRedo());
525  if (rIDUR.DoesUndo())
526  {
527  rIDUR.AppendUndo(std::make_unique<SwUndoDelTextFieldmark>(*this));
528  }
529  ::sw::UndoGuard const ug(rIDUR); // prevent SwUndoDeletes
530  lcl_RemoveFieldMarks(this, pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND);
531  }
532 
534  : Fieldmark(rPaM)
535  { }
536 
537  void NonTextFieldmark::InitDoc(SwDoc* const io_pDoc,
538  sw::mark::InsertMode const eMode, SwPosition const*const pSepPos)
539  {
540  assert(pSepPos == nullptr);
541  if (eMode == sw::mark::InsertMode::New)
542  {
543  lcl_SetFieldMarks(this, io_pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FORMELEMENT, pSepPos);
544 
545  // For some reason the end mark is moved from 1 by the Insert:
546  // we don't want this for checkboxes
547  SwPosition aNewEndPos = GetMarkEnd();
548  aNewEndPos.nContent--;
549  SetMarkEndPos( aNewEndPos );
550  }
551  else
552  {
553  lcl_AssertFieldMarksSet(this, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FORMELEMENT);
554  }
555  }
556 
558  {
559  IDocumentUndoRedo & rIDUR(pDoc->GetIDocumentUndoRedo());
560  if (rIDUR.DoesUndo())
561  {
562  rIDUR.AppendUndo(std::make_unique<SwUndoDelNoTextFieldmark>(*this));
563  }
564  ::sw::UndoGuard const ug(rIDUR); // prevent SwUndoDeletes
565  lcl_RemoveFieldMarks(this, pDoc,
567  }
568 
569 
571  : NonTextFieldmark(rPaM)
572  { }
573 
574  void CheckboxFieldmark::SetChecked(bool checked)
575  {
576  if ( IsChecked() != checked )
577  {
578  (*GetParameters())[OUString(ODF_FORMCHECKBOX_RESULT)] <<= checked;
579  // mark document as modified
580  SwDoc *const pDoc( GetMarkPos().GetDoc() );
581  if ( pDoc )
582  pDoc->getIDocumentState().SetModified();
583  }
584  }
585 
587  {
588  bool bResult = false;
589  parameter_map_t::const_iterator pResult = GetParameters()->find(OUString(ODF_FORMCHECKBOX_RESULT));
590  if(pResult != GetParameters()->end())
591  pResult->second >>= bResult;
592  return bResult;
593  }
594 
596  : NonTextFieldmark(rPaM)
597  , m_pButton(nullptr)
598  {
599  }
600 
602  {
604  }
605 
607  {
608  if(m_pButton)
609  m_pButton->Show(false);
610  }
611 
613  {
614  if(m_pButton)
616  }
617 
620  {
621  }
622 
624  {
625  }
626 
628  {
629  if(pEditWin)
630  {
631  if(!m_pButton)
634  m_pButton->Show();
635  }
636  }
637 
638  void DropDownFieldmark::SetPortionPaintArea(const SwRect& rPortionPaintArea)
639  {
640  if(m_aPortionPaintArea == rPortionPaintArea &&
642  return;
643 
644  m_aPortionPaintArea = rPortionPaintArea;
645  if(m_pButton)
646  {
647  m_pButton->Show();
650  }
651  }
652 
655  , m_pNumberFormatter(nullptr)
656  , m_pDocumentContentOperationsManager(nullptr)
657  {
658  }
659 
661  {
662  }
663 
664  void DateFieldmark::InitDoc(SwDoc* const io_pDoc,
665  sw::mark::InsertMode eMode, SwPosition const*const pSepPos)
666  {
669  if (eMode == sw::mark::InsertMode::New)
670  {
671  lcl_SetFieldMarks(this, io_pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND, pSepPos);
672  }
673  else
674  {
675  lcl_AssertFieldMarksSet(this, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND);
676  }
677  }
678 
680  {
681  IDocumentUndoRedo & rIDUR(pDoc->GetIDocumentUndoRedo());
682  if (rIDUR.DoesUndo())
683  {
684  // TODO does this need a 3rd Undo class?
685  rIDUR.AppendUndo(std::make_unique<SwUndoDelTextFieldmark>(*this));
686  }
687  ::sw::UndoGuard const ug(rIDUR); // prevent SwUndoDeletes
688  lcl_RemoveFieldMarks(this, pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND);
689  }
690 
692  {
693  if(pEditWin)
694  {
695  if(!m_pButton)
698  m_pButton->CalcPosAndSize(aPaintArea);
699  m_pButton->Show();
700  }
701  }
702 
703  void DateFieldmark::SetPortionPaintAreaStart(const SwRect& rPortionPaintArea)
704  {
705  if (rPortionPaintArea.IsEmpty())
706  return;
707 
708  m_aPaintAreaStart = rPortionPaintArea;
710  }
711 
712  void DateFieldmark::SetPortionPaintAreaEnd(const SwRect& rPortionPaintArea)
713  {
714  if (rPortionPaintArea.IsEmpty())
715  return;
716 
717  if(m_aPaintAreaEnd == rPortionPaintArea &&
719  return;
720 
721  m_aPaintAreaEnd = rPortionPaintArea;
722  if(m_pButton)
723  {
724  m_pButton->Show();
726  m_pButton->CalcPosAndSize(aPaintArea);
728  }
730  }
731 
732  OUString DateFieldmark::GetContent() const
733  {
734  const SwTextNode* const pTextNode = GetMarkEnd().nNode.GetNode().GetTextNode();
735  SwPosition const sepPos(sw::mark::FindFieldSep(*this));
736  const sal_Int32 nStart(sepPos.nContent.GetIndex());
737  const sal_Int32 nEnd (GetMarkEnd().nContent.GetIndex());
738 
739  OUString sContent;
740  if(nStart + 1 < pTextNode->GetText().getLength() && nEnd <= pTextNode->GetText().getLength() &&
741  nEnd > nStart + 2)
742  sContent = pTextNode->GetText().copy(nStart + 1, nEnd - nStart - 2);
743  return sContent;
744  }
745 
746  void DateFieldmark::ReplaceContent(const OUString& sNewContent)
747  {
749  return;
750 
751  const SwTextNode* const pTextNode = GetMarkEnd().nNode.GetNode().GetTextNode();
752  SwPosition const sepPos(sw::mark::FindFieldSep(*this));
753  const sal_Int32 nStart(sepPos.nContent.GetIndex());
754  const sal_Int32 nEnd (GetMarkEnd().nContent.GetIndex());
755 
756  if(nStart + 1 < pTextNode->GetText().getLength() && nEnd <= pTextNode->GetText().getLength() &&
757  nEnd > nStart + 2)
758  {
759  SwPaM aFieldPam(GetMarkStart().nNode, nStart + 1,
760  GetMarkStart().nNode, nEnd - 1);
761  m_pDocumentContentOperationsManager->ReplaceRange(aFieldPam, sNewContent, false);
762  }
763  else
764  {
765  SwPaM aFieldStartPam(GetMarkStart().nNode, nStart + 1);
766  m_pDocumentContentOperationsManager->InsertString(aFieldStartPam, sNewContent);
767  }
768 
769  }
770 
771  std::pair<bool, double> DateFieldmark::GetCurrentDate() const
772  {
773  // Check current date param first
774  std::pair<bool, double> aResult = ParseCurrentDateParam();
775  if(aResult.first)
776  return aResult;
777 
779  bool bFoundValidDate = false;
780  double dCurrentDate = 0;
781  OUString sDateFormat;
782  auto pResult = pParameters->find(ODF_FORMDATE_DATEFORMAT);
783  if (pResult != pParameters->end())
784  {
785  pResult->second >>= sDateFormat;
786  }
787 
788  OUString sLang;
789  pResult = pParameters->find(ODF_FORMDATE_DATEFORMAT_LANGUAGE);
790  if (pResult != pParameters->end())
791  {
792  pResult->second >>= sLang;
793  }
794 
795  // Get current content of the field
796  OUString sContent = GetContent();
797 
798  sal_uInt32 nFormat = m_pNumberFormatter->GetEntryKey(sDateFormat, LanguageTag(sLang).getLanguageType());
799  if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
800  {
801  sal_Int32 nCheckPos = 0;
803  m_pNumberFormatter->PutEntry(sDateFormat,
804  nCheckPos,
805  nType,
806  nFormat,
807  LanguageTag(sLang).getLanguageType());
808  }
809 
810  if (nFormat != NUMBERFORMAT_ENTRY_NOT_FOUND)
811  {
812  bFoundValidDate = m_pNumberFormatter->IsNumberFormat(sContent, nFormat, dCurrentDate);
813  }
814  return std::pair<bool, double>(bFoundValidDate, dCurrentDate);
815  }
816 
817  void DateFieldmark::SetCurrentDate(double fDate)
818  {
819  // Replace current content with the selected date
821 
822  // Also save the current date in a standard format
824  (*pParameters)[ODF_FORMDATE_CURRENTDATE] <<= GetDateInStandardDateFormat(fDate);
825  }
826 
827  OUString DateFieldmark::GetDateInStandardDateFormat(double fDate) const
828  {
829  OUString sCurrentDate;
831  if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
832  {
833  sal_Int32 nCheckPos = 0;
835  OUString sFormat = ODF_FORMDATE_CURRENTDATE_FORMAT;
836  m_pNumberFormatter->PutEntry(sFormat,
837  nCheckPos,
838  nType,
839  nFormat,
841  }
842 
843  if (nFormat != NUMBERFORMAT_ENTRY_NOT_FOUND)
844  {
845  Color* pCol = nullptr;
846  m_pNumberFormatter->GetOutputString(fDate, nFormat, sCurrentDate, &pCol, false);
847  }
848  return sCurrentDate;
849  }
850 
851  std::pair<bool, double> DateFieldmark::ParseCurrentDateParam() const
852  {
853  bool bFoundValidDate = false;
854  double dCurrentDate = 0;
855 
857  auto pResult = pParameters->find(ODF_FORMDATE_CURRENTDATE);
858  OUString sCurrentDate;
859  if (pResult != pParameters->end())
860  {
861  pResult->second >>= sCurrentDate;
862  }
863  if(!sCurrentDate.isEmpty())
864  {
866  if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
867  {
868  sal_Int32 nCheckPos = 0;
870  OUString sFormat = ODF_FORMDATE_CURRENTDATE_FORMAT;
871  m_pNumberFormatter->PutEntry(sFormat,
872  nCheckPos,
873  nType,
874  nFormat,
876  }
877 
878  if(nFormat != NUMBERFORMAT_ENTRY_NOT_FOUND)
879  {
880  bFoundValidDate = m_pNumberFormatter->IsNumberFormat(sCurrentDate, nFormat, dCurrentDate);
881  }
882  }
883  return std::pair<bool, double>(bFoundValidDate, dCurrentDate);
884  }
885 
886 
887  OUString DateFieldmark::GetDateInCurrentDateFormat(double fDate) const
888  {
889  // Get current date format and language
890  OUString sDateFormat;
892  auto pResult = pParameters->find(ODF_FORMDATE_DATEFORMAT);
893  if (pResult != pParameters->end())
894  {
895  pResult->second >>= sDateFormat;
896  }
897 
898  OUString sLang;
899  pResult = pParameters->find(ODF_FORMDATE_DATEFORMAT_LANGUAGE);
900  if (pResult != pParameters->end())
901  {
902  pResult->second >>= sLang;
903  }
904 
905  // Fill the content with the specified format
906  OUString sCurrentContent;
907  sal_uInt32 nFormat = m_pNumberFormatter->GetEntryKey(sDateFormat, LanguageTag(sLang).getLanguageType());
908  if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
909  {
910  sal_Int32 nCheckPos = 0;
912  OUString sFormat = sDateFormat;
913  m_pNumberFormatter->PutEntry(sFormat,
914  nCheckPos,
915  nType,
916  nFormat,
917  LanguageTag(sLang).getLanguageType());
918  }
919 
920  if (nFormat != NUMBERFORMAT_ENTRY_NOT_FOUND)
921  {
922  Color* pCol = nullptr;
923  m_pNumberFormatter->GetOutputString(fDate, nFormat, sCurrentContent, &pCol, false);
924  }
925  return sCurrentContent;
926  }
927 
929  {
930  std::pair<bool, double> aResult = ParseCurrentDateParam();
931  if(!aResult.first)
932  return;
933 
934  // Current date became invalid
935  if(GetDateInCurrentDateFormat(aResult.second) != GetContent())
936  {
938  (*pParameters)[ODF_FORMDATE_CURRENTDATE] <<= OUString();
939  }
940  }
941 }}
942 
943 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void SetMarkStartPos(const SwPosition &rNewStartPos)
Definition: bookmrk.cxx:451
OUString m_aName
Definition: bookmrk.hxx:120
static OUString GenerateNewName(const OUString &rPrefix)
Definition: bookmrk.cxx:305
virtual std::pair< bool, double > GetCurrentDate() const override
Definition: bookmrk.cxx:771
bool is() const
DateFieldmark(const SwPaM &rPaM)
Definition: bookmrk.cxx:653
virtual void Modify(const SfxPoolItem *pOld, const SfxPoolItem *pNew) override
Definition: bookmrk.cxx:330
std::map< OUString, css::uno::Any > parameter_map_t
Definition: IMark.hxx:94
Marks a position in the document model.
Definition: pam.hxx:35
OUString m_aFieldHelptext
Definition: bookmrk.hxx:238
bool IsChecked() const override
Definition: bookmrk.cxx:586
sal_uLong StartOfSectionIndex() const
Definition: node.hxx:673
virtual void ShowButton(SwEditWin *pEditWin) override
Definition: bookmrk.cxx:627
const OUString & GetText() const
Definition: ndtxt.hxx:210
virtual bool IsInUndo() const override
Definition: bookmrk.cxx:423
virtual void ReplaceContent(const OUString &sNewContent) override
Definition: bookmrk.cxx:746
SvNumberFormatter * GetNumberFormatter(bool bCreate=true)
Definition: doc.hxx:1405
SwNodeIndex nNode
Definition: pam.hxx:37
void GetOutputString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &sOutString, Color **ppColor, bool bUseStarFormat=false)
virtual void ReleaseDoc(SwDoc *const pDoc) override
Definition: bookmrk.cxx:557
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:273
virtual void SetModified()=0
Must be called manually at changes of format.
sal_uIntPtr sal_uLong
void disposeAndClear()
const SwPosition * GetMark() const
Definition: pam.hxx:209
sal_Int64 n
#define ODF_FORMDATE_CURRENTDATE
virtual SwUndoId EndUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Closes undo block.
virtual void dumpAsXml(xmlTextWriterPtr pWriter) const override
Definition: bookmrk.cxx:484
Definition: doc.hxx:185
#define ODF_FORMDATE_DATEFORMAT_LANGUAGE
virtual SwPosition & GetMarkStart() const override
Definition: bookmrk.hxx:65
virtual void InitDoc(SwDoc *const io_pDoc, sw::mark::InsertMode eMode, SwPosition const *pSepPos) override
Definition: bookmrk.cxx:664
IDocumentLinksAdministration const & getIDocumentLinksAdministration() const
Definition: doc.cxx:259
sw::DocumentContentOperationsManager * m_pDocumentContentOperationsManager
Definition: bookmrk.hxx:335
OUString m_aFieldname
Definition: bookmrk.hxx:237
SwPosition FindFieldSep(IFieldmark const &rMark)
return position of the CH_TXT_ATR_FIELDSEP for rMark
Definition: bookmrk.cxx:50
void SetChecked(bool checked) override
Definition: bookmrk.cxx:574
virtual OUString ToString() const override
Definition: bookmrk.cxx:279
SwNode & GetNode() const
Definition: ndindex.hxx:119
virtual void ReleaseDoc(SwDoc *const pDoc) override
Definition: bookmrk.cxx:522
UnoMark(const SwPaM &rPaM)
Definition: bookmrk.cxx:343
virtual ::sfx2::IXmlIdRegistry & GetRegistry() override
Definition: bookmrk.cxx:409
virtual void ReleaseDoc(SwDoc *const pDoc) override
Definition: bookmrk.cxx:679
Dialog to specify the properties of date form field.
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:143
Of course Writer needs its own rectangles.
Definition: swrect.hxx:34
#define RES_REMOVE_UNO_OBJECT
Definition: hintids.hxx:305
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:314
void SetPortionPaintAreaEnd(const SwRect &rPortionPaintArea)
Definition: bookmrk.cxx:712
virtual bool IsCoveringPosition(const SwPosition &rPos) const override
Definition: bookmrk.cxx:262
#define CH_TXT_ATR_FORMELEMENT
Definition: hintids.hxx:50
virtual ~DdeBookmark() override
Definition: bookmrk.cxx:362
bool InsertString(const SwPaM &rRg, const OUString &, const SwInsertFlags nInsertMode=SwInsertFlags::EMPTYEXPAND) override
Insert string into existing text node at position rRg.Point().
TextFieldmark(const SwPaM &rPaM, const OUString &rName)
Definition: bookmrk.cxx:502
#define ODF_FORMCHECKBOX_RESULT
bool IsInHeaderFooter(const SwNodeIndex &rIdx) const
Definition: doclay.cxx:1542
Fieldmark with a drop down button (e.g. this button opens the date picker for a date field) ...
Definition: bookmrk.hxx:273
unsigned int uniform_uint_distribution(unsigned int a, unsigned int b)
void InvalidatePaM()
Definition: pam.cxx:1074
std::unique_ptr< SwPosition > m_pPos1
Definition: bookmrk.hxx:118
virtual bool IsExpanded() const override
Definition: bookmrk.hxx:83
Point TopLeft() const
Definition: swrect.cxx:174
#define ODF_FORMDATE_CURRENTDATE_LANGUAGE
virtual SwPosition & GetMarkEnd() const override
Definition: bookmrk.hxx:73
sal_uInt16 sal_Unicode
SwIndex nContent
Definition: pam.hxx:38
std::unique_ptr< SwPosition > m_pPos2
Definition: bookmrk.hxx:119
constexpr sal_uInt32 NUMBERFORMAT_ENTRY_NOT_FOUND
virtual ~DropDownFieldmark() override
Definition: bookmrk.cxx:623
int nCount
void RemoveServer(SvLinkSource *rObj)
sal_uLong GetIndex() const
Definition: ndindex.hxx:152
std::pair< bool, double > ParseCurrentDateParam() const
Definition: bookmrk.cxx:851
::sfx2::IXmlIdRegistry & GetXmlIdRegistry()
Definition: docnew.cxx:784
OUString GetDateInCurrentDateFormat(double fDate) const
Definition: bookmrk.cxx:887
void InvalidateCurrentDateParam()
Definition: bookmrk.cxx:928
virtual parameter_map_t * GetParameters()=0
#define ODF_FORMDATE_CURRENTDATE_FORMAT
void DeleteDummyChar(SwPosition const &rPos, sal_Unicode cDummy)
bool IsEmpty() const
Definition: swrect.hxx:294
virtual bool DoesUndo() const =0
Is Undo enabled?
bool PutEntry(OUString &rString, sal_Int32 &nCheckPos, SvNumFormatType &nType, sal_uInt32 &nKey, LanguageType eLnge=LANGUAGE_DONTKNOW)
Bookmark(const SwPaM &rPaM, const vcl::KeyCode &rCode, const OUString &rName)
Definition: bookmrk.cxx:375
virtual void ShowButton(SwEditWin *pEditWin) override
Definition: bookmrk.cxx:691
void SetRefObject(SwServerObject *pObj)
Definition: bookmrk.cxx:351
Point BottomRight() const
Definition: swrect.cxx:177
OUString m_aName
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
void swap(cow_wrapper< T, P > &a, cow_wrapper< T, P > &b)
struct _xmlTextWriter * xmlTextWriterPtr
static css::uno::Reference< css::text::XTextContent > CreateXBookmark(SwDoc &rDoc,::sw::mark::IMark *pBookmark)
Definition: unobkm.cxx:155
T * get() const
virtual bool InsertString(const SwPaM &rRg, const OUString &, const SwInsertFlags nInsertMode=SwInsertFlags::EMPTYEXPAND)=0
Insert string into existing text node at position rRg.Point().
virtual void AppendUndo(std::unique_ptr< SwUndo > pUndo)=0
Add new Undo action.
virtual SwUndoId StartUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Opens undo block.
#define SAL_MAX_INT32
const SwPosition * GetPoint() const
Definition: pam.hxx:207
void SetMarkEndPos(const SwPosition &rNewEndPos)
Definition: bookmrk.cxx:459
Window class for the Writer edit area, this is the one handling mouse and keyboard events and doing t...
Definition: edtwin.hxx:58
SwIndex & Assign(SwIndexReg *, sal_Int32)
Definition: index.cxx:198
virtual void dumpAsXml(xmlTextWriterPtr pWriter) const override
Definition: bookmrk.cxx:286
::sw::DocumentContentOperationsManager const & GetDocumentContentOperationsManager() const
Definition: doc.cxx:324
void CalcPosAndSize(const SwRect &rPortionPaintArea)
virtual void InitDoc(SwDoc *const io_Doc, sw::mark::InsertMode eMode, SwPosition const *pSepPos) override
Definition: bookmrk.cxx:386
int i
QPRO_FUNC_TYPE const nType
virtual void Invalidate(InvalidateFlags nFlags=InvalidateFlags::NONE)
void SetNoServer()
Definition: swserv.cxx:249
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:205
virtual ~MarkBase() override
Definition: bookmrk.cxx:302
#define CH_TXT_ATR_FIELDSTART
Definition: hintids.hxx:52
SvNumberFormatter * m_pNumberFormatter
Definition: bookmrk.hxx:334
IDocumentState const & getIDocumentState() const
Definition: doc.cxx:393
DdeBookmark(const SwPaM &rPaM)
Definition: bookmrk.cxx:347
virtual css::uno::Reference< css::rdf::XMetadatable > MakeUnoObject() override
Definition: bookmrk.cxx:435
bool IsNoTextNode() const
Definition: node.hxx:648
SvNumFormatType
bool IsNumberFormat(const OUString &sString, sal_uInt32 &F_Index, double &fOutNumber)
bool IsEndNode() const
Definition: node.hxx:632
void SetPortionPaintAreaStart(const SwRect &rPortionPaintArea)
Definition: bookmrk.cxx:703
#define ODF_FORMDATE_DATEFORMAT
DropDownFieldmark(const SwPaM &rPaM)
Definition: bookmrk.cxx:618
CheckboxFieldmark(const SwPaM &rPaM)
Definition: bookmrk.cxx:570
enumrange< T >::Iterator end(enumrange< T >)
virtual OUString ToString() const override
Definition: bookmrk.cxx:467
virtual void DeregisterFromDoc(SwDoc *const io_pDoc) override
Definition: bookmrk.cxx:397
void NotifyClients(const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue)
Definition: calbck.cxx:167
bool HasDataLinks() const
NavigatorReminder(const SwPaM &rPaM)
Definition: bookmrk.cxx:339
NonTextFieldmark(const SwPaM &rPaM)
Definition: bookmrk.cxx:533
virtual void InitDoc(SwDoc *const io_pDoc, sw::mark::InsertMode eMode, SwPosition const *pSepPos) override
Definition: bookmrk.cxx:509
virtual SwPosition & GetOtherMarkPos() const override
Definition: bookmrk.hxx:60
FieldmarkWithDropDownButton(const SwPaM &rPaM)
Definition: bookmrk.cxx:595
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
MarkBase(const SwPaM &rPaM, const OUString &rName)
Definition: bookmrk.cxx:245
void SetXBookmark(css::uno::Reference< css::text::XTextContent > const &xBkmk)
Definition: bookmrk.hxx:110
virtual bool IsInContent() const override
Definition: bookmrk.cxx:428
bool IsVisible() const
virtual bool IsInClipboard() const override
Definition: bookmrk.cxx:416
#define SAL_INFO(area, stream)
sal_Int32 GetIndex() const
Definition: index.hxx:95
virtual void InitDoc(SwDoc *const io_pDoc, sw::mark::InsertMode eMode, SwPosition const *pSepPos) override
Definition: bookmrk.cxx:537
bool IsClipBoard() const
Definition: doc.hxx:960
virtual SwPosition & GetMarkPos() const override
Definition: bookmrk.hxx:56
static VclPtr< reference_type > Create(Arg &&...arg)
virtual void SetMarkPos(const SwPosition &rNewPos)
Definition: bookmrk.cxx:267
void dumpAsXml(xmlTextWriterPtr pWriter) const
Definition: pam.cxx:181
void * p
void SetPortionPaintArea(const SwRect &rPortionPaintArea)
Definition: bookmrk.cxx:638
IFieldmark::parameter_map_t m_vParams
Definition: bookmrk.hxx:239
virtual const SwPosition & GetMarkEnd() const =0
virtual ~DateFieldmark() override
Definition: bookmrk.cxx:660
#define CH_TXT_ATR_FIELDEND
Definition: hintids.hxx:54
virtual void SetCurrentDate(double fDate) override
Definition: bookmrk.cxx:817
sal_uInt32 GetEntryKey(const OUString &sStr, LanguageType eLnge=LANGUAGE_DONTKNOW)
virtual OUString GetContent() const override
Definition: bookmrk.cxx:732
Fieldmark(const SwPaM &rPaM)
Definition: bookmrk.cxx:444
virtual sfx2::LinkManager & GetLinkManager()=0
virtual void DeregisterFromDoc(SwDoc *const pDoc)
Definition: bookmrk.cxx:356
tools::SvRef< SwServerObject > m_aRefObj
Definition: bookmrk.hxx:157
virtual const SwPosition & GetMarkStart() const =0
bool ReplaceRange(SwPaM &rPam, const OUString &rNewStr, const bool bRegExReplace) override
Replace selected range in a TextNode with string.
InsertMode
Definition: IMark.hxx:31
virtual void SetOtherMarkPos(const SwPosition &rNewPos)
Definition: bookmrk.cxx:273
virtual ~FieldmarkWithDropDownButton() override
Definition: bookmrk.cxx:601
#define CH_TXT_ATR_FIELDSEP
Definition: hintids.hxx:53
bool IsTextNode() const
Definition: node.hxx:636
sal_uInt16 Which() const
virtual void Invalidate() override
Definition: bookmrk.cxx:476
VclPtr< FormFieldButton > m_pButton
Definition: bookmrk.hxx:285
virtual IFieldmark::parameter_map_t * GetParameters() override
Definition: bookmrk.hxx:216
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:842
OUString anyToString(uno::Any const &value)
void Show(bool bVisible=true, ShowFlags nFlags=ShowFlags::NONE)
Base class of the Writer document model elements.
Definition: node.hxx:79
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo
virtual OUString GetDateInStandardDateFormat(double fDate) const override
Definition: bookmrk.cxx:827