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