1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: SwXMLTextBlocks.cxx,v $
10 * $Revision: 1.39.136.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <com/sun/star/embed/ElementModes.hpp>
36 #include <com/sun/star/embed/XTransactedObject.hpp>
37 #include <tools/urlobj.hxx>
38 #include <sot/stg.hxx>
39 #include <sfx2/docfile.hxx>
40 #include <unotools/localfilehelper.hxx>
41 #include <unotools/ucbstreamhelper.hxx>
43 #include <comphelper/storagehelper.hxx>
49 #include <swblocks.hxx>
51 #include <shellio.hxx>
52 #include <poolfmt.hxx>
53 #include <SwXMLTextBlocks.hxx>
55 #include <SwXMLBlockImport.hxx>
56 #include <SwXMLBlockExport.hxx>
59 #define STREAM_STGREAD ( STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE )
60 #define STREAM_STGWRITE ( STREAM_READ | STREAM_WRITE | STREAM_SHARE_DENYWRITE )
62 using namespace ::com::sun::star
;
65 void SwXMLTextBlocks::InitBlockMode ( const uno::Reference
< embed::XStorage
>& rStorage
)
71 void SwXMLTextBlocks::ResetBlockMode ( )
77 SwXMLTextBlocks::SwXMLTextBlocks( const String
& rFile
)
78 : SwImpBlocks( rFile
), bAutocorrBlock( FALSE
), nFlags ( 0 )
80 SwDocShell
* pDocSh
= new SwDocShell ( SFX_CREATE_MODE_INTERNAL
);
81 if( !pDocSh
->DoInitNew( 0 ) )
84 pDoc
= pDocSh
->GetDoc();
85 xDocShellRef
= pDocSh
;
86 pDoc
->SetOle2Link( Link() );
87 pDoc
->DoUndo( FALSE
); // always FALSE
89 uno::Reference
< embed::XStorage
> refStg
;
90 if( !aDateModified
.GetDate() || !aTimeModified
.GetTime() )
91 Touch(); // falls neu angelegt -> neuen ZeitStempel besorgen
94 refStg
= comphelper::OStorageHelper::GetStorageFromURL( rFile
, embed::ElementModes::READWRITE
);
97 catch( const uno::Exception
& )
99 //couldn't open the file - maybe it's readonly
105 refStg
= comphelper::OStorageHelper::GetStorageFromURL( rFile
, embed::ElementModes::READ
);
107 catch( const uno::Exception
& )
109 DBG_ERROR("exception while creating AutoText storage");
112 InitBlockMode ( refStg
);
115 bInfoChanged
= FALSE
;
118 SwXMLTextBlocks::SwXMLTextBlocks( const uno::Reference
< embed::XStorage
>& rStg
, const String
& rName
)
119 : SwImpBlocks( rName
)
120 , bAutocorrBlock( TRUE
)
123 SwDocShell
* pDocSh
= new SwDocShell ( SFX_CREATE_MODE_INTERNAL
);
124 if( !pDocSh
->DoInitNew( 0 ) )
127 pDoc
= pDocSh
->GetDoc();
128 xDocShellRef
= pDocSh
;
129 pDoc
->SetOle2Link( Link() );
130 pDoc
->DoUndo( FALSE
);
133 InitBlockMode ( rStg
);
135 bInfoChanged
= FALSE
;
138 SwXMLTextBlocks::~SwXMLTextBlocks()
143 if(xDocShellRef
.Is())
144 xDocShellRef
->DoClose();
146 if( pDoc
&& !pDoc
->release() )
150 void SwXMLTextBlocks::ClearDoc()
152 SwDocShell
* pDocShell
= pDoc
->GetDocShell();
153 pDocShell
->InvalidateModel();
154 pDocShell
->ReactivateModel();
157 pDocShell
->ClearEmbeddedObjects();
159 void SwXMLTextBlocks::AddName( const String
& rShort
, const String
& rLong
, BOOL bOnlyTxt
)
161 USHORT nIdx
= GetIndex( rShort
);
162 SwBlockName
* pNew
= NULL
;
163 if( nIdx
!= (USHORT
) -1 )
164 aNames
.DeleteAndDestroy( nIdx
);
166 GeneratePackageName( rShort
, aPackageName
);
167 pNew
= new SwBlockName( rShort
, rLong
, aPackageName
);
169 pNew
->bIsOnlyTxtFlagInit
= TRUE
;
170 pNew
->bIsOnlyTxt
= bOnlyTxt
;
171 aNames
.C40_PTR_INSERT( SwBlockName
, pNew
);
174 void SwXMLTextBlocks::AddName( const String
& rShort
, const String
& rLong
,
175 const String
& rPackageName
, BOOL bOnlyTxt
)
177 USHORT nIdx
= GetIndex( rShort
);
178 if( nIdx
!= (USHORT
) -1 )
179 aNames
.DeleteAndDestroy( nIdx
);
180 SwBlockName
* pNew
= new SwBlockName( rShort
, rLong
, rPackageName
);
181 pNew
->bIsOnlyTxtFlagInit
= TRUE
;
182 pNew
->bIsOnlyTxt
= bOnlyTxt
;
183 aNames
.C40_PTR_INSERT( SwBlockName
, pNew
);
187 ULONG
SwXMLTextBlocks::Delete( USHORT n
)
189 String
aPckName (aNames
[ n
]->aPackageName
);
190 uno::Reference
< container::XNameAccess
> xAccess( xBlkRoot
, uno::UNO_QUERY
);
192 xAccess
->hasByName( aPckName
) && xBlkRoot
->isStreamElement( aPckName
) )
196 xBlkRoot
->removeElement ( aPckName
);
197 uno::Reference
< embed::XTransactedObject
> xTrans( xBlkRoot
, uno::UNO_QUERY
);
202 catch ( uno::Exception
)
204 return ERR_SWG_WRITE_ERROR
;
210 ULONG
SwXMLTextBlocks::Rename( USHORT nIdx
, const String
& rNewShort
, const String
& )
212 DBG_ASSERT( xBlkRoot
.is(), "No storage set" );
215 String
aOldName (aNames
[ nIdx
]->aPackageName
);
217 GeneratePackageName( aShort
, aPackageName
);
218 if (IsOnlyTextBlock ( nIdx
) )
220 String
sExt( String::CreateFromAscii( ".xml" ));
221 String
aOldStreamName( aOldName
); aOldStreamName
+= sExt
;
222 String
aNewStreamName( aPackageName
); aNewStreamName
+= sExt
;
224 xRoot
= xBlkRoot
->openStorageElement( aOldName
, embed::ElementModes::READWRITE
);
225 xRoot
->renameElement ( aOldStreamName
, aNewStreamName
);
226 uno::Reference
< embed::XTransactedObject
> xTrans( xRoot
, uno::UNO_QUERY
);
232 if(aOldName
!= aPackageName
)
236 xBlkRoot
->renameElement ( aOldName
, aPackageName
);
238 catch( const container::ElementExistException
& rEx
)
243 uno::Reference
< embed::XTransactedObject
> xTrans( xBlkRoot
, uno::UNO_QUERY
);
246 // No need to commit xBlkRoot here as SwTextBlocks::Rename calls
247 // WriteInfo which does the commit
251 ULONG
SwXMLTextBlocks::CopyBlock( SwImpBlocks
& rDestImp
, String
& rShort
,
256 rDestImp
.OpenFile(FALSE
);
257 String
aGroup( rShort
);
258 BOOL bTextOnly
= IsOnlyTextBlock ( rShort
) ;//pImp->pBlkRoot->IsStream( aGroup );
259 USHORT nIndex
= GetIndex ( rShort
);
260 String
sDestShortName( GetPackageName (nIndex
) );
263 DBG_ASSERT( xBlkRoot
.is(), "No storage set" );
265 return ERR_SWG_WRITE_ERROR
;
267 uno::Reference
< container::XNameAccess
> xAccess( ((SwXMLTextBlocks
&)rDestImp
).xBlkRoot
, uno::UNO_QUERY
);
268 while ( xAccess
->hasByName( sDestShortName
) )
271 //falls wirklich mal einer so verrueckt ist
272 if(USHRT_MAX
== nIdx
)
275 rDestImp
.CloseFile();
276 return ERR_SWG_WRITE_ERROR
;
278 sDestShortName
+= String::CreateFromInt32( nIdx
);
283 uno::Reference
< embed::XStorage
> rSourceRoot
= xBlkRoot
->openStorageElement( aGroup
, embed::ElementModes::READ
);
284 uno::Reference
< embed::XStorage
> rDestRoot
= ((SwXMLTextBlocks
&)rDestImp
).xBlkRoot
->openStorageElement( sDestShortName
, embed::ElementModes::READWRITE
);
285 //if(!rSourceRoot.Is())
286 // nError = ERR_SWG_READ_ERROR;
289 rSourceRoot
->copyToStorage( rDestRoot
);
291 catch ( uno::Exception
& )
293 nError
= ERR_SWG_WRITE_ERROR
;
296 /* I think this should work now that text only blocks are in sub-storages as well
299 SvStorageStreamRef rSourceStream = xBlkRoot->OpenStream( aGroup, STREAM_STGREAD );
300 SvStorageStreamRef rDestStream = ((SwXMLTextBlocks&)rDestImp).xBlkRoot-> OpenStream( sDestShortName, STREAM_STGWRITE );
301 if(!rDestStream.Is())
302 nError = ERR_SWG_WRITE_ERROR;
305 if(!rSourceStream->CopyTo(&rDestStream))
306 nError = ERR_SWG_WRITE_ERROR;
308 rDestStream->Commit();
314 rShort
= sDestShortName
;
315 //((SwXMLTextBlocks&)rDestImp).xBlkRoot->Commit();
316 ((SwXMLTextBlocks
&)rDestImp
).AddName( rShort
, rLong
, bTextOnly
);
317 ((SwXMLTextBlocks
&)rDestImp
).MakeBlockList();
320 rDestImp
.CloseFile();
325 ULONG
SwXMLTextBlocks::StartPutBlock( const String
& rShort
, const String
& rPackageName
)
327 DBG_ASSERT( xBlkRoot
.is(), "No storage set" );
332 if( xBlkRoot->IsContained( rPackageName ) )
334 xBlkRoot->Remove( rPackageName );
340 xRoot
= xBlkRoot
->openStorageElement( rPackageName
, embed::ElementModes::READWRITE
);
342 uno::Reference
< beans::XPropertySet
> xRootProps( xRoot
, uno::UNO_QUERY_THROW
);
343 ::rtl::OUString
aPropName( RTL_CONSTASCII_USTRINGPARAM("MediaType") );
344 ::rtl::OUString
aMime( SotExchange::GetFormatMimeType( SOT_FORMATSTR_ID_STARWRITER_8
) );
345 xRootProps
->setPropertyValue( aPropName
, uno::makeAny( aMime
) );
347 catch (uno::Exception
&)
352 ULONG
SwXMLTextBlocks::BeginPutDoc( const String
& rShort
, const String
& rLong
)
354 // In der Basisklasse ablegen!
357 GeneratePackageName( rShort
, aPackageName
);
358 SetIsTextOnly( rShort
, FALSE
);
359 return StartPutBlock (rShort
, aPackageName
);
362 ULONG
SwXMLTextBlocks::PutBlock( SwPaM
& , const String
& )
365 USHORT nCommitFlags
= nFlags
& (SWXML_CONVBLOCK
|SWXML_NOROOTCOMMIT
);
367 nFlags
|= nCommitFlags
;
370 ::GetXMLWriter ( aEmptyStr
, GetBaseURL(), xWrt
);
371 SwWriter
aWriter (xRoot
, *pDoc
);
373 xWrt
->bBlock
= sal_True
;
374 nRes
= aWriter
.Write ( xWrt
);
375 xWrt
->bBlock
= sal_False
;
376 // Save OLE objects if there are some
377 SwDocShell
*pDocSh
= pDoc
->GetDocShell();
379 sal_Bool bHasChildren
= pDocSh
&& pDocSh
->GetEmbeddedObjectContainer().HasEmbeddedObjects();
380 if( !nRes
&& bHasChildren
)
382 // we have to write to the temporary storage first, since the used below functions are optimized
383 // TODO/LATER: it is only a temporary solution, that should be changed soon, the used methods should be
384 // called without optimization
386 sal_Bool bOK
= sal_False
;
390 SfxMedium
* pTmpMedium
= NULL
;
393 uno::Reference
< embed::XStorage
> xTempStorage
=
394 ::comphelper::OStorageHelper::GetTemporaryStorage();
396 xRoot
->copyToStorage( xTempStorage
);
398 // TODO/LATER: no progress bar?!
399 // TODO/MBA: strange construct
400 pTmpMedium
= new SfxMedium( xTempStorage
, GetBaseURL() );
401 sal_Bool bTmpOK
= pDocSh
->SaveAsChildren( *pTmpMedium
);
403 bTmpOK
= pDocSh
->SaveCompletedChildren( sal_False
);
405 xTempStorage
->copyToStorage( xRoot
);
408 catch( uno::Exception
& )
413 DELETEZ( pTmpMedium
);
417 nRes
= ERR_SWG_WRITE_ERROR
;
422 uno::Reference
< embed::XTransactedObject
> xTrans( xRoot
, uno::UNO_QUERY
);
428 uno::Reference
< embed::XTransactedObject
> xTmpTrans( xBlkRoot
, uno::UNO_QUERY
);
429 if ( xTmpTrans
.is() )
433 catch (uno::Exception
&)
437 //TODO/LATER: error handling
439 ULONG nErr = xBlkRoot->GetError();
440 if( nErr == SVSTREAM_DISK_FULL )
441 nRes = ERR_W4W_WRITE_FULL;
442 else if( nErr != SVSTREAM_OK )
443 nRes = ERR_SWG_WRITE_ERROR;
444 nFlags |= nCommitFlags;
449 ULONG
SwXMLTextBlocks::PutDoc()
451 SwPaM
* pPaM
= MakePaM();
452 ULONG nErr
= PutBlock(*pPaM
, aLong
);
457 ULONG
SwXMLTextBlocks::GetText( USHORT nIdx
, String
& rText
)
459 return GetBlockText( aNames
[ nIdx
]->aShort
, rText
);
462 ULONG
SwXMLTextBlocks::GetText( const String
& rShort
, String
& rText
)
464 return GetBlockText( rShort
, rText
);
468 ULONG
SwXMLTextBlocks::MakeBlockList()
474 BOOL
SwXMLTextBlocks::PutMuchEntries( BOOL bOn
)
479 if( bInPutMuchBlocks
)
481 ASSERT( !this, "verschachtelte Aufrufe sind nicht erlaubt" );
483 else if( !IsFileChanged() )
485 bRet
= 0 == OpenFile( FALSE
);
488 nFlags
|= SWXML_NOROOTCOMMIT
;
489 bInPutMuchBlocks
= TRUE
;
493 else if( bInPutMuchBlocks
)
495 nFlags
&= ~SWXML_NOROOTCOMMIT
;
500 uno::Reference
< embed::XTransactedObject
> xTrans( xBlkRoot
, uno::UNO_QUERY
);
506 bInPutMuchBlocks
= FALSE
;
509 catch (uno::Exception
&)
517 ULONG
SwXMLTextBlocks::OpenFile( BOOL bRdOnly
)
524 uno::Reference
< embed::XStorage
> refStg
= comphelper::OStorageHelper::GetStorageFromURL( aFile
,
525 bRdOnly
? embed::ElementModes::READ
: embed::ElementModes::READWRITE
);
526 InitBlockMode ( refStg
);
528 catch ( uno::Exception
& )
530 //TODO/LATER: error handling
537 void SwXMLTextBlocks::CloseFile()
539 if ( !bAutocorrBlock
)
547 void SwXMLTextBlocks::SetIsTextOnly( const String
& rShort
, BOOL bNewValue
)
549 USHORT nIdx
= GetIndex ( rShort
);
550 if (nIdx
!= (USHORT
) -1 && nIdx
!= USHRT_MAX
)
551 aNames
[nIdx
]->bIsOnlyTxt
= bNewValue
;
554 void SwXMLTextBlocks::SetIsTextOnly( USHORT nIdx
, BOOL bNewValue
)
556 aNames
[nIdx
]->bIsOnlyTxt
= bNewValue
;
559 BOOL
SwXMLTextBlocks::IsOnlyTextBlock( const String
& rShort
) const
561 USHORT nIdx
= GetIndex ( rShort
);
563 if (nIdx
!= (USHORT
) -1 && nIdx
!= USHRT_MAX
)
565 bRet
= aNames
[nIdx
]->bIsOnlyTxt
;
569 BOOL
SwXMLTextBlocks::IsOnlyTextBlock( USHORT nIdx
) const
571 return aNames
[nIdx
]->bIsOnlyTxt
;
574 BOOL
SwXMLTextBlocks::IsFileUCBStorage( const String
& rFileName
)
576 String
aName( rFileName
);
577 INetURLObject
aObj( aName
);
578 if ( aObj
.GetProtocol() == INET_PROT_NOT_VALID
)
581 ::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName
, aURL
);
583 aName
= aObj
.GetMainURL( INetURLObject::NO_DECODE
);
586 SvStream
* pStm
= ::utl::UcbStreamHelper::CreateStream( aName
, STREAM_STD_READ
);
587 BOOL bRet
= UCBStorage::IsStorageFile( pStm
);
594 short SwXMLTextBlocks::GetFileType ( void ) const
599 void SwXMLTextBlocks::GeneratePackageName ( const String
& rShort
, String
& rPackageName
)
601 rPackageName
= rShort
;
603 sal_Unicode pDelims
[] = { '!', '/', ':', '.', '\\', 0 };
604 ByteString
sByte ( rPackageName
, RTL_TEXTENCODING_UTF7
);
605 rPackageName
= String (sByte
, RTL_TEXTENCODING_ASCII_US
);
606 while( STRING_NOTFOUND
!= ( nPos
= rPackageName
.SearchChar( pDelims
, nPos
)))
608 rPackageName
.SetChar( nPos
, '_' );
613 ULONG
SwXMLTextBlocks::PutText( const String
& rShort
, const String
& rName
,
614 const String
& rText
)
620 SetIsTextOnly( aShort
, TRUE
);
621 GeneratePackageName( rShort
, aPackageName
);
623 nRes
= PutBlockText( rShort
, rName
, rText
, aPackageName
);
627 void SwXMLTextBlocks::MakeBlockText( const String
& rText
)
629 SwTxtNode
* pTxtNode
= pDoc
->GetNodes()[ pDoc
->GetNodes().GetEndOfContent().
630 GetIndex() - 1 ]->GetTxtNode();
631 //JP 18.09.98: Bug 56706 - Standard sollte zumindest gesetzt sein!
632 if( pTxtNode
->GetTxtColl() == pDoc
->GetDfltTxtFmtColl() )
633 pTxtNode
->ChgFmtColl( pDoc
->GetTxtCollFromPool( RES_POOLCOLL_STANDARD
));
640 pTxtNode
= (SwTxtNode
*)pTxtNode
->AppendNode( SwPosition( *pTxtNode
) );
642 SwIndex
aIdx( pTxtNode
);
643 String
sTemp(rText
.GetToken( 0, '\015', nPos
) );
644 pTxtNode
->InsertText( sTemp
, aIdx
);
645 } while ( STRING_NOTFOUND
!= nPos
);