Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / sw / source / uibase / uiview / formatclipboard.cxx
blob7fb50ee8c7c79c8d72e859c6adf65755e9d205eb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <memory>
21 #include <utility>
23 #include <formatclipboard.hxx>
25 #include <o3tl/make_unique.hxx>
26 #include <svx/svxids.hrc>
27 #include <cmdid.h>
28 #include <charfmt.hxx>
29 #include <frmfmt.hxx>
30 #include <docstyle.hxx>
31 #include <fchrfmt.hxx>
32 #include <svx/svdview.hxx>
33 #include <editeng/brushitem.hxx>
34 #include <editeng/shaditem.hxx>
35 #include <editeng/boxitem.hxx>
36 #include <editeng/formatbreakitem.hxx>
37 #include <fmtlsplt.hxx>
38 #include <editeng/keepitem.hxx>
39 #include <editeng/frmdiritem.hxx>
40 #include <fmtpdsc.hxx>
41 #include <fmtrowsplt.hxx>
42 #include <frmatr.hxx>
44 namespace
47 std::unique_ptr<SfxItemSet> lcl_CreateEmptyItemSet( SelectionType nSelectionType, SfxItemPool& rPool, bool bNoParagraphFormats = false )
49 std::unique_ptr<SfxItemSet> pItemSet;
50 if( nSelectionType & (SelectionType::Frame | SelectionType::Ole | SelectionType::Graphic) )
52 pItemSet = o3tl::make_unique<SfxItemSet>(
53 rPool,
54 svl::Items<
55 RES_FRMATR_BEGIN, RES_FILL_ORDER,
56 // no RES_FRM_SIZE
57 RES_PAPER_BIN, RES_SURROUND,
58 // no RES_VERT_ORIENT
59 // no RES_HORI_ORIENT
60 // no RES_ANCHOR
61 RES_BACKGROUND, RES_SHADOW,
62 // no RES_FRMMACRO
63 RES_COL, RES_KEEP,
64 // no RES_URL
65 RES_EDIT_IN_READONLY, RES_LAYOUT_SPLIT,
66 // no RES_CHAIN
67 RES_TEXTGRID, RES_FRMATR_END - 1>{});
69 else if( nSelectionType & SelectionType::DrawObject )
71 //is handled different
73 else if( nSelectionType & SelectionType::Text )
75 if( bNoParagraphFormats )
76 pItemSet = o3tl::make_unique<SfxItemSet>(rPool,
77 svl::Items<RES_CHRATR_BEGIN, RES_CHRATR_END - 1>{});
78 else
79 pItemSet = o3tl::make_unique<SfxItemSet>(
80 rPool,
81 svl::Items<
82 RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
83 RES_PARATR_BEGIN, RES_FILL_ORDER,
84 // no RES_FRM_SIZE
85 RES_PAPER_BIN, RES_SURROUND,
86 // no RES_VERT_ORIENT
87 // no RES_HORI_ORIENT
88 // no RES_ANCHOR
89 RES_BACKGROUND, RES_SHADOW,
90 // no RES_FRMMACRO
91 RES_COL, RES_KEEP,
92 // no RES_URL
93 RES_EDIT_IN_READONLY, RES_LAYOUT_SPLIT,
94 // no RES_CHAIN
95 RES_TEXTGRID, RES_FRMATR_END - 1>{});
97 return pItemSet;
100 void lcl_getTableAttributes( SfxItemSet& rSet, SwWrtShell &rSh )
102 SvxBrushItem aBrush( RES_BACKGROUND );
103 rSh.GetBoxBackground(aBrush);
104 rSet.Put( aBrush );
105 if(rSh.GetRowBackground(aBrush))
107 aBrush.SetWhich(SID_ATTR_BRUSH_ROW);
108 rSet.Put( aBrush );
110 else
111 rSet.InvalidateItem(SID_ATTR_BRUSH_ROW);
112 rSh.GetTabBackground(aBrush);
113 aBrush.SetWhich(SID_ATTR_BRUSH_TABLE);
114 rSet.Put( aBrush );
116 SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER );
117 rSet.Put(aBoxInfo);
118 rSh.GetTabBorders( rSet );
120 SvxFrameDirectionItem aBoxDirection( SvxFrameDirection::Environment, RES_FRAMEDIR );
121 if(rSh.GetBoxDirection( aBoxDirection ))
123 aBoxDirection.SetWhich(FN_TABLE_BOX_TEXTORIENTATION);
124 rSet.Put(aBoxDirection);
127 rSet.Put(SfxUInt16Item(FN_TABLE_SET_VERT_ALIGN, rSh.GetBoxAlign()));
129 rSet.Put( SfxUInt16Item( FN_PARAM_TABLE_HEADLINE, rSh.GetRowsToRepeat() ) );
131 SwFrameFormat *pFrameFormat = rSh.GetTableFormat();
132 if(pFrameFormat)
134 rSet.Put( pFrameFormat->GetShadow() );
135 rSet.Put( pFrameFormat->GetBreak() );
136 rSet.Put( pFrameFormat->GetPageDesc() );
137 rSet.Put( pFrameFormat->GetLayoutSplit() );
138 rSet.Put( pFrameFormat->GetKeep() );
139 rSet.Put( pFrameFormat->GetFrameDir() );
142 SwFormatRowSplit* pSplit = nullptr;
143 rSh.GetRowSplit(pSplit);
144 if(pSplit)
145 rSet.Put(*pSplit);
148 void lcl_setTableAttributes( const SfxItemSet& rSet, SwWrtShell &rSh )
150 const SfxPoolItem* pItem = nullptr;
151 bool bBorder = ( SfxItemState::SET == rSet.GetItemState( RES_BOX ) ||
152 SfxItemState::SET == rSet.GetItemState( SID_ATTR_BORDER_INNER ) );
153 bool bBackground = SfxItemState::SET == rSet.GetItemState( RES_BACKGROUND, false, &pItem );
154 const SfxPoolItem* pRowItem = nullptr, *pTableItem = nullptr;
155 bBackground |= SfxItemState::SET == rSet.GetItemState( SID_ATTR_BRUSH_ROW, false, &pRowItem );
156 bBackground |= SfxItemState::SET == rSet.GetItemState( SID_ATTR_BRUSH_TABLE, false, &pTableItem );
158 if(bBackground)
160 if(pItem)
161 rSh.SetBoxBackground( *static_cast<const SvxBrushItem*>(pItem) );
162 if(pRowItem)
164 SvxBrushItem aBrush(*static_cast<const SvxBrushItem*>(pRowItem));
165 aBrush.SetWhich(RES_BACKGROUND);
166 rSh.SetRowBackground(aBrush);
168 if(pTableItem)
170 SvxBrushItem aBrush(*static_cast<const SvxBrushItem*>(pTableItem));
171 aBrush.SetWhich(RES_BACKGROUND);
172 rSh.SetTabBackground( aBrush );
175 if(bBorder)
176 rSh.SetTabBorders( rSet );
178 if( SfxItemState::SET == rSet.GetItemState( FN_PARAM_TABLE_HEADLINE, false, &pItem) )
179 rSh.SetRowsToRepeat( static_cast<const SfxUInt16Item*>(pItem)->GetValue() );
181 SwFrameFormat* pFrameFormat = rSh.GetTableFormat();
182 if(pFrameFormat)
184 //RES_SHADOW
185 pItem=nullptr;
186 rSet.GetItemState(rSet.GetPool()->GetWhich(RES_SHADOW), false, &pItem);
187 if(pItem)
188 pFrameFormat->SetFormatAttr( *pItem );
190 //RES_BREAK
191 pItem=nullptr;
192 rSet.GetItemState(rSet.GetPool()->GetWhich(RES_BREAK), false, &pItem);
193 if(pItem)
194 pFrameFormat->SetFormatAttr( *pItem );
196 //RES_PAGEDESC
197 pItem=nullptr;
198 rSet.GetItemState(rSet.GetPool()->GetWhich(RES_PAGEDESC), false, &pItem);
199 if(pItem)
200 pFrameFormat->SetFormatAttr( *pItem );
202 //RES_LAYOUT_SPLIT
203 pItem=nullptr;
204 rSet.GetItemState(rSet.GetPool()->GetWhich(RES_LAYOUT_SPLIT), false, &pItem);
205 if(pItem)
206 pFrameFormat->SetFormatAttr( *pItem );
208 //RES_KEEP
209 pItem=nullptr;
210 rSet.GetItemState(rSet.GetPool()->GetWhich(RES_KEEP), false, &pItem);
211 if(pItem)
212 pFrameFormat->SetFormatAttr( *pItem );
214 //RES_FRAMEDIR
215 pItem=nullptr;
216 rSet.GetItemState(rSet.GetPool()->GetWhich(RES_FRAMEDIR), false, &pItem);
217 if(pItem)
218 pFrameFormat->SetFormatAttr( *pItem );
221 if( SfxItemState::SET == rSet.GetItemState( FN_TABLE_BOX_TEXTORIENTATION, false, &pItem) )
223 SvxFrameDirectionItem aDirection( SvxFrameDirection::Environment, RES_FRAMEDIR );
224 aDirection.SetValue(static_cast< const SvxFrameDirectionItem* >(pItem)->GetValue());
225 rSh.SetBoxDirection(aDirection);
228 if( SfxItemState::SET == rSet.GetItemState( FN_TABLE_SET_VERT_ALIGN, false, &pItem))
229 rSh.SetBoxAlign(static_cast<const SfxUInt16Item*>(pItem)->GetValue());
231 if( SfxItemState::SET == rSet.GetItemState( RES_ROW_SPLIT, false, &pItem) )
232 rSh.SetRowSplit(*static_cast<const SwFormatRowSplit*>(pItem));
234 }//end anonymous namespace
236 SwFormatClipboard::SwFormatClipboard()
237 : m_nSelectionType(SelectionType::NONE)
238 , m_bPersistentCopy(false)
242 bool SwFormatClipboard::HasContent() const
244 return m_pItemSet_TextAttr!=nullptr
245 || m_pItemSet_ParAttr!=nullptr
246 || m_pTableItemSet != nullptr
247 || !m_aCharStyle.isEmpty()
248 || !m_aParaStyle.isEmpty()
251 bool SwFormatClipboard::HasContentForThisType( SelectionType nSelectionType ) const
253 if( !HasContent() )
254 return false;
256 if( m_nSelectionType == nSelectionType )
257 return true;
259 if( ( nSelectionType & (SelectionType::Frame | SelectionType::Ole | SelectionType::Graphic) )
261 ( m_nSelectionType & (SelectionType::Frame | SelectionType::Ole | SelectionType::Graphic) )
263 return true;
265 if( nSelectionType & SelectionType::Text && m_nSelectionType & SelectionType::Text )
266 return true;
268 return false;
271 bool SwFormatClipboard::CanCopyThisType( SelectionType nSelectionType )
273 return bool(nSelectionType
274 & (SelectionType::Frame | SelectionType::Ole | SelectionType::Graphic
275 | SelectionType::Text | SelectionType::DrawObject | SelectionType::Table | SelectionType::TableCell ));
278 void SwFormatClipboard::Copy( SwWrtShell& rWrtShell, SfxItemPool& rPool, bool bPersistentCopy )
280 // first clear the previously stored attributes
281 Erase();
282 m_bPersistentCopy = bPersistentCopy;
284 SelectionType nSelectionType = rWrtShell.GetSelectionType();
285 auto pItemSet_TextAttr = lcl_CreateEmptyItemSet( nSelectionType, rPool, true );
286 auto pItemSet_ParAttr = lcl_CreateEmptyItemSet( nSelectionType, rPool );
288 rWrtShell.StartAction();
289 rWrtShell.Push();
291 // modify the "Point and Mark" of the cursor
292 // in order to select only the last character of the
293 // selection(s) and then to get the attributes of this single character
294 if( nSelectionType == SelectionType::Text )
296 // get the current PaM, the cursor
297 // if there several selection it currently point
298 // on the last (sort by there creation time) selection
299 SwPaM* pCursor = rWrtShell.GetCursor();
301 bool bHasSelection = pCursor->HasMark();
302 bool bForwardSelection = false;
304 if(!bHasSelection && pCursor->IsMultiSelection())
306 // if cursor has multiple selections
308 // clear all the selections except the last
309 rWrtShell.KillPams();
311 // reset the cursor to the remaining selection
312 pCursor = rWrtShell.GetCursor();
313 bHasSelection = true;
316 bool dontMove = false;
317 if (bHasSelection)
319 bForwardSelection = (*pCursor->GetPoint()) > (*pCursor->GetMark());
321 // clear the selection leaving just the cursor
322 pCursor->DeleteMark();
323 pCursor->SetMark();
325 else
327 bool rightToLeft = rWrtShell.IsInRightToLeftText();
328 // if there were no selection (only a cursor) and the cursor was at
329 // the end of the paragraph then don't move
330 if ( rWrtShell.IsEndPara() && !rightToLeft )
331 dontMove = true;
333 // revert left and right
334 if ( rightToLeft )
336 if (pCursor->GetPoint()->nContent == 0)
337 dontMove = true;
338 else
339 bForwardSelection = !bForwardSelection;
343 // move the cursor in order to select one character
344 if (!dontMove)
345 pCursor->Move( bForwardSelection ? fnMoveBackward : fnMoveForward );
348 if(pItemSet_TextAttr)
350 if( nSelectionType & (SelectionType::Frame | SelectionType::Ole | SelectionType::Graphic) )
351 rWrtShell.GetFlyFrameAttr(*pItemSet_TextAttr);
352 else
354 // get the text attributes from named and automatic formatting
355 rWrtShell.GetCurAttr(*pItemSet_TextAttr);
357 if( nSelectionType & SelectionType::Text )
359 // get the paragraph attributes (could be character properties)
360 // from named and automatic formatting
361 rWrtShell.GetCurParAttr(*pItemSet_ParAttr);
365 else if ( nSelectionType & SelectionType::DrawObject )
367 SdrView* pDrawView = rWrtShell.GetDrawView();
368 if(pDrawView)
370 if( pDrawView->AreObjectsMarked() )
372 pItemSet_TextAttr = o3tl::make_unique<SfxItemSet>( pDrawView->GetAttrFromMarked(true/*bOnlyHardAttr*/) );
373 //remove attributes defining the type/data of custom shapes
374 pItemSet_TextAttr->ClearItem(SDRATTR_CUSTOMSHAPE_ENGINE);
375 pItemSet_TextAttr->ClearItem(SDRATTR_CUSTOMSHAPE_DATA);
376 pItemSet_TextAttr->ClearItem(SDRATTR_CUSTOMSHAPE_GEOMETRY);
381 if( nSelectionType & SelectionType::TableCell )//only copy table attributes if really cells are selected (not only text in tables)
383 m_pTableItemSet = o3tl::make_unique<SfxItemSet>(
384 rPool,
385 svl::Items<
386 RES_PAGEDESC, RES_BREAK,
387 RES_BACKGROUND, RES_SHADOW, // RES_BOX is inbetween
388 RES_KEEP, RES_KEEP,
389 RES_LAYOUT_SPLIT, RES_LAYOUT_SPLIT,
390 RES_FRAMEDIR, RES_FRAMEDIR,
391 RES_ROW_SPLIT, RES_ROW_SPLIT,
392 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_SHADOW,
393 // SID_ATTR_BORDER_OUTER is inbetween
394 SID_ATTR_BRUSH_ROW, SID_ATTR_BRUSH_TABLE,
395 FN_TABLE_SET_VERT_ALIGN, FN_TABLE_SET_VERT_ALIGN,
396 FN_TABLE_BOX_TEXTORIENTATION, FN_TABLE_BOX_TEXTORIENTATION,
397 FN_PARAM_TABLE_HEADLINE, FN_PARAM_TABLE_HEADLINE>{});
398 lcl_getTableAttributes( *m_pTableItemSet, rWrtShell );
401 m_nSelectionType = nSelectionType;
402 m_pItemSet_TextAttr = std::move(pItemSet_TextAttr);
403 m_pItemSet_ParAttr = std::move(pItemSet_ParAttr);
405 if( nSelectionType & SelectionType::Text )
407 // if text is selected save the named character format
408 SwFormat* pFormat = rWrtShell.GetCurCharFormat();
409 if( pFormat )
410 m_aCharStyle = pFormat->GetName();
412 // and the named paragraph format
413 pFormat = rWrtShell.GetCurTextFormatColl();
414 if( pFormat )
415 m_aParaStyle = pFormat->GetName();
418 rWrtShell.Pop(SwCursorShell::PopMode::DeleteCurrent);
419 rWrtShell.EndAction();
422 typedef std::shared_ptr< SfxPoolItem > SfxPoolItemSharedPtr;
423 typedef std::vector< SfxPoolItemSharedPtr > ItemVector;
424 // collect all PoolItems from the applied styles
425 static void lcl_AppendSetItems( ItemVector& rItemVector, const SfxItemSet& rStyleAttrSet )
427 const sal_uInt16* pRanges = rStyleAttrSet.GetRanges();
428 while( *pRanges )
430 for ( sal_uInt16 nWhich = *pRanges; nWhich <= *(pRanges+1); ++nWhich )
432 const SfxPoolItem* pItem;
433 if( SfxItemState::SET == rStyleAttrSet.GetItemState( nWhich, false, &pItem ) )
435 rItemVector.push_back( SfxPoolItemSharedPtr( pItem->Clone() ) );
438 pRanges += 2;
441 // remove all items that are inherited from the styles
442 static void lcl_RemoveEqualItems( SfxItemSet& rTemplateItemSet, const ItemVector& rItemVector )
444 ItemVector::const_iterator aEnd = rItemVector.end();
445 ItemVector::const_iterator aIter = rItemVector.begin();
446 while( aIter != aEnd )
448 const SfxPoolItem* pItem;
449 if( SfxItemState::SET == rTemplateItemSet.GetItemState( (*aIter)->Which(), true, &pItem ) &&
450 *pItem == *(*aIter) )
452 rTemplateItemSet.ClearItem( (*aIter)->Which() );
454 ++aIter;
458 void SwFormatClipboard::Paste( SwWrtShell& rWrtShell, SfxStyleSheetBasePool* pPool
459 , bool bNoCharacterFormats, bool bNoParagraphFormats )
461 SelectionType nSelectionType = rWrtShell.GetSelectionType();
462 if( !HasContentForThisType(nSelectionType) )
464 if(!m_bPersistentCopy)
465 Erase();
466 return;
469 rWrtShell.StartAction();
470 rWrtShell.StartUndo(SwUndoId::INSATTR);
472 ItemVector aItemVector;
474 if( nSelectionType & SelectionType::Text )
476 // apply the named text and paragraph formatting
477 if( pPool )
479 // if there is a named text format recorded and the user wants to apply it
480 if(!m_aCharStyle.isEmpty() && !bNoCharacterFormats )
482 // look for the named text format in the pool
483 SwDocStyleSheet* pStyle = static_cast<SwDocStyleSheet*>(pPool->Find(m_aCharStyle, SfxStyleFamily::Char));
485 // if the style is found
486 if( pStyle )
488 SwFormatCharFormat aFormat(pStyle->GetCharFormat());
489 // store the attributes from this style in aItemVector in order
490 // not to apply them as automatic formatting attributes later in the code
491 lcl_AppendSetItems( aItemVector, aFormat.GetCharFormat()->GetAttrSet());
493 // apply the named format
494 rWrtShell.SetAttrItem( aFormat );
498 // if there is a named paragraph format recorded and the user wants to apply it
499 if(!m_aParaStyle.isEmpty() && !bNoParagraphFormats )
501 // look for the named pragraph format in the pool
502 SwDocStyleSheet* pStyle = static_cast<SwDocStyleSheet*>(pPool->Find(m_aParaStyle, SfxStyleFamily::Para));
503 if( pStyle )
505 // store the attributes from this style in aItemVector in order
506 // not to apply them as automatic formatting attributes later in the code
507 lcl_AppendSetItems( aItemVector, pStyle->GetCollection()->GetAttrSet());
509 // apply the named format
510 rWrtShell.SetTextFormatColl( pStyle->GetCollection() );
515 // apply the paragraph automatic attributes
516 if ( m_pItemSet_ParAttr && m_pItemSet_ParAttr->Count() != 0 && !bNoParagraphFormats )
518 // temporary SfxItemSet
519 std::unique_ptr<SfxItemSet> pTemplateItemSet(lcl_CreateEmptyItemSet(
520 nSelectionType, *m_pItemSet_ParAttr->GetPool()));
521 // no need to verify the existence of pTemplateItemSet as we
522 // know that here the selection type is SEL_TXT
524 pTemplateItemSet->Put( *m_pItemSet_ParAttr );
526 // remove attribute that were applied by named text and paragraph formatting
527 lcl_RemoveEqualItems( *pTemplateItemSet, aItemVector );
529 // apply the paragraph automatic attributes to all the nodes in the selection
530 rWrtShell.SetAttrSet(*pTemplateItemSet);
532 // store the attributes in aItemVector in order not to apply them as
533 // text automatic formatting attributes later in the code
534 lcl_AppendSetItems( aItemVector, *pTemplateItemSet);
538 if(m_pItemSet_TextAttr)
540 if( nSelectionType & SelectionType::DrawObject )
542 SdrView* pDrawView = rWrtShell.GetDrawView();
543 if(pDrawView)
545 pDrawView->SetAttrToMarked(*m_pItemSet_TextAttr, true/*bReplaceAll*/);
548 else
550 // temporary SfxItemSet
551 std::unique_ptr<SfxItemSet> pTemplateItemSet(lcl_CreateEmptyItemSet(
552 nSelectionType, *m_pItemSet_TextAttr->GetPool(), true ));
554 if(pTemplateItemSet)
556 // copy the stored automatic text attributes in a temporary SfxItemSet
557 pTemplateItemSet->Put( *m_pItemSet_TextAttr );
559 // only attributes that were not apply by named style attributes and automatic
560 // paragraph attributes should be applied
561 lcl_RemoveEqualItems( *pTemplateItemSet, aItemVector );
563 // apply the character automatic attributes
564 if( nSelectionType & (SelectionType::Frame | SelectionType::Ole | SelectionType::Graphic) )
565 rWrtShell.SetFlyFrameAttr(*pTemplateItemSet);
566 else if ( !bNoCharacterFormats )
567 rWrtShell.SetAttrSet(*pTemplateItemSet);
572 if( m_pTableItemSet && nSelectionType & (SelectionType::Table | SelectionType::TableCell) )
573 lcl_setTableAttributes( *m_pTableItemSet, rWrtShell );
575 rWrtShell.EndUndo(SwUndoId::INSATTR);
576 rWrtShell.EndAction();
578 if(!m_bPersistentCopy)
579 Erase();
582 void SwFormatClipboard::Erase()
584 m_nSelectionType = SelectionType::NONE;
586 m_pItemSet_TextAttr.reset();
588 m_pItemSet_ParAttr.reset();
590 m_pTableItemSet.reset();
592 if( !m_aCharStyle.isEmpty() )
593 m_aCharStyle.clear();
594 if( !m_aParaStyle.isEmpty() )
595 m_aParaStyle.clear();
597 m_bPersistentCopy = false;
600 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */