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 .
20 #include <com/sun/star/util/SearchAlgorithms2.hpp>
21 #include <com/sun/star/util/SearchFlags.hpp>
22 #include <i18nlangtag/languagetag.hxx>
23 #include <i18nutil/transliteration.hxx>
24 #include <i18nutil/searchopt.hxx>
25 #include <svl/fstathelper.hxx>
26 #include <osl/diagnose.h>
27 #include <osl/thread.h>
28 #include <unotools/syslocale.hxx>
30 #include <sfx2/docfile.hxx>
32 #include <swtypes.hxx>
33 #include <rootfrm.hxx>
36 #include <IDocumentContentOperations.hxx>
37 #include <IDocumentUndoRedo.hxx>
44 #include <strings.hrc>
45 #include <iodetect.hxx>
47 using namespace ::com::sun::star
;
48 using namespace ::com::sun::star::i18n
;
49 using namespace ::com::sun::star::lang
;
50 using namespace ::com::sun::star::util
;
52 // Add/delete listing markers to a document
54 void SwEditShell::Insert(const SwTOXMark
& rMark
)
56 bool bInsAtPos
= rMark
.IsAlternativeText();
58 for(SwPaM
& rPaM
: GetCursor()->GetRingContainer())
60 auto [pStt
, pEnd
] = rPaM
.StartEnd(); // SwPosition*
64 GetDoc()->getIDocumentContentOperations().InsertPoolItem( aTmp
, rMark
);
66 else if( *pEnd
!= *pStt
)
68 GetDoc()->getIDocumentContentOperations().InsertPoolItem(
69 rPaM
, rMark
, SetAttrMode::DONTEXPAND
);
76 void SwEditShell::DeleteTOXMark( SwTOXMark
const * pMark
)
78 CurrShell
aCurr( this );
81 mxDoc
->DeleteTOXMark( pMark
);
86 /// Collect all listing markers
87 void SwEditShell::GetCurTOXMarks(SwTOXMarks
& rMarks
) const
89 SwDoc::GetCurTOXMark( *GetCursor()->Start(), rMarks
);
92 bool SwEditShell::IsTOXBaseReadonly(const SwTOXBase
& rTOXBase
)
94 assert( dynamic_cast<const SwTOXBaseSection
*>( &rTOXBase
) && "no TOXBaseSection!" );
95 const SwTOXBaseSection
& rTOXSect
= static_cast<const SwTOXBaseSection
&>(rTOXBase
);
96 return rTOXSect
.IsProtect();
99 void SwEditShell::SetTOXBaseReadonly(const SwTOXBase
& rTOXBase
, bool bReadonly
)
101 assert( dynamic_cast<const SwTOXBaseSection
*>( &rTOXBase
) && "no TOXBaseSection!" );
102 const SwTOXBaseSection
& rTOXSect
= static_cast<const SwTOXBaseSection
&>(rTOXBase
);
103 const_cast<SwTOXBase
&>(rTOXBase
).SetProtected(bReadonly
);
104 OSL_ENSURE( rTOXSect
.SwSection::GetType() == SectionType::ToxContent
, "not a TOXContentSection" );
106 SwSectionData
aSectionData(rTOXSect
);
107 aSectionData
.SetProtectFlag(bReadonly
);
108 UpdateSection( GetSectionFormatPos( *rTOXSect
.GetFormat() ), aSectionData
);
111 const SwTOXBase
* SwEditShell::GetDefaultTOXBase( TOXTypes eTyp
, bool bCreate
)
113 return GetDoc()->GetDefaultTOXBase( eTyp
, bCreate
);
116 void SwEditShell::SetDefaultTOXBase(const SwTOXBase
& rBase
)
118 GetDoc()->SetDefaultTOXBase(rBase
);
121 /// Insert listing and create content
122 void SwEditShell::InsertTableOf( const SwTOXBase
& rTOX
, const SfxItemSet
* pSet
)
124 CurrShell
aCurr( this );
127 SwDocShell
* pDocSh
= GetDoc()->GetDocShell();
128 ::StartProgress( STR_STATSTR_TOX_INSERT
, 0, 0, pDocSh
);
131 const SwTOXBaseSection
* pTOX
= mxDoc
->InsertTableOf(
132 *GetCursor()->GetPoint(), rTOX
, pSet
, true, GetLayout() );
133 OSL_ENSURE(pTOX
, "No current TOX");
138 // insert page numbering
139 const_cast<SwTOXBaseSection
*>(pTOX
)->UpdatePageNum();
141 pTOX
->SetPosAtStartEnd( *GetCursor()->GetPoint() );
143 // Fix for empty listing
144 InvalidateWindows( maVisArea
);
145 ::EndProgress( pDocSh
);
149 /// update tables of content
150 void SwEditShell::UpdateTableOf(const SwTOXBase
& rTOX
, const SfxItemSet
* pSet
)
152 assert(dynamic_cast<const SwTOXBaseSection
*>(&rTOX
) && "no TOXBaseSection!");
153 SwTOXBaseSection
& rTOXSect
= static_cast<SwTOXBaseSection
&>(const_cast<SwTOXBase
&>(rTOX
));
154 if (!rTOXSect
.GetFormat()->GetSectionNode())
157 SwDoc
* pMyDoc
= GetDoc();
158 SwDocShell
* pDocSh
= pMyDoc
->GetDocShell();
160 bool bInIndex
= &rTOX
== GetCurTOX();
161 CurrShell
aCurr( this );
164 ::StartProgress( STR_STATSTR_TOX_UPDATE
, 0, 0, pDocSh
);
166 pMyDoc
->GetIDocumentUndoRedo().StartUndo(SwUndoId::TOXCHANGE
, nullptr);
168 // create listing stub
169 rTOXSect
.Update(pSet
, GetLayout());
173 rTOXSect
.SetPosAtStartEnd(*GetCursor()->GetPoint());
176 // tdf#139426 ...but allow suppression of AssertFlyPages
177 GetLayout()->SetTableUpdateInProgress(true);
179 GetLayout()->SetTableUpdateInProgress(false);
181 // insert page numbering
182 rTOXSect
.UpdatePageNum();
184 pMyDoc
->GetIDocumentUndoRedo().EndUndo(SwUndoId::TOXCHANGE
, nullptr);
186 ::EndProgress( pDocSh
);
190 /// Get current listing before or at the Cursor
191 const SwTOXBase
* SwEditShell::GetCurTOX() const
193 return SwDoc::GetCurTOX( *GetCursor()->GetPoint() );
196 bool SwEditShell::DeleteTOX( const SwTOXBase
& rTOXBase
, bool bDelNodes
)
198 return GetDoc()->DeleteTOX( rTOXBase
, bDelNodes
);
201 // manage types of listings
203 const SwTOXType
* SwEditShell::GetTOXType(TOXTypes eTyp
, sal_uInt16 nId
) const
205 return mxDoc
->GetTOXType(eTyp
, nId
);
208 // manage keys for the alphabetical index
210 void SwEditShell::GetTOIKeys( SwTOIKeyType eTyp
, std::vector
<OUString
>& rArr
) const
212 GetDoc()->GetTOIKeys( eTyp
, rArr
, *GetLayout() );
215 sal_uInt16
SwEditShell::GetTOXCount() const
217 const SwSectionFormats
& rFormats
= GetDoc()->GetSections();
219 for( auto n
= rFormats
.size(); n
; )
221 const SwSection
* pSect
= rFormats
[ --n
]->GetSection();
222 if( SectionType::ToxContent
== pSect
->GetType() &&
223 pSect
->GetFormat()->GetSectionNode() )
229 const SwTOXBase
* SwEditShell::GetTOX( sal_uInt16 nPos
) const
231 const SwSectionFormats
& rFormats
= GetDoc()->GetSections();
233 for( const SwSectionFormat
*pFormat
: rFormats
)
235 const SwSection
* pSect
= pFormat
->GetSection();
236 if( SectionType::ToxContent
== pSect
->GetType() &&
237 pSect
->GetFormat()->GetSectionNode() &&
240 assert( dynamic_cast<const SwTOXBaseSection
*>( pSect
) && "no TOXBaseSection!" );
241 return static_cast<const SwTOXBaseSection
*>(pSect
);
247 /** Update of all listings after reading-in a file */
248 void SwEditShell::SetUpdateTOX( bool bFlag
)
250 GetDoc()->SetUpdateTOX( bFlag
);
253 bool SwEditShell::IsUpdateTOX() const
255 return GetDoc()->IsUpdateTOX();
258 OUString
const & SwEditShell::GetTOIAutoMarkURL() const
260 return GetDoc()->GetTOIAutoMarkURL();
263 void SwEditShell::SetTOIAutoMarkURL(const OUString
& rSet
)
265 GetDoc()->SetTOIAutoMarkURL(rSet
);
268 void SwEditShell::ApplyAutoMark()
271 bool bDoesUndo
= DoesUndo();
273 //1. remove all automatic generated index entries if AutoMarkURL has a
274 // length and the file exists
276 //3. select all occurrences of the searched words
277 //4. apply index entries
279 OUString
sAutoMarkURL(GetDoc()->GetTOIAutoMarkURL());
280 if( !sAutoMarkURL
.isEmpty() && FStatHelper::IsDocument( sAutoMarkURL
))
283 const SwTOXType
* pTOXType
= GetTOXType(TOX_INDEX
, 0);
286 pTOXType
->CollectTextMarks(aMarks
);
287 for( SwTOXMark
* pMark
: aMarks
)
289 if(pMark
->IsAutoGenerated() && pMark
->GetTextTOXMark())
290 // mba: test iteration; objects are deleted in iteration
291 DeleteTOXMark(pMark
);
295 SfxMedium
aMedium( sAutoMarkURL
, StreamMode::STD_READ
);
296 SvStream
& rStrm
= *aMedium
.GetInStream();
298 // tdf#106899 - import tox concordance file using the appropriate character set
299 rtl_TextEncoding eChrSet
= SwIoSystem::GetTextEncoding(rStrm
);
300 if (eChrSet
== RTL_TEXTENCODING_DONTKNOW
)
301 eChrSet
= ::osl_getThreadTextEncoding();
303 // SearchOptions to be used in loop below
304 sal_Int32
const nLEV_Other
= 2; // -> changedChars;
305 sal_Int32
const nLEV_Longer
= 3; //! -> deletedChars;
306 sal_Int32
const nLEV_Shorter
= 1; //! -> insertedChars;
308 i18nutil::SearchOptions2
aSearchOpt(
309 SearchAlgorithms_ABSOLUTE
,
310 SearchFlags::LEV_RELAXED
,
312 SvtSysLocale().GetLanguageTag().getLocale(),
313 nLEV_Other
, nLEV_Longer
, nLEV_Shorter
,
314 TransliterationFlags::NONE
,
315 SearchAlgorithms2::ABSOLUTE
,
318 OStringBuffer aRdLine
;
321 rStrm
.ReadLine( aRdLine
);
324 // ; -> delimiter between entries ->
325 // Format: TextToSearchFor;AlternativeString;PrimaryKey;SecondaryKey;CaseSensitive;WordOnly
326 // Leading and trailing blanks are ignored
327 if( !aRdLine
.isEmpty() && '#' != aRdLine
[0] )
329 OUString
sLine(OStringToOUString(aRdLine
, eChrSet
));
331 sal_Int32 nTokenPos
= 0;
332 OUString
sToSelect( sLine
.getToken(0, ';', nTokenPos
) );
333 if( !sToSelect
.isEmpty() )
335 OUString sAlternative
= sLine
.getToken(0, ';', nTokenPos
);
336 OUString sPrimary
= sLine
.getToken(0, ';', nTokenPos
);
337 OUString sSecondary
= sLine
.getToken(0, ';', nTokenPos
);
338 OUString sCase
= sLine
.getToken(0, ';', nTokenPos
);
339 OUString sWordOnly
= sLine
.getToken(0, ';', nTokenPos
);
342 bool bCaseSensitive
= !sCase
.isEmpty() && sCase
!= "0";
343 bool bWordOnly
= !sWordOnly
.isEmpty() && sWordOnly
!= "0";
347 aSearchOpt
.transliterateFlags
|=
348 TransliterationFlags::IGNORE_CASE
;
352 aSearchOpt
.transliterateFlags
&=
353 ~TransliterationFlags::IGNORE_CASE
;
356 aSearchOpt
.searchFlag
|= SearchFlags::NORM_WORD_ONLY
;
358 aSearchOpt
.searchFlag
&= ~SearchFlags::NORM_WORD_ONLY
;
360 aSearchOpt
.searchString
= sToSelect
;
365 // todo/mba: assuming that notes shouldn't be searched
366 sal_Int32 nRet
= Find_Text(aSearchOpt
, false/*bSearchInNotes*/, SwDocPositions::Start
, SwDocPositions::End
, bCancel
,
367 FindRanges::InSelAll
);
371 SwTOXMark
* pTmpMark
= new SwTOXMark(pTOXType
);
372 if( !sPrimary
.isEmpty() )
374 pTmpMark
->SetPrimaryKey( sPrimary
);
375 if( !sSecondary
.isEmpty() )
376 pTmpMark
->SetSecondaryKey( sSecondary
);
378 if( !sAlternative
.isEmpty() )
379 pTmpMark
->SetAlternativeText(sAlternative
);
380 pTmpMark
->SetMainEntry(false);
381 pTmpMark
->SetAutoGenerated(true);
383 SwEditShell::Insert(*pTmpMark
);
389 Pop(PopMode::DeleteCurrent
);
395 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */