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