Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / core / edit / edtox.cxx
blob655a6dfd0174e0fb3becda8a1943d50bbd82f84a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
34 #include <editsh.hxx>
35 #include <doc.hxx>
36 #include <IDocumentContentOperations.hxx>
37 #include <IDocumentUndoRedo.hxx>
38 #include <pam.hxx>
39 #include <swundo.hxx>
40 #include <tox.hxx>
41 #include <doctxm.hxx>
42 #include <docary.hxx>
43 #include <mdiexp.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();
57 StartAllAction();
58 for(SwPaM& rPaM : GetCursor()->GetRingContainer())
60 auto [pStt, pEnd] = rPaM.StartEnd(); // SwPosition*
61 if( bInsAtPos )
63 SwPaM aTmp( *pStt );
64 GetDoc()->getIDocumentContentOperations().InsertPoolItem( aTmp, rMark );
66 else if( *pEnd != *pStt )
68 GetDoc()->getIDocumentContentOperations().InsertPoolItem(
69 rPaM, rMark, SetAttrMode::DONTEXPAND );
73 EndAllAction();
76 void SwEditShell::DeleteTOXMark( SwTOXMark const * pMark )
78 CurrShell aCurr( this );
79 StartAllAction();
81 mxDoc->DeleteTOXMark( pMark );
83 EndAllAction();
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 );
125 StartAllAction();
127 SwDocShell* pDocSh = GetDoc()->GetDocShell();
128 ::StartProgress( STR_STATSTR_TOX_INSERT, 0, 0, pDocSh );
130 // Insert listing
131 const SwTOXBaseSection* pTOX = mxDoc->InsertTableOf(
132 *GetCursor()->GetPoint(), rTOX, pSet, true, GetLayout() );
133 OSL_ENSURE(pTOX, "No current TOX");
135 // start formatting
136 CalcLayout();
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 );
146 EndAllAction();
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())
155 return;
157 SwDoc* pMyDoc = GetDoc();
158 SwDocShell* pDocSh = pMyDoc->GetDocShell();
160 bool bInIndex = &rTOX == GetCurTOX();
161 CurrShell aCurr( this );
162 StartAllAction();
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());
171 // correct Cursor
172 if( bInIndex )
173 rTOXSect.SetPosAtStartEnd(*GetCursor()->GetPoint());
175 // start formatting
176 // tdf#139426 ...but allow suppression of AssertFlyPages
177 GetLayout()->SetTableUpdateInProgress(true);
178 CalcLayout();
179 GetLayout()->SetTableUpdateInProgress(false);
181 // insert page numbering
182 rTOXSect.UpdatePageNum();
184 pMyDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::TOXCHANGE, nullptr);
186 ::EndProgress( pDocSh );
187 EndAllAction();
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();
218 sal_uInt16 nRet = 0;
219 for( auto n = rFormats.size(); n; )
221 const SwSection* pSect = rFormats[ --n ]->GetSection();
222 if( SectionType::ToxContent == pSect->GetType() &&
223 pSect->GetFormat()->GetSectionNode() )
224 ++nRet;
226 return nRet;
229 const SwTOXBase* SwEditShell::GetTOX( sal_uInt16 nPos ) const
231 const SwSectionFormats& rFormats = GetDoc()->GetSections();
232 sal_uInt16 nCnt {0};
233 for( const SwSectionFormat *pFormat : rFormats )
235 const SwSection* pSect = pFormat->GetSection();
236 if( SectionType::ToxContent == pSect->GetType() &&
237 pSect->GetFormat()->GetSectionNode() &&
238 nCnt++ == nPos )
240 assert( dynamic_cast<const SwTOXBaseSection*>( pSect) && "no TOXBaseSection!" );
241 return static_cast<const SwTOXBaseSection*>(pSect);
244 return nullptr;
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()
270 StartAllAction();
271 bool bDoesUndo = DoesUndo();
272 DoUndo(false);
273 //1. remove all automatic generated index entries if AutoMarkURL has a
274 // length and the file exists
275 //2. load file
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 ))
282 //1.
283 const SwTOXType* pTOXType = GetTOXType(TOX_INDEX, 0);
285 SwTOXMarks aMarks;
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);
294 //2.
295 SfxMedium aMedium( sAutoMarkURL, StreamMode::STD_READ );
296 SvStream& rStrm = *aMedium.GetInStream();
297 Push();
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,
311 "", "",
312 SvtSysLocale().GetLanguageTag().getLocale(),
313 nLEV_Other, nLEV_Longer, nLEV_Shorter,
314 TransliterationFlags::NONE,
315 SearchAlgorithms2::ABSOLUTE,
316 '\\' );
318 OStringBuffer aRdLine;
319 while (rStrm.good())
321 rStrm.ReadLine( aRdLine );
323 // # -> comment
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);
341 //3.
342 bool bCaseSensitive = !sCase.isEmpty() && sCase != "0";
343 bool bWordOnly = !sWordOnly.isEmpty() && sWordOnly != "0";
345 if (!bCaseSensitive)
347 aSearchOpt.transliterateFlags |=
348 TransliterationFlags::IGNORE_CASE;
350 else
352 aSearchOpt.transliterateFlags &=
353 ~TransliterationFlags::IGNORE_CASE;
355 if ( bWordOnly)
356 aSearchOpt.searchFlag |= SearchFlags::NORM_WORD_ONLY;
357 else
358 aSearchOpt.searchFlag &= ~SearchFlags::NORM_WORD_ONLY;
360 aSearchOpt.searchString = sToSelect;
362 KillPams();
363 bool bCancel;
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 );
369 if(nRet)
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);
382 //4.
383 SwEditShell::Insert(*pTmpMark);
388 KillPams();
389 Pop(PopMode::DeleteCurrent);
391 DoUndo(bDoesUndo);
392 EndAllAction();
395 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */