1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
23 #include <formatclipboard.hxx>
26 #include <charfmt.hxx>
28 #include <docstyle.hxx>
29 #include <fchrfmt.hxx>
30 #include <svx/svdview.hxx>
31 #include <editeng/brushitem.hxx>
32 #include <editeng/shaditem.hxx>
33 #include <editeng/boxitem.hxx>
34 #include <editeng/formatbreakitem.hxx>
35 #include <fmtlsplt.hxx>
36 #include <editeng/keepitem.hxx>
37 #include <editeng/frmdiritem.hxx>
38 #include <fmtpdsc.hxx>
39 #include <fmtrowsplt.hxx>
45 std::unique_ptr
<SfxItemSet
> lcl_CreateEmptyItemSet( SelectionType nSelectionType
, SfxItemPool
& rPool
, bool bNoParagraphFormats
= false )
47 std::unique_ptr
<SfxItemSet
> pItemSet
;
48 if( nSelectionType
& (SelectionType::Frame
| SelectionType::Ole
| SelectionType::Graphic
) )
50 pItemSet
= std::make_unique
<SfxItemSetFixed
<
51 RES_FRMATR_BEGIN
, RES_FILL_ORDER
,
53 RES_PAPER_BIN
, RES_SURROUND
,
57 RES_BACKGROUND
, RES_SHADOW
,
61 RES_EDIT_IN_READONLY
, RES_LAYOUT_SPLIT
,
63 RES_TEXTGRID
, RES_FRMATR_END
- 1>>(rPool
);
65 else if( nSelectionType
& SelectionType::DrawObject
)
67 //is handled different
69 else if( nSelectionType
& SelectionType::Text
)
71 if( bNoParagraphFormats
)
72 pItemSet
= std::make_unique
<SfxItemSetFixed
73 <RES_CHRATR_BEGIN
, RES_CHRATR_END
- 1>>(rPool
);
75 pItemSet
= std::make_unique
<SfxItemSetFixed
<
76 RES_CHRATR_BEGIN
, RES_CHRATR_END
- 1,
77 RES_PARATR_BEGIN
, RES_FILL_ORDER
,
79 RES_PAPER_BIN
, RES_SURROUND
,
83 RES_BACKGROUND
, RES_SHADOW
,
87 RES_EDIT_IN_READONLY
, RES_LAYOUT_SPLIT
,
89 RES_TEXTGRID
, RES_FRMATR_END
- 1>>(rPool
);
94 void lcl_getTableAttributes( SfxItemSet
& rSet
, SwWrtShell
&rSh
)
96 std::unique_ptr
<SvxBrushItem
> aBrush(std::make_unique
<SvxBrushItem
>(RES_BACKGROUND
));
97 rSh
.GetBoxBackground(aBrush
);
99 if(rSh
.GetRowBackground(aBrush
))
101 aBrush
->SetWhich(SID_ATTR_BRUSH_ROW
);
105 rSet
.InvalidateItem(SID_ATTR_BRUSH_ROW
);
106 rSh
.GetTabBackground(aBrush
);
107 aBrush
->SetWhich(SID_ATTR_BRUSH_TABLE
);
110 SvxBoxInfoItem
aBoxInfo( SID_ATTR_BORDER_INNER
);
112 rSh
.GetTabBorders( rSet
);
114 std::unique_ptr
<SvxFrameDirectionItem
> aBoxDirection(std::make_unique
<SvxFrameDirectionItem
>(SvxFrameDirection::Environment
, RES_FRAMEDIR
));
115 if(rSh
.GetBoxDirection( aBoxDirection
))
117 aBoxDirection
->SetWhich(FN_TABLE_BOX_TEXTORIENTATION
);
118 rSet
.Put(std::move(aBoxDirection
));
121 rSet
.Put(SfxUInt16Item(FN_TABLE_SET_VERT_ALIGN
, rSh
.GetBoxAlign()));
123 rSet
.Put( SfxUInt16Item( FN_PARAM_TABLE_HEADLINE
, rSh
.GetRowsToRepeat() ) );
125 SwFrameFormat
*pFrameFormat
= rSh
.GetTableFormat();
128 rSet
.Put( pFrameFormat
->GetShadow() );
129 rSet
.Put( pFrameFormat
->GetBreak() );
130 rSet
.Put( pFrameFormat
->GetPageDesc() );
131 rSet
.Put( pFrameFormat
->GetLayoutSplit() );
132 rSet
.Put( pFrameFormat
->GetKeep() );
133 rSet
.Put( pFrameFormat
->GetFrameDir() );
136 std::unique_ptr
<SwFormatRowSplit
> pSplit
= rSh
.GetRowSplit();
138 rSet
.Put(std::move(pSplit
));
141 void lcl_setTableAttributes( const SfxItemSet
& rSet
, SwWrtShell
&rSh
)
143 bool bBorder
= ( SfxItemState::SET
== rSet
.GetItemState( RES_BOX
) ||
144 SfxItemState::SET
== rSet
.GetItemState( SID_ATTR_BORDER_INNER
) );
145 const SvxBrushItem
* pBackgroundItem
= rSet
.GetItemIfSet( RES_BACKGROUND
, false );
146 const SvxBrushItem
* pRowItem
= rSet
.GetItemIfSet( SID_ATTR_BRUSH_ROW
, false );
147 const SvxBrushItem
* pTableItem
= rSet
.GetItemIfSet( SID_ATTR_BRUSH_TABLE
, false );
148 bool bBackground
= pBackgroundItem
|| pRowItem
|| pTableItem
;
153 rSh
.SetBoxBackground( *pBackgroundItem
);
156 std::unique_ptr
<SvxBrushItem
> aBrush(pRowItem
->Clone());
157 aBrush
->SetWhich(RES_BACKGROUND
);
158 rSh
.SetRowBackground(*aBrush
);
162 std::unique_ptr
<SvxBrushItem
> aBrush(pTableItem
->Clone());
163 aBrush
->SetWhich(RES_BACKGROUND
);
164 rSh
.SetTabBackground(*aBrush
);
168 rSh
.SetTabBorders( rSet
);
170 if( const SfxUInt16Item
* pHeadlineItem
= rSet
.GetItemIfSet( FN_PARAM_TABLE_HEADLINE
, false) )
171 rSh
.SetRowsToRepeat( pHeadlineItem
->GetValue() );
173 SwFrameFormat
* pFrameFormat
= rSh
.GetTableFormat();
177 const SfxPoolItem
* pItem
= rSet
.GetItemIfSet(rSet
.GetPool()->GetWhich(RES_SHADOW
), false);
179 pFrameFormat
->SetFormatAttr( *pItem
);
182 pItem
= rSet
.GetItemIfSet(rSet
.GetPool()->GetWhich(RES_BREAK
), false);
184 pFrameFormat
->SetFormatAttr( *pItem
);
187 pItem
= rSet
.GetItemIfSet(rSet
.GetPool()->GetWhich(RES_PAGEDESC
), false);
189 pFrameFormat
->SetFormatAttr( *pItem
);
192 pItem
= rSet
.GetItemIfSet(rSet
.GetPool()->GetWhich(RES_LAYOUT_SPLIT
), false);
194 pFrameFormat
->SetFormatAttr( *pItem
);
197 pItem
= rSet
.GetItemIfSet(rSet
.GetPool()->GetWhich(RES_KEEP
), false);
199 pFrameFormat
->SetFormatAttr( *pItem
);
202 pItem
= rSet
.GetItemIfSet(rSet
.GetPool()->GetWhich(RES_FRAMEDIR
), false);
204 pFrameFormat
->SetFormatAttr( *pItem
);
207 if( const SvxFrameDirectionItem
* pTextOriItem
= rSet
.GetItemIfSet( FN_TABLE_BOX_TEXTORIENTATION
, false ) )
209 SvxFrameDirectionItem
aDirection( SvxFrameDirection::Environment
, RES_FRAMEDIR
);
210 aDirection
.SetValue(pTextOriItem
->GetValue());
211 rSh
.SetBoxDirection(aDirection
);
214 if( const SfxUInt16Item
* pVertAlignItem
= rSet
.GetItemIfSet( FN_TABLE_SET_VERT_ALIGN
, false ))
215 rSh
.SetBoxAlign(pVertAlignItem
->GetValue());
217 if( const SwFormatRowSplit
* pSplitItem
= rSet
.GetItemIfSet( RES_ROW_SPLIT
, false ) )
218 rSh
.SetRowSplit(*pSplitItem
);
220 }//end anonymous namespace
222 SwFormatClipboard::SwFormatClipboard()
223 : m_nSelectionType(SelectionType::NONE
)
224 , m_bPersistentCopy(false)
228 bool SwFormatClipboard::HasContent() const
230 return m_pItemSet_TextAttr
!=nullptr
231 || m_pItemSet_ParAttr
!=nullptr
232 || m_pTableItemSet
!= nullptr
233 || !m_aCharStyle
.isEmpty()
234 || !m_aParaStyle
.isEmpty()
237 bool SwFormatClipboard::HasContentForThisType( SelectionType nSelectionType
) const
242 if( m_nSelectionType
== nSelectionType
)
245 if( ( nSelectionType
& (SelectionType::Frame
| SelectionType::Ole
| SelectionType::Graphic
) )
247 ( m_nSelectionType
& (SelectionType::Frame
| SelectionType::Ole
| SelectionType::Graphic
) )
251 if( nSelectionType
& SelectionType::Text
&& m_nSelectionType
& SelectionType::Text
)
257 bool SwFormatClipboard::CanCopyThisType( SelectionType nSelectionType
)
259 return bool(nSelectionType
260 & (SelectionType::Frame
| SelectionType::Ole
| SelectionType::Graphic
261 | SelectionType::Text
| SelectionType::DrawObject
| SelectionType::Table
| SelectionType::TableCell
));
264 void SwFormatClipboard::Copy( SwWrtShell
& rWrtShell
, SfxItemPool
& rPool
, bool bPersistentCopy
)
266 // first clear the previously stored attributes
268 m_bPersistentCopy
= bPersistentCopy
;
270 SelectionType nSelectionType
= rWrtShell
.GetSelectionType();
271 auto pItemSet_TextAttr
= lcl_CreateEmptyItemSet( nSelectionType
, rPool
, true );
272 auto pItemSet_ParAttr
= lcl_CreateEmptyItemSet( nSelectionType
, rPool
);
274 rWrtShell
.StartAction();
277 // modify the "Point and Mark" of the cursor
278 // in order to select only the last character of the
279 // selection(s) and then to get the attributes of this single character
280 if( nSelectionType
== SelectionType::Text
)
282 // get the current PaM, the cursor
283 // if there several selection it currently point
284 // on the last (sort by there creation time) selection
285 SwPaM
* pCursor
= rWrtShell
.GetCursor();
287 bool bHasSelection
= pCursor
->HasMark();
288 bool bForwardSelection
= false;
290 if(!bHasSelection
&& pCursor
->IsMultiSelection())
292 // if cursor has multiple selections
294 // clear all the selections except the last
295 rWrtShell
.KillPams();
297 // reset the cursor to the remaining selection
298 pCursor
= rWrtShell
.GetCursor();
299 bHasSelection
= true;
302 bool dontMove
= false;
305 bForwardSelection
= (*pCursor
->GetPoint()) > (*pCursor
->GetMark());
307 // clear the selection leaving just the cursor
308 pCursor
->DeleteMark();
313 bool rightToLeft
= rWrtShell
.IsInRightToLeftText();
314 // if there were no selection (only a cursor) and the cursor was at
315 // the end of the paragraph then don't move
316 if ( rWrtShell
.IsEndPara() && !rightToLeft
)
319 // revert left and right
322 if (pCursor
->GetPoint()->GetContentIndex() == 0)
325 bForwardSelection
= !bForwardSelection
;
329 // move the cursor in order to select one character
331 pCursor
->Move( bForwardSelection
? fnMoveBackward
: fnMoveForward
);
334 if(pItemSet_TextAttr
)
336 if( nSelectionType
& (SelectionType::Frame
| SelectionType::Ole
| SelectionType::Graphic
) )
337 rWrtShell
.GetFlyFrameAttr(*pItemSet_TextAttr
);
340 // get the text attributes from named and automatic formatting
341 rWrtShell
.GetCurAttr(*pItemSet_TextAttr
);
343 if( nSelectionType
& SelectionType::Text
)
345 // get the paragraph attributes (could be character properties)
346 // from named and automatic formatting
347 rWrtShell
.GetCurParAttr(*pItemSet_ParAttr
);
351 else if ( nSelectionType
& SelectionType::DrawObject
)
353 SdrView
* pDrawView
= rWrtShell
.GetDrawView();
356 if( pDrawView
->AreObjectsMarked() )
358 pItemSet_TextAttr
= std::make_unique
<SfxItemSet
>( pDrawView
->GetAttrFromMarked(true/*bOnlyHardAttr*/) );
359 //remove attributes defining the type/data of custom shapes
360 pItemSet_TextAttr
->ClearItem(SDRATTR_CUSTOMSHAPE_ENGINE
);
361 pItemSet_TextAttr
->ClearItem(SDRATTR_CUSTOMSHAPE_DATA
);
362 pItemSet_TextAttr
->ClearItem(SDRATTR_CUSTOMSHAPE_GEOMETRY
);
367 if( nSelectionType
& SelectionType::TableCell
)//only copy table attributes if really cells are selected (not only text in tables)
369 m_pTableItemSet
= std::make_unique
<SfxItemSetFixed
<
370 RES_PAGEDESC
, RES_BREAK
,
371 RES_BACKGROUND
, RES_SHADOW
, // RES_BOX is inbetween
373 RES_LAYOUT_SPLIT
, RES_LAYOUT_SPLIT
,
374 RES_FRAMEDIR
, RES_FRAMEDIR
,
375 RES_ROW_SPLIT
, RES_ROW_SPLIT
,
376 SID_ATTR_BORDER_INNER
, SID_ATTR_BORDER_SHADOW
,
377 // SID_ATTR_BORDER_OUTER is inbetween
378 SID_ATTR_BRUSH_ROW
, SID_ATTR_BRUSH_TABLE
,
379 FN_TABLE_SET_VERT_ALIGN
, FN_TABLE_SET_VERT_ALIGN
,
380 FN_TABLE_BOX_TEXTORIENTATION
, FN_TABLE_BOX_TEXTORIENTATION
,
381 FN_PARAM_TABLE_HEADLINE
, FN_PARAM_TABLE_HEADLINE
>>(rPool
);
382 lcl_getTableAttributes( *m_pTableItemSet
, rWrtShell
);
385 m_nSelectionType
= nSelectionType
;
386 m_pItemSet_TextAttr
= std::move(pItemSet_TextAttr
);
387 m_pItemSet_ParAttr
= std::move(pItemSet_ParAttr
);
389 if( nSelectionType
& SelectionType::Text
)
391 // if text is selected save the named character format
392 SwFormat
* pFormat
= rWrtShell
.GetCurCharFormat();
394 m_aCharStyle
= pFormat
->GetName();
396 // and the named paragraph format
397 pFormat
= rWrtShell
.GetCurTextFormatColl();
399 m_aParaStyle
= pFormat
->GetName();
402 rWrtShell
.Pop(SwCursorShell::PopMode::DeleteCurrent
);
403 rWrtShell
.EndAction();
406 typedef std::vector
< std::unique_ptr
< SfxPoolItem
> > ItemVector
;
407 // collect all PoolItems from the applied styles
408 static void lcl_AppendSetItems( ItemVector
& rItemVector
, const SfxItemSet
& rStyleAttrSet
)
410 const WhichRangesContainer
& pRanges
= rStyleAttrSet
.GetRanges();
411 for(const auto & rPair
: pRanges
)
413 for ( sal_uInt16 nWhich
= rPair
.first
; nWhich
<= rPair
.second
; ++nWhich
)
415 const SfxPoolItem
* pItem
;
416 if( SfxItemState::SET
== rStyleAttrSet
.GetItemState( nWhich
, false, &pItem
) )
418 rItemVector
.emplace_back( pItem
->Clone() );
423 // remove all items that are inherited from the styles
424 static void lcl_RemoveEqualItems( SfxItemSet
& rTemplateItemSet
, const ItemVector
& rItemVector
)
426 for( const auto& rItem
: rItemVector
)
428 const SfxPoolItem
* pItem
;
429 if( SfxItemState::SET
== rTemplateItemSet
.GetItemState( rItem
->Which(), true, &pItem
) &&
432 rTemplateItemSet
.ClearItem( rItem
->Which() );
437 void SwFormatClipboard::Paste( SwWrtShell
& rWrtShell
, SfxStyleSheetBasePool
* pPool
438 , bool bNoCharacterFormats
, bool bNoParagraphFormats
)
440 SelectionType nSelectionType
= rWrtShell
.GetSelectionType();
441 if( !HasContentForThisType(nSelectionType
) )
443 if(!m_bPersistentCopy
)
448 rWrtShell
.StartAction();
449 rWrtShell
.StartUndo(SwUndoId::INSATTR
);
451 ItemVector aItemVector
;
453 if( nSelectionType
& SelectionType::Text
)
455 // apply the named text and paragraph formatting
458 // if there is a named text format recorded and the user wants to apply it
459 if(!m_aCharStyle
.isEmpty() && !bNoCharacterFormats
)
461 // look for the named text format in the pool
462 SwDocStyleSheet
* pStyle
= static_cast<SwDocStyleSheet
*>(pPool
->Find(m_aCharStyle
, SfxStyleFamily::Char
));
464 // if the style is found
467 SwFormatCharFormat
aFormat(pStyle
->GetCharFormat());
468 // store the attributes from this style in aItemVector in order
469 // not to apply them as automatic formatting attributes later in the code
470 lcl_AppendSetItems( aItemVector
, aFormat
.GetCharFormat()->GetAttrSet());
472 // apply the named format
473 rWrtShell
.SetAttrItem( aFormat
);
477 // if there is a named paragraph format recorded and the user wants to apply it
478 if(!m_aParaStyle
.isEmpty() && !bNoParagraphFormats
)
480 // look for the named paragraph format in the pool
481 SwDocStyleSheet
* pStyle
= static_cast<SwDocStyleSheet
*>(pPool
->Find(m_aParaStyle
, SfxStyleFamily::Para
));
484 // store the attributes from this style in aItemVector in order
485 // not to apply them as automatic formatting attributes later in the code
486 lcl_AppendSetItems( aItemVector
, pStyle
->GetCollection()->GetAttrSet());
488 // apply the named format
489 rWrtShell
.SetTextFormatColl( pStyle
->GetCollection() );
494 // apply the paragraph automatic attributes
495 if ( m_pItemSet_ParAttr
&& m_pItemSet_ParAttr
->Count() != 0 && !bNoParagraphFormats
)
497 // temporary SfxItemSet
498 std::unique_ptr
<SfxItemSet
> pTemplateItemSet(lcl_CreateEmptyItemSet(
499 nSelectionType
, *m_pItemSet_ParAttr
->GetPool()));
500 // no need to verify the existence of pTemplateItemSet as we
501 // know that here the selection type is SEL_TXT
503 pTemplateItemSet
->Put( *m_pItemSet_ParAttr
);
505 // remove attribute that were applied by named text and paragraph formatting
506 lcl_RemoveEqualItems( *pTemplateItemSet
, aItemVector
);
508 // apply the paragraph automatic attributes to all the nodes in the selection
509 rWrtShell
.SetAttrSet(*pTemplateItemSet
);
511 // store the attributes in aItemVector in order not to apply them as
512 // text automatic formatting attributes later in the code
513 lcl_AppendSetItems( aItemVector
, *pTemplateItemSet
);
517 if(m_pItemSet_TextAttr
)
519 if( nSelectionType
& SelectionType::DrawObject
)
521 SdrView
* pDrawView
= rWrtShell
.GetDrawView();
524 pDrawView
->SetAttrToMarked(*m_pItemSet_TextAttr
, true/*bReplaceAll*/);
529 // temporary SfxItemSet
530 std::unique_ptr
<SfxItemSet
> pTemplateItemSet(lcl_CreateEmptyItemSet(
531 nSelectionType
, *m_pItemSet_TextAttr
->GetPool(), true ));
535 // copy the stored automatic text attributes in a temporary SfxItemSet
536 pTemplateItemSet
->Put( *m_pItemSet_TextAttr
);
538 // reset all direct formatting
539 o3tl::sorted_vector
<sal_uInt16
> aAttrs
;
540 for( sal_uInt16 nWhich
= RES_CHRATR_BEGIN
; nWhich
< RES_CHRATR_END
; nWhich
++ )
541 aAttrs
.insert( nWhich
);
542 rWrtShell
.ResetAttr( { aAttrs
} );
544 // only attributes that were not apply by named style attributes and automatic
545 // paragraph attributes should be applied
546 lcl_RemoveEqualItems( *pTemplateItemSet
, aItemVector
);
548 // apply the character automatic attributes
549 if( nSelectionType
& (SelectionType::Frame
| SelectionType::Ole
| SelectionType::Graphic
) )
550 rWrtShell
.SetFlyFrameAttr(*pTemplateItemSet
);
551 else if ( !bNoCharacterFormats
)
553 rWrtShell
.SetAttrSet(*pTemplateItemSet
);
559 if( m_pTableItemSet
&& nSelectionType
& (SelectionType::Table
| SelectionType::TableCell
) )
560 lcl_setTableAttributes( *m_pTableItemSet
, rWrtShell
);
562 rWrtShell
.EndUndo(SwUndoId::INSATTR
);
563 rWrtShell
.EndAction();
565 if(!m_bPersistentCopy
)
569 void SwFormatClipboard::Erase()
571 m_nSelectionType
= SelectionType::NONE
;
573 m_pItemSet_TextAttr
.reset();
575 m_pItemSet_ParAttr
.reset();
577 m_pTableItemSet
.reset();
579 if( !m_aCharStyle
.isEmpty() )
580 m_aCharStyle
.clear();
581 if( !m_aParaStyle
.isEmpty() )
582 m_aParaStyle
.clear();
584 m_bPersistentCopy
= false;
587 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */