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 <sal/config.h>
21 
22 #include <o3tl/safeint.hxx>
23 #include <osl/diagnose.h>
24 #include <osl/endian.h>
25 #include <tools/urlobj.hxx>
26 #include <doc.hxx>
27 #include <IDocumentRedlineAccess.hxx>
28 #include <IDocumentFieldsAccess.hxx>
29 #include <pam.hxx>
30 #include <editsh.hxx>
31 #include <frmfmt.hxx>
32 #include <rootfrm.hxx>
33 #include <ndtxt.hxx>
34 #include <swtable.hxx>
35 #include <shellio.hxx>
36 #include <iodetect.hxx>
37 #include <frameformats.hxx>
38 
InsertGlossary(SwTextBlocks & rGlossary,const OUString & rStr)39 void SwEditShell::InsertGlossary( SwTextBlocks& rGlossary, const OUString& rStr )
40 {
41     StartAllAction();
42     GetDoc()->InsertGlossary( rGlossary, rStr, *GetCursor(), this );
43     EndAllAction();
44 }
45 
46 /// convert current selection into text block and add to the text block document, incl. templates
MakeGlossary(SwTextBlocks & rBlks,const OUString & rName,const OUString & rShortName,bool bSaveRelFile,const OUString * pOnlyText)47 sal_uInt16 SwEditShell::MakeGlossary( SwTextBlocks& rBlks, const OUString& rName, const OUString& rShortName,
48                                     bool bSaveRelFile, const OUString* pOnlyText )
49 {
50     SwDoc* pGDoc = rBlks.GetDoc();
51 
52     OUString sBase;
53     if(bSaveRelFile)
54     {
55         INetURLObject aURL( rBlks.GetFileName() );
56         sBase = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
57     }
58     rBlks.SetBaseURL( sBase );
59 
60     if( pOnlyText )
61         return rBlks.PutText( rShortName, rName, *pOnlyText );
62 
63     rBlks.ClearDoc();
64     if( rBlks.BeginPutDoc( rShortName, rName ) )
65     {
66         rBlks.GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::DeleteRedlines );
67         CopySelToDoc(*pGDoc);
68         rBlks.GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::NONE );
69         return rBlks.PutDoc();
70     }
71 
72     return USHRT_MAX;
73 }
74 
SaveGlossaryDoc(SwTextBlocks & rBlock,const OUString & rName,const OUString & rShortName,bool bSaveRelFile,bool bOnlyText)75 sal_uInt16 SwEditShell::SaveGlossaryDoc( SwTextBlocks& rBlock,
76                                     const OUString& rName,
77                                     const OUString& rShortName,
78                                     bool bSaveRelFile,
79                                     bool bOnlyText )
80 {
81     StartAllAction();
82 
83     SwDoc* pGDoc = rBlock.GetDoc();
84     SwDoc* pMyDoc = GetDoc();
85 
86     OUString sBase;
87     if(bSaveRelFile)
88     {
89         INetURLObject aURL( rBlock.GetFileName() );
90         sBase = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
91     }
92     rBlock.SetBaseURL( sBase );
93     sal_uInt16 nRet = USHRT_MAX;
94 
95     if( bOnlyText )
96     {
97         KillPams();
98 
99         SwPaM* pCursor = GetCursor();
100 
101         SwNodeIndex aStt( pMyDoc->GetNodes().GetEndOfExtras(), 1 );
102         SwContentNode* pContentNd = pMyDoc->GetNodes().GoNext( &aStt );
103         const SwNode* pNd = pContentNd->FindTableNode();
104         if( !pNd )
105             pNd = pContentNd;
106 
107         pCursor->GetPoint()->nNode = *pNd;
108         if( pNd == pContentNd )
109             pCursor->GetPoint()->nContent.Assign( pContentNd, 0 );
110         pCursor->SetMark();
111 
112         // then until the end of the Node array
113         pCursor->GetPoint()->nNode = pMyDoc->GetNodes().GetEndOfContent().GetIndex()-1;
114         pContentNd = pCursor->GetContentNode();
115         if( pContentNd )
116             pCursor->GetPoint()->nContent.Assign( pContentNd, pContentNd->Len() );
117 
118         OUString sBuf;
119         GetSelectedText( sBuf, ParaBreakType::ToOnlyCR );
120         if( !sBuf.isEmpty() )
121             nRet = rBlock.PutText( rShortName, rName, sBuf );
122     }
123     else
124     {
125         rBlock.ClearDoc();
126         if( rBlock.BeginPutDoc( rShortName, rName ) )
127         {
128             SwNodeIndex aStt( pMyDoc->GetNodes().GetEndOfExtras(), 1 );
129             SwContentNode* pContentNd = pMyDoc->GetNodes().GoNext( &aStt );
130             const SwNode* pNd = pContentNd->FindTableNode();
131             if( !pNd ) pNd = pContentNd;
132             SwPaM aCpyPam( *pNd );
133             aCpyPam.SetMark();
134 
135             // then until the end of the nodes array
136             aCpyPam.GetPoint()->nNode = pMyDoc->GetNodes().GetEndOfContent().GetIndex()-1;
137             pContentNd = aCpyPam.GetContentNode();
138             aCpyPam.GetPoint()->nContent.Assign(
139                    pContentNd, pContentNd ? pContentNd->Len() : 0);
140 
141             aStt = pGDoc->GetNodes().GetEndOfExtras();
142             pContentNd = pGDoc->GetNodes().GoNext( &aStt );
143             SwPosition aInsPos( aStt, SwIndex( pContentNd ));
144             pMyDoc->getIDocumentContentOperations().CopyRange(aCpyPam, aInsPos, SwCopyFlags::CheckPosInFly);
145 
146             nRet = rBlock.PutDoc();
147         }
148     }
149     EndAllAction();
150     return nRet;
151 }
152 
153 /// copy all selections to the doc
CopySelToDoc(SwDoc & rInsDoc)154 bool SwEditShell::CopySelToDoc( SwDoc& rInsDoc )
155 {
156     SwNodes& rNds = rInsDoc.GetNodes();
157 
158     SwNodeIndex aIdx( rNds.GetEndOfContent(), -1 );
159     SwContentNode *const pContentNode = aIdx.GetNode().GetContentNode();
160     SwPosition aPos( aIdx,
161         SwIndex(pContentNode, pContentNode ? pContentNode->Len() : 0));
162 
163     bool bRet = false;
164     CurrShell aCurr( this );
165 
166     rInsDoc.getIDocumentFieldsAccess().LockExpFields();
167 
168     if( IsTableMode() )
169     {
170         // Copy parts of a table: create a table with the width of the original one and copy the
171         // selected boxes. The sizes are corrected on a percentage basis.
172 
173         // search boxes using the layout
174         SwTableNode* pTableNd;
175         SwSelBoxes aBoxes;
176         GetTableSel( *this, aBoxes );
177         if( !aBoxes.empty() && nullptr != (pTableNd = const_cast<SwTableNode*>(aBoxes[0]
178             ->GetSttNd()->FindTableNode()) ))
179         {
180             // check if the table name can be copied
181             bool bCpyTableNm = aBoxes.size() == pTableNd->GetTable().GetTabSortBoxes().size();
182             if( bCpyTableNm )
183             {
184                 const OUString rTableName = pTableNd->GetTable().GetFrameFormat()->GetName();
185                 const SwFrameFormats& rTableFormats = *rInsDoc.GetTableFrameFormats();
186                 for( auto n = rTableFormats.size(); n; )
187                     if( rTableFormats[ --n ]->GetName() == rTableName )
188                     {
189                         bCpyTableNm = false;
190                         break;
191                     }
192             }
193             bRet = rInsDoc.InsCopyOfTable( aPos, aBoxes, nullptr, bCpyTableNm, false, pTableNd->GetTable().GetTableStyleName() );
194         }
195         else
196             bRet = false;
197     }
198     else
199     {
200         bool bColSel = GetCursor_()->IsColumnSelection();
201         if( bColSel && rInsDoc.IsClipBoard() )
202             rInsDoc.SetColumnSelection( true );
203         bool bSelectAll = StartsWithTable() && ExtendedSelectedAll();
204         {
205             for(SwPaM& rPaM : GetCursor()->GetRingContainer())
206             {
207                 if( !rPaM.HasMark() )
208                 {
209                     SwContentNode *const pNd = rPaM.GetContentNode();
210                     if (nullptr != pNd &&
211                         ( bColSel || !pNd->GetTextNode() ) )
212                     {
213                         rPaM.SetMark();
214                         rPaM.Move( fnMoveForward, GoInContent );
215                         bRet = GetDoc()->getIDocumentContentOperations().CopyRange(rPaM, aPos, SwCopyFlags::CheckPosInFly)
216                             || bRet;
217                         rPaM.Exchange();
218                         rPaM.DeleteMark();
219                     }
220                 }
221                 else
222                 {
223                     // Make a copy, so that in case we need to adjust the selection
224                     // for the purpose of copying, our shell cursor is not touched.
225                     // (Otherwise we would have to restore it.)
226                     SwPaM aPaM(*rPaM.GetMark(), *rPaM.GetPoint());
227                     if (bSelectAll)
228                     {
229                         // Selection starts at the first para of the first cell,
230                         // but we want to copy the table and the start node before
231                         // the first cell as well.
232                         // tdf#133982 tables can be nested
233                         while (SwTableNode const* pTableNode =
234                             aPaM.Start()->nNode.GetNode().StartOfSectionNode()->FindTableNode())
235                         {
236                             aPaM.Start()->nNode = *pTableNode;
237                         }
238                         while (SwSectionNode const* pSectionNode =
239                             aPaM.Start()->nNode.GetNode().StartOfSectionNode()->FindSectionNode())
240                         {
241                             aPaM.Start()->nNode = *pSectionNode;
242                         }
243                         aPaM.Start()->nContent.Assign(nullptr, 0);
244                     }
245                     bRet = GetDoc()->getIDocumentContentOperations().CopyRange( aPaM, aPos, SwCopyFlags::CheckPosInFly)
246                         || bRet;
247                 }
248             }
249         }
250     }
251 
252     rInsDoc.getIDocumentFieldsAccess().UnlockExpFields();
253     if( !rInsDoc.getIDocumentFieldsAccess().IsExpFieldsLocked() )
254         rInsDoc.getIDocumentFieldsAccess().UpdateExpFields(nullptr, true);
255 
256     return bRet;
257 }
258 
259 /** Get text in a Selection
260  */
GetSelectedText(OUString & rBuf,ParaBreakType nHndlParaBrk)261 void SwEditShell::GetSelectedText( OUString &rBuf, ParaBreakType nHndlParaBrk )
262 {
263     GetCursor();  // creates all cursors if needed
264     if( IsSelOnePara() )
265     {
266         rBuf = GetSelText();
267         if( ParaBreakType::ToBlank == nHndlParaBrk )
268         {
269             rBuf = rBuf.replaceAll("\x0a", " ");
270         }
271         else if( IsSelFullPara() &&
272             ParaBreakType::ToOnlyCR != nHndlParaBrk )
273         {
274 #ifdef _WIN32
275                 rBuf += "\015\012";
276 #else
277                 rBuf += "\012";
278 #endif
279         }
280     }
281     else if( IsSelection() )
282     {
283         SvMemoryStream aStream;
284 #ifdef OSL_BIGENDIAN
285         aStream.SetEndian( SvStreamEndian::BIG );
286 #else
287         aStream.SetEndian( SvStreamEndian::LITTLE );
288 #endif
289         WriterRef xWrt;
290         SwReaderWriter::GetWriter( FILTER_TEXT, OUString(), xWrt );
291         if( xWrt.is() )
292         {
293             // write selected areas into an ASCII document
294             SwWriter aWriter( aStream, *this);
295             xWrt->SetShowProgress(false);
296 
297             switch( nHndlParaBrk )
298             {
299             case ParaBreakType::ToBlank:
300                 xWrt->m_bASCII_ParaAsBlank = true;
301                 xWrt->m_bASCII_NoLastLineEnd = true;
302                 break;
303 
304             case ParaBreakType::ToOnlyCR:
305                 xWrt->m_bASCII_ParaAsCR = true;
306                 xWrt->m_bASCII_NoLastLineEnd = true;
307                 break;
308             }
309 
310             //JP 09.05.00: write as UNICODE ! (and not as ANSI)
311             SwAsciiOptions aAsciiOpt( xWrt->GetAsciiOptions() );
312             aAsciiOpt.SetCharSet( RTL_TEXTENCODING_UCS2 );
313             xWrt->SetAsciiOptions( aAsciiOpt );
314             xWrt->m_bUCS2_WithStartChar = false;
315             xWrt->m_bHideDeleteRedlines = GetLayout()->IsHideRedlines();
316 
317             if ( ! aWriter.Write(xWrt).IsError() )
318             {
319                 aStream.WriteUInt16( '\0' );
320 
321                 const sal_Unicode *p = static_cast<sal_Unicode const *>(aStream.GetData());
322                 if (p)
323                     rBuf = OUString(p);
324                 else
325                 {
326                     const sal_uInt64 nLen = aStream.GetSize();
327                     OSL_ENSURE( nLen/sizeof( sal_Unicode )<o3tl::make_unsigned(SAL_MAX_INT32), "Stream can't fit in OUString" );
328                     rtl_uString *pStr = rtl_uString_alloc(static_cast<sal_Int32>(nLen / sizeof( sal_Unicode )));
329                     aStream.Seek( 0 );
330                     aStream.ResetError();
331                     //endian specific?, yipes!
332                     aStream.ReadBytes(pStr->buffer, nLen);
333                     rBuf = OUString(pStr, SAL_NO_ACQUIRE);
334                 }
335             }
336         }
337     }
338 }
339 
340 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
341