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 .
24 #include <com/sun/star/container/XNamed.hpp>
26 #include <unotools/transliterationwrapper.hxx>
29 #ifndef __RSC //autogen
30 #include <tools/errinf.hxx>
32 #include <osl/diagnose.h>
33 #include <svl/urihelper.hxx>
34 #include <svl/fstathelper.hxx>
35 #include <unotools/pathoptions.hxx>
36 #include <unotools/tempfile.hxx>
37 #include <comphelper/string.hxx>
38 #include <swtypes.hxx>
40 #include <glosdoc.hxx>
41 #include <shellio.hxx>
42 #include <swunohelper.hxx>
44 #include <unoatxt.hxx>
46 #include <globals.hrc>
48 using namespace ::com::sun::star
;
49 using namespace ::com::sun::star::uno
;
51 // PUBLIC METHODES -------------------------------------------------------
52 static String
lcl_CheckFileName( const String
& rNewFilePath
,
53 const String
& rNewGroupName
)
56 //group name should contain only A-Z and a-z and spaces
57 for( xub_StrLen i
= 0; i
< rNewGroupName
.Len(); i
++ )
59 sal_Unicode cChar
= rNewGroupName
.GetChar(i
);
60 if (comphelper::string::isalnumAscii(cChar
) ||
61 cChar
== '_' || cChar
== 0x20)
66 sRet
= comphelper::string::strip(sRet
, ' ');
71 String
sTmpDir(rNewFilePath
);
72 sTmpDir
+= INET_PATH_TOKEN
;
74 sTmpDir
+= SwGlossaries::GetExtension();
75 bOk
= !FStatHelper::IsDocument( sTmpDir
);
80 String rSG
= SwGlossaries::GetExtension();
81 //generate generic name
82 utl::TempFile
aTemp(OUString("group"),
83 &rSG
, &rNewFilePath
);
84 aTemp
.EnableKillingFile();
86 INetURLObject
aTempURL( aTemp
.GetURL() );
87 sRet
= aTempURL
.GetBase();
92 /*------------------------------------------------------------------------
93 Description: supplies the default group's name
94 ------------------------------------------------------------------------*/
95 String
SwGlossaries::GetDefName()
97 return OUString("standard");
101 /*------------------------------------------------------------------------
102 Description: supplies the number of text block groups
103 ------------------------------------------------------------------------*/
104 sal_uInt16
SwGlossaries::GetGroupCnt()
106 return static_cast<sal_uInt16
>(GetNameList().size());
109 /*------------------------------------------------------------------------
110 Description: supplies the group's name
111 ------------------------------------------------------------------------*/
112 sal_Bool
SwGlossaries::FindGroupName(String
& rGroup
)
114 // if the group name doesn't contain a path, a suitable group entry
115 // can the searched for here;
116 sal_uInt16 nCount
= GetGroupCnt();
118 for(i
= 0; i
< nCount
; i
++)
120 String
sTemp(GetGroupName(i
));
121 if(rGroup
.Equals( sTemp
.GetToken(0, GLOS_DELIM
)))
127 // you can search two times because for more directories the case sensitive
128 // name could occur multiple times
129 const ::utl::TransliterationWrapper
& rSCmp
= GetAppCmpStrIgnore();
130 for(i
= 0; i
< nCount
; i
++)
132 String
sTemp( GetGroupName( i
));
133 sal_uInt16 nPath
= (sal_uInt16
)sTemp
.GetToken(1, GLOS_DELIM
).ToInt32();
135 if (!SWUnoHelper::UCB_IsCaseSensitiveFileName( m_PathArr
[nPath
] )
136 && rSCmp
.isEqual( rGroup
, sTemp
.GetToken( 0, GLOS_DELIM
) ) )
145 String
SwGlossaries::GetGroupName(sal_uInt16 nGroupId
)
147 OSL_ENSURE(static_cast<size_t>(nGroupId
) < m_GlosArr
.size(),
148 "SwGlossaries::GetGroupName: index out of bounds");
149 return m_GlosArr
[nGroupId
];
152 String
SwGlossaries::GetGroupTitle( const String
& rGroupName
)
155 String
sGroup(rGroupName
);
156 if(STRING_NOTFOUND
== sGroup
.Search(GLOS_DELIM
))
157 FindGroupName(sGroup
);
158 SwTextBlocks
* pGroup
= GetGroupDoc(sGroup
, sal_False
);
161 sRet
= pGroup
->GetName();
162 PutGroupDoc( pGroup
);
167 /*------------------------------------------------------------------------
168 Description: supplies the group rName's text block document
169 ------------------------------------------------------------------------*/
170 SwTextBlocks
* SwGlossaries::GetGroupDoc(const String
&rName
,
173 // insert to the list of text blocks if applicable
174 if(bCreate
&& !m_GlosArr
.empty())
176 std::vector
<String
>::const_iterator
it(m_GlosArr
.begin());
177 for (; it
!= m_GlosArr
.end(); ++it
)
182 if (it
== m_GlosArr
.end())
183 { // block not in the list
184 m_GlosArr
.push_back(rName
);
187 return GetGlosDoc( rName
, bCreate
);
190 /*------------------------------------------------------------------------
191 Description: delete a text block
192 ------------------------------------------------------------------------*/
193 void SwGlossaries::PutGroupDoc(SwTextBlocks
*pBlock
) {
197 /*------------------------------------------------------------------------
198 Description: Creates a new document with the group name. temporarly
199 also created as file so that groups remain there later
201 ------------------------------------------------------------------------*/
202 sal_Bool
SwGlossaries::NewGroupDoc(String
& rGroupName
, const String
& rTitle
)
204 sal_uInt16 nNewPath
= (sal_uInt16
)rGroupName
.GetToken(1, GLOS_DELIM
).ToInt32();
205 if (static_cast<size_t>(nNewPath
) >= m_PathArr
.size())
207 String
sNewFilePath(m_PathArr
[nNewPath
]);
208 String sNewGroup
= lcl_CheckFileName(sNewFilePath
, rGroupName
.GetToken(0, GLOS_DELIM
));
209 sNewGroup
+= GLOS_DELIM
;
210 sNewGroup
+= rGroupName
.GetToken(1, GLOS_DELIM
);
211 SwTextBlocks
*pBlock
= GetGlosDoc( sNewGroup
);
214 GetNameList().push_back(sNewGroup
);
215 pBlock
->SetName(rTitle
);
217 rGroupName
= sNewGroup
;
223 sal_Bool
SwGlossaries::RenameGroupDoc(
224 const String
& rOldGroup
, String
& rNewGroup
, const String
& rNewTitle
)
226 sal_Bool bRet
= sal_False
;
227 sal_uInt16 nOldPath
= (sal_uInt16
)rOldGroup
.GetToken(1, GLOS_DELIM
).ToInt32();
228 if (static_cast<size_t>(nOldPath
) < m_PathArr
.size())
230 String
sOldFileURL(m_PathArr
[nOldPath
]);
231 sOldFileURL
+= INET_PATH_TOKEN
;
232 sOldFileURL
+= rOldGroup
.GetToken(0, GLOS_DELIM
);
233 sOldFileURL
+= SwGlossaries::GetExtension();
234 sal_Bool bExist
= FStatHelper::IsDocument( sOldFileURL
);
235 OSL_ENSURE(bExist
, "group doesn't exist!");
238 sal_uInt16 nNewPath
= (sal_uInt16
)rNewGroup
.GetToken(1, GLOS_DELIM
).ToInt32();
239 if (static_cast<size_t>(nNewPath
) < m_PathArr
.size())
241 String
sNewFilePath(m_PathArr
[nNewPath
]);
242 String sNewFileName
= lcl_CheckFileName(
243 sNewFilePath
, rNewGroup
.GetToken(0, GLOS_DELIM
));
244 const sal_uInt16 nFileNameLen
= sNewFileName
.Len();
245 sNewFileName
+= SwGlossaries::GetExtension();
246 String
sTempNewFilePath(sNewFilePath
);
247 sTempNewFilePath
+= INET_PATH_TOKEN
;
248 sTempNewFilePath
+= sNewFileName
;
249 bExist
= FStatHelper::IsDocument( sTempNewFilePath
);
250 OSL_ENSURE(!bExist
, "group already exists!");
253 sal_Bool bCopyCompleted
= SWUnoHelper::UCB_CopyFile(
254 sOldFileURL
, sTempNewFilePath
, sal_True
);
258 RemoveFileFromList( rOldGroup
);
260 rNewGroup
= sNewFileName
.Copy(0, nFileNameLen
);
261 rNewGroup
+= GLOS_DELIM
;
262 rNewGroup
+= OUString::number(nNewPath
);
263 if (m_GlosArr
.empty())
269 m_GlosArr
.push_back(rNewGroup
);
272 sNewFilePath
+= INET_PATH_TOKEN
;
273 sNewFilePath
+= sNewFileName
;
274 SwTextBlocks
* pNewBlock
= new SwTextBlocks( sNewFilePath
);
275 pNewBlock
->SetName(rNewTitle
);
285 /*------------------------------------------------------------------------
286 Description: Deletes a text block group
287 ------------------------------------------------------------------------*/
288 sal_Bool
SwGlossaries::DelGroupDoc(const String
&rName
)
290 sal_uInt16 nPath
= (sal_uInt16
)rName
.GetToken(1, GLOS_DELIM
).ToInt32();
291 if (static_cast<size_t>(nPath
) >= m_PathArr
.size())
293 String
sFileURL(m_PathArr
[nPath
]);
294 String
aTmp( rName
.GetToken(0, GLOS_DELIM
));
297 aName
+= OUString::number(nPath
);
299 aTmp
+= SwGlossaries::GetExtension();
300 sFileURL
+= INET_PATH_TOKEN
;
302 // Even if the file doesn't exist it hast to be deleted from
303 // the list of text block regions
304 // no && because of CFfront
305 sal_Bool bRemoved
= SWUnoHelper::UCB_DeleteFile( sFileURL
);
306 OSL_ENSURE(bRemoved
, "file has not been removed");
307 RemoveFileFromList( aName
);
311 SwGlossaries::~SwGlossaries()
313 InvalidateUNOOjects();
316 /*------------------------------------------------------------------------
317 Description: read a block document
318 ------------------------------------------------------------------------*/
319 SwTextBlocks
* SwGlossaries::GetGlosDoc( const String
&rName
, sal_Bool bCreate
) const
321 sal_uInt16 nPath
= (sal_uInt16
)rName
.GetToken(1, GLOS_DELIM
).ToInt32();
322 SwTextBlocks
*pTmp
= 0;
323 if (static_cast<size_t>(nPath
) < m_PathArr
.size())
325 String
sFileURL(m_PathArr
[nPath
]);
326 String
aTmp( rName
.GetToken(0, GLOS_DELIM
));
327 aTmp
+= SwGlossaries::GetExtension();
328 sFileURL
+= INET_PATH_TOKEN
;
331 sal_Bool bExist
= sal_False
;
333 bExist
= FStatHelper::IsDocument( sFileURL
);
335 if (bCreate
|| bExist
)
337 pTmp
= new SwTextBlocks( sFileURL
);
339 if( pTmp
->GetError() )
341 ErrorHandler::HandleError( pTmp
->GetError() );
342 bOk
= !IsError( pTmp
->GetError() );
345 if( bOk
&& !pTmp
->GetName().Len() )
346 pTmp
->SetName( rName
);
353 /*------------------------------------------------------------------------
354 Description: access to the list of names; read in if applicable
355 ------------------------------------------------------------------------*/
356 std::vector
<String
> & SwGlossaries::GetNameList()
358 if (m_GlosArr
.empty())
360 String
sExt( SwGlossaries::GetExtension() );
361 for (size_t i
= 0; i
< m_PathArr
.size(); ++i
)
363 std::vector
<String
*> aFiles
;
365 SWUnoHelper::UCB_GetFileListOfFolder(m_PathArr
[i
], aFiles
, &sExt
);
366 for( std::vector
<String
*>::const_iterator
filesIt(aFiles
.begin());
367 filesIt
!= aFiles
.end(); ++filesIt
)
369 String
*pTitle
= *filesIt
;
370 String
sName( pTitle
->Copy( 0, pTitle
->Len() - sExt
.Len() ));
372 sName
+= OUString::number( static_cast<sal_Int16
>(i
) );
373 m_GlosArr
.push_back(sName
);
375 // don't need any more these pointers
379 if (m_GlosArr
.empty())
381 // the standard block is inside of the path's first part
382 String
tmp( SwGlossaries::GetDefName() );
385 m_GlosArr
.push_back( tmp
);
391 SwGlossaries::SwGlossaries()
393 UpdateGlosPath(sal_True
);
396 /*------------------------------------------------------------------------
397 Description: set new path and recreate internal array
398 ------------------------------------------------------------------------*/
400 rtl::OUString
lcl_makePath(const std::vector
<rtl::OUString
>& rPaths
)
402 std::vector
<rtl::OUString
>::const_iterator
aIt(rPaths
.begin());
403 const std::vector
<rtl::OUString
>::const_iterator
aEnd(rPaths
.end());
404 rtl::OUStringBuffer
aPath(*aIt
);
405 for (++aIt
; aIt
!= aEnd
; ++aIt
)
407 aPath
.append(SVT_SEARCHPATH_DELIMITER
);
408 const INetURLObject
aTemp(*aIt
);
409 aPath
.append(aTemp
.GetFull());
411 return aPath
.getStr();
414 void SwGlossaries::UpdateGlosPath(sal_Bool bFull
)
416 SvtPathOptions aPathOpt
;
417 String
aNewPath( aPathOpt
.GetAutoTextPath() );
418 bool bPathChanged
= m_aPath
!= aNewPath
;
419 if (bFull
|| bPathChanged
)
425 sal_uInt16 nTokenCount
= comphelper::string::getTokenCount(m_aPath
, SVT_SEARCHPATH_DELIMITER
);
426 std::vector
<String
> aDirArr
;
427 std::vector
<rtl::OUString
> aInvalidPaths
;
428 for( sal_uInt16 i
= 0; i
< nTokenCount
; i
++ )
430 String
sPth(m_aPath
.GetToken(i
, SVT_SEARCHPATH_DELIMITER
));
431 sPth
= URIHelper::SmartRel2Abs(
432 INetURLObject(), sPth
, URIHelper::GetMaybeFileHdl());
434 if(i
&& std::find(aDirArr
.begin(), aDirArr
.end(), sPth
) != aDirArr
.end())
438 aDirArr
.push_back(sPth
);
439 if( !FStatHelper::IsFolder( sPth
) )
440 aInvalidPaths
.push_back(sPth
);
442 m_PathArr
.push_back(sPth
);
445 if(!nTokenCount
|| !aInvalidPaths
.empty())
447 std::sort(aInvalidPaths
.begin(), aInvalidPaths
.end());
448 aInvalidPaths
.erase(std::unique(aInvalidPaths
.begin(), aInvalidPaths
.end()), aInvalidPaths
.end());
449 if (bPathChanged
|| (m_aInvalidPaths
!= aInvalidPaths
))
451 m_aInvalidPaths
= aInvalidPaths
;
452 // wrong path, that means AutoText directory doesn't exist
454 ErrorHandler::HandleError( *new StringErrorInfo(
455 ERR_AUTOPATH_ERROR
, lcl_makePath(m_aInvalidPaths
),
456 ERRCODE_BUTTON_OK
| ERRCODE_MSG_ERROR
));
460 m_bError
= sal_False
;
463 m_bError
= sal_False
;
465 if (!m_GlosArr
.empty())
473 void SwGlossaries::ShowError()
475 sal_uInt32 nPathError
= *new StringErrorInfo(ERR_AUTOPATH_ERROR
,
476 lcl_makePath(m_aInvalidPaths
), ERRCODE_BUTTON_OK
);
477 ErrorHandler::HandleError( nPathError
);
480 String
SwGlossaries::GetExtension()
482 return OUString(".bau");
485 void SwGlossaries::RemoveFileFromList( const String
& rGroup
)
487 if (!m_GlosArr
.empty())
489 for (std::vector
<String
>::iterator
it(m_GlosArr
.begin());
490 it
!= m_GlosArr
.end(); ++it
)
494 OUString aUName
= rGroup
;
496 // tell the UNO AutoTextGroup object that it's not valid anymore
497 for ( UnoAutoTextGroups::iterator aLoop
= m_aGlossaryGroups
.begin();
498 aLoop
!= m_aGlossaryGroups
.end();
502 Reference
< container::XNamed
> xNamed( aLoop
->get(), UNO_QUERY
);
503 if ( xNamed
.is() && ( xNamed
->getName() == aUName
) )
505 static_cast< SwXAutoTextGroup
* >( xNamed
.get() )->Invalidate();
506 // note that this static_cast works because we know that the array only
507 // contains SwXAutoTextGroup implementation
508 m_aGlossaryGroups
.erase( aLoop
);
515 // tell all our UNO AutoTextEntry objects that they're not valid anymore
516 for ( UnoAutoTextEntries::iterator aLoop
= m_aGlossaryEntries
.begin();
517 aLoop
!= m_aGlossaryEntries
.end();
520 Reference
< lang::XUnoTunnel
> xEntryTunnel( aLoop
->get(), UNO_QUERY
);
522 SwXAutoTextEntry
* pEntry
= NULL
;
523 if ( xEntryTunnel
.is() )
524 pEntry
= reinterpret_cast< SwXAutoTextEntry
* >(
525 xEntryTunnel
->getSomething( SwXAutoTextEntry::getUnoTunnelId() ) );
527 if ( pEntry
&& ( pEntry
->GetGroupName() == rGroup
) )
529 pEntry
->Invalidate();
530 aLoop
= m_aGlossaryEntries
.erase( aLoop
);
544 String
SwGlossaries::GetCompleteGroupName( const OUString
& GroupName
)
546 sal_uInt16 nCount
= GetGroupCnt();
547 // when the group name was created internally the path is here as well
548 String
sGroup(GroupName
);
549 String
sGroupName(sGroup
.GetToken(0, GLOS_DELIM
));
550 String sPath
= sGroup
.GetToken(1, GLOS_DELIM
);
551 bool bPathLen
= sPath
.Len() > 0;
552 for ( sal_uInt16 i
= 0; i
< nCount
; i
++ )
554 String sGrpName
= GetGroupName(i
);
555 if(bPathLen
? sGroup
== sGrpName
: sGroupName
== sGrpName
.GetToken(0, GLOS_DELIM
))
563 void SwGlossaries::InvalidateUNOOjects()
565 // invalidate all the AutoTextGroup-objects
566 for ( UnoAutoTextGroups::iterator aGroupLoop
= m_aGlossaryGroups
.begin();
567 aGroupLoop
!= m_aGlossaryGroups
.end();
571 Reference
< text::XAutoTextGroup
> xGroup( aGroupLoop
->get(), UNO_QUERY
);
573 static_cast< SwXAutoTextGroup
* >( xGroup
.get() )->Invalidate();
575 UnoAutoTextGroups aTmpg
= UnoAutoTextGroups();
576 m_aGlossaryGroups
.swap( aTmpg
);
578 // invalidate all the AutoTextEntry-objects
579 for ( UnoAutoTextEntries::const_iterator aEntryLoop
= m_aGlossaryEntries
.begin();
580 aEntryLoop
!= m_aGlossaryEntries
.end();
584 Reference
< lang::XUnoTunnel
> xEntryTunnel( aEntryLoop
->get(), UNO_QUERY
);
585 SwXAutoTextEntry
* pEntry
= NULL
;
586 if ( xEntryTunnel
.is() )
587 pEntry
= reinterpret_cast< SwXAutoTextEntry
* >(
588 xEntryTunnel
->getSomething( SwXAutoTextEntry::getUnoTunnelId() ) );
591 pEntry
->Invalidate();
593 UnoAutoTextEntries aTmpe
= UnoAutoTextEntries();
594 m_aGlossaryEntries
.swap( aTmpe
);
597 Reference
< text::XAutoTextGroup
> SwGlossaries::GetAutoTextGroup( const OUString
& _rGroupName
, bool _bCreate
)
599 // first, find the name with path-extension
600 String sCompleteGroupName
= GetCompleteGroupName( _rGroupName
);
602 Reference
< text::XAutoTextGroup
> xGroup
;
604 // look up the group in the cache
605 UnoAutoTextGroups::iterator aSearch
= m_aGlossaryGroups
.begin();
606 for ( ; aSearch
!= m_aGlossaryGroups
.end(); )
608 Reference
< lang::XUnoTunnel
> xGroupTunnel( aSearch
->get(), UNO_QUERY
);
610 SwXAutoTextGroup
* pSwGroup
= 0;
611 if ( xGroupTunnel
.is() )
612 pSwGroup
= reinterpret_cast< SwXAutoTextGroup
* >( xGroupTunnel
->getSomething( SwXAutoTextGroup::getUnoTunnelId() ) );
616 // the object is dead in the meantime -> remove from cache
617 aSearch
= m_aGlossaryGroups
.erase( aSearch
);
621 if ( _rGroupName
== pSwGroup
->getName() )
622 { // the group is already cached
623 if ( sCompleteGroupName
.Len() )
624 { // the group still exists -> return it
630 // this group does not exist (anymore) -> release the cached UNO object for it
631 aSearch
= m_aGlossaryGroups
.erase( aSearch
);
632 // so it won't be created below
633 _bCreate
= sal_False
;
641 if ( !xGroup
.is() && _bCreate
)
643 xGroup
= new SwXAutoTextGroup( sCompleteGroupName
, this );
645 m_aGlossaryGroups
.push_back( AutoTextGroupRef( xGroup
) );
651 Reference
< text::XAutoTextEntry
> SwGlossaries::GetAutoTextEntry( const String
& _rCompleteGroupName
, const OUString
& _rGroupName
, const OUString
& _rEntryName
,
654 //standard must be created
655 sal_Bool bCreate
= ( _rCompleteGroupName
== GetDefName() );
656 ::std::auto_ptr
< SwTextBlocks
> pGlosGroup( GetGroupDoc( _rCompleteGroupName
, bCreate
) );
658 if ( pGlosGroup
.get() && !pGlosGroup
->GetError() )
660 sal_uInt16 nIdx
= pGlosGroup
->GetIndex( _rEntryName
);
661 if ( USHRT_MAX
== nIdx
)
662 throw container::NoSuchElementException();
665 throw lang::WrappedTargetException();
667 Reference
< text::XAutoTextEntry
> xReturn
;
668 String
sGroupName( _rGroupName
);
669 String
sEntryName( _rEntryName
);
671 UnoAutoTextEntries::iterator
aSearch( m_aGlossaryEntries
.begin() );
672 for ( ; aSearch
!= m_aGlossaryEntries
.end(); )
674 Reference
< lang::XUnoTunnel
> xEntryTunnel( aSearch
->get(), UNO_QUERY
);
676 SwXAutoTextEntry
* pEntry
= NULL
;
677 if ( xEntryTunnel
.is() )
678 pEntry
= reinterpret_cast< SwXAutoTextEntry
* >( xEntryTunnel
->getSomething( SwXAutoTextEntry::getUnoTunnelId() ) );
681 // the object is dead in the meantime -> remove from cache
682 aSearch
= m_aGlossaryEntries
.erase( aSearch
);
687 && ( COMPARE_EQUAL
== pEntry
->GetGroupName().CompareTo( sGroupName
) )
688 && ( COMPARE_EQUAL
== pEntry
->GetEntryName().CompareTo( sEntryName
) )
698 if ( !xReturn
.is() && _bCreate
)
700 xReturn
= new SwXAutoTextEntry( this, sGroupName
, sEntryName
);
702 m_aGlossaryEntries
.push_back( AutoTextEntryRef( xReturn
) );
708 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */