Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / uibase / uiview / formatclipboard.cxx
blob74fd772f5cfa647654e373ae6f03e9405464d6c3
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 <cmdid.h>
26 #include <charfmt.hxx>
27 #include <frmfmt.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>
40 #include <frmatr.hxx>
42 namespace
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,
52 // no RES_FRM_SIZE
53 RES_PAPER_BIN, RES_SURROUND,
54 // no RES_VERT_ORIENT
55 // no RES_HORI_ORIENT
56 // no RES_ANCHOR
57 RES_BACKGROUND, RES_SHADOW,
58 // no RES_FRMMACRO
59 RES_COL, RES_KEEP,
60 // no RES_URL
61 RES_EDIT_IN_READONLY, RES_LAYOUT_SPLIT,
62 // no RES_CHAIN
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);
74 else
75 pItemSet = std::make_unique<SfxItemSetFixed<
76 RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
77 RES_PARATR_BEGIN, RES_FILL_ORDER,
78 // no RES_FRM_SIZE
79 RES_PAPER_BIN, RES_SURROUND,
80 // no RES_VERT_ORIENT
81 // no RES_HORI_ORIENT
82 // no RES_ANCHOR
83 RES_BACKGROUND, RES_SHADOW,
84 // no RES_FRMMACRO
85 RES_COL, RES_KEEP,
86 // no RES_URL
87 RES_EDIT_IN_READONLY, RES_LAYOUT_SPLIT,
88 // no RES_CHAIN
89 RES_TEXTGRID, RES_FRMATR_END - 1>>(rPool);
91 return pItemSet;
94 void lcl_getTableAttributes( SfxItemSet& rSet, SwWrtShell &rSh )
96 std::unique_ptr<SvxBrushItem> aBrush(std::make_unique<SvxBrushItem>(RES_BACKGROUND));
97 rSh.GetBoxBackground(aBrush);
98 rSet.Put( *aBrush );
99 if(rSh.GetRowBackground(aBrush))
101 aBrush->SetWhich(SID_ATTR_BRUSH_ROW);
102 rSet.Put( *aBrush );
104 else
105 rSet.InvalidateItem(SID_ATTR_BRUSH_ROW);
106 rSh.GetTabBackground(aBrush);
107 aBrush->SetWhich(SID_ATTR_BRUSH_TABLE);
108 rSet.Put( *aBrush );
110 SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER );
111 rSet.Put(aBoxInfo);
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();
126 if(pFrameFormat)
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();
137 if(pSplit)
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;
150 if(bBackground)
152 if(pBackgroundItem)
153 rSh.SetBoxBackground( *pBackgroundItem );
154 if(pRowItem)
156 std::unique_ptr<SvxBrushItem> aBrush(pRowItem->Clone());
157 aBrush->SetWhich(RES_BACKGROUND);
158 rSh.SetRowBackground(*aBrush);
160 if(pTableItem)
162 std::unique_ptr<SvxBrushItem> aBrush(pTableItem->Clone());
163 aBrush->SetWhich(RES_BACKGROUND);
164 rSh.SetTabBackground(*aBrush);
167 if(bBorder)
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();
174 if(pFrameFormat)
176 //RES_SHADOW
177 const SfxPoolItem* pItem = rSet.GetItemIfSet(rSet.GetPool()->GetWhich(RES_SHADOW), false);
178 if(pItem)
179 pFrameFormat->SetFormatAttr( *pItem );
181 //RES_BREAK
182 pItem = rSet.GetItemIfSet(rSet.GetPool()->GetWhich(RES_BREAK), false);
183 if(pItem)
184 pFrameFormat->SetFormatAttr( *pItem );
186 //RES_PAGEDESC
187 pItem = rSet.GetItemIfSet(rSet.GetPool()->GetWhich(RES_PAGEDESC), false);
188 if(pItem)
189 pFrameFormat->SetFormatAttr( *pItem );
191 //RES_LAYOUT_SPLIT
192 pItem = rSet.GetItemIfSet(rSet.GetPool()->GetWhich(RES_LAYOUT_SPLIT), false);
193 if(pItem)
194 pFrameFormat->SetFormatAttr( *pItem );
196 //RES_KEEP
197 pItem = rSet.GetItemIfSet(rSet.GetPool()->GetWhich(RES_KEEP), false);
198 if(pItem)
199 pFrameFormat->SetFormatAttr( *pItem );
201 //RES_FRAMEDIR
202 pItem = rSet.GetItemIfSet(rSet.GetPool()->GetWhich(RES_FRAMEDIR), false);
203 if(pItem)
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
239 if( !HasContent() )
240 return false;
242 if( m_nSelectionType == nSelectionType )
243 return true;
245 if( ( nSelectionType & (SelectionType::Frame | SelectionType::Ole | SelectionType::Graphic) )
247 ( m_nSelectionType & (SelectionType::Frame | SelectionType::Ole | SelectionType::Graphic) )
249 return true;
251 if( nSelectionType & SelectionType::Text && m_nSelectionType & SelectionType::Text )
252 return true;
254 return false;
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
267 Erase();
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();
275 rWrtShell.Push();
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;
303 if (bHasSelection)
305 bForwardSelection = (*pCursor->GetPoint()) > (*pCursor->GetMark());
307 // clear the selection leaving just the cursor
308 pCursor->DeleteMark();
309 pCursor->SetMark();
311 else
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 )
317 dontMove = true;
319 // revert left and right
320 if ( rightToLeft )
322 if (pCursor->GetPoint()->GetContentIndex() == 0)
323 dontMove = true;
324 else
325 bForwardSelection = !bForwardSelection;
329 // move the cursor in order to select one character
330 if (!dontMove)
331 pCursor->Move( bForwardSelection ? fnMoveBackward : fnMoveForward );
334 if(pItemSet_TextAttr)
336 if( nSelectionType & (SelectionType::Frame | SelectionType::Ole | SelectionType::Graphic) )
337 rWrtShell.GetFlyFrameAttr(*pItemSet_TextAttr);
338 else
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();
354 if(pDrawView)
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
372 RES_KEEP, RES_KEEP,
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();
393 if( pFormat )
394 m_aCharStyle = pFormat->GetName();
396 // and the named paragraph format
397 pFormat = rWrtShell.GetCurTextFormatColl();
398 if( pFormat )
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 ) &&
430 *pItem == *rItem )
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)
444 Erase();
445 return;
448 rWrtShell.StartAction();
449 rWrtShell.StartUndo(SwUndoId::INSATTR);
451 ItemVector aItemVector;
453 if( nSelectionType & SelectionType::Text )
455 // apply the named text and paragraph formatting
456 if( pPool )
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
465 if( pStyle )
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));
482 if( pStyle )
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();
522 if(pDrawView)
524 pDrawView->SetAttrToMarked(*m_pItemSet_TextAttr, true/*bReplaceAll*/);
527 else
529 // temporary SfxItemSet
530 std::unique_ptr<SfxItemSet> pTemplateItemSet(lcl_CreateEmptyItemSet(
531 nSelectionType, *m_pItemSet_TextAttr->GetPool(), true ));
533 if(pTemplateItemSet)
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)
566 Erase();
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: */