LibreOffice Module sw (master)  1
SwXMLTextBlocks.cxx
Go to the documentation of this file.
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 <com/sun/star/embed/ElementModes.hpp>
21 #include <com/sun/star/embed/XTransactedObject.hpp>
22 #include <com/sun/star/embed/XStorage.hpp>
23 #include <com/sun/star/container/XNameAccess.hpp>
24 #include <com/sun/star/container/ElementExistException.hpp>
25 #include <com/sun/star/beans/XPropertySet.hpp>
26 #include <osl/file.hxx>
27 #include <rtl/ustring.hxx>
28 #include <sal/log.hxx>
29 #include <sot/exchange.hxx>
30 #include <sot/stg.hxx>
31 #include <sfx2/docfile.hxx>
32 #include <tools/urlobj.hxx>
34 
36 #include <doc.hxx>
37 #include <IDocumentUndoRedo.hxx>
39 #include <docsh.hxx>
40 #include <pam.hxx>
41 #include <swblocks.hxx>
42 #include <ndtxt.hxx>
43 #include <shellio.hxx>
44 #include <poolfmt.hxx>
45 #include <SwXMLTextBlocks.hxx>
46 #include <SwXMLBlockImport.hxx>
47 #include <SwXMLBlockExport.hxx>
48 #include <swerror.h>
49 
50 using namespace ::com::sun::star;
51 
52 void SwXMLTextBlocks::InitBlockMode ( const uno::Reference < embed::XStorage >& rStorage )
53 {
54  xBlkRoot = rStorage;
55  xRoot = nullptr;
56 }
57 
59 {
60  xBlkRoot = nullptr;
61  xRoot = nullptr;
62 }
63 
64 SwXMLTextBlocks::SwXMLTextBlocks( const OUString& rFile )
65  : SwImpBlocks(rFile)
66  , nFlags(SwXmlFlags::NONE)
67 {
68  SwDocShell* pDocSh = new SwDocShell ( SfxObjectCreateMode::INTERNAL );
69  if( !pDocSh->DoInitNew() )
70  return;
71  m_bReadOnly = true;
72  m_xDoc = pDocSh->GetDoc();
73  xDocShellRef = pDocSh;
74  m_xDoc->SetOle2Link( Link<bool,void>() );
75  m_xDoc->GetIDocumentUndoRedo().DoUndo(false);
76  uno::Reference< embed::XStorage > refStg;
78  Touch(); // If it's created anew -> get a new timestamp
79 
80  try
81  {
82  refStg = comphelper::OStorageHelper::GetStorageFromURL( rFile, embed::ElementModes::READWRITE );
83  m_bReadOnly = false;
84  }
85  catch(const uno::Exception&)
86  {
87  //FIXME: couldn't open the file - maybe it's readonly
88  }
89  if( !refStg.is())
90  {
91  try
92  {
93  refStg = comphelper::OStorageHelper::GetStorageFromURL( rFile, embed::ElementModes::READ );
94  }
95  catch(const uno::Exception&)
96  {
97  OSL_FAIL("exception while creating AutoText storage");
98  }
99  }
100  InitBlockMode ( refStg );
101  ReadInfo();
102  ResetBlockMode ();
103  m_bInfoChanged = false;
104 }
105 
106 SwXMLTextBlocks::SwXMLTextBlocks( const uno::Reference < embed::XStorage >& rStg, const OUString& rName )
107  : SwImpBlocks( rName )
108  , nFlags(SwXmlFlags::NONE)
109 {
110  SwDocShell* pDocSh = new SwDocShell ( SfxObjectCreateMode::INTERNAL );
111  if( !pDocSh->DoInitNew() )
112  return;
113  m_bReadOnly = false;
114  m_xDoc = pDocSh->GetDoc();
115  xDocShellRef = pDocSh;
116  m_xDoc->SetOle2Link( Link<bool,void>() );
117  m_xDoc->GetIDocumentUndoRedo().DoUndo(false);
118 
119  InitBlockMode ( rStg );
120  ReadInfo();
121  m_bInfoChanged = false;
122 }
123 
125 {
126  if ( m_bInfoChanged )
127  WriteInfo();
128  ResetBlockMode ();
129  if(xDocShellRef.is())
131  xDocShellRef = nullptr;
132 }
133 
135 {
136  SwDocShell * pDocShell = m_xDoc->GetDocShell();
137  pDocShell->InvalidateModel();
138  pDocShell->ReactivateModel();
139 
140  m_xDoc->ClearDoc();
141  pDocShell->ClearEmbeddedObjects();
142 }
143 
144 void SwXMLTextBlocks::AddName( const OUString& rShort, const OUString& rLong, bool bOnlyText )
145 {
146  aPackageName = GeneratePackageName( rShort );
147  AddName(rShort, rLong, aPackageName, bOnlyText);
148 }
149 
150 void SwXMLTextBlocks::AddName( const OUString& rShort, const OUString& rLong,
151  const OUString& rPackageName, bool bOnlyText )
152 {
153  sal_uInt16 nIdx = GetIndex( rShort );
154  if (nIdx != USHRT_MAX)
155  {
156  m_aNames.erase( m_aNames.begin() + nIdx );
157  }
158  std::unique_ptr<SwBlockName> pNew(new SwBlockName( rShort, rLong, rPackageName ));
159  pNew->bIsOnlyTextFlagInit = true;
160  pNew->bIsOnlyText = bOnlyText;
161  m_aNames.insert( std::move(pNew) );
162  m_bInfoChanged = true;
163 }
164 
166 {
167  const OUString aPckName (m_aNames[n]->aPackageName);
168  if ( xBlkRoot.is() &&
169  xBlkRoot->hasByName( aPckName ) && xBlkRoot->isStreamElement( aPckName ) )
170  {
171  try
172  {
173  xBlkRoot->removeElement ( aPckName );
174  uno::Reference < embed::XTransactedObject > xTrans( xBlkRoot, uno::UNO_QUERY );
175  if ( xTrans.is() )
176  xTrans->commit();
177  return ERRCODE_NONE;
178  }
179  catch (const uno::Exception&)
180  {
181  return ERR_SWG_WRITE_ERROR;
182  }
183  }
184  return ERRCODE_NONE;
185 }
186 
187 ErrCode SwXMLTextBlocks::Rename( sal_uInt16 nIdx, const OUString& rNewShort, const OUString& )
188 {
189  OSL_ENSURE( xBlkRoot.is(), "No storage set" );
190  if(!xBlkRoot.is())
191  return ERRCODE_NONE;
192  OUString aOldName (m_aNames[nIdx]->aPackageName);
193  m_aShort = rNewShort;
195 
196  if(aOldName != aPackageName)
197  {
198  if (IsOnlyTextBlock ( nIdx ) )
199  {
200  OUString sExt(".xml");
201  OUString aOldStreamName( aOldName ); aOldStreamName += sExt;
202  OUString aNewStreamName( aPackageName ); aNewStreamName += sExt;
203 
204  xRoot = xBlkRoot->openStorageElement( aOldName, embed::ElementModes::READWRITE );
205  try
206  {
207  xRoot->renameElement ( aOldStreamName, aNewStreamName );
208  }
209  catch(const container::ElementExistException&)
210  {
211  SAL_WARN("sw", "Couldn't rename " << aOldStreamName << " to " << aNewStreamName);
212  }
213  uno::Reference < embed::XTransactedObject > xTrans( xRoot, uno::UNO_QUERY );
214  if ( xTrans.is() )
215  xTrans->commit();
216  xRoot = nullptr;
217  }
218 
219  try
220  {
221  xBlkRoot->renameElement ( aOldName, aPackageName );
222  }
223  catch(const container::ElementExistException&)
224  {
225  SAL_WARN("sw", "Couldn't rename " << aOldName << " to " << aPackageName);
226  }
227  }
228  uno::Reference < embed::XTransactedObject > xTrans( xBlkRoot, uno::UNO_QUERY );
229  if ( xTrans.is() )
230  xTrans->commit();
231  // No need to commit xBlkRoot here as SwTextBlocks::Rename calls
232  // WriteInfo which does the commit
233  return ERRCODE_NONE;
234 }
235 
236 ErrCode SwXMLTextBlocks::StartPutBlock( const OUString& rShort, const OUString& rPackageName )
237 {
238  OSL_ENSURE( xBlkRoot.is(), "No storage set" );
239  if(!xBlkRoot.is())
240  return ERRCODE_NONE;
241  GetIndex ( rShort );
242  try
243  {
244  xRoot = xBlkRoot->openStorageElement( rPackageName, embed::ElementModes::READWRITE );
245 
246  uno::Reference< beans::XPropertySet > xRootProps( xRoot, uno::UNO_QUERY_THROW );
247  OUString aMime( SotExchange::GetFormatMimeType( SotClipboardFormatId::STARWRITER_8 ) );
248  xRootProps->setPropertyValue( "MediaType", uno::makeAny( aMime ) );
249  }
250  catch (const uno::Exception&)
251  {
252  }
253  return ERRCODE_NONE;
254 }
255 
256 ErrCode SwXMLTextBlocks::BeginPutDoc( const OUString& rShort, const OUString& rLong )
257 {
258  // Store in base class
259  m_aShort = rShort;
260  m_aLong = rLong;
261  aPackageName = GeneratePackageName( rShort );
262  SetIsTextOnly( rShort, false);
263  return StartPutBlock (rShort, aPackageName);
264 }
265 
267 {
268  ErrCode nRes = ERRCODE_NONE; // dead variable, this always returns 0
269  SwXmlFlags nCommitFlags = nFlags;
270 
271  WriterRef xWrt;
272  ::GetXMLWriter ( OUString(), GetBaseURL(), xWrt);
273  SwWriter aWriter (xRoot, *m_xDoc );
274 
275  xWrt->m_bBlock = true;
276  nRes = aWriter.Write ( xWrt );
277  xWrt->m_bBlock = false;
278  // Save OLE objects if there are some
279  SwDocShell *pDocSh = m_xDoc->GetDocShell();
280 
281  bool bHasChildren = pDocSh && pDocSh->GetEmbeddedObjectContainer().HasEmbeddedObjects();
282  if( !nRes && bHasChildren )
283  {
284  // we have to write to the temporary storage first, since the used below functions are optimized
285  // TODO/LATER: it is only a temporary solution, that should be changed soon, the used methods should be
286  // called without optimization
287  bool bOK = false;
288 
289  if ( xRoot.is() )
290  {
291  std::unique_ptr<SfxMedium> pTmpMedium;
292  try
293  {
294  uno::Reference< embed::XStorage > xTempStorage =
296 
297  xRoot->copyToStorage( xTempStorage );
298 
299  // TODO/LATER: no progress bar?!
300  // TODO/MBA: strange construct
301  pTmpMedium.reset(new SfxMedium(xTempStorage, GetBaseURL()));
302  bool bTmpOK = pDocSh->SaveAsChildren( *pTmpMedium );
303  if( bTmpOK )
304  bTmpOK = pDocSh->SaveCompletedChildren();
305 
306  xTempStorage->copyToStorage( xRoot );
307  bOK = bTmpOK;
308  }
309  catch(const uno::Exception&)
310  {
311  }
312  }
313 
314  if( !bOK )
315  nRes = ERR_SWG_WRITE_ERROR;
316  }
317 
318  try
319  {
320  uno::Reference < embed::XTransactedObject > xTrans( xRoot, uno::UNO_QUERY );
321  if ( xTrans.is() )
322  xTrans->commit();
323  xRoot = nullptr;
324  if ( nCommitFlags == SwXmlFlags::NONE )
325  {
326  uno::Reference < embed::XTransactedObject > xTmpTrans( xBlkRoot, uno::UNO_QUERY );
327  if ( xTmpTrans.is() )
328  xTmpTrans->commit();
329  }
330  }
331  catch (const uno::Exception&)
332  {
333  }
334 
335  //TODO/LATER: error handling
336  return ERRCODE_NONE;
337 }
338 
340 {
341  std::unique_ptr<SwPaM> pPaM = MakePaM();
342  ErrCode nErr = PutBlock();
343  return nErr;
344 }
345 
346 ErrCode SwXMLTextBlocks::GetText( const OUString& rShort, OUString& rText )
347 {
348  return GetBlockText( rShort, rText );
349 }
350 
352 {
353  WriteInfo();
354  return ERRCODE_NONE;
355 }
356 
358 {
359  bool bRet = false;
360  if( bOn )
361  {
362  if( m_bInPutMuchBlocks )
363  {
364  OSL_ENSURE( false, "Nested calls are not allowed");
365  }
366  else if( !IsFileChanged() )
367  {
368  bRet = ERRCODE_NONE == OpenFile( false );
369  if( bRet )
370  {
372  m_bInPutMuchBlocks = true;
373  }
374  }
375  }
376  else if( m_bInPutMuchBlocks )
377  {
379  if( xBlkRoot.is() )
380  {
381  try
382  {
383  uno::Reference < embed::XTransactedObject > xTrans( xBlkRoot, uno::UNO_QUERY );
384  if ( xTrans.is() )
385  xTrans->commit();
386  MakeBlockList();
387  CloseFile();
388  Touch();
389  m_bInPutMuchBlocks = false;
390  bRet = true;
391  }
392  catch (const uno::Exception&)
393  {
394  }
395  }
396  }
397  return bRet;
398 }
399 
401 {
402  ErrCode nRet = ERRCODE_NONE;
403  try
404  {
405  uno::Reference < embed::XStorage > refStg = comphelper::OStorageHelper::GetStorageFromURL( m_aFile,
406  bRdOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE );
407  InitBlockMode ( refStg );
408  }
409  catch (const uno::Exception&)
410  {
411  //TODO/LATER: error handling
412  nRet = ErrCode(1);
413  }
414 
415  return nRet;
416 }
417 
419 {
420  if (m_bInfoChanged)
421  WriteInfo();
422  ResetBlockMode();
423 }
424 
425 void SwXMLTextBlocks::SetIsTextOnly( const OUString& rShort, bool bNewValue )
426 {
427  sal_uInt16 nIdx = GetIndex ( rShort );
428  if (nIdx != USHRT_MAX)
429  m_aNames[nIdx]->bIsOnlyText = bNewValue;
430 }
431 
432 bool SwXMLTextBlocks::IsOnlyTextBlock( const OUString& rShort ) const
433 {
434  sal_uInt16 nIdx = GetIndex ( rShort );
435  bool bRet = false;
436  if (nIdx != USHRT_MAX)
437  {
438  bRet = m_aNames[nIdx]->bIsOnlyText;
439  }
440  return bRet;
441 }
442 bool SwXMLTextBlocks::IsOnlyTextBlock( sal_uInt16 nIdx ) const
443 {
444  return m_aNames[nIdx]->bIsOnlyText;
445 }
446 
447 bool SwXMLTextBlocks::IsFileUCBStorage( const OUString & rFileName)
448 {
449  OUString aName( rFileName );
450  INetURLObject aObj( aName );
451  if ( aObj.GetProtocol() == INetProtocol::NotValid )
452  {
453  OUString aURL;
454  osl::FileBase::getFileURLFromSystemPath( aName, aURL );
455  aObj.SetURL( aURL );
457  }
458 
459  std::unique_ptr<SvStream> pStm = ::utl::UcbStreamHelper::CreateStream( aName, StreamMode::STD_READ );
460  bool bRet = UCBStorage::IsStorageFile( pStm.get() );
461  return bRet;
462 }
463 
465 {
466  return FileType::XML;
467 }
468 
469 OUString SwXMLTextBlocks::GeneratePackageName ( const OUString& rShort )
470 {
471  OString sByte(OUStringToOString(rShort, RTL_TEXTENCODING_UTF7));
472  OUStringBuffer aBuf(OStringToOUString(sByte, RTL_TEXTENCODING_ASCII_US));
473  const sal_Int32 nLen = aBuf.getLength();
474  for (sal_Int32 nPos=0; nPos<nLen; ++nPos)
475  {
476  switch (aBuf[nPos])
477  {
478  case '!':
479  case '/':
480  case ':':
481  case '.':
482  case '\\':
483  aBuf[nPos] = '_';
484  break;
485  default:
486  break;
487  }
488  }
489  return aBuf.makeStringAndClear();
490 }
491 
492 ErrCode SwXMLTextBlocks::PutText( const OUString& rShort, const OUString& rName,
493  const OUString& rText )
494 {
495  ErrCode nRes = ERRCODE_NONE;
496  m_aShort = rShort;
497  m_aLong = rName;
498  m_aCurrentText = rText;
499  SetIsTextOnly( m_aShort, true );
500  aPackageName = GeneratePackageName( rShort );
501  ClearDoc();
502  nRes = PutBlockText( rShort, rText, aPackageName );
503  return nRes;
504 }
505 
506 void SwXMLTextBlocks::MakeBlockText( const OUString& rText )
507 {
508  SwTextNode* pTextNode = m_xDoc->GetNodes()[ m_xDoc->GetNodes().GetEndOfContent().
509  GetIndex() - 1 ]->GetTextNode();
510  if( pTextNode->GetTextColl() == m_xDoc->GetDfltTextFormatColl() )
511  pTextNode->ChgFormatColl( m_xDoc->getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD ));
512 
513  sal_Int32 nPos = 0;
514  do
515  {
516  if ( nPos )
517  {
518  pTextNode = static_cast<SwTextNode*>(pTextNode->AppendNode( SwPosition( *pTextNode ) ));
519  }
520  SwIndex aIdx( pTextNode );
521  pTextNode->InsertText( rText.getToken( 0, '\015', nPos ), aIdx );
522  } while ( -1 != nPos );
523 }
524 
525 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool is() const
void GetXMLWriter(const OUString &, const OUString &rBaseURL, WriterRef &xRet)
Definition: wrtxml.cxx:568
Marks a position in the document model.
Definition: pam.hxx:35
void InitBlockMode(const css::uno::Reference< css::embed::XStorage > &rStorage)
#define ERR_SWG_WRITE_ERROR
Definition: swerror.h:30
bool SaveCompletedChildren()
rtl::Reference< SwDoc > m_xDoc
Definition: swblocks.hxx:66
sal_uInt16 GetIndex(const OUString &) const
Get count of Text Blocks.
Definition: swblocks.cxx:137
virtual ~SwXMLTextBlocks() override
aBuf
ErrCode PutBlockText(const OUString &rShort, const OUString &rText, const OUString &rPackageName)
ErrCode Write(WriterRef const &rxWriter, const OUString *=nullptr)
Definition: shellio.cxx:727
virtual bool IsOnlyTextBlock(const OUString &rShort) const override
virtual ErrCode Delete(sal_uInt16) override
OUString const m_aFile
Definition: swblocks.hxx:58
virtual ErrCode OpenFile(bool bReadOnly=true) override
virtual void CloseFile() override
tools::Time m_aTimeModified
Definition: swblocks.hxx:65
static std::unique_ptr< SvStream > CreateStream(const OUString &rFileName, StreamMode eOpenMode, css::uno::Reference< css::awt::XWindow > xParentWin=nullptr)
virtual void ClearDoc() override
Delete the document's content.
SfxObjectShellRef xDocShellRef
sal_Int32 GetDate() const
SwContentNode * AppendNode(const SwPosition &)
Definition: ndtxt.cxx:3033
bool IsFileChanged() const
Definition: swblocks.cxx:199
OUString m_aShort
Definition: swblocks.hxx:61
virtual ErrCode PutText(const OUString &, const OUString &, const OUString &) override
SwXmlFlags
void SetIsTextOnly(const OUString &rShort, bool bNewValue)
SwDoc * GetDoc()
returns Doc. But be careful!
Definition: docsh.hxx:203
virtual ErrCode MakeBlockList() override
css::uno::Reference< css::embed::XStorage > xBlkRoot
static css::uno::Reference< css::embed::XStorage > GetTemporaryStorage(const css::uno::Reference< css::uno::XComponentContext > &rxContext=css::uno::Reference< css::uno::XComponentContext >())
bool m_bInfoChanged
Definition: swblocks.hxx:70
const OUString & GetBaseURL() const
Definition: swblocks.hxx:106
virtual bool PutMuchEntries(bool bOn) override
virtual ErrCode PutDoc() override
SwXMLTextBlocks(const OUString &rFile)
virtual FileType GetFileType() const override
Marks a character position inside a document model node.
Definition: index.hxx:37
virtual SwFormatColl * ChgFormatColl(SwFormatColl *) override
Definition: ndtxt.cxx:3928
static css::uno::Reference< css::embed::XStorage > GetStorageFromURL(const OUString &aURL, sal_Int32 nStorageMode, const css::uno::Reference< css::uno::XComponentContext > &rxContext=css::uno::Reference< css::uno::XComponentContext >())
static OUString GetFormatMimeType(SotClipboardFormatId nFormat)
virtual ErrCode Rename(sal_uInt16, const OUString &, const OUString &) override
void AddName(const OUString &, const OUString &, const OUString &, bool bOnlyText)
const_iterator begin() const
OString OUStringToOString(const OUString &str, ConnectionSettings const *settings)
std::unique_ptr< SwPaM > MakePaM()
Creating a PaM, that spans the whole document.
Definition: swblocks.cxx:119
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
OUString m_aLong
Definition: swblocks.hxx:61
void InvalidateModel()
Definition: docshini.cxx:460
ErrCode StartPutBlock(const OUString &rShort, const OUString &rPackageName)
OUString InsertText(const OUString &rStr, const SwIndex &rIdx, const SwInsertFlags nMode=SwInsertFlags::DEFAULT)
insert text content
Definition: ndtxt.cxx:2283
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
comphelper::EmbeddedObjectContainer & GetEmbeddedObjectContainer() const
void MakeBlockText(const OUString &rText)
#define ERRCODE_NONE
OUString m_aCurrentText
Definition: swblocks.hxx:60
const o3tl::enumarray< SvxAdjust, unsigned short > aSvxToUnoAdjust USHRT_MAX
Definition: unosett.cxx:261
static bool IsStorageFile(SvStream *)
INetProtocol GetProtocol() const
bool DoInitNew(SfxMedium *pMedium=nullptr)
css::uno::Reference< css::embed::XStorage > xRoot
sal_Int64 GetTime() const
virtual ErrCode BeginPutDoc(const OUString &, const OUString &) override
ErrCode GetBlockText(const OUString &rShort, OUString &rText)
static OUString GeneratePackageName(const OUString &rShort)
bool m_bReadOnly
Definition: swblocks.hxx:68
bool SaveAsChildren(SfxMedium &rMedium)
Date m_aDateModified
Definition: swblocks.hxx:64
OString const aName
#define SAL_WARN(area, stream)
bool SetURL(OUString const &rTheAbsURIRef, EncodeMechanism eMechanism=EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
std::pair< const_iterator, bool > insert(Value &&x)
bool m_bInPutMuchBlocks
Definition: swblocks.hxx:69
sal_Int32 nPos
void ClearEmbeddedObjects()
SwBlockNames m_aNames
Definition: swblocks.hxx:63
ErrCode GetText(const OUString &rShort, OUString &)
static bool IsFileUCBStorage(const OUString &rFileName)
size_type erase(const Value &x)
void Touch()
Definition: swblocks.cxx:208
void ReactivateModel()
Definition: docshini.cxx:466
SwTextFormatColl * GetTextColl() const
Definition: ndtxt.hxx:837