/src/libreoffice/sw/source/uibase/misc/glosdoc.cxx
Line | Count | Source |
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 <algorithm> |
21 | | #include <string_view> |
22 | | |
23 | | #include <com/sun/star/container/XNamed.hpp> |
24 | | #include <com/sun/star/ucb/InteractiveIOException.hpp> |
25 | | |
26 | | #include <comphelper/diagnose_ex.hxx> |
27 | | #include <comphelper/processfactory.hxx> |
28 | | #include <comphelper/servicehelper.hxx> |
29 | | |
30 | | #include <unotools/transliterationwrapper.hxx> |
31 | | |
32 | | #include <vcl/errinf.hxx> |
33 | | #include <vcl/svapp.hxx> |
34 | | #include <vcl/weld/MessageDialog.hxx> |
35 | | #include <osl/diagnose.h> |
36 | | #include <osl/file.hxx> |
37 | | #include <rtl/character.hxx> |
38 | | #include <svl/urihelper.hxx> |
39 | | #include <svl/fstathelper.hxx> |
40 | | #include <ucbhelper/content.hxx> |
41 | | #include <unotools/pathoptions.hxx> |
42 | | #include <unotools/tempfile.hxx> |
43 | | #include <o3tl/string_view.hxx> |
44 | | #include <swtypes.hxx> |
45 | | #include <glosdoc.hxx> |
46 | | #include <shellio.hxx> |
47 | | #include <swunohelper.hxx> |
48 | | |
49 | | #include <unoatxt.hxx> |
50 | | #include <swerror.h> |
51 | | #include <strings.hrc> |
52 | | |
53 | | #include <memory> |
54 | | |
55 | | #ifdef _WIN32 |
56 | | #include <o3tl/char16_t2wchar_t.hxx> |
57 | | #include <shlwapi.h> |
58 | | #endif |
59 | | |
60 | | using namespace ::com::sun::star; |
61 | | using namespace ::com::sun::star::uno; |
62 | | |
63 | | namespace |
64 | | { |
65 | | |
66 | | OUString lcl_FullPathName(std::u16string_view sPath, std::u16string_view sName) |
67 | 0 | { |
68 | 0 | return OUString::Concat(sPath) + "/" + sName + SwGlossaries::GetExtension(); |
69 | 0 | } |
70 | | |
71 | | OUString lcl_CheckFileName( const OUString& rNewFilePath, |
72 | | std::u16string_view aNewGroupName ) |
73 | 0 | { |
74 | 0 | const sal_Int32 nLen = aNewGroupName.size(); |
75 | 0 | OUStringBuffer aBuf(nLen); |
76 | | //group name should contain only A-Z and a-z and spaces |
77 | 0 | for( sal_Int32 i=0; i < nLen; ++i ) |
78 | 0 | { |
79 | 0 | const sal_Unicode cChar = aNewGroupName[i]; |
80 | 0 | if (rtl::isAsciiAlphanumeric(cChar) || |
81 | 0 | cChar == '_' || cChar == 0x20) |
82 | 0 | { |
83 | 0 | aBuf.append(cChar); |
84 | 0 | } |
85 | 0 | } |
86 | |
|
87 | 0 | const OUString sRet = aBuf.makeStringAndClear().trim(); |
88 | 0 | if ( !sRet.isEmpty() ) |
89 | 0 | { |
90 | 0 | if (!FStatHelper::IsDocument( lcl_FullPathName(rNewFilePath, sRet) )) |
91 | 0 | return sRet; |
92 | 0 | } |
93 | | |
94 | | //generate generic name |
95 | 0 | utl::TempFileNamed aTemp(u"group", true, SwGlossaries::GetExtension(), &rNewFilePath); |
96 | 0 | aTemp.EnableKillingFile(); |
97 | |
|
98 | 0 | INetURLObject aTempURL( aTemp.GetURL() ); |
99 | 0 | return aTempURL.GetBase(); |
100 | 0 | } |
101 | | |
102 | | } |
103 | | |
104 | | // supplies the default group's name |
105 | | OUString SwGlossaries::GetDefName() |
106 | 0 | { |
107 | 0 | return u"standard"_ustr; |
108 | |
|
109 | 0 | } |
110 | | |
111 | | // supplies the number of text block groups |
112 | | size_t SwGlossaries::GetGroupCnt() |
113 | 0 | { |
114 | 0 | return GetNameList().size(); |
115 | 0 | } |
116 | | |
117 | | // supplies the group's name |
118 | | bool SwGlossaries::FindGroupName(OUString& rGroup) |
119 | 0 | { |
120 | | // if the group name doesn't contain a path, a suitable group entry |
121 | | // can the searched for here; |
122 | 0 | const size_t nCount = GetGroupCnt(); |
123 | 0 | for(size_t i = 0; i < nCount; ++i) |
124 | 0 | { |
125 | 0 | const OUString sTemp(GetGroupName(i)); |
126 | 0 | if (rGroup == o3tl::getToken(sTemp, 0, GLOS_DELIM)) |
127 | 0 | { |
128 | 0 | rGroup = sTemp; |
129 | 0 | return true; |
130 | 0 | } |
131 | 0 | } |
132 | | // you can search two times because for more directories the case sensitive |
133 | | // name could occur multiple times |
134 | 0 | const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore(); |
135 | 0 | for(size_t i = 0; i < nCount; ++i) |
136 | 0 | { |
137 | 0 | const OUString sTemp( GetGroupName( i )); |
138 | 0 | sal_uInt16 nPath = o3tl::toUInt32(o3tl::getToken(sTemp, 1, GLOS_DELIM)); |
139 | |
|
140 | 0 | if (!SWUnoHelper::UCB_IsCaseSensitiveFileName( m_PathArr[nPath] ) |
141 | 0 | && rSCmp.isEqual( rGroup, sTemp.getToken( 0, GLOS_DELIM) ) ) |
142 | 0 | { |
143 | 0 | rGroup = sTemp; |
144 | 0 | return true; |
145 | 0 | } |
146 | 0 | } |
147 | 0 | return false; |
148 | 0 | } |
149 | | |
150 | | OUString const & SwGlossaries::GetGroupName(size_t nGroupId) |
151 | 0 | { |
152 | 0 | OSL_ENSURE(nGroupId < m_GlosArr.size(), |
153 | 0 | "SwGlossaries::GetGroupName: index out of bounds"); |
154 | 0 | return m_GlosArr[nGroupId]; |
155 | 0 | } |
156 | | |
157 | | OUString SwGlossaries::GetGroupTitle( const OUString& rGroupName ) |
158 | 0 | { |
159 | 0 | OUString sRet; |
160 | 0 | OUString sGroup(rGroupName); |
161 | 0 | if (sGroup.indexOf(GLOS_DELIM)<0) |
162 | 0 | FindGroupName(sGroup); |
163 | 0 | std::unique_ptr<SwTextBlocks> pGroup = GetGroupDoc(sGroup); |
164 | 0 | if(pGroup) |
165 | 0 | { |
166 | 0 | sRet = pGroup->GetName(); |
167 | 0 | } |
168 | 0 | return sRet; |
169 | 0 | } |
170 | | |
171 | | // supplies the group rName's text block document |
172 | | std::unique_ptr<SwTextBlocks> SwGlossaries::GetGroupDoc(const OUString &rName, |
173 | | bool bCreate) |
174 | 0 | { |
175 | | // insert to the list of text blocks if applicable |
176 | 0 | if(bCreate && !m_GlosArr.empty()) |
177 | 0 | { |
178 | 0 | if (std::none_of(m_GlosArr.begin(), m_GlosArr.end(), |
179 | 0 | [&rName](const OUString& rEntry) { return rEntry == rName; })) |
180 | 0 | { // block not in the list |
181 | 0 | m_GlosArr.push_back(rName); |
182 | 0 | } |
183 | 0 | } |
184 | 0 | return GetGlosDoc( rName, bCreate ); |
185 | 0 | } |
186 | | |
187 | | // Creates a new document with the group name. temporarily also created as file |
188 | | // so that groups remain there later (without access). |
189 | | bool SwGlossaries::NewGroupDoc(OUString& rGroupName, const OUString& rTitle) |
190 | 0 | { |
191 | 0 | const std::u16string_view sNewPath(o3tl::getToken(rGroupName, 1, GLOS_DELIM)); |
192 | 0 | sal_uInt16 nNewPath = o3tl::narrowing<sal_uInt16>(o3tl::toInt32(sNewPath)); |
193 | 0 | if (static_cast<size_t>(nNewPath) >= m_PathArr.size()) |
194 | 0 | return false; |
195 | 0 | const OUString sNewFilePath(m_PathArr[nNewPath]); |
196 | 0 | const OUString sNewGroup = lcl_CheckFileName(sNewFilePath, o3tl::getToken(rGroupName, 0, GLOS_DELIM)) |
197 | 0 | + OUStringChar(GLOS_DELIM) + sNewPath; |
198 | 0 | std::unique_ptr<SwTextBlocks> pBlock = GetGlosDoc( sNewGroup ); |
199 | 0 | if(pBlock) |
200 | 0 | { |
201 | 0 | GetNameList().push_back(sNewGroup); |
202 | 0 | pBlock->SetName(rTitle); |
203 | 0 | rGroupName = sNewGroup; |
204 | 0 | return true; |
205 | 0 | } |
206 | 0 | return false; |
207 | 0 | } |
208 | | |
209 | | bool SwGlossaries::RenameGroupDoc( |
210 | | const OUString& rOldGroup, OUString& rNewGroup, const OUString& rNewTitle ) |
211 | 0 | { |
212 | 0 | sal_uInt16 nOldPath = o3tl::narrowing<sal_uInt16>(o3tl::toInt32(o3tl::getToken(rOldGroup, 1, GLOS_DELIM))); |
213 | 0 | if (static_cast<size_t>(nOldPath) >= m_PathArr.size()) |
214 | 0 | return false; |
215 | | |
216 | 0 | const OUString sOldFileURL = |
217 | 0 | lcl_FullPathName(m_PathArr[nOldPath], o3tl::getToken(rOldGroup, 0, GLOS_DELIM)); |
218 | |
|
219 | 0 | if (!FStatHelper::IsDocument( sOldFileURL )) |
220 | 0 | { |
221 | 0 | OSL_FAIL("group doesn't exist!"); |
222 | 0 | return false; |
223 | 0 | } |
224 | | |
225 | 0 | sal_uInt16 nNewPath = o3tl::narrowing<sal_uInt16>(o3tl::toInt32(o3tl::getToken(rNewGroup, 1, GLOS_DELIM))); |
226 | 0 | if (static_cast<size_t>(nNewPath) >= m_PathArr.size()) |
227 | 0 | return false; |
228 | | |
229 | 0 | const OUString sNewFileName = lcl_CheckFileName(m_PathArr[nNewPath], |
230 | 0 | o3tl::getToken(rNewGroup, 0, GLOS_DELIM)); |
231 | 0 | const OUString sNewFileURL = lcl_FullPathName(m_PathArr[nNewPath], sNewFileName); |
232 | |
|
233 | 0 | if (FStatHelper::IsDocument( sNewFileURL )) |
234 | 0 | { |
235 | 0 | OSL_FAIL("group already exists!"); |
236 | 0 | return false; |
237 | 0 | } |
238 | | |
239 | 0 | if (!SWUnoHelper::UCB_MoveFile(sOldFileURL, sNewFileURL )) |
240 | 0 | return false; |
241 | | |
242 | 0 | RemoveFileFromList( rOldGroup ); |
243 | |
|
244 | 0 | rNewGroup = sNewFileName + OUStringChar(GLOS_DELIM) + OUString::number(nNewPath); |
245 | 0 | if (m_GlosArr.empty()) |
246 | 0 | { |
247 | 0 | GetNameList(); |
248 | 0 | } |
249 | 0 | else |
250 | 0 | { |
251 | 0 | m_GlosArr.push_back(rNewGroup); |
252 | 0 | } |
253 | |
|
254 | 0 | SwTextBlocks aNewBlock( sNewFileURL ); |
255 | 0 | aNewBlock.SetName(rNewTitle); |
256 | |
|
257 | 0 | return true; |
258 | 0 | } |
259 | | |
260 | | // Deletes a text block group |
261 | | bool SwGlossaries::DelGroupDoc(std::u16string_view rName) |
262 | 0 | { |
263 | 0 | sal_uInt16 nPath = o3tl::narrowing<sal_uInt16>(o3tl::toInt32(o3tl::getToken(rName, 1, GLOS_DELIM))); |
264 | 0 | if (static_cast<size_t>(nPath) >= m_PathArr.size()) |
265 | 0 | return false; |
266 | 0 | const std::u16string_view sBaseName(o3tl::getToken(rName, 0, GLOS_DELIM)); |
267 | 0 | const OUString sFileURL = lcl_FullPathName(m_PathArr[nPath], sBaseName); |
268 | 0 | const OUString aName = sBaseName + OUStringChar(GLOS_DELIM) + OUString::number(nPath); |
269 | | // Even if the file doesn't exist it has to be deleted from |
270 | | // the list of text block regions |
271 | | // no && because of CFfront |
272 | 0 | bool bRemoved = SWUnoHelper::UCB_DeleteFile( sFileURL ); |
273 | 0 | OSL_ENSURE(bRemoved, "file has not been removed"); |
274 | 0 | RemoveFileFromList( aName ); |
275 | 0 | return bRemoved; |
276 | 0 | } |
277 | | |
278 | | SwGlossaries::~SwGlossaries() |
279 | 0 | { |
280 | 0 | InvalidateUNOOjects(); |
281 | 0 | } |
282 | | |
283 | | // read a block document |
284 | | std::unique_ptr<SwTextBlocks> SwGlossaries::GetGlosDoc( const OUString &rName, bool bCreate ) const |
285 | 0 | { |
286 | 0 | sal_uInt16 nPath = o3tl::narrowing<sal_uInt16>(o3tl::toInt32(o3tl::getToken(rName, 1, GLOS_DELIM))); |
287 | 0 | std::unique_ptr<SwTextBlocks> pTmp; |
288 | 0 | if (static_cast<size_t>(nPath) < m_PathArr.size()) |
289 | 0 | { |
290 | 0 | const OUString sFileURL = |
291 | 0 | lcl_FullPathName(m_PathArr[nPath], o3tl::getToken(rName, 0, GLOS_DELIM)); |
292 | |
|
293 | 0 | bool bExist = false; |
294 | 0 | if(!bCreate) |
295 | 0 | bExist = FStatHelper::IsDocument( sFileURL ); |
296 | |
|
297 | 0 | if (bCreate || bExist) |
298 | 0 | { |
299 | 0 | pTmp.reset(new SwTextBlocks( sFileURL )); |
300 | 0 | bool bOk = true; |
301 | 0 | if( pTmp->GetError() ) |
302 | 0 | { |
303 | 0 | ErrorHandler::HandleError( pTmp->GetError() ); |
304 | 0 | bOk = ! pTmp->GetError().IsError(); |
305 | 0 | } |
306 | |
|
307 | 0 | if( bOk && pTmp->GetName().isEmpty() ) |
308 | 0 | pTmp->SetName( rName ); |
309 | 0 | } |
310 | 0 | } |
311 | |
|
312 | 0 | return pTmp; |
313 | 0 | } |
314 | | |
315 | | // access to the list of names; read in if applicable |
316 | | std::vector<OUString> & SwGlossaries::GetNameList() |
317 | 0 | { |
318 | 0 | if (m_GlosArr.empty()) |
319 | 0 | { |
320 | 0 | const OUString sExt( SwGlossaries::GetExtension() ); |
321 | 0 | for (size_t i = 0; i < m_PathArr.size(); ++i) |
322 | 0 | { |
323 | 0 | std::vector<OUString> aFiles; |
324 | |
|
325 | 0 | SWUnoHelper::UCB_GetFileListOfFolder(m_PathArr[i], aFiles, &sExt); |
326 | 0 | for (const OUString& aTitle : aFiles) |
327 | 0 | { |
328 | 0 | const OUString sName( aTitle.subView( 0, aTitle.getLength() - sExt.getLength() ) |
329 | 0 | + OUStringChar(GLOS_DELIM) + OUString::number( static_cast<sal_Int16>(i) )); |
330 | 0 | m_GlosArr.push_back(sName); |
331 | 0 | } |
332 | 0 | } |
333 | 0 | if (m_GlosArr.empty()) |
334 | 0 | { |
335 | | // the standard block is inside of the path's first part |
336 | 0 | m_GlosArr.emplace_back(SwGlossaries::GetDefName() + OUStringChar(GLOS_DELIM) + "0" ); |
337 | 0 | } |
338 | 0 | } |
339 | 0 | return m_GlosArr; |
340 | 0 | } |
341 | | |
342 | | SwGlossaries::SwGlossaries() |
343 | 0 | { |
344 | 0 | UpdateGlosPath(true); |
345 | 0 | } |
346 | | |
347 | | // set new path and recreate internal array |
348 | | static OUString lcl_makePath(const std::vector<OUString>& rPaths) |
349 | 0 | { |
350 | 0 | std::vector<OUString>::const_iterator aIt(rPaths.begin()); |
351 | 0 | const std::vector<OUString>::const_iterator aEnd(rPaths.end()); |
352 | 0 | OUStringBuffer aPath(*aIt); |
353 | 0 | for (++aIt; aIt != aEnd; ++aIt) |
354 | 0 | { |
355 | 0 | aPath.append(SVT_SEARCHPATH_DELIMITER); |
356 | 0 | const INetURLObject aTemp(*aIt); |
357 | 0 | aPath.append(aTemp.GetFull()); |
358 | 0 | } |
359 | 0 | return aPath.makeStringAndClear(); |
360 | 0 | } |
361 | | |
362 | | void SwGlossaries::UpdateGlosPath(bool bFull) |
363 | 0 | { |
364 | 0 | SvtPathOptions aPathOpt; |
365 | 0 | const OUString& aNewPath( aPathOpt.GetAutoTextPath() ); |
366 | 0 | bool bPathChanged = m_aPath != aNewPath; |
367 | 0 | if (!(bFull || bPathChanged)) |
368 | 0 | return; |
369 | | |
370 | 0 | m_aPath = aNewPath; |
371 | |
|
372 | 0 | m_PathArr.clear(); |
373 | |
|
374 | 0 | std::vector<OUString> aDirArr; |
375 | 0 | decltype(m_aInvalidPaths) aInvalidPaths; |
376 | 0 | if (!m_aPath.isEmpty()) |
377 | 0 | { |
378 | 0 | sal_Int32 nIndex = 0; |
379 | 0 | do |
380 | 0 | { |
381 | 0 | const OUString sPth = URIHelper::SmartRel2Abs( |
382 | 0 | INetURLObject(), |
383 | 0 | m_aPath.getToken(0, SVT_SEARCHPATH_DELIMITER, nIndex), |
384 | 0 | URIHelper::GetMaybeFileHdl()); |
385 | 0 | if (!aDirArr.empty() && |
386 | 0 | std::find(aDirArr.begin(), aDirArr.end(), sPth) != aDirArr.end()) |
387 | 0 | { |
388 | 0 | continue; |
389 | 0 | } |
390 | 0 | aDirArr.push_back(sPth); |
391 | 0 | try |
392 | 0 | { |
393 | 0 | ::ucbhelper::Content content{sPth, |
394 | 0 | uno::Reference<ucb::XCommandEnvironment>{}, |
395 | 0 | ::comphelper::getProcessComponentContext()}; |
396 | 0 | if (content.isFolder()) |
397 | 0 | { |
398 | 0 | m_PathArr.push_back(sPth); |
399 | 0 | } |
400 | 0 | else |
401 | 0 | { |
402 | 0 | aInvalidPaths.push_back({sPth, {}}); |
403 | 0 | } |
404 | 0 | } |
405 | 0 | catch (ucb::InteractiveIOException const& e) |
406 | 0 | { |
407 | 0 | TOOLS_INFO_EXCEPTION("sw.ui", "AutoText path IO Exception: "); |
408 | 0 | aInvalidPaths.emplace_back(sPth, e.Code); |
409 | 0 | } |
410 | 0 | catch (...) |
411 | 0 | { |
412 | 0 | TOOLS_INFO_EXCEPTION("sw.ui", "AutoText path Exception: "); |
413 | 0 | aInvalidPaths.push_back({sPth, {}}); |
414 | 0 | } |
415 | 0 | } |
416 | 0 | while (nIndex>=0); |
417 | 0 | } |
418 | | |
419 | 0 | if (m_aPath.isEmpty() || !aInvalidPaths.empty()) |
420 | 0 | { |
421 | 0 | std::sort(aInvalidPaths.begin(), aInvalidPaths.end()); |
422 | 0 | aInvalidPaths.erase(std::unique(aInvalidPaths.begin(), aInvalidPaths.end()), aInvalidPaths.end()); |
423 | 0 | if (bPathChanged || (m_aInvalidPaths != aInvalidPaths)) |
424 | 0 | { |
425 | 0 | m_aInvalidPaths = std::move(aInvalidPaths); |
426 | | // AutoText directory not accessible or doesn't exist |
427 | 0 | ShowError(); |
428 | |
|
429 | 0 | m_bError = true; |
430 | 0 | } |
431 | 0 | else |
432 | 0 | m_bError = false; |
433 | 0 | } |
434 | 0 | else |
435 | 0 | m_bError = false; |
436 | |
|
437 | 0 | if (!m_GlosArr.empty()) |
438 | 0 | { |
439 | 0 | m_GlosArr.clear(); |
440 | 0 | GetNameList(); |
441 | 0 | } |
442 | 0 | } |
443 | | |
444 | | void SwGlossaries::ShowError() |
445 | 0 | { |
446 | 0 | std::vector<OUString> netaccess; |
447 | 0 | std::vector<OUString> others; |
448 | 0 | for (auto const& it : m_aInvalidPaths) |
449 | 0 | { |
450 | | #ifdef _WIN32 |
451 | | OUString path; |
452 | | if (it.second && *it.second == ucb::IOErrorCode_ACCESS_DENIED |
453 | | && osl::FileBase::getSystemPathFromFileURL(it.first, path) == osl::FileBase::E_None |
454 | | && PathIsNetworkPathW(o3tl::toW(path.getStr())) == TRUE) |
455 | | { |
456 | | netaccess.emplace_back(it.first); |
457 | | } |
458 | | else |
459 | | #endif |
460 | 0 | { |
461 | 0 | others.emplace_back(it.first); |
462 | 0 | } |
463 | 0 | } |
464 | 0 | if (!netaccess.empty()) |
465 | 0 | { |
466 | 0 | std::unique_ptr<weld::MessageDialog> const xDialog{ |
467 | 0 | Application::CreateMessageDialog(nullptr, |
468 | 0 | VclMessageType::Error, VclButtonsType::Close, |
469 | 0 | SwResId(STR_ERR_GLOS_NET_PATH_ACCESS) + u"\n\n" + lcl_makePath(netaccess))}; |
470 | 0 | xDialog->run(); |
471 | 0 | } |
472 | 0 | if (!others.empty()) |
473 | 0 | { |
474 | 0 | ErrCodeMsg nPathError(ERR_AUTOPATH_ERROR, lcl_makePath(others), DialogMask::ButtonsOk); |
475 | 0 | ErrorHandler::HandleError( nPathError ); |
476 | 0 | } |
477 | 0 | } |
478 | | |
479 | | OUString SwGlossaries::GetExtension() |
480 | 0 | { |
481 | 0 | return u".bau"_ustr; |
482 | 0 | } |
483 | | |
484 | | void SwGlossaries::RemoveFileFromList( const OUString& rGroup ) |
485 | 0 | { |
486 | 0 | if (m_GlosArr.empty()) |
487 | 0 | return; |
488 | | |
489 | 0 | auto it = std::find(m_GlosArr.begin(), m_GlosArr.end(), rGroup); |
490 | 0 | if (it == m_GlosArr.end()) |
491 | 0 | return; |
492 | | |
493 | 0 | { |
494 | | // tell the UNO AutoTextGroup object that it's not valid anymore |
495 | 0 | for ( UnoAutoTextGroups::iterator aLoop = m_aGlossaryGroups.begin(); |
496 | 0 | aLoop != m_aGlossaryGroups.end(); |
497 | 0 | ) |
498 | 0 | { |
499 | 0 | rtl::Reference< SwXAutoTextGroup > xNamed( aLoop->get() ); |
500 | 0 | if ( !xNamed.is() ) |
501 | 0 | { |
502 | 0 | aLoop = m_aGlossaryGroups.erase(aLoop); |
503 | 0 | } |
504 | 0 | else if ( xNamed->getName() == rGroup ) |
505 | 0 | { |
506 | 0 | xNamed->Invalidate(); |
507 | | // note that this static_cast works because we know that the array only |
508 | | // contains SwXAutoTextGroup implementation |
509 | 0 | m_aGlossaryGroups.erase( aLoop ); |
510 | 0 | break; |
511 | 0 | } else |
512 | 0 | ++aLoop; |
513 | 0 | } |
514 | 0 | } |
515 | |
|
516 | 0 | { |
517 | | // tell all our UNO AutoTextEntry objects that they're not valid anymore |
518 | 0 | for ( UnoAutoTextEntries::iterator aLoop = m_aGlossaryEntries.begin(); |
519 | 0 | aLoop != m_aGlossaryEntries.end(); |
520 | 0 | ) |
521 | 0 | { |
522 | 0 | rtl::Reference<SwXAutoTextEntry> pEntry = aLoop->get(); |
523 | 0 | if ( pEntry && ( pEntry->GetGroupName() == rGroup ) ) |
524 | 0 | { |
525 | 0 | pEntry->Invalidate(); |
526 | 0 | aLoop = m_aGlossaryEntries.erase( aLoop ); |
527 | 0 | } |
528 | 0 | else |
529 | 0 | ++aLoop; |
530 | 0 | } |
531 | 0 | } |
532 | |
|
533 | 0 | m_GlosArr.erase(it); |
534 | 0 | } |
535 | | |
536 | | OUString SwGlossaries::GetCompleteGroupName( std::u16string_view rGroupName ) |
537 | 0 | { |
538 | 0 | const size_t nCount = GetGroupCnt(); |
539 | | // when the group name was created internally the path is here as well |
540 | 0 | sal_Int32 nIndex = 0; |
541 | 0 | const std::u16string_view sGroupName(o3tl::getToken(rGroupName, 0, GLOS_DELIM, nIndex)); |
542 | 0 | const bool bPathLen = !o3tl::getToken(rGroupName, 0, GLOS_DELIM, nIndex).empty(); |
543 | 0 | for ( size_t i = 0; i < nCount; i++ ) |
544 | 0 | { |
545 | 0 | const OUString sGrpName = GetGroupName(i); |
546 | 0 | if (bPathLen) |
547 | 0 | { |
548 | 0 | if (rGroupName == sGrpName) |
549 | 0 | return sGrpName; |
550 | 0 | } |
551 | 0 | else |
552 | 0 | { |
553 | 0 | if (sGroupName == o3tl::getToken(sGrpName, 0, GLOS_DELIM)) |
554 | 0 | return sGrpName; |
555 | 0 | } |
556 | 0 | } |
557 | 0 | return OUString(); |
558 | 0 | } |
559 | | |
560 | | void SwGlossaries::InvalidateUNOOjects() |
561 | 0 | { |
562 | | // invalidate all the AutoTextGroup-objects |
563 | 0 | for (const auto& rGroup : m_aGlossaryGroups) |
564 | 0 | { |
565 | 0 | rtl::Reference< SwXAutoTextGroup > xGroup( rGroup.get() ); |
566 | 0 | if ( xGroup.is() ) |
567 | 0 | xGroup->Invalidate(); |
568 | 0 | } |
569 | 0 | UnoAutoTextGroups().swap(m_aGlossaryGroups); |
570 | | |
571 | | // invalidate all the AutoTextEntry-objects |
572 | 0 | for (const auto& rEntry : m_aGlossaryEntries) |
573 | 0 | { |
574 | 0 | rtl::Reference<SwXAutoTextEntry> pEntry = rEntry.get(); |
575 | 0 | if ( pEntry ) |
576 | 0 | pEntry->Invalidate(); |
577 | 0 | } |
578 | 0 | UnoAutoTextEntries().swap(m_aGlossaryEntries); |
579 | 0 | } |
580 | | |
581 | | Reference< text::XAutoTextGroup > SwGlossaries::GetAutoTextGroup( std::u16string_view _rGroupName ) |
582 | 0 | { |
583 | 0 | bool _bCreate = true; |
584 | | // first, find the name with path-extension |
585 | 0 | const OUString sCompleteGroupName = GetCompleteGroupName( _rGroupName ); |
586 | |
|
587 | 0 | rtl::Reference< SwXAutoTextGroup > xGroup; |
588 | | |
589 | | // look up the group in the cache |
590 | 0 | UnoAutoTextGroups::iterator aSearch = m_aGlossaryGroups.begin(); |
591 | 0 | for ( ; aSearch != m_aGlossaryGroups.end(); ) |
592 | 0 | { |
593 | 0 | rtl::Reference<SwXAutoTextGroup> pSwGroup = aSearch->get(); |
594 | 0 | if ( !pSwGroup ) |
595 | 0 | { |
596 | | // the object is dead in the meantime -> remove from cache |
597 | 0 | aSearch = m_aGlossaryGroups.erase( aSearch ); |
598 | 0 | continue; |
599 | 0 | } |
600 | | |
601 | 0 | if ( _rGroupName == pSwGroup->getName() ) |
602 | 0 | { // the group is already cached |
603 | 0 | if ( !sCompleteGroupName.isEmpty() ) |
604 | 0 | { // the group still exists -> return it |
605 | 0 | xGroup = std::move(pSwGroup); |
606 | 0 | break; |
607 | 0 | } |
608 | 0 | else |
609 | 0 | { |
610 | | // this group does not exist (anymore) -> release the cached UNO object for it |
611 | 0 | aSearch = m_aGlossaryGroups.erase( aSearch ); |
612 | | // so it won't be created below |
613 | 0 | _bCreate = false; |
614 | 0 | break; |
615 | 0 | } |
616 | 0 | } |
617 | | |
618 | 0 | ++aSearch; |
619 | 0 | } |
620 | |
|
621 | 0 | if ( !xGroup.is() && _bCreate ) |
622 | 0 | { |
623 | 0 | xGroup = new SwXAutoTextGroup( sCompleteGroupName, this ); |
624 | | // cache it |
625 | 0 | m_aGlossaryGroups.emplace_back( xGroup ); |
626 | 0 | } |
627 | |
|
628 | 0 | return xGroup; |
629 | 0 | } |
630 | | |
631 | | Reference< text::XAutoTextEntry > SwGlossaries::GetAutoTextEntry( |
632 | | const OUString& rCompleteGroupName, |
633 | | const OUString& rGroupName, |
634 | | const OUString& rEntryName ) |
635 | 0 | { |
636 | | //standard must be created |
637 | 0 | bool bCreate = ( rCompleteGroupName == GetDefName() ); |
638 | 0 | std::unique_ptr< SwTextBlocks > pGlosGroup( GetGroupDoc( rCompleteGroupName, bCreate ) ); |
639 | |
|
640 | 0 | if (!pGlosGroup || pGlosGroup->GetError()) |
641 | 0 | throw lang::WrappedTargetException(); |
642 | | |
643 | 0 | sal_uInt16 nIdx = pGlosGroup->GetIndex( rEntryName ); |
644 | 0 | if ( USHRT_MAX == nIdx ) |
645 | 0 | throw container::NoSuchElementException(); |
646 | | |
647 | 0 | rtl::Reference< SwXAutoTextEntry > xReturn; |
648 | |
|
649 | 0 | UnoAutoTextEntries::iterator aSearch( m_aGlossaryEntries.begin() ); |
650 | 0 | for ( ; aSearch != m_aGlossaryEntries.end(); ) |
651 | 0 | { |
652 | 0 | rtl::Reference< SwXAutoTextEntry > pEntry( aSearch->get() ); |
653 | |
|
654 | 0 | if ( !pEntry ) |
655 | 0 | { |
656 | | // the object is dead in the meantime -> remove from cache |
657 | 0 | aSearch = m_aGlossaryEntries.erase( aSearch ); |
658 | 0 | continue; |
659 | 0 | } |
660 | | |
661 | 0 | if ( pEntry |
662 | 0 | && pEntry->GetGroupName() == rGroupName |
663 | 0 | && pEntry->GetEntryName() == rEntryName |
664 | 0 | ) |
665 | 0 | { |
666 | 0 | xReturn = std::move(pEntry); |
667 | 0 | break; |
668 | 0 | } |
669 | | |
670 | 0 | ++aSearch; |
671 | 0 | } |
672 | |
|
673 | 0 | if ( !xReturn.is() ) |
674 | 0 | { |
675 | 0 | xReturn = new SwXAutoTextEntry( this, rGroupName, rEntryName ); |
676 | | // cache it |
677 | 0 | m_aGlossaryEntries.emplace_back( xReturn ); |
678 | 0 | } |
679 | |
|
680 | 0 | return xReturn; |
681 | 0 | } |
682 | | |
683 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |