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);
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 
339  // TODO: everything else uses MarkBase::GenerateNewName ?
341  : MarkBase(rPaM, "__NavigatorReminder__")
342  { }
343 
344  UnoMark::UnoMark(const SwPaM& aPaM)
345  : MarkBase(aPaM, MarkBase::GenerateNewName("__UnoMark__"))
346  { }
347 
349  : MarkBase(aPaM, MarkBase::GenerateNewName("__DdeLink__"))
350  { }
351 
353  {
354  m_aRefObj = pObj;
355  }
356 
358  {
359  if(m_aRefObj.is())
361  }
362 
364  {
365  if( m_aRefObj.is() )
366  {
367  if(m_aRefObj->HasDataLinks())
368  {
370  p->SendDataChanged();
371  }
373  }
374  }
375 
377  const vcl::KeyCode& rCode,
378  const OUString& rName)
379  : DdeBookmark(aPaM)
380  , ::sfx2::Metadatable()
381  , m_aCode(rCode)
382  , m_bHidden(false)
383  {
384  m_aName = rName;
385  }
386 
387  void Bookmark::InitDoc(SwDoc* const io_pDoc,
388  sw::mark::InsertMode const, SwPosition const*const)
389  {
390  if (io_pDoc->GetIDocumentUndoRedo().DoesUndo())
391  {
392  io_pDoc->GetIDocumentUndoRedo().AppendUndo(
393  std::make_unique<SwUndoInsBookmark>(*this));
394  }
395  io_pDoc->getIDocumentState().SetModified();
396  }
397 
398  void Bookmark::DeregisterFromDoc(SwDoc* const io_pDoc)
399  {
401 
402  if (io_pDoc->GetIDocumentUndoRedo().DoesUndo())
403  {
404  io_pDoc->GetIDocumentUndoRedo().AppendUndo(
405  std::make_unique<SwUndoDeleteBookmark>(*this));
406  }
407  io_pDoc->getIDocumentState().SetModified();
408  }
409 
411  {
412  SwDoc *const pDoc( GetMarkPos().GetDoc() );
413  assert(pDoc);
414  return pDoc->GetXmlIdRegistry();
415  }
416 
418  {
419  SwDoc *const pDoc( GetMarkPos().GetDoc() );
420  assert(pDoc);
421  return pDoc->IsClipBoard();
422  }
423 
424  bool Bookmark::IsInUndo() const
425  {
426  return false;
427  }
428 
430  {
431  SwDoc *const pDoc( GetMarkPos().GetDoc() );
432  assert(pDoc);
433  return !pDoc->IsInHeaderFooter( GetMarkPos().nNode );
434  }
435 
436  uno::Reference< rdf::XMetadatable > Bookmark::MakeUnoObject()
437  {
438  SwDoc *const pDoc( GetMarkPos().GetDoc() );
439  assert(pDoc);
440  const uno::Reference< rdf::XMetadatable> xMeta(
441  SwXBookmark::CreateXBookmark(*pDoc, this), uno::UNO_QUERY);
442  return xMeta;
443  }
444 
446  : MarkBase(rPaM, MarkBase::GenerateNewName("__Fieldmark__"))
447  {
448  if(!IsExpanded())
450  }
451 
452  void Fieldmark::SetMarkStartPos( const SwPosition& rNewStartPos )
453  {
454  if ( GetMarkPos( ) <= GetOtherMarkPos( ) )
455  return SetMarkPos( rNewStartPos );
456  else
457  return SetOtherMarkPos( rNewStartPos );
458  }
459 
460  void Fieldmark::SetMarkEndPos( const SwPosition& rNewEndPos )
461  {
462  if ( GetMarkPos( ) <= GetOtherMarkPos( ) )
463  return SetOtherMarkPos( rNewEndPos );
464  else
465  return SetMarkPos( rNewEndPos );
466  }
467 
468  OUString Fieldmark::ToString( ) const
469  {
470  return "Fieldmark: ( Name, Type, [ Nd1, Id1 ], [ Nd2, Id2 ] ): ( " + m_aName + ", "
471  + m_aFieldname + ", [ " + OUString::number( GetMarkPos().nNode.GetIndex( ) )
472  + ", " + OUString::number( GetMarkPos( ).nContent.GetIndex( ) ) + " ], ["
473  + OUString::number( GetOtherMarkPos().nNode.GetIndex( ) ) + ", "
474  + OUString::number( GetOtherMarkPos( ).nContent.GetIndex( ) ) + " ] ) ";
475  }
476 
478  {
479  // TODO: Does exist a better solution to trigger a format of the
480  // fieldmark portion? If yes, please use it.
481  SwPaM aPaM( GetMarkPos(), GetOtherMarkPos() );
482  aPaM.InvalidatePaM();
483  }
484 
486  {
487  xmlTextWriterStartElement(pWriter, BAD_CAST("Fieldmark"));
488  xmlTextWriterWriteAttribute(pWriter, BAD_CAST("fieldname"), BAD_CAST(m_aFieldname.toUtf8().getStr()));
489  xmlTextWriterWriteAttribute(pWriter, BAD_CAST("fieldHelptext"), BAD_CAST(m_aFieldHelptext.toUtf8().getStr()));
490  MarkBase::dumpAsXml(pWriter);
491  xmlTextWriterStartElement(pWriter, BAD_CAST("parameters"));
492  for (auto& rParam : m_vParams)
493  {
494  xmlTextWriterStartElement(pWriter, BAD_CAST("parameter"));
495  xmlTextWriterWriteAttribute(pWriter, BAD_CAST("name"), BAD_CAST(rParam.first.toUtf8().getStr()));
496  xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(comphelper::anyToString(rParam.second).toUtf8().getStr()));
497  xmlTextWriterEndElement(pWriter);
498  }
499  xmlTextWriterEndElement(pWriter);
500  xmlTextWriterEndElement(pWriter);
501  }
502 
503  TextFieldmark::TextFieldmark(const SwPaM& rPaM, const OUString& rName)
504  : Fieldmark(rPaM)
505  {
506  if ( !rName.isEmpty() )
507  m_aName = rName;
508  }
509 
510  void TextFieldmark::InitDoc(SwDoc* const io_pDoc,
511  sw::mark::InsertMode const eMode, SwPosition const*const pSepPos)
512  {
513  if (eMode == sw::mark::InsertMode::New)
514  {
515  lcl_SetFieldMarks(this, io_pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND, pSepPos);
516  }
517  else
518  {
519  lcl_AssertFieldMarksSet(this, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND);
520  }
521  }
522 
524  {
525  IDocumentUndoRedo & rIDUR(pDoc->GetIDocumentUndoRedo());
526  if (rIDUR.DoesUndo())
527  {
528  rIDUR.AppendUndo(std::make_unique<SwUndoDelTextFieldmark>(*this));
529  }
530  ::sw::UndoGuard const ug(rIDUR); // prevent SwUndoDeletes
531  lcl_RemoveFieldMarks(this, pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND);
532  }
533 
535  : Fieldmark(rPaM)
536  { }
537 
538  void NonTextFieldmark::InitDoc(SwDoc* const io_pDoc,
539  sw::mark::InsertMode const eMode, SwPosition const*const pSepPos)
540  {
541  assert(pSepPos == nullptr);
542  if (eMode == sw::mark::InsertMode::New)
543  {
544  lcl_SetFieldMarks(this, io_pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FORMELEMENT, pSepPos);
545 
546  // For some reason the end mark is moved from 1 by the Insert:
547  // we don't want this for checkboxes
548  SwPosition aNewEndPos = GetMarkEnd();
549  aNewEndPos.nContent--;
550  SetMarkEndPos( aNewEndPos );
551  }
552  else
553  {
554  lcl_AssertFieldMarksSet(this, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FORMELEMENT);
555  }
556  }
557 
559  {
560  IDocumentUndoRedo & rIDUR(pDoc->GetIDocumentUndoRedo());
561  if (rIDUR.DoesUndo())
562  {
563  rIDUR.AppendUndo(std::make_unique<SwUndoDelNoTextFieldmark>(*this));
564  }
565  ::sw::UndoGuard const ug(rIDUR); // prevent SwUndoDeletes
566  lcl_RemoveFieldMarks(this, pDoc,
568  }
569 
570 
572  : NonTextFieldmark(rPaM)
573  { }
574 
575  void CheckboxFieldmark::SetChecked(bool checked)
576  {
577  if ( IsChecked() != checked )
578  {
579  (*GetParameters())[OUString(ODF_FORMCHECKBOX_RESULT)] <<= checked;
580  // mark document as modified
581  SwDoc *const pDoc( GetMarkPos().GetDoc() );
582  if ( pDoc )
583  pDoc->getIDocumentState().SetModified();
584  }
585  }
586 
588  {
589  bool bResult = false;
590  parameter_map_t::const_iterator pResult = GetParameters()->find(OUString(ODF_FORMCHECKBOX_RESULT));
591  if(pResult != GetParameters()->end())
592  pResult->second >>= bResult;
593  return bResult;
594  }
595 
597  : NonTextFieldmark(rPaM)
598  , m_pButton(nullptr)
599  {
600  }
601 
603  {
605  }
606 
608  {
609  if(m_pButton)
610  m_pButton->Show(false);
611  }
612 
614  {
615  if(m_pButton)
617  }
618 
621  {
622  }
623 
625  {
626  }
627 
629  {
630  if(pEditWin)
631  {
632  if(!m_pButton)
635  m_pButton->Show();
636  }
637  }
638 
639  void DropDownFieldmark::SetPortionPaintArea(const SwRect& rPortionPaintArea)
640  {
641  if(m_aPortionPaintArea == rPortionPaintArea &&
643  return;
644 
645  m_aPortionPaintArea = rPortionPaintArea;
646  if(m_pButton)
647  {
648  m_pButton->Show();
651  }
652  }
653 
656  , m_pNumberFormatter(nullptr)
657  , m_pDocumentContentOperationsManager(nullptr)
658  {
659  }
660 
662  {
663  }
664 
665  void DateFieldmark::InitDoc(SwDoc* const io_pDoc,
666  sw::mark::InsertMode eMode, SwPosition const*const pSepPos)
667  {
670  if (eMode == sw::mark::InsertMode::New)
671  {
672  lcl_SetFieldMarks(this, io_pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND, pSepPos);
673  }
674  else
675  {
676  lcl_AssertFieldMarksSet(this, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND);
677  }
678  }
679 
681  {
682  IDocumentUndoRedo & rIDUR(pDoc->GetIDocumentUndoRedo());
683  if (rIDUR.DoesUndo())
684  {
685  // TODO does this need a 3rd Undo class?
686  rIDUR.AppendUndo(std::make_unique<SwUndoDelTextFieldmark>(*this));
687  }
688  ::sw::UndoGuard const ug(rIDUR); // prevent SwUndoDeletes
689  lcl_RemoveFieldMarks(this, pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND);
690  }
691 
693  {
694  if(pEditWin)
695  {
696  if(!m_pButton)
699  m_pButton->CalcPosAndSize(aPaintArea);
700  m_pButton->Show();
701  }
702  }
703 
704  void DateFieldmark::SetPortionPaintAreaStart(const SwRect& rPortionPaintArea)
705  {
706  if (rPortionPaintArea.IsEmpty())
707  return;
708 
709  m_aPaintAreaStart = rPortionPaintArea;
711  }
712 
713  void DateFieldmark::SetPortionPaintAreaEnd(const SwRect& rPortionPaintArea)
714  {
715  if (rPortionPaintArea.IsEmpty())
716  return;
717 
718  if(m_aPaintAreaEnd == rPortionPaintArea &&
720  return;
721 
722  m_aPaintAreaEnd = rPortionPaintArea;
723  if(m_pButton)
724  {
725  m_pButton->Show();
727  m_pButton->CalcPosAndSize(aPaintArea);
729  }
731  }
732 
733  OUString DateFieldmark::GetContent() const
734  {
735  const SwTextNode* const pTextNode = GetMarkEnd().nNode.GetNode().GetTextNode();
736  SwPosition const sepPos(sw::mark::FindFieldSep(*this));
737  const sal_Int32 nStart(sepPos.nContent.GetIndex());
738  const sal_Int32 nEnd (GetMarkEnd().nContent.GetIndex());
739 
740  OUString sContent;
741  if(nStart + 1 < pTextNode->GetText().getLength() && nEnd <= pTextNode->GetText().getLength() &&
742  nEnd > nStart + 2)
743  sContent = pTextNode->GetText().copy(nStart + 1, nEnd - nStart - 2);
744  return sContent;
745  }
746 
747  void DateFieldmark::ReplaceContent(const OUString& sNewContent)
748  {
750  return;
751 
752  const SwTextNode* const pTextNode = GetMarkEnd().nNode.GetNode().GetTextNode();
753  SwPosition const sepPos(sw::mark::FindFieldSep(*this));
754  const sal_Int32 nStart(sepPos.nContent.GetIndex());
755  const sal_Int32 nEnd (GetMarkEnd().nContent.GetIndex());
756 
757  if(nStart + 1 < pTextNode->GetText().getLength() && nEnd <= pTextNode->GetText().getLength() &&
758  nEnd > nStart + 2)
759  {
760  SwPaM aFieldPam(GetMarkStart().nNode, nStart + 1,
761  GetMarkStart().nNode, nEnd - 1);
762  m_pDocumentContentOperationsManager->ReplaceRange(aFieldPam, sNewContent, false);
763  }
764  else
765  {
766  SwPaM aFieldStartPam(GetMarkStart().nNode, nStart + 1);
767  m_pDocumentContentOperationsManager->InsertString(aFieldStartPam, sNewContent);
768  }
769 
770  }
771 
772  std::pair<bool, double> DateFieldmark::GetCurrentDate() const
773  {
774  // Check current date param first
775  std::pair<bool, double> aResult = ParseCurrentDateParam();
776  if(aResult.first)
777  return aResult;
778 
780  bool bFoundValidDate = false;
781  double dCurrentDate = 0;
782  OUString sDateFormat;
783  auto pResult = pParameters->find(ODF_FORMDATE_DATEFORMAT);
784  if (pResult != pParameters->end())
785  {
786  pResult->second >>= sDateFormat;
787  }
788 
789  OUString sLang;
790  pResult = pParameters->find(ODF_FORMDATE_DATEFORMAT_LANGUAGE);
791  if (pResult != pParameters->end())
792  {
793  pResult->second >>= sLang;
794  }
795 
796  // Get current content of the field
797  OUString sContent = GetContent();
798 
799  sal_uInt32 nFormat = m_pNumberFormatter->GetEntryKey(sDateFormat, LanguageTag(sLang).getLanguageType());
800  if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
801  {
802  sal_Int32 nCheckPos = 0;
804  m_pNumberFormatter->PutEntry(sDateFormat,
805  nCheckPos,
806  nType,
807  nFormat,
808  LanguageTag(sLang).getLanguageType());
809  }
810 
811  if (nFormat != NUMBERFORMAT_ENTRY_NOT_FOUND)
812  {
813  bFoundValidDate = m_pNumberFormatter->IsNumberFormat(sContent, nFormat, dCurrentDate);
814  }
815  return std::pair<bool, double>(bFoundValidDate, dCurrentDate);
816  }
817 
818  void DateFieldmark::SetCurrentDate(double fDate)
819  {
820  // Replace current content with the selected date
822 
823  // Also save the current date in a standard format
825  (*pParameters)[ODF_FORMDATE_CURRENTDATE] <<= GetDateInStandardDateFormat(fDate);
826  }
827 
828  OUString DateFieldmark::GetDateInStandardDateFormat(double fDate) const
829  {
830  OUString sCurrentDate;
832  if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
833  {
834  sal_Int32 nCheckPos = 0;
836  OUString sFormat = ODF_FORMDATE_CURRENTDATE_FORMAT;
837  m_pNumberFormatter->PutEntry(sFormat,
838  nCheckPos,
839  nType,
840  nFormat,
842  }
843 
844  if (nFormat != NUMBERFORMAT_ENTRY_NOT_FOUND)
845  {
846  Color* pCol = nullptr;
847  m_pNumberFormatter->GetOutputString(fDate, nFormat, sCurrentDate, &pCol, false);
848  }
849  return sCurrentDate;
850  }
851 
852  std::pair<bool, double> DateFieldmark::ParseCurrentDateParam() const
853  {
854  bool bFoundValidDate = false;
855  double dCurrentDate = 0;
856 
858  auto pResult = pParameters->find(ODF_FORMDATE_CURRENTDATE);
859  OUString sCurrentDate;
860  if (pResult != pParameters->end())
861  {
862  pResult->second >>= sCurrentDate;
863  }
864  if(!sCurrentDate.isEmpty())
865  {
867  if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
868  {
869  sal_Int32 nCheckPos = 0;
871  OUString sFormat = ODF_FORMDATE_CURRENTDATE_FORMAT;
872  m_pNumberFormatter->PutEntry(sFormat,
873  nCheckPos,
874  nType,
875  nFormat,
877  }
878 
879  if(nFormat != NUMBERFORMAT_ENTRY_NOT_FOUND)
880  {
881  bFoundValidDate = m_pNumberFormatter->IsNumberFormat(sCurrentDate, nFormat, dCurrentDate);
882  }
883  }
884  return std::pair<bool, double>(bFoundValidDate, dCurrentDate);
885  }
886 
887 
888  OUString DateFieldmark::GetDateInCurrentDateFormat(double fDate) const
889  {
890  // Get current date format and language
891  OUString sDateFormat;
893  auto pResult = pParameters->find(ODF_FORMDATE_DATEFORMAT);
894  if (pResult != pParameters->end())
895  {
896  pResult->second >>= sDateFormat;
897  }
898 
899  OUString sLang;
900  pResult = pParameters->find(ODF_FORMDATE_DATEFORMAT_LANGUAGE);
901  if (pResult != pParameters->end())
902  {
903  pResult->second >>= sLang;
904  }
905 
906  // Fill the content with the specified format
907  OUString sCurrentContent;
908  sal_uInt32 nFormat = m_pNumberFormatter->GetEntryKey(sDateFormat, LanguageTag(sLang).getLanguageType());
909  if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
910  {
911  sal_Int32 nCheckPos = 0;
913  OUString sFormat = sDateFormat;
914  m_pNumberFormatter->PutEntry(sFormat,
915  nCheckPos,
916  nType,
917  nFormat,
918  LanguageTag(sLang).getLanguageType());
919  }
920 
921  if (nFormat != NUMBERFORMAT_ENTRY_NOT_FOUND)
922  {
923  Color* pCol = nullptr;
924  m_pNumberFormatter->GetOutputString(fDate, nFormat, sCurrentContent, &pCol, false);
925  }
926  return sCurrentContent;
927  }
928 
930  {
931  std::pair<bool, double> aResult = ParseCurrentDateParam();
932  if(!aResult.first)
933  return;
934 
935  // Current date became invalid
936  if(GetDateInCurrentDateFormat(aResult.second) != GetContent())
937  {
939  (*pParameters)[ODF_FORMDATE_CURRENTDATE] <<= OUString();
940  }
941  }
942 }}
943 
944 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void SetMarkStartPos(const SwPosition &rNewStartPos)
Definition: bookmrk.cxx:452
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:772
bool is() const
DateFieldmark(const SwPaM &rPaM)
Definition: bookmrk.cxx:654
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:587
sal_uLong StartOfSectionIndex() const
Definition: node.hxx:673
virtual void ShowButton(SwEditWin *pEditWin) override
Definition: bookmrk.cxx:628
const OUString & GetText() const
Definition: ndtxt.hxx:210
virtual bool IsInUndo() const override
Definition: bookmrk.cxx:424
virtual void ReplaceContent(const OUString &sNewContent) override
Definition: bookmrk.cxx:747
SvNumberFormatter * GetNumberFormatter(bool bCreate=true)
Definition: doc.hxx:1401
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:558
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:284
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
#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:485
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:665
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:575
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:523
UnoMark(const SwPaM &rPaM)
Definition: bookmrk.cxx:344
virtual ::sfx2::IXmlIdRegistry & GetRegistry() override
Definition: bookmrk.cxx:410
virtual void ReleaseDoc(SwDoc *const pDoc) override
Definition: bookmrk.cxx:680
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:713
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:363
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:503
#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:1064
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:624
void RemoveServer(SvLinkSource *rObj)
sal_uLong GetIndex() const
Definition: ndindex.hxx:152
std::pair< bool, double > ParseCurrentDateParam() const
Definition: bookmrk.cxx:852
::sfx2::IXmlIdRegistry & GetXmlIdRegistry()
Definition: docnew.cxx:783
OUString GetDateInCurrentDateFormat(double fDate) const
Definition: bookmrk.cxx:888
void InvalidateCurrentDateParam()
Definition: bookmrk.cxx:929
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:376
virtual void ShowButton(SwEditWin *pEditWin) override
Definition: bookmrk.cxx:692
void SetRefObject(SwServerObject *pObj)
Definition: bookmrk.cxx:352
Point BottomRight() const
Definition: swrect.cxx:177
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:158
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:460
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:387
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:348
virtual css::uno::Reference< css::rdf::XMetadatable > MakeUnoObject() override
Definition: bookmrk.cxx:436
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:704
#define ODF_FORMDATE_DATEFORMAT
DropDownFieldmark(const SwPaM &rPaM)
Definition: bookmrk.cxx:619
CheckboxFieldmark(const SwPaM &rPaM)
Definition: bookmrk.cxx:571
enumrange< T >::Iterator end(enumrange< T >)
virtual OUString ToString() const override
Definition: bookmrk.cxx:468
virtual void DeregisterFromDoc(SwDoc *const io_pDoc) override
Definition: bookmrk.cxx:398
void NotifyClients(const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue)
Definition: calbck.cxx:167
bool HasDataLinks() const
NavigatorReminder(const SwPaM &rPaM)
Definition: bookmrk.cxx:340
NonTextFieldmark(const SwPaM &rPaM)
Definition: bookmrk.cxx:534
virtual void InitDoc(SwDoc *const io_pDoc, sw::mark::InsertMode eMode, SwPosition const *pSepPos) override
Definition: bookmrk.cxx:510
virtual SwPosition & GetOtherMarkPos() const override
Definition: bookmrk.hxx:60
FieldmarkWithDropDownButton(const SwPaM &rPaM)
Definition: bookmrk.cxx:596
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:429
bool IsVisible() const
virtual bool IsInClipboard() const override
Definition: bookmrk.cxx:417
#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:538
bool IsClipBoard() const
Definition: doc.hxx:956
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 SetPortionPaintArea(const SwRect &rPortionPaintArea)
Definition: bookmrk.cxx:639
IFieldmark::parameter_map_t m_vParams
Definition: bookmrk.hxx:239
virtual const SwPosition & GetMarkEnd() const =0
virtual ~DateFieldmark() override
Definition: bookmrk.cxx:661
#define CH_TXT_ATR_FIELDEND
Definition: hintids.hxx:54
virtual void SetCurrentDate(double fDate) override
Definition: bookmrk.cxx:818
sal_uInt32 GetEntryKey(const OUString &sStr, LanguageType eLnge=LANGUAGE_DONTKNOW)
virtual OUString GetContent() const override
Definition: bookmrk.cxx:733
Fieldmark(const SwPaM &rPaM)
Definition: bookmrk.cxx:445
virtual sfx2::LinkManager & GetLinkManager()=0
virtual void DeregisterFromDoc(SwDoc *const pDoc)
Definition: bookmrk.cxx:357
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:602
#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:477
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:828