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