1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <bookmark.hxx>
22 #include <IDocumentUndoRedo.hxx>
23 #include <IDocumentLinksAdministration.hxx>
24 #include <IDocumentState.hxx>
29 #include <sfx2/linkmgr.hxx>
30 #include <sfx2/viewsh.hxx>
31 #include <UndoBookmark.hxx>
32 #include <unobookmark.hxx>
34 #include <xmloff/odffields.hxx>
35 #include <libxml/xmlwriter.h>
36 #include <comphelper/random.hxx>
37 #include <comphelper/sequence.hxx>
38 #include <comphelper/anytostring.hxx>
39 #include <sal/log.hxx>
40 #include <svl/numformat.hxx>
41 #include <svl/zforlist.hxx>
43 #include <DateFormFieldButton.hxx>
44 #include <DropDownFormFieldButton.hxx>
45 #include <DocumentContentOperationsManager.hxx>
46 #include <comphelper/lok.hxx>
48 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
49 #include <rtl/strbuf.hxx>
50 #include <strings.hrc>
51 #include <tools/json_writer.hxx>
53 using namespace ::sw::mark
;
54 using namespace ::com::sun::star
;
55 using namespace ::com::sun::star::uno
;
60 SwPosition
FindFieldSep(IFieldmark
const& rMark
)
62 SwPosition
const& rStartPos(rMark
.GetMarkStart());
63 SwPosition
const& rEndPos(rMark
.GetMarkEnd());
64 SwNodes
const& rNodes(rStartPos
.GetNodes());
65 SwNodeOffset
const nStartNode(rStartPos
.GetNodeIndex());
66 SwNodeOffset
const nEndNode(rEndPos
.GetNodeIndex());
68 std::optional
<SwPosition
> ret
;
69 for (SwNodeOffset n
= nEndNode
; nStartNode
<= n
; --n
)
71 SwNode
*const pNode(rNodes
[n
]);
72 if (pNode
->IsTextNode())
74 SwTextNode
& rTextNode(*pNode
->GetTextNode());
75 sal_Int32
const nStart(n
== nStartNode
76 ? rStartPos
.GetContentIndex() + 1
78 sal_Int32
const nEnd(n
== nEndNode
79 // subtract 1 to ignore the end char
80 ? rEndPos
.GetContentIndex() - 1
82 for (sal_Int32 i
= nEnd
; nStart
< i
; --i
)
84 const sal_Unicode
c(rTextNode
.GetText()[i
- 1]);
87 case CH_TXT_ATR_FIELDSTART
:
91 case CH_TXT_ATR_FIELDEND
:
93 // fields in field result could happen by manual
94 // editing, although the field update deletes them
96 case CH_TXT_ATR_FIELDSEP
:
99 assert(!ret
); // one per field
100 ret
.emplace(rTextNode
, i
- 1);
109 else if (pNode
->IsEndNode() && !pNode
->StartOfSectionNode()->IsSectionNode())
111 assert(nStartNode
<= pNode
->StartOfSectionIndex());
112 // fieldmark cannot overlap node section, unless it's a section
113 n
= pNode
->StartOfSectionIndex();
117 assert(pNode
->IsNoTextNode() || pNode
->IsSectionNode()
118 || (pNode
->IsEndNode() && pNode
->StartOfSectionNode()->IsSectionNode()));
121 assert(ret
); // must have found it
124 } // namespace sw::mark
128 void lcl_FixPosition(SwPosition
& rPos
)
130 // make sure the position has 1) the proper node, and 2) a proper index
131 SwTextNode
* pTextNode
= rPos
.GetNode().GetTextNode();
132 if(pTextNode
== nullptr && rPos
.GetContentIndex() > 0)
136 "illegal position: " << rPos
.GetContentIndex()
137 << " without proper TextNode");
138 rPos
.nContent
.Assign(nullptr, 0);
140 else if(pTextNode
!= nullptr && rPos
.GetContentIndex() > pTextNode
->Len())
144 "illegal position: " << rPos
.GetContentIndex()
145 << " is beyond " << pTextNode
->Len());
146 rPos
.nContent
.Assign(pTextNode
, pTextNode
->Len());
150 void lcl_AssertFieldMarksSet(const Fieldmark
& rField
,
151 const sal_Unicode aStartMark
,
152 const sal_Unicode aEndMark
)
154 if (aEndMark
!= CH_TXT_ATR_FORMELEMENT
)
156 SwPosition
const& rStart(rField
.GetMarkStart());
157 assert(rStart
.GetNode().GetTextNode()->GetText()[rStart
.GetContentIndex()] == aStartMark
); (void) rStart
; (void) aStartMark
;
158 SwPosition
const sepPos(sw::mark::FindFieldSep(rField
));
159 assert(sepPos
.GetNode().GetTextNode()->GetText()[sepPos
.GetContentIndex()] == CH_TXT_ATR_FIELDSEP
); (void) sepPos
;
162 { // must be m_pPos1 < m_pPos2 because of asymmetric SplitNode update
163 assert(rField
.GetMarkPos().GetContentIndex() + 1 == rField
.GetOtherMarkPos().GetContentIndex());
165 SwPosition
const& rEnd(rField
.GetMarkEnd());
166 assert(rEnd
.GetNode().GetTextNode()->GetText()[rEnd
.GetContentIndex() - 1] == aEndMark
); (void) rEnd
;
169 void lcl_SetFieldMarks(Fieldmark
& rField
,
171 const sal_Unicode aStartMark
,
172 const sal_Unicode aEndMark
,
173 SwPosition
const*const pSepPos
)
175 io_rDoc
.GetIDocumentUndoRedo().StartUndo(SwUndoId::UI_REPLACE
, nullptr);
176 OUString
startChar(aStartMark
);
177 if (aEndMark
!= CH_TXT_ATR_FORMELEMENT
178 && rField
.GetMarkStart() == rField
.GetMarkEnd())
180 // do only 1 InsertString call - to expand existing bookmarks at the
181 // position over the whole field instead of just aStartMark
182 startChar
+= OUStringChar(CH_TXT_ATR_FIELDSEP
) + OUStringChar(aEndMark
);
185 SwPosition start
= rField
.GetMarkStart();
186 if (aEndMark
!= CH_TXT_ATR_FORMELEMENT
)
188 SwPaM
aStartPaM(start
);
189 io_rDoc
.getIDocumentContentOperations().InsertString(aStartPaM
, startChar
);
190 start
.AdjustContent( -startChar
.getLength() ); // restore, it was moved by InsertString
191 // do not manipulate via reference directly but call SetMarkStartPos
192 // which works even if start and end pos were the same
193 rField
.SetMarkStartPos( start
);
194 SwPosition
& rEnd
= rField
.GetMarkEnd(); // note: retrieve after
195 // setting start, because if start==end it can go stale, see SetMarkPos()
196 assert(pSepPos
== nullptr || (start
< *pSepPos
&& *pSepPos
<= rEnd
));
197 if (startChar
.getLength() == 1)
199 *aStartPaM
.GetPoint() = pSepPos
? *pSepPos
: rEnd
;
200 io_rDoc
.getIDocumentContentOperations().InsertString(aStartPaM
, OUString(CH_TXT_ATR_FIELDSEP
));
201 if (!pSepPos
|| rEnd
< *pSepPos
)
202 { // rEnd is not moved automatically if it's same as insert pos
203 rEnd
.AdjustContent(1);
206 assert(pSepPos
== nullptr || (start
< *pSepPos
&& *pSepPos
<= rEnd
));
210 assert(pSepPos
== nullptr);
213 SwPosition
& rEnd
= rField
.GetMarkEnd();
214 if (aEndMark
&& startChar
.getLength() == 1)
217 io_rDoc
.getIDocumentContentOperations().InsertString(aEndPaM
, OUString(aEndMark
));
218 if (aEndMark
!= CH_TXT_ATR_FORMELEMENT
)
220 rEnd
.AdjustContent(1); // InsertString didn't move non-empty mark
223 { // InsertString moved the mark's end, not its start
224 assert(rField
.GetMarkPos().GetContentIndex() + 1 == rField
.GetOtherMarkPos().GetContentIndex());
227 lcl_AssertFieldMarksSet(rField
, aStartMark
, aEndMark
);
229 io_rDoc
.GetIDocumentUndoRedo().EndUndo(SwUndoId::UI_REPLACE
, nullptr);
232 void lcl_RemoveFieldMarks(const Fieldmark
& rField
,
234 const sal_Unicode aStartMark
,
235 const sal_Unicode aEndMark
)
237 io_rDoc
.GetIDocumentUndoRedo().StartUndo(SwUndoId::UI_REPLACE
, nullptr);
239 const SwPosition
& rStart
= rField
.GetMarkStart();
240 SwTextNode
const*const pStartTextNode
= rStart
.GetNode().GetTextNode();
241 assert(pStartTextNode
);
242 if (aEndMark
!= CH_TXT_ATR_FORMELEMENT
)
244 (void) pStartTextNode
;
245 // check this before start / end because of the +1 / -1 ...
246 SwPosition
const sepPos(sw::mark::FindFieldSep(rField
));
247 io_rDoc
.GetDocumentContentOperationsManager().DeleteDummyChar(rStart
, aStartMark
);
248 io_rDoc
.GetDocumentContentOperationsManager().DeleteDummyChar(sepPos
, CH_TXT_ATR_FIELDSEP
);
251 const SwPosition
& rEnd
= rField
.GetMarkEnd();
252 SwTextNode
*const pEndTextNode
= rEnd
.GetNode().GetTextNode();
253 assert(pEndTextNode
);
254 const sal_Int32 nEndPos
= (rEnd
== rStart
)
255 ? rEnd
.GetContentIndex()
256 : rEnd
.GetContentIndex() - 1;
257 assert(pEndTextNode
->GetText()[nEndPos
] == aEndMark
);
258 SwPosition
const aEnd(*pEndTextNode
, nEndPos
);
259 io_rDoc
.GetDocumentContentOperationsManager().DeleteDummyChar(aEnd
, aEndMark
);
261 io_rDoc
.GetIDocumentUndoRedo().EndUndo(SwUndoId::UI_REPLACE
, nullptr);
264 auto InvalidatePosition(SwPosition
const& rPos
) -> void
266 SwUpdateAttr
const aHint(rPos
.GetContentIndex(), rPos
.GetContentIndex(), 0);
267 rPos
.GetNode().GetTextNode()->CallSwClientNotify(sw::LegacyModifyHint(&aHint
, &aHint
));
273 MarkBase::MarkBase(const SwPaM
& aPaM
,
275 : m_oPos1(*aPaM
.GetPoint())
276 , m_aName(std::move(aName
))
278 m_oPos1
->SetMark(this);
279 lcl_FixPosition(*m_oPos1
);
280 if (aPaM
.HasMark() && (*aPaM
.GetMark() != *aPaM
.GetPoint()))
282 MarkBase::SetOtherMarkPos(*(aPaM
.GetMark()));
283 lcl_FixPosition(*m_oPos2
);
287 void MarkBase::SetXBookmark(rtl::Reference
<SwXBookmark
> const& xBkmk
)
288 { m_wXBookmark
= xBkmk
.get(); }
290 // For fieldmarks, the CH_TXT_ATR_FIELDSTART and CH_TXT_ATR_FIELDEND
291 // themselves are part of the covered range. This is guaranteed by
292 // TextFieldmark::InitDoc/lcl_AssureFieldMarksSet.
293 bool MarkBase::IsCoveringPosition(const SwPosition
& rPos
) const
295 return GetMarkStart() <= rPos
&& rPos
< GetMarkEnd();
298 void MarkBase::SetMarkPos(const SwPosition
& rNewPos
)
300 m_oPos1
.emplace(rNewPos
);
301 m_oPos1
->SetMark(this);
304 void MarkBase::SetOtherMarkPos(const SwPosition
& rNewPos
)
306 m_oPos2
.emplace(rNewPos
);
307 m_oPos2
->SetMark(this);
310 OUString
MarkBase::ToString( ) const
312 return "Mark: ( Name, [ Node1, Index1 ] ): ( " + m_aName
+ ", [ "
313 + OUString::number( sal_Int32(GetMarkPos().GetNodeIndex()) ) + ", "
314 + OUString::number( GetMarkPos().GetContentIndex( ) ) + " ] )";
317 void MarkBase::dumpAsXml(xmlTextWriterPtr pWriter
) const
319 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("MarkBase"));
320 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("name"), BAD_CAST(m_aName
.toUtf8().getStr()));
321 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("markPos"));
322 GetMarkPos().dumpAsXml(pWriter
);
323 (void)xmlTextWriterEndElement(pWriter
);
326 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("otherMarkPos"));
327 GetOtherMarkPos().dumpAsXml(pWriter
);
328 (void)xmlTextWriterEndElement(pWriter
);
330 (void)xmlTextWriterEndElement(pWriter
);
333 MarkBase::~MarkBase()
336 OUString
MarkBase::GenerateNewName(std::u16string_view rPrefix
)
338 static bool bHack
= (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != nullptr);
342 static sal_Int64 nIdCounter
= SAL_CONST_INT64(6000000000);
343 return rPrefix
+ OUString::number(nIdCounter
++);
347 static OUString sUniquePostfix
;
348 static sal_Int32 nCount
= SAL_MAX_INT32
;
349 if(nCount
== SAL_MAX_INT32
)
351 unsigned int const n(comphelper::rng::uniform_uint_distribution(0,
352 std::numeric_limits
<unsigned int>::max()));
353 sUniquePostfix
= "_" + OUString::number(n
);
356 // putting the counter in front of the random parts will speed up string comparisons
357 return rPrefix
+ OUString::number(nCount
++) + sUniquePostfix
;
361 void MarkBase::SwClientNotify(const SwModify
&, const SfxHint
& rHint
)
363 CallSwClientNotify(rHint
);
364 if (rHint
.GetId() != SfxHintId::SwLegacyModify
)
366 auto pLegacy
= static_cast<const sw::LegacyModifyHint
*>(&rHint
);
367 if(RES_REMOVE_UNO_OBJECT
== pLegacy
->GetWhich())
368 { // invalidate cached uno object
369 SetXBookmark(nullptr);
373 auto MarkBase::InvalidateFrames() -> void
377 NavigatorReminder::NavigatorReminder(const SwPaM
& rPaM
)
378 : MarkBase(rPaM
, MarkBase::GenerateNewName(u
"__NavigatorReminder__"))
381 UnoMark::UnoMark(const SwPaM
& aPaM
)
382 : MarkBase(aPaM
, MarkBase::GenerateNewName(u
"__UnoMark__"))
385 DdeBookmark::DdeBookmark(const SwPaM
& aPaM
)
386 : MarkBase(aPaM
, MarkBase::GenerateNewName(u
"__DdeLink__"))
389 void DdeBookmark::SetRefObject(SwServerObject
* pObj
)
394 void DdeBookmark::DeregisterFromDoc(SwDoc
& rDoc
)
397 rDoc
.getIDocumentLinksAdministration().GetLinkManager().RemoveServer(m_aRefObj
.get());
400 DdeBookmark::~DdeBookmark()
404 if(m_aRefObj
->HasDataLinks())
406 ::sfx2::SvLinkSource
* p
= m_aRefObj
.get();
407 p
->SendDataChanged();
409 m_aRefObj
->SetNoServer();
413 Bookmark::Bookmark(const SwPaM
& aPaM
,
414 const vcl::KeyCode
& rCode
,
415 const OUString
& rName
)
423 void Bookmark::sendLOKDeleteCallback()
425 if (!comphelper::LibreOfficeKit::isActive() || GetMarkPos().GetDoc().IsClipBoard())
428 SfxViewShell
* pViewShell
= SfxViewShell::Current();
432 OUString fieldCommand
= GetName();
433 tools::JsonWriter aJson
;
434 aJson
.put("commandName", ".uno:DeleteBookmark");
435 aJson
.put("success", true);
437 auto result
= aJson
.startNode("result");
438 aJson
.put("DeleteBookmark", fieldCommand
);
441 pViewShell
->libreOfficeKitViewCallback(LOK_CALLBACK_UNO_COMMAND_RESULT
, aJson
.finishAndGetAsOString());
444 void Bookmark::InitDoc(SwDoc
& io_rDoc
,
445 sw::mark::InsertMode
const, SwPosition
const*const)
447 if (io_rDoc
.GetIDocumentUndoRedo().DoesUndo())
449 io_rDoc
.GetIDocumentUndoRedo().AppendUndo(
450 std::make_unique
<SwUndoInsBookmark
>(*this));
452 io_rDoc
.getIDocumentState().SetModified();
456 void Bookmark::DeregisterFromDoc(SwDoc
& io_rDoc
)
458 DdeBookmark::DeregisterFromDoc(io_rDoc
);
460 if (io_rDoc
.GetIDocumentUndoRedo().DoesUndo())
462 io_rDoc
.GetIDocumentUndoRedo().AppendUndo(
463 std::make_unique
<SwUndoDeleteBookmark
>(*this));
465 io_rDoc
.getIDocumentState().SetModified();
469 // invalidate text frames in case it's hidden or Formatting Marks enabled
470 auto Bookmark::InvalidateFrames() -> void
472 InvalidatePosition(GetMarkPos());
475 InvalidatePosition(GetOtherMarkPos());
479 void Bookmark::Hide(bool const isHide
)
481 if (isHide
!= m_bHidden
)
488 void Bookmark::SetHideCondition(OUString
const& rHideCondition
)
490 if (m_sHideCondition
!= rHideCondition
)
492 m_sHideCondition
= rHideCondition
;
493 // don't eval condition here yet - probably only needed for
494 // UI editing condition and that doesn't exist yet
498 ::sfx2::IXmlIdRegistry
& Bookmark::GetRegistry()
500 SwDoc
& rDoc( GetMarkPos().GetDoc() );
501 return rDoc
.GetXmlIdRegistry();
504 bool Bookmark::IsInClipboard() const
506 SwDoc
& rDoc( GetMarkPos().GetDoc() );
507 return rDoc
.IsClipBoard();
510 bool Bookmark::IsInUndo() const
515 bool Bookmark::IsInContent() const
517 SwDoc
& rDoc( GetMarkPos().GetDoc() );
518 return !rDoc
.IsInHeaderFooter( GetMarkPos().GetNode() );
521 uno::Reference
< rdf::XMetadatable
> Bookmark::MakeUnoObject()
523 SwDoc
& rDoc( GetMarkPos().GetDoc() );
524 const uno::Reference
< rdf::XMetadatable
> xMeta(
525 SwXBookmark::CreateXBookmark(rDoc
, this) );
529 Fieldmark::Fieldmark(const SwPaM
& rPaM
)
530 : MarkBase(rPaM
, MarkBase::GenerateNewName(u
"__Fieldmark__"))
533 SetOtherMarkPos(GetMarkPos());
536 void Fieldmark::SetMarkStartPos( const SwPosition
& rNewStartPos
)
538 if ( GetMarkPos( ) <= GetOtherMarkPos( ) )
539 return SetMarkPos( rNewStartPos
);
541 return SetOtherMarkPos( rNewStartPos
);
544 OUString
Fieldmark::ToString( ) const
546 return "Fieldmark: ( Name, Type, [ Nd1, Id1 ], [ Nd2, Id2 ] ): ( " + m_aName
+ ", "
547 + m_aFieldname
+ ", [ " + OUString::number( sal_Int32(GetMarkPos().GetNodeIndex( )) )
548 + ", " + OUString::number( GetMarkPos( ).GetContentIndex( ) ) + " ], ["
549 + OUString::number( sal_Int32(GetOtherMarkPos().GetNodeIndex( )) ) + ", "
550 + OUString::number( GetOtherMarkPos( ).GetContentIndex( ) ) + " ] ) ";
553 void Fieldmark::Invalidate( )
555 // TODO: Does exist a better solution to trigger a format of the
556 // fieldmark portion? If yes, please use it.
557 SwPaM
aPaM( GetMarkPos(), GetOtherMarkPos() );
558 aPaM
.InvalidatePaM();
561 void Fieldmark::dumpAsXml(xmlTextWriterPtr pWriter
) const
563 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("Fieldmark"));
564 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("fieldname"), BAD_CAST(m_aFieldname
.toUtf8().getStr()));
565 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("fieldHelptext"), BAD_CAST(m_aFieldHelptext
.toUtf8().getStr()));
566 MarkBase::dumpAsXml(pWriter
);
567 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("parameters"));
568 for (auto& rParam
: m_vParams
)
570 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("parameter"));
571 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("name"), BAD_CAST(rParam
.first
.toUtf8().getStr()));
572 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("value"), BAD_CAST(comphelper::anyToString(rParam
.second
).toUtf8().getStr()));
573 (void)xmlTextWriterEndElement(pWriter
);
575 (void)xmlTextWriterEndElement(pWriter
);
576 (void)xmlTextWriterEndElement(pWriter
);
579 TextFieldmark::TextFieldmark(const SwPaM
& rPaM
, const OUString
& rName
)
581 , m_pDocumentContentOperationsManager(nullptr)
583 if ( !rName
.isEmpty() )
587 TextFieldmark::~TextFieldmark()
589 if (!comphelper::LibreOfficeKit::isActive() || GetMarkPos().GetDoc().IsClipBoard())
592 SfxViewShell
* pViewShell
= SfxViewShell::Current();
596 OUString fieldCommand
;
597 (*GetParameters())[OUString(ODF_CODE_PARAM
)] >>= fieldCommand
;
598 tools::JsonWriter aJson
;
599 aJson
.put("commandName", ".uno:DeleteTextFormField");
600 aJson
.put("success", true);
602 auto result
= aJson
.startNode("result");
603 aJson
.put("DeleteTextFormField", fieldCommand
);
606 pViewShell
->libreOfficeKitViewCallback(LOK_CALLBACK_UNO_COMMAND_RESULT
, aJson
.finishAndGetAsOString());
609 void TextFieldmark::InitDoc(SwDoc
& io_rDoc
,
610 sw::mark::InsertMode
const eMode
, SwPosition
const*const pSepPos
)
612 m_pDocumentContentOperationsManager
= &io_rDoc
.GetDocumentContentOperationsManager();
613 if (eMode
== sw::mark::InsertMode::New
)
615 lcl_SetFieldMarks(*this, io_rDoc
, CH_TXT_ATR_FIELDSTART
, CH_TXT_ATR_FIELDEND
, pSepPos
);
619 lcl_AssertFieldMarksSet(*this, CH_TXT_ATR_FIELDSTART
, CH_TXT_ATR_FIELDEND
);
623 void TextFieldmark::ReleaseDoc(SwDoc
& rDoc
)
625 IDocumentUndoRedo
& rIDUR(rDoc
.GetIDocumentUndoRedo());
626 if (rIDUR
.DoesUndo())
628 rIDUR
.AppendUndo(std::make_unique
<SwUndoDelTextFieldmark
>(*this));
630 ::sw::UndoGuard
const ug(rIDUR
); // prevent SwUndoDeletes
631 lcl_RemoveFieldMarks(*this, rDoc
, CH_TXT_ATR_FIELDSTART
, CH_TXT_ATR_FIELDEND
);
632 // notify layouts to unhide - for the entire fieldmark, as in InitDoc()
633 SwPaM
const tmp(GetMarkPos(), GetOtherMarkPos());
634 sw::UpdateFramesForRemoveDeleteRedline(rDoc
, tmp
);
637 OUString
TextFieldmark::GetContent() const
639 const SwTextNode
& rTextNode
= *GetMarkEnd().GetNode().GetTextNode();
640 SwPosition
const sepPos(sw::mark::FindFieldSep(*this));
641 const sal_Int32
nStart(sepPos
.GetContentIndex());
642 const sal_Int32
nEnd(GetMarkEnd().GetContentIndex());
645 const sal_Int32 nLen
= rTextNode
.GetText().getLength();
646 if (nStart
+ 1 < nLen
&& nEnd
<= nLen
&& nEnd
> nStart
+ 2)
647 sContent
= rTextNode
.GetText().copy(nStart
+ 1, nEnd
- nStart
- 2);
652 void TextFieldmark::ReplaceContent(const OUString
& sNewContent
)
654 if (!m_pDocumentContentOperationsManager
)
657 SwPosition
const sepPos(sw::mark::FindFieldSep(*this));
658 const sal_Int32
nStart(sepPos
.GetContentIndex());
659 const sal_Int32
nEnd(GetMarkEnd().GetContentIndex());
661 const sal_Int32 nLen
= GetMarkEnd().GetNode().GetTextNode()->GetText().getLength();
662 if (nStart
+ 1 < nLen
&& nEnd
<= nLen
&& nEnd
> nStart
+ 2)
664 SwPaM
aFieldPam(GetMarkStart().GetNode(), nStart
+ 1,
665 GetMarkStart().GetNode(), nEnd
- 1);
666 m_pDocumentContentOperationsManager
->ReplaceRange(aFieldPam
, sNewContent
, false);
670 SwPaM
aFieldStartPam(GetMarkStart().GetNode(), nStart
+ 1);
671 m_pDocumentContentOperationsManager
->InsertString(aFieldStartPam
, sNewContent
);
676 NonTextFieldmark::NonTextFieldmark(const SwPaM
& rPaM
)
680 void NonTextFieldmark::InitDoc(SwDoc
& io_rDoc
,
681 sw::mark::InsertMode
const eMode
, SwPosition
const*const pSepPos
)
683 assert(pSepPos
== nullptr);
684 if (eMode
== sw::mark::InsertMode::New
)
686 lcl_SetFieldMarks(*this, io_rDoc
, CH_TXT_ATR_FIELDSTART
, CH_TXT_ATR_FORMELEMENT
, pSepPos
);
690 lcl_AssertFieldMarksSet(*this, CH_TXT_ATR_FIELDSTART
, CH_TXT_ATR_FORMELEMENT
);
694 void NonTextFieldmark::ReleaseDoc(SwDoc
& rDoc
)
696 IDocumentUndoRedo
& rIDUR(rDoc
.GetIDocumentUndoRedo());
697 if (rIDUR
.DoesUndo())
699 rIDUR
.AppendUndo(std::make_unique
<SwUndoDelNoTextFieldmark
>(*this));
701 ::sw::UndoGuard
const ug(rIDUR
); // prevent SwUndoDeletes
702 lcl_RemoveFieldMarks(*this, rDoc
,
703 CH_TXT_ATR_FIELDSTART
, CH_TXT_ATR_FORMELEMENT
);
707 CheckboxFieldmark::CheckboxFieldmark(const SwPaM
& rPaM
, const OUString
& rName
)
708 : NonTextFieldmark(rPaM
)
710 if (!rName
.isEmpty())
714 void CheckboxFieldmark::SetChecked(bool checked
)
716 if ( IsChecked() != checked
)
718 (*GetParameters())[OUString(ODF_FORMCHECKBOX_RESULT
)] <<= checked
;
719 // mark document as modified
720 SwDoc
& rDoc( GetMarkPos().GetDoc() );
721 rDoc
.getIDocumentState().SetModified();
725 bool CheckboxFieldmark::IsChecked() const
727 bool bResult
= false;
728 parameter_map_t::const_iterator pResult
= GetParameters()->find(OUString(ODF_FORMCHECKBOX_RESULT
));
729 if(pResult
!= GetParameters()->end())
730 pResult
->second
>>= bResult
;
734 OUString
CheckboxFieldmark::GetContent() const
736 return IsChecked() ? "1" : "0";
739 void CheckboxFieldmark::ReplaceContent(const OUString
& sNewContent
)
741 SetChecked(sNewContent
.toBoolean());
745 FieldmarkWithDropDownButton::FieldmarkWithDropDownButton(const SwPaM
& rPaM
)
746 : NonTextFieldmark(rPaM
)
751 FieldmarkWithDropDownButton::~FieldmarkWithDropDownButton()
753 m_pButton
.disposeAndClear();
756 void FieldmarkWithDropDownButton::RemoveButton()
759 m_pButton
.disposeAndClear();
762 void FieldmarkWithDropDownButton::LaunchPopup()
767 m_pButton
->Invalidate();
768 m_pButton
->LaunchPopup();
771 DropDownFieldmark::DropDownFieldmark(const SwPaM
& rPaM
, const OUString
& rName
)
772 : FieldmarkWithDropDownButton(rPaM
)
774 if (!rName
.isEmpty())
778 DropDownFieldmark::~DropDownFieldmark()
782 void DropDownFieldmark::ShowButton(SwEditWin
* pEditWin
)
787 m_pButton
= VclPtr
<DropDownFormFieldButton
>::Create(pEditWin
, *this);
788 m_pButton
->CalcPosAndSize(m_aPortionPaintArea
);
793 void DropDownFieldmark::RemoveButton()
795 FieldmarkWithDropDownButton::RemoveButton();
799 * @param pIndex The zero-based index to retrieve
800 * [in] if pIndex is null or negative, return the listbox's chosen result,
801 * else return the indicated entry (or last entry for invalid choice).
802 * [out] the index of the returned result or -1 if error
804 OUString
DropDownFieldmark::GetContent(sal_Int32
* pIndex
) const
806 sal_Int32 nIndex
= pIndex
? *pIndex
: -1;
807 auto rParameters
= *GetParameters();
809 rParameters
[ODF_FORMDROPDOWN_RESULT
] >>= nIndex
;
811 uno::Sequence
<OUString
> aSeq
;
812 rParameters
[ODF_FORMDROPDOWN_LISTENTRY
] >>= aSeq
;
813 nIndex
= std::min(nIndex
, aSeq
.getLength() - 1);
828 OUString
DropDownFieldmark::GetContent() const
830 return GetContent(nullptr);
833 /** AddContent : INSERTS a new choice
834 * @param rText: The choice to add to the list choices.
836 * @param pIndex [optional]
837 * [in] If pIndex is null or invalid, append to the end of the list.
838 * [out] Modified to point to the position of the choice if it already exists.
840 void DropDownFieldmark::AddContent(const OUString
& rText
, sal_Int32
* pIndex
)
842 uno::Sequence
<OUString
> aSeq
;
843 sw::mark::IFieldmark::parameter_map_t
* pParameters
= GetParameters();
844 (*pParameters
)[ODF_FORMDROPDOWN_LISTENTRY
] >>= aSeq
;
846 // no duplicates: if it already exists, modify the given index to point to it
847 const sal_Int32 nCurrentTextPos
= comphelper::findValue(aSeq
, rText
);
848 if (nCurrentTextPos
!= -1)
851 *pIndex
= nCurrentTextPos
;
855 const sal_Int32 nLen
= aSeq
.getLength();
856 const sal_Int32 nNewPos
= pIndex
&& *pIndex
> -1 ? std::min(*pIndex
, nLen
) : nLen
;
858 // need to shift list result index up if adding new entry before it
859 sal_Int32 nResultIndex
= -1;
860 (*pParameters
)[ODF_FORMDROPDOWN_RESULT
] >>= nResultIndex
;
861 if (nNewPos
<= nResultIndex
)
862 (*pParameters
)[ODF_FORMDROPDOWN_RESULT
] <<= nResultIndex
+ 1;
864 auto aList
= comphelper::sequenceToContainer
<std::vector
<OUString
>>(aSeq
);
866 aList
.insert(aList
.begin() + nNewPos
, rText
);
871 aList
.push_back(rText
);
874 (*pParameters
)[ODF_FORMDROPDOWN_LISTENTRY
] <<= comphelper::containerToSequence(aList
);
879 * ReplaceContent : changes the list result index or renames the existing choices
881 * [in] If pIndex is null, change the list result index to this provided choice
882 * (but do nothing if pText is an invalid choice)
883 * else rename that entry.
886 * [in] If pText is null, change the list result index to this provided Index
887 * (or the last position if it is an invalid choice)
888 * else rename this entry (doing nothing for invalid indexes).
889 * [out] If pIndex is invalid, it is modified to use the last position.
891 * This function allows duplicate entries - which is also allowed in MS Word.
893 void DropDownFieldmark::ReplaceContent(const OUString
* pText
, sal_Int32
* pIndex
)
895 if (!pIndex
&& !pText
)
898 uno::Sequence
<OUString
> aSeq
;
899 sw::mark::IFieldmark::parameter_map_t
* pParameters
= GetParameters();
900 (*pParameters
)[ODF_FORMDROPDOWN_LISTENTRY
] >>= aSeq
;
901 const sal_Int32 nLen
= aSeq
.getLength();
905 if (*pIndex
< 0 || *pIndex
>= nLen
)
908 // select pIndex as the new value for the list box
909 (*pParameters
)[ODF_FORMDROPDOWN_RESULT
] <<= *pIndex
;
916 const sal_Int32 nNewPos
= comphelper::findValue(aSeq
, *pText
);
919 (*pParameters
)[ODF_FORMDROPDOWN_RESULT
] <<= nNewPos
;
925 if (*pIndex
> -1 && *pIndex
< nLen
)
927 auto aList
= comphelper::sequenceToContainer
<std::vector
<OUString
>>(aSeq
);
928 aList
[*pIndex
] = *pText
;
929 (*pParameters
)[ODF_FORMDROPDOWN_LISTENTRY
] <<= comphelper::containerToSequence(aList
);
934 void DropDownFieldmark::ReplaceContent(const OUString
& rNewContent
)
936 ReplaceContent(&rNewContent
, nullptr);
940 * Remove everything if the given index is negative, else remove the given index (if valid).
941 * If deleting the currently selected choice, reset the selection to the first choice.
943 void DropDownFieldmark::DelContent(sal_Int32 nDelIndex
)
945 sw::mark::IFieldmark::parameter_map_t
* pParameters
= GetParameters();
946 uno::Sequence
<OUString
> aSeq
;
949 pParameters
->erase(ODF_FORMDROPDOWN_RESULT
);
950 (*pParameters
)[ODF_FORMDROPDOWN_LISTENTRY
] <<= aSeq
;
955 (*pParameters
)[ODF_FORMDROPDOWN_LISTENTRY
] >>= aSeq
;
956 if (nDelIndex
>= aSeq
.getLength())
959 // If deleting the current choice, select the first entry instead
960 // else need to shift list result index down if deleting an entry before it
961 sal_Int32 nResultIndex
= -1;
962 (*pParameters
)[ODF_FORMDROPDOWN_RESULT
] >>= nResultIndex
;
963 if (nDelIndex
== nResultIndex
)
965 else if (nDelIndex
< nResultIndex
)
968 comphelper::removeElementAt(aSeq
, nDelIndex
);
969 if (nResultIndex
!= -1)
970 (*pParameters
)[ODF_FORMDROPDOWN_RESULT
] <<= nResultIndex
;
971 (*pParameters
)[ODF_FORMDROPDOWN_LISTENTRY
] <<= aSeq
;
975 void DropDownFieldmark::SetPortionPaintArea(const SwRect
& rPortionPaintArea
)
977 m_aPortionPaintArea
= rPortionPaintArea
;
981 m_pButton
->CalcPosAndSize(m_aPortionPaintArea
);
985 void DropDownFieldmark::SendLOKShowMessage(const SfxViewShell
* pViewShell
)
987 if (!comphelper::LibreOfficeKit::isActive())
990 if (!pViewShell
|| pViewShell
->isLOKMobilePhone())
993 if (m_aPortionPaintArea
.IsEmpty())
996 OStringBuffer sPayload
;
997 sPayload
= OString::Concat("{\"action\": \"show\","
998 " \"type\": \"drop-down\", \"textArea\": \"") +
999 m_aPortionPaintArea
.SVRect().toString() + "\",";
1000 // Add field params to the message
1001 sPayload
.append(" \"params\": { \"items\": [");
1004 auto pParameters
= this->GetParameters();
1005 auto pListEntriesIter
= pParameters
->find(ODF_FORMDROPDOWN_LISTENTRY
);
1006 css::uno::Sequence
<OUString
> vListEntries
;
1007 if (pListEntriesIter
!= pParameters
->end())
1009 pListEntriesIter
->second
>>= vListEntries
;
1010 for (const OUString
& sItem
: std::as_const(vListEntries
))
1011 sPayload
.append("\"" + OUStringToOString(sItem
, RTL_TEXTENCODING_UTF8
) + "\", ");
1012 sPayload
.setLength(sPayload
.getLength() - 2);
1014 sPayload
.append("], ");
1017 auto pSelectedItemIter
= pParameters
->find(ODF_FORMDROPDOWN_RESULT
);
1018 sal_Int32 nSelection
= -1;
1019 if (pSelectedItemIter
!= pParameters
->end())
1021 pSelectedItemIter
->second
>>= nSelection
;
1023 sPayload
.append("\"selected\": \"" + OString::number(nSelection
) + "\", ");
1026 sPayload
.append("\"placeholderText\": \"" + OUStringToOString(SwResId(STR_DROP_DOWN_EMPTY_LIST
), RTL_TEXTENCODING_UTF8
) + "\"}}");
1027 pViewShell
->libreOfficeKitViewCallback(LOK_CALLBACK_FORM_FIELD_BUTTON
, sPayload
.toString());
1030 void DropDownFieldmark::SendLOKHideMessage(const SfxViewShell
* pViewShell
)
1032 pViewShell
->libreOfficeKitViewCallback(LOK_CALLBACK_FORM_FIELD_BUTTON
,
1033 "{\"action\": \"hide\", \"type\": \"drop-down\"}");
1036 DateFieldmark::DateFieldmark(const SwPaM
& rPaM
)
1037 : FieldmarkWithDropDownButton(rPaM
)
1038 , m_pNumberFormatter(nullptr)
1039 , m_pDocumentContentOperationsManager(nullptr)
1043 DateFieldmark::~DateFieldmark()
1047 void DateFieldmark::InitDoc(SwDoc
& io_rDoc
,
1048 sw::mark::InsertMode eMode
, SwPosition
const*const pSepPos
)
1050 m_pNumberFormatter
= io_rDoc
.GetNumberFormatter();
1051 m_pDocumentContentOperationsManager
= &io_rDoc
.GetDocumentContentOperationsManager();
1052 if (eMode
== sw::mark::InsertMode::New
)
1054 lcl_SetFieldMarks(*this, io_rDoc
, CH_TXT_ATR_FIELDSTART
, CH_TXT_ATR_FIELDEND
, pSepPos
);
1058 lcl_AssertFieldMarksSet(*this, CH_TXT_ATR_FIELDSTART
, CH_TXT_ATR_FIELDEND
);
1062 void DateFieldmark::ReleaseDoc(SwDoc
& rDoc
)
1064 IDocumentUndoRedo
& rIDUR(rDoc
.GetIDocumentUndoRedo());
1065 if (rIDUR
.DoesUndo())
1067 // TODO does this need a 3rd Undo class?
1068 rIDUR
.AppendUndo(std::make_unique
<SwUndoDelTextFieldmark
>(*this));
1070 ::sw::UndoGuard
const ug(rIDUR
); // prevent SwUndoDeletes
1071 lcl_RemoveFieldMarks(*this, rDoc
, CH_TXT_ATR_FIELDSTART
, CH_TXT_ATR_FIELDEND
);
1072 // notify layouts to unhide - for the entire fieldmark, as in InitDoc()
1073 SwPaM
const tmp(GetMarkPos(), GetOtherMarkPos());
1074 sw::UpdateFramesForRemoveDeleteRedline(rDoc
, tmp
);
1077 void DateFieldmark::ShowButton(SwEditWin
* pEditWin
)
1082 m_pButton
= VclPtr
<DateFormFieldButton
>::Create(pEditWin
, *this, m_pNumberFormatter
);
1083 SwRect
aPaintArea(m_aPaintAreaStart
.TopLeft(), m_aPaintAreaEnd
.BottomRight());
1084 m_pButton
->CalcPosAndSize(aPaintArea
);
1089 void DateFieldmark::SetPortionPaintAreaStart(const SwRect
& rPortionPaintArea
)
1091 if (rPortionPaintArea
.IsEmpty())
1094 m_aPaintAreaStart
= rPortionPaintArea
;
1095 InvalidateCurrentDateParam();
1098 void DateFieldmark::SetPortionPaintAreaEnd(const SwRect
& rPortionPaintArea
)
1100 if (rPortionPaintArea
.IsEmpty())
1103 if(m_aPaintAreaEnd
== rPortionPaintArea
&&
1104 m_pButton
&& m_pButton
->IsVisible())
1107 m_aPaintAreaEnd
= rPortionPaintArea
;
1111 SwRect
aPaintArea(m_aPaintAreaStart
.TopLeft(), m_aPaintAreaEnd
.BottomRight());
1112 m_pButton
->CalcPosAndSize(aPaintArea
);
1113 m_pButton
->Invalidate();
1115 InvalidateCurrentDateParam();
1118 OUString
DateFieldmark::GetContent() const
1120 const SwTextNode
* const pTextNode
= GetMarkEnd().GetNode().GetTextNode();
1121 SwPosition
const sepPos(sw::mark::FindFieldSep(*this));
1122 const sal_Int32
nStart(sepPos
.GetContentIndex());
1123 const sal_Int32
nEnd (GetMarkEnd().GetContentIndex());
1126 if(nStart
+ 1 < pTextNode
->GetText().getLength() && nEnd
<= pTextNode
->GetText().getLength() &&
1128 sContent
= pTextNode
->GetText().copy(nStart
+ 1, nEnd
- nStart
- 2);
1132 void DateFieldmark::ReplaceContent(const OUString
& sNewContent
)
1134 if(!m_pDocumentContentOperationsManager
)
1137 const SwTextNode
* const pTextNode
= GetMarkEnd().GetNode().GetTextNode();
1138 SwPosition
const sepPos(sw::mark::FindFieldSep(*this));
1139 const sal_Int32
nStart(sepPos
.GetContentIndex());
1140 const sal_Int32
nEnd (GetMarkEnd().GetContentIndex());
1142 if(nStart
+ 1 < pTextNode
->GetText().getLength() && nEnd
<= pTextNode
->GetText().getLength() &&
1145 SwPaM
aFieldPam(GetMarkStart().GetNode(), nStart
+ 1,
1146 GetMarkStart().GetNode(), nEnd
- 1);
1147 m_pDocumentContentOperationsManager
->ReplaceRange(aFieldPam
, sNewContent
, false);
1151 SwPaM
aFieldStartPam(GetMarkStart().GetNode(), nStart
+ 1);
1152 m_pDocumentContentOperationsManager
->InsertString(aFieldStartPam
, sNewContent
);
1157 std::pair
<bool, double> DateFieldmark::GetCurrentDate() const
1159 // Check current date param first
1160 std::pair
<bool, double> aResult
= ParseCurrentDateParam();
1164 const sw::mark::IFieldmark::parameter_map_t
* pParameters
= GetParameters();
1165 bool bFoundValidDate
= false;
1166 double dCurrentDate
= 0;
1167 OUString sDateFormat
;
1168 auto pResult
= pParameters
->find(ODF_FORMDATE_DATEFORMAT
);
1169 if (pResult
!= pParameters
->end())
1171 pResult
->second
>>= sDateFormat
;
1175 pResult
= pParameters
->find(ODF_FORMDATE_DATEFORMAT_LANGUAGE
);
1176 if (pResult
!= pParameters
->end())
1178 pResult
->second
>>= sLang
;
1181 // Get current content of the field
1182 OUString sContent
= GetContent();
1184 sal_uInt32 nFormat
= m_pNumberFormatter
->GetEntryKey(sDateFormat
, LanguageTag(sLang
).getLanguageType());
1185 if (nFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
1187 sal_Int32 nCheckPos
= 0;
1188 SvNumFormatType nType
;
1189 m_pNumberFormatter
->PutEntry(sDateFormat
,
1193 LanguageTag(sLang
).getLanguageType());
1196 if (nFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
1198 bFoundValidDate
= m_pNumberFormatter
->IsNumberFormat(sContent
, nFormat
, dCurrentDate
);
1200 return std::pair
<bool, double>(bFoundValidDate
, dCurrentDate
);
1203 void DateFieldmark::SetCurrentDate(double fDate
)
1205 // Replace current content with the selected date
1206 ReplaceContent(GetDateInCurrentDateFormat(fDate
));
1208 // Also save the current date in a standard format
1209 sw::mark::IFieldmark::parameter_map_t
* pParameters
= GetParameters();
1210 (*pParameters
)[ODF_FORMDATE_CURRENTDATE
] <<= GetDateInStandardDateFormat(fDate
);
1213 OUString
DateFieldmark::GetDateInStandardDateFormat(double fDate
) const
1215 OUString sCurrentDate
;
1216 sal_uInt32 nFormat
= m_pNumberFormatter
->GetEntryKey(ODF_FORMDATE_CURRENTDATE_FORMAT
, ODF_FORMDATE_CURRENTDATE_LANGUAGE
);
1217 if (nFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
1219 sal_Int32 nCheckPos
= 0;
1220 SvNumFormatType nType
;
1221 OUString sFormat
= ODF_FORMDATE_CURRENTDATE_FORMAT
;
1222 m_pNumberFormatter
->PutEntry(sFormat
,
1226 ODF_FORMDATE_CURRENTDATE_LANGUAGE
);
1229 if (nFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
1231 const Color
* pCol
= nullptr;
1232 m_pNumberFormatter
->GetOutputString(fDate
, nFormat
, sCurrentDate
, &pCol
, false);
1234 return sCurrentDate
;
1237 std::pair
<bool, double> DateFieldmark::ParseCurrentDateParam() const
1239 bool bFoundValidDate
= false;
1240 double dCurrentDate
= 0;
1242 const sw::mark::IFieldmark::parameter_map_t
* pParameters
= GetParameters();
1243 auto pResult
= pParameters
->find(ODF_FORMDATE_CURRENTDATE
);
1244 OUString sCurrentDate
;
1245 if (pResult
!= pParameters
->end())
1247 pResult
->second
>>= sCurrentDate
;
1249 if(!sCurrentDate
.isEmpty())
1251 sal_uInt32 nFormat
= m_pNumberFormatter
->GetEntryKey(ODF_FORMDATE_CURRENTDATE_FORMAT
, ODF_FORMDATE_CURRENTDATE_LANGUAGE
);
1252 if (nFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
1254 sal_Int32 nCheckPos
= 0;
1255 SvNumFormatType nType
;
1256 OUString sFormat
= ODF_FORMDATE_CURRENTDATE_FORMAT
;
1257 m_pNumberFormatter
->PutEntry(sFormat
,
1261 ODF_FORMDATE_CURRENTDATE_LANGUAGE
);
1264 if(nFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
1266 bFoundValidDate
= m_pNumberFormatter
->IsNumberFormat(sCurrentDate
, nFormat
, dCurrentDate
);
1269 return std::pair
<bool, double>(bFoundValidDate
, dCurrentDate
);
1273 OUString
DateFieldmark::GetDateInCurrentDateFormat(double fDate
) const
1275 // Get current date format and language
1276 OUString sDateFormat
;
1277 const sw::mark::IFieldmark::parameter_map_t
* pParameters
= GetParameters();
1278 auto pResult
= pParameters
->find(ODF_FORMDATE_DATEFORMAT
);
1279 if (pResult
!= pParameters
->end())
1281 pResult
->second
>>= sDateFormat
;
1285 pResult
= pParameters
->find(ODF_FORMDATE_DATEFORMAT_LANGUAGE
);
1286 if (pResult
!= pParameters
->end())
1288 pResult
->second
>>= sLang
;
1291 // Fill the content with the specified format
1292 OUString sCurrentContent
;
1293 sal_uInt32 nFormat
= m_pNumberFormatter
->GetEntryKey(sDateFormat
, LanguageTag(sLang
).getLanguageType());
1294 if (nFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
1296 sal_Int32 nCheckPos
= 0;
1297 SvNumFormatType nType
;
1298 OUString sFormat
= sDateFormat
;
1299 m_pNumberFormatter
->PutEntry(sFormat
,
1303 LanguageTag(sLang
).getLanguageType());
1306 if (nFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
1308 const Color
* pCol
= nullptr;
1309 m_pNumberFormatter
->GetOutputString(fDate
, nFormat
, sCurrentContent
, &pCol
, false);
1311 return sCurrentContent
;
1314 void DateFieldmark::InvalidateCurrentDateParam()
1316 std::pair
<bool, double> aResult
= ParseCurrentDateParam();
1320 // Current date became invalid
1321 if(GetDateInCurrentDateFormat(aResult
.second
) != GetContent())
1323 sw::mark::IFieldmark::parameter_map_t
* pParameters
= GetParameters();
1324 (*pParameters
)[ODF_FORMDATE_CURRENTDATE
] <<= OUString();
1329 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */