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 .
22 #include <svx/sdr/table/tablecontroller.hxx>
23 #include <tablemodel.hxx>
25 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
26 #include <com/sun/star/container/XIndexAccess.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/table/XMergeableCellRange.hpp>
30 #include <com/sun/star/table/XMergeableCell.hpp>
32 #include <sal/config.h>
34 #include <vcl/svapp.hxx>
35 #include <vcl/settings.hxx>
37 #include <svl/whiter.hxx>
39 #include <sfx2/request.hxx>
41 #include <editeng/scripttypeitem.hxx>
42 #include <svx/svdotable.hxx>
43 #include <svx/sdr/overlay/overlayobjectcell.hxx>
44 #include <svx/sdr/overlay/overlaymanager.hxx>
45 #include <svx/svxids.hrc>
46 #include <editeng/outlobj.hxx>
47 #include <svx/svdoutl.hxx>
48 #include <svx/svdpagv.hxx>
49 #include <svx/svdetc.hxx>
50 #include <editeng/editobj.hxx>
51 #include "editeng/editstat.hxx"
52 #include "editeng/unolingu.hxx"
53 #include "svx/sdrpagewindow.hxx"
54 #include <svx/selectioncontroller.hxx>
55 #include <svx/svdmodel.hxx>
56 #include "svx/sdrpaintwindow.hxx"
57 #include <svx/svxdlg.hxx>
58 #include <editeng/boxitem.hxx>
60 #include <editeng/borderline.hxx>
61 #include <editeng/colritem.hxx>
62 #include "editeng/lineitem.hxx"
63 #include "svx/svdstr.hrc"
64 #include "svdglob.hxx"
65 #include "svx/svdpage.hxx"
66 #include "tableundo.hxx"
67 #include "tablelayouter.hxx"
68 #include <vcl/msgbox.hxx>
69 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
71 #include <o3tl/enumarray.hxx>
72 #include <o3tl/enumrange.hxx>
74 using ::editeng::SvxBorderLine
;
75 using namespace sdr::table
;
76 using namespace ::com::sun::star
;
77 using namespace ::com::sun::star::uno
;
78 using namespace ::com::sun::star::table
;
79 using namespace ::com::sun::star::beans
;
80 using namespace ::com::sun::star::container
;
81 using namespace ::com::sun::star::text
;
82 using namespace ::com::sun::star::style
;
84 namespace sdr
{ namespace table
{
86 class SvxTableControllerModifyListener
: public ::cppu::WeakImplHelper1
< ::com::sun::star::util::XModifyListener
>
89 SvxTableControllerModifyListener( SvxTableController
* pController
)
90 : mpController( pController
) {}
93 virtual void SAL_CALL
modified( const ::com::sun::star::lang::EventObject
& aEvent
) throw (::com::sun::star::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
96 virtual void SAL_CALL
disposing( const ::com::sun::star::lang::EventObject
& Source
) throw (::com::sun::star::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
98 SvxTableController
* mpController
;
105 void SAL_CALL
SvxTableControllerModifyListener::modified( const ::com::sun::star::lang::EventObject
& ) throw (::com::sun::star::uno::RuntimeException
, std::exception
)
108 mpController
->onTableModified();
115 void SAL_CALL
SvxTableControllerModifyListener::disposing( const ::com::sun::star::lang::EventObject
& ) throw (::com::sun::star::uno::RuntimeException
, std::exception
)
121 // class SvxTableController
124 rtl::Reference
< sdr::SelectionController
> CreateTableController( SdrObjEditView
* pView
, const SdrObject
* pObj
, const rtl::Reference
< sdr::SelectionController
>& xRefController
)
126 return SvxTableController::create( pView
, pObj
, xRefController
);
131 rtl::Reference
< sdr::SelectionController
> SvxTableController::create( SdrObjEditView
* pView
, const SdrObject
* pObj
, const rtl::Reference
< sdr::SelectionController
>& xRefController
)
133 if( xRefController
.is() )
135 SvxTableController
* pController
= dynamic_cast< SvxTableController
* >( xRefController
.get() );
136 if( pController
&& (pController
->mxTableObj
.get() == pObj
) && (pController
->mpView
== pView
) )
137 return xRefController
;
139 return new SvxTableController( pView
, pObj
);
144 SvxTableController::SvxTableController( SdrObjEditView
* pView
, const SdrObject
* pObj
)
145 : mbCellSelectionMode(false)
146 , mbLeftButtonDown(false)
147 , mpSelectionOverlay(0)
148 , mpView( dynamic_cast< SdrView
* >( pView
) )
149 , mxTableObj( dynamic_cast< SdrTableObj
* >( const_cast< SdrObject
* >( pObj
) ) )
155 mpModel
= pObj
->GetModel();
157 if( mxTableObj
.is() )
159 static_cast< const SdrTableObj
* >( pObj
)->getActiveCellPos( maCursorFirstPos
);
160 maCursorLastPos
= maCursorFirstPos
;
162 Reference
< XTable
> xTable( static_cast< const SdrTableObj
* >( pObj
)->getTable() );
165 mxModifyListener
= new SvxTableControllerModifyListener( this );
166 xTable
->addModifyListener( mxModifyListener
);
168 mxTable
.set( dynamic_cast< TableModel
* >( xTable
.get() ) );
174 SvxTableController::~SvxTableController()
178 Application::RemoveUserEvent( mnUpdateEvent
);
181 if( mxModifyListener
.is() && mxTableObj
.get() )
183 Reference
< XTable
> xTable( static_cast< SdrTableObj
* >( mxTableObj
.get() )->getTable() );
186 xTable
->removeModifyListener( mxModifyListener
);
187 mxModifyListener
.clear();
194 const sal_uInt16 ACTION_NONE
= 0;
195 const sal_uInt16 ACTION_GOTO_FIRST_CELL
= 1;
196 const sal_uInt16 ACTION_GOTO_FIRST_COLUMN
= 2;
197 const sal_uInt16 ACTION_GOTO_FIRST_ROW
= 3;
198 const sal_uInt16 ACTION_GOTO_LEFT_CELL
= 4;
199 const sal_uInt16 ACTION_GOTO_UP_CELL
= 5;
200 const sal_uInt16 ACTION_GOTO_RIGHT_CELL
= 6;
201 const sal_uInt16 ACTION_GOTO_DOWN_CELL
= 7;
202 const sal_uInt16 ACTION_GOTO_LAST_CELL
= 8;
203 const sal_uInt16 ACTION_GOTO_LAST_COLUMN
= 9;
204 const sal_uInt16 ACTION_GOTO_LAST_ROW
= 10;
205 const sal_uInt16 ACTION_EDIT_CELL
= 11;
206 const sal_uInt16 ACTION_STOP_TEXT_EDIT
= 12;
207 const sal_uInt16 ACTION_REMOVE_SELECTION
= 13;
208 const sal_uInt16 ACTION_START_SELECTION
= 14;
209 const sal_uInt16 ACTION_HANDLED_BY_VIEW
= 15;
210 const sal_uInt16 ACTION_TAB
= 18;
212 bool SvxTableController::onKeyInput(const KeyEvent
& rKEvt
, vcl::Window
* pWindow
)
214 if( !checkTableObject() )
217 // check if we are read only
218 if( mpModel
&& mpModel
->IsReadOnly())
220 switch( rKEvt
.GetKeyCode().GetCode() )
225 case awt::Key::RIGHT
:
233 case awt::Key::ESCAPE
:
237 // tell the view we eat the event, no further processing needed
242 sal_uInt16 nAction
= getKeyboardAction( rKEvt
, pWindow
);
244 return executeAction( nAction
, rKEvt
.GetKeyCode().IsShift(), pWindow
);
248 // ::com::sun::star::awt::XMouseClickHandler:
251 bool SvxTableController::onMouseButtonDown(const MouseEvent
& rMEvt
, vcl::Window
* pWindow
)
253 if (mxTableObj
->GetModel()->isTiledRendering() && !pWindow
)
255 // Tiled rendering: get the window that has the disabled map mode.
256 if (OutputDevice
* pOutputDevice
= mpView
->GetFirstOutputDevice())
258 if (pOutputDevice
->GetOutDevType() == OUTDEV_WINDOW
)
259 pWindow
= static_cast<vcl::Window
*>(pOutputDevice
);
263 if( !pWindow
|| !checkTableObject() )
267 if( !rMEvt
.IsRight() && mpView
->PickAnything(rMEvt
,SdrMouseEventKind::BUTTONDOWN
, aVEvt
) == SDRHIT_HANDLE
)
270 TableHitKind eHit
= static_cast< SdrTableObj
* >(mxTableObj
.get())->CheckTableHit( pWindow
->PixelToLogic(rMEvt
.GetPosPixel()), maMouseDownPos
.mnCol
, maMouseDownPos
.mnRow
, 0 );
272 mbLeftButtonDown
= (rMEvt
.GetClicks() == 1) && rMEvt
.IsLeft();
274 if( eHit
== SDRTABLEHIT_CELL
)
276 StartSelection( maMouseDownPos
);
280 if( rMEvt
.IsRight() && eHit
!= SDRTABLEHIT_NONE
)
281 return true; // right click will become context menu
283 // for cell selection with the mouse remember our first hit
284 if( mbLeftButtonDown
)
288 Point
aPnt(rMEvt
.GetPosPixel());
290 aPnt
=pWindow
->PixelToLogic(aPnt
);
292 SdrHdl
* pHdl
= mpView
->PickHandle(aPnt
);
296 mbLeftButtonDown
= false;
300 sdr::table::SdrTableObj
* pTableObj
= dynamic_cast< sdr::table::SdrTableObj
* >( mxTableObj
.get() );
302 if( !pWindow
|| !pTableObj
|| eHit
== SDRTABLEHIT_NONE
)
304 mbLeftButtonDown
= false;
309 if (mxTableObj
->GetModel()->isTiledRendering() && rMEvt
.GetClicks() == 2 && rMEvt
.IsLeft() && eHit
== SDRTABLEHIT_CELLTEXTAREA
)
311 bool bEmptyOutliner
= false;
312 if (Outliner
* pOutliner
= mpView
->GetTextEditOutliner())
314 if (pOutliner
->GetParagraphCount() == 1)
316 if (Paragraph
* pParagraph
= pOutliner
->GetParagraph(0))
317 bEmptyOutliner
= pOutliner
->GetText(pParagraph
).isEmpty();
322 // Tiled rendering: a left double-click in an empty cell: select it.
323 StartSelection(maMouseDownPos
);
324 setSelectedCells(maMouseDownPos
, maMouseDownPos
);
325 // Update graphic selection, should be hidden now.
326 mpView
->AdjustMarkHdl();
336 bool SvxTableController::onMouseButtonUp(const MouseEvent
& rMEvt
, vcl::Window
* /*pWin*/)
338 if( !checkTableObject() )
341 mbLeftButtonDown
= false;
343 if( rMEvt
.GetClicks() == 2 )
351 bool SvxTableController::onMouseMove(const MouseEvent
& rMEvt
, vcl::Window
* pWindow
)
353 if( !checkTableObject() )
356 SdrTableObj
* pTableObj
= dynamic_cast< SdrTableObj
* >( mxTableObj
.get() );
358 if( mbLeftButtonDown
&& pTableObj
&& pTableObj
->CheckTableHit( pWindow
->PixelToLogic(rMEvt
.GetPosPixel()), aPos
.mnCol
, aPos
.mnRow
, 0 ) != SDRTABLEHIT_NONE
)
360 if(aPos
!= maMouseDownPos
)
362 if( mbCellSelectionMode
)
364 setSelectedCells( maMouseDownPos
, aPos
);
369 StartSelection( maMouseDownPos
);
372 else if( mbCellSelectionMode
)
374 UpdateSelection( aPos
);
383 void SvxTableController::onSelectionHasChanged()
385 bool bSelected
= false;
387 SdrTableObj
* pTableObj
= dynamic_cast< SdrTableObj
* >( mxTableObj
.get() );
388 if( pTableObj
&& pTableObj
->IsTextEditActive() )
390 pTableObj
->getActiveCellPos( maCursorFirstPos
);
391 maCursorLastPos
= maCursorFirstPos
;
392 mbCellSelectionMode
= false;
396 const SdrMarkList
& rMarkList
= mpView
->GetMarkedObjectList();
397 if( rMarkList
.GetMarkCount() == 1 )
398 bSelected
= mxTableObj
.get() == rMarkList
.GetMark(0)->GetMarkedSdrObj();
399 /* fdo#46186 Selecting the table means selecting the entire cells */
400 if (!hasSelectedCells() && pTableObj
)
402 maCursorFirstPos
= SdrTableObj::getFirstCell();
403 maCursorLastPos
= pTableObj
->getLastCell();
404 mbCellSelectionMode
=true;
410 updateSelectionOverlay();
414 destroySelectionOverlay();
420 void SvxTableController::GetState( SfxItemSet
& rSet
)
422 if( !mxTable
.is() || !mxTableObj
.is() || !mxTableObj
->GetModel() )
425 std::unique_ptr
<SfxItemSet
> xSet
;
427 bool bVertDone
= false;
429 // Iterate over all requested items in the set.
430 SfxWhichIter
aIter( rSet
);
431 sal_uInt16 nWhich
= aIter
.FirstWhich();
436 case SID_TABLE_VERT_BOTTOM
:
437 case SID_TABLE_VERT_CENTER
:
438 case SID_TABLE_VERT_NONE
:
440 if( !mxTable
.is() || !mxTableObj
->GetModel() )
442 rSet
.DisableItem(nWhich
);
448 xSet
.reset(new SfxItemSet( mxTableObj
->GetModel()->GetItemPool() ));
449 MergeAttrFromSelectedCells(*xSet
, false);
452 SdrTextVertAdjust eAdj
= SDRTEXTVERTADJUST_BLOCK
;
454 if (xSet
->GetItemState( SDRATTR_TEXT_VERTADJUST
) != SfxItemState::DONTCARE
)
455 eAdj
= static_cast<const SdrTextVertAdjustItem
&>(xSet
->Get(SDRATTR_TEXT_VERTADJUST
)).GetValue();
457 rSet
.Put(SfxBoolItem(SID_TABLE_VERT_BOTTOM
, eAdj
== SDRTEXTVERTADJUST_BOTTOM
));
458 rSet
.Put(SfxBoolItem(SID_TABLE_VERT_CENTER
, eAdj
== SDRTEXTVERTADJUST_CENTER
));
459 rSet
.Put(SfxBoolItem(SID_TABLE_VERT_NONE
, eAdj
== SDRTEXTVERTADJUST_TOP
));
464 case SID_TABLE_DELETE_ROW
:
465 if( !mxTable
.is() || !hasSelectedCells() || (mxTable
->getRowCount() <= 1) )
466 rSet
.DisableItem(SID_TABLE_DELETE_ROW
);
468 case SID_TABLE_DELETE_COL
:
469 if( !mxTable
.is() || !hasSelectedCells() || (mxTable
->getColumnCount() <= 1) )
470 rSet
.DisableItem(SID_TABLE_DELETE_COL
);
472 case SID_TABLE_MERGE_CELLS
:
473 if( !mxTable
.is() || !hasSelectedCells() )
474 rSet
.DisableItem(SID_TABLE_MERGE_CELLS
);
476 case SID_TABLE_SPLIT_CELLS
:
477 if( !hasSelectedCells() || !mxTable
.is() )
478 rSet
.DisableItem(SID_TABLE_SPLIT_CELLS
);
481 case SID_OPTIMIZE_TABLE
:
482 case SID_TABLE_DISTRIBUTE_COLUMNS
:
483 case SID_TABLE_DISTRIBUTE_ROWS
:
485 bool bDistributeColumns
= false;
486 bool bDistributeRows
= false;
489 CellPos aStart
, aEnd
;
490 getSelectedCells( aStart
, aEnd
);
492 bDistributeColumns
= aStart
.mnCol
!= aEnd
.mnCol
;
493 bDistributeRows
= aStart
.mnRow
!= aEnd
.mnRow
;
495 if( !bDistributeColumns
&& !bDistributeRows
)
496 rSet
.DisableItem(SID_OPTIMIZE_TABLE
);
497 if( !bDistributeColumns
)
498 rSet
.DisableItem(SID_TABLE_DISTRIBUTE_COLUMNS
);
499 if( !bDistributeRows
)
500 rSet
.DisableItem(SID_TABLE_DISTRIBUTE_ROWS
);
505 case SID_TABLE_SORT_DIALOG
:
506 case SID_TABLE_AUTOSUM
:
507 // if( !mxTable.is() )
508 // rSet.DisableItem( nWhich );
513 nWhich
= aIter
.NextWhich();
519 void SvxTableController::onInsert( sal_uInt16 nSId
, const SfxItemSet
* pArgs
)
521 sdr::table::SdrTableObj
* pTableObj
= dynamic_cast< sdr::table::SdrTableObj
* >( mxTableObj
.get() );
525 if( mxTable
.is() ) try
528 bool bInsertAfter
= true;
529 sal_uInt16 nCount
= 0;
532 const SfxPoolItem
* pItem
= 0;
533 pArgs
->GetItemState(nSId
, false, &pItem
);
536 nCount
= static_cast<const SfxInt16Item
*>(pItem
)->GetValue();
537 if(SfxItemState::SET
== pArgs
->GetItemState(SID_TABLE_PARAM_INSERT_AFTER
, true, &pItem
))
538 bInsertAfter
= static_cast<const SfxBoolItem
*>(pItem
)->GetValue();
542 CellPos aStart
, aEnd
;
543 if( hasSelectedCells() )
545 getSelectedCells( aStart
, aEnd
);
551 aStart
.mnCol
= mxTable
->getColumnCount() - 1;
552 aStart
.mnRow
= mxTable
->getRowCount() - 1;
557 if( pTableObj
->IsTextEditActive() )
558 mpView
->SdrEndTextEdit(true);
562 const OUString
sSize( "Size" );
564 const bool bUndo
= mpModel
&& mpModel
->IsUndoEnabled();
568 case SID_TABLE_INSERT_COL
:
570 TableModelNotifyGuard
aGuard( mxTable
.get() );
574 mpModel
->BegUndo( ImpGetResStr(STR_TABLE_INSCOL
) );
575 mpModel
->AddUndo( mpModel
->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj
) );
578 Reference
< XTableColumns
> xCols( mxTable
->getColumns() );
579 const sal_Int32 nNewColumns
= (nCount
== 0) ? (aEnd
.mnCol
- aStart
.mnCol
+ 1) : nCount
;
580 const sal_Int32 nNewStartColumn
= aEnd
.mnCol
+ (bInsertAfter
? 1 : 0);
581 xCols
->insertByIndex( nNewStartColumn
, nNewColumns
);
583 for( sal_Int32 nOffset
= 0; nOffset
< nNewColumns
; nOffset
++ )
585 // Resolves fdo#61540
586 // On Insert before, the reference column whose size is going to be
587 // used for newly created column(s) is wrong. As the new columns are
588 // inserted before the reference column, the reference column moved
589 // to the new position by no., of new columns i.e (earlier+newcolumns).
590 Reference
< XPropertySet
>(xCols
->getByIndex(nNewStartColumn
+nOffset
), UNO_QUERY_THROW
)->
591 setPropertyValue( sSize
,
592 Reference
< XPropertySet
>(xCols
->getByIndex( bInsertAfter
?nNewStartColumn
-1:nNewStartColumn
+nNewColumns
), UNO_QUERY_THROW
)->
593 getPropertyValue( sSize
) );
596 // Copy cell properties
597 sal_Int32 nPropSrcCol
= (bInsertAfter
? aEnd
.mnCol
: aStart
.mnCol
+ nNewColumns
);
598 sal_Int32 nRowSpan
= 0;
599 bool bNewSpan
= false;
601 for( sal_Int32 nRow
= 0; nRow
< mxTable
->getRowCount(); ++nRow
)
603 CellRef
xSourceCell( dynamic_cast< Cell
* >( mxTable
->getCellByPosition( nPropSrcCol
, nRow
).get() ) );
605 // When we insert new COLUMNs, we want to copy ROW spans.
606 if (xSourceCell
.is() && nRowSpan
== 0)
608 // we are not in a span yet. Let's find out if the current cell is in a span.
609 sal_Int32 nColSpan
= sal_Int32();
610 sal_Int32 nSpanInfoCol
= sal_Int32();
612 if( xSourceCell
->getRowSpan() > 1 )
614 // The current cell is the top-left cell in a span.
615 // Get the span info and propagate it to the target.
616 nRowSpan
= xSourceCell
->getRowSpan();
617 nColSpan
= xSourceCell
->getColumnSpan();
618 nSpanInfoCol
= nPropSrcCol
;
620 else if( xSourceCell
->isMerged() )
622 // The current cell is a middle cell in a 2D span.
623 // Look for the top-left cell in the span.
624 for( nSpanInfoCol
= nPropSrcCol
- 1; nSpanInfoCol
>= 0; --nSpanInfoCol
)
626 CellRef
xMergeInfoCell( dynamic_cast< Cell
* >( mxTable
->getCellByPosition( nSpanInfoCol
, nRow
).get() ) );
627 if (xMergeInfoCell
.is() && !xMergeInfoCell
->isMerged())
629 nRowSpan
= xMergeInfoCell
->getRowSpan();
630 nColSpan
= xMergeInfoCell
->getColumnSpan();
638 // The target colomns are outside the span; Start a new span.
639 if( nRowSpan
> 0 && ( nNewStartColumn
< nSpanInfoCol
|| nSpanInfoCol
+ nColSpan
<= nNewStartColumn
) )
643 // Now copy the properties from the source to the targets
644 for( sal_Int32 nOffset
= 0; nOffset
< nNewColumns
; nOffset
++ )
646 CellRef
xTargetCell( dynamic_cast< Cell
* >( mxTable
->getCellByPosition( nNewStartColumn
+ nOffset
, nRow
).get() ) );
647 if( xTargetCell
.is() )
652 xTargetCell
->merge( 1, nRowSpan
);
654 xTargetCell
->setMerged();
656 xTargetCell
->copyFormatFrom( xSourceCell
);
670 aStart
.mnCol
= nNewStartColumn
;
672 aEnd
.mnCol
= aStart
.mnCol
+ nNewColumns
- 1;
673 aEnd
.mnRow
= mxTable
->getRowCount() - 1;
677 case SID_TABLE_INSERT_ROW
:
679 TableModelNotifyGuard
aGuard( mxTable
.get() );
683 mpModel
->BegUndo( ImpGetResStr(STR_TABLE_INSROW
) );
684 mpModel
->AddUndo( mpModel
->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj
) );
687 Reference
< XTableRows
> xRows( mxTable
->getRows() );
688 const sal_Int32 nNewRows
= (nCount
== 0) ? (aEnd
.mnRow
- aStart
.mnRow
+ 1) : nCount
;
689 const sal_Int32 nNewRowStart
= aEnd
.mnRow
+ (bInsertAfter
? 1 : 0);
690 xRows
->insertByIndex( nNewRowStart
, nNewRows
);
692 for( sal_Int32 nOffset
= 0; nOffset
< nNewRows
; nOffset
++ )
694 Reference
< XPropertySet
>( xRows
->getByIndex( aEnd
.mnRow
+ nOffset
+ 1 ), UNO_QUERY_THROW
)->
695 setPropertyValue( sSize
,
696 Reference
< XPropertySet
>( xRows
->getByIndex( aStart
.mnRow
+ nOffset
), UNO_QUERY_THROW
)->
697 getPropertyValue( sSize
) );
700 // Copy the cell properties
701 sal_Int32 nPropSrcRow
= (bInsertAfter
? aEnd
.mnRow
: aStart
.mnRow
+ nNewRows
);
702 sal_Int32 nColSpan
= 0;
703 bool bNewSpan
= false;
705 for( sal_Int32 nCol
= 0; nCol
< mxTable
->getColumnCount(); ++nCol
)
707 CellRef
xSourceCell( dynamic_cast< Cell
* >( mxTable
->getCellByPosition( nCol
, nPropSrcRow
).get() ) );
709 if (!xSourceCell
.is())
712 // When we insert new ROWs, we want to copy COLUMN spans.
715 // we are not in a span yet. Let's find out if the current cell is in a span.
716 sal_Int32 nRowSpan
= sal_Int32();
717 sal_Int32 nSpanInfoRow
= sal_Int32();
719 if( xSourceCell
->getColumnSpan() > 1 )
721 // The current cell is the top-left cell in a span.
722 // Get the span info and propagate it to the target.
723 nColSpan
= xSourceCell
->getColumnSpan();
724 nRowSpan
= xSourceCell
->getRowSpan();
725 nSpanInfoRow
= nPropSrcRow
;
727 else if( xSourceCell
->isMerged() )
729 // The current cell is a middle cell in a 2D span.
730 // Look for the top-left cell in the span.
731 for( nSpanInfoRow
= nPropSrcRow
- 1; nSpanInfoRow
>= 0; --nSpanInfoRow
)
733 CellRef
xMergeInfoCell( dynamic_cast< Cell
* >( mxTable
->getCellByPosition( nCol
, nSpanInfoRow
).get() ) );
734 if (xMergeInfoCell
.is() && !xMergeInfoCell
->isMerged())
736 nColSpan
= xMergeInfoCell
->getColumnSpan();
737 nRowSpan
= xMergeInfoCell
->getRowSpan();
745 // Inserted rows are outside the span; Start a new span.
746 if( nColSpan
> 0 && ( nNewRowStart
< nSpanInfoRow
|| nSpanInfoRow
+ nRowSpan
<= nNewRowStart
) )
750 // Now copy the properties from the source to the targets
751 for( sal_Int32 nOffset
= 0; nOffset
< nNewRows
; ++nOffset
)
753 CellRef
xTargetCell( dynamic_cast< Cell
* >( mxTable
->getCellByPosition( nCol
, nNewRowStart
+ nOffset
).get() ) );
754 if( xTargetCell
.is() )
759 xTargetCell
->merge( nColSpan
, 1 );
761 xTargetCell
->setMerged();
763 xTargetCell
->copyFormatFrom( xSourceCell
);
778 aStart
.mnRow
= nNewRowStart
;
779 aEnd
.mnCol
= mxTable
->getColumnCount() - 1;
780 aEnd
.mnRow
= aStart
.mnRow
+ nNewRows
- 1;
785 StartSelection( aStart
);
786 UpdateSelection( aEnd
);
790 OSL_FAIL("svx::SvxTableController::onInsert(), exception caught!");
796 void SvxTableController::onDelete( sal_uInt16 nSId
)
798 sdr::table::SdrTableObj
* pTableObj
= dynamic_cast< sdr::table::SdrTableObj
* >( mxTableObj
.get() );
802 if( mxTable
.is() && hasSelectedCells() )
804 CellPos aStart
, aEnd
;
805 getSelectedCells( aStart
, aEnd
);
807 if( pTableObj
->IsTextEditActive() )
808 mpView
->SdrEndTextEdit(true);
812 bool bDeleteTable
= false;
815 case SID_TABLE_DELETE_COL
:
817 const sal_Int32 nRemovedColumns
= aEnd
.mnCol
- aStart
.mnCol
+ 1;
818 if( nRemovedColumns
== mxTable
->getColumnCount() )
824 Reference
< XTableColumns
> xCols( mxTable
->getColumns() );
825 xCols
->removeByIndex( aStart
.mnCol
, nRemovedColumns
);
830 case SID_TABLE_DELETE_ROW
:
832 const sal_Int32 nRemovedRows
= aEnd
.mnRow
- aStart
.mnRow
+ 1;
833 if( nRemovedRows
== mxTable
->getRowCount() )
839 Reference
< XTableRows
> xRows( mxTable
->getRows() );
840 xRows
->removeByIndex( aStart
.mnRow
, nRemovedRows
);
847 mpView
->DeleteMarkedObj();
855 void SvxTableController::onSelect( sal_uInt16 nSId
)
859 const sal_Int32 nRowCount
= mxTable
->getRowCount();
860 const sal_Int32 nColCount
= mxTable
->getColumnCount();
861 if( nRowCount
&& nColCount
)
863 CellPos aStart
, aEnd
;
864 getSelectedCells( aStart
, aEnd
);
868 case SID_TABLE_SELECT_ALL
:
869 aEnd
.mnCol
= 0; aEnd
.mnRow
= 0;
870 aStart
.mnCol
= nColCount
- 1; aStart
.mnRow
= nRowCount
- 1;
872 case SID_TABLE_SELECT_COL
:
873 aEnd
.mnRow
= nRowCount
- 1;
876 case SID_TABLE_SELECT_ROW
:
877 aEnd
.mnCol
= nColCount
- 1;
882 StartSelection( aEnd
);
883 gotoCell( aStart
, true, 0 );
890 SvxBoxItem
mergeDrawinglayerTextDistancesAndSvxBoxItem(const SfxItemSet
& rAttrSet
)
892 // merge drawing layer text distance items into SvxBoxItem used by the dialog
893 SvxBoxItem
aBoxItem( static_cast< const SvxBoxItem
& >( rAttrSet
.Get( SDRATTR_TABLE_BORDER
) ) );
894 aBoxItem
.SetDistance( sal::static_int_cast
< sal_uInt16
>( static_cast<const SdrMetricItem
&>(rAttrSet
.Get(SDRATTR_TEXT_LEFTDIST
)).GetValue()), SvxBoxItemLine::LEFT
);
895 aBoxItem
.SetDistance( sal::static_int_cast
< sal_uInt16
>( static_cast<const SdrMetricItem
&>(rAttrSet
.Get(SDRATTR_TEXT_RIGHTDIST
)).GetValue()), SvxBoxItemLine::RIGHT
);
896 aBoxItem
.SetDistance( sal::static_int_cast
< sal_uInt16
>( static_cast<const SdrMetricItem
&>(rAttrSet
.Get(SDRATTR_TEXT_UPPERDIST
)).GetValue()), SvxBoxItemLine::TOP
);
897 aBoxItem
.SetDistance( sal::static_int_cast
< sal_uInt16
>( static_cast<const SdrMetricItem
&>(rAttrSet
.Get(SDRATTR_TEXT_LOWERDIST
)).GetValue()), SvxBoxItemLine::BOTTOM
);
902 void SvxTableController::onFormatTable( SfxRequest
& rReq
)
904 sdr::table::SdrTableObj
* pTableObj
= dynamic_cast< sdr::table::SdrTableObj
* >( mxTableObj
.get() );
908 const SfxItemSet
* pArgs
= rReq
.GetArgs();
910 if( !pArgs
&& pTableObj
->GetModel() )
912 SfxItemSet
aNewAttr( pTableObj
->GetModel()->GetItemPool() );
914 // merge drawing layer text distance items into SvxBoxItem used by the dialog
915 SvxBoxItem
aBoxItem(mergeDrawinglayerTextDistancesAndSvxBoxItem(aNewAttr
));
917 SvxBoxInfoItem
aBoxInfoItem( static_cast< const SvxBoxInfoItem
& >( aNewAttr
.Get( SDRATTR_TABLE_BORDER_INNER
) ) );
919 MergeAttrFromSelectedCells(aNewAttr
, false);
920 FillCommonBorderAttrFromSelectedCells( aBoxItem
, aBoxInfoItem
);
921 aNewAttr
.Put( aBoxItem
);
922 aNewAttr
.Put( aBoxInfoItem
);
924 SvxAbstractDialogFactory
* pFact
= SvxAbstractDialogFactory::Create();
925 std::unique_ptr
< SfxAbstractTabDialog
> xDlg( pFact
? pFact
->CreateSvxFormatCellsDialog( NULL
, &aNewAttr
, pTableObj
->GetModel(), pTableObj
) : 0 );
926 // Even Cancel Button is returning positive(101) value,
927 if (xDlg
.get() && xDlg
->Execute() == RET_OK
)
929 SfxItemSet
aNewSet(*(xDlg
->GetOutputItemSet()));
931 //Only properties that were unchanged by the dialog appear in this
932 //itemset. We had constructed these two properties from other
933 //ones, so if they were not changed, then forcible set them back to
934 //their originals in the new result set so we can decompose that
935 //unchanged state back to their input properties
936 if (aNewSet
.GetItemState(SDRATTR_TABLE_BORDER
, false) != SfxItemState::SET
)
938 aNewSet
.Put(aBoxItem
);
940 if (aNewSet
.GetItemState(SDRATTR_TABLE_BORDER_INNER
, false) != SfxItemState::SET
)
942 aNewSet
.Put(aBoxInfoItem
);
945 SvxBoxItem
aNewBoxItem( static_cast< const SvxBoxItem
& >( aNewSet
.Get( SDRATTR_TABLE_BORDER
) ) );
947 if( aNewBoxItem
.GetDistance( SvxBoxItemLine::LEFT
) != aBoxItem
.GetDistance( SvxBoxItemLine::LEFT
) )
948 aNewSet
.Put(makeSdrTextLeftDistItem( aNewBoxItem
.GetDistance( SvxBoxItemLine::LEFT
) ) );
950 if( aNewBoxItem
.GetDistance( SvxBoxItemLine::RIGHT
) != aBoxItem
.GetDistance( SvxBoxItemLine::RIGHT
) )
951 aNewSet
.Put(makeSdrTextRightDistItem( aNewBoxItem
.GetDistance( SvxBoxItemLine::RIGHT
) ) );
953 if( aNewBoxItem
.GetDistance( SvxBoxItemLine::TOP
) != aBoxItem
.GetDistance( SvxBoxItemLine::TOP
) )
954 aNewSet
.Put(makeSdrTextUpperDistItem( aNewBoxItem
.GetDistance( SvxBoxItemLine::TOP
) ) );
956 if( aNewBoxItem
.GetDistance( SvxBoxItemLine::BOTTOM
) != aBoxItem
.GetDistance( SvxBoxItemLine::BOTTOM
) )
957 aNewSet
.Put(makeSdrTextLowerDistItem( aNewBoxItem
.GetDistance( SvxBoxItemLine::BOTTOM
) ) );
959 SetAttrToSelectedCells(aNewSet
, false);
964 void SvxTableController::Execute( SfxRequest
& rReq
)
966 const sal_uInt16 nSId
= rReq
.GetSlot();
969 case SID_TABLE_INSERT_ROW
:
970 case SID_TABLE_INSERT_COL
:
971 onInsert( nSId
, rReq
.GetArgs() );
973 case SID_TABLE_DELETE_ROW
:
974 case SID_TABLE_DELETE_COL
:
977 case SID_TABLE_SELECT_ALL
:
978 case SID_TABLE_SELECT_COL
:
979 case SID_TABLE_SELECT_ROW
:
982 case SID_FORMAT_TABLE_DLG
:
983 onFormatTable( rReq
);
986 case SID_FRAME_LINESTYLE
:
987 case SID_FRAME_LINECOLOR
:
988 case SID_ATTR_BORDER
:
990 const SfxItemSet
* pArgs
= rReq
.GetArgs();
992 ApplyBorderAttr( *pArgs
);
996 case SID_ATTR_FILL_STYLE
:
998 const SfxItemSet
* pArgs
= rReq
.GetArgs();
1000 SetAttributes( *pArgs
, false );
1004 case SID_TABLE_MERGE_CELLS
:
1008 case SID_TABLE_SPLIT_CELLS
:
1012 case SID_TABLE_DISTRIBUTE_COLUMNS
:
1013 DistributeColumns();
1016 case SID_TABLE_DISTRIBUTE_ROWS
:
1020 case SID_TABLE_VERT_BOTTOM
:
1021 case SID_TABLE_VERT_CENTER
:
1022 case SID_TABLE_VERT_NONE
:
1023 SetVertical( nSId
);
1026 case SID_AUTOFORMAT
:
1027 case SID_TABLE_SORT_DIALOG
:
1028 case SID_TABLE_AUTOSUM
:
1032 case SID_TABLE_STYLE
:
1033 SetTableStyle( rReq
.GetArgs() );
1036 case SID_TABLE_STYLE_SETTINGS
:
1037 SetTableStyleSettings( rReq
.GetArgs() );
1042 void SvxTableController::SetTableStyle( const SfxItemSet
* pArgs
)
1044 SdrTableObj
* pTableObj
= dynamic_cast< sdr::table::SdrTableObj
* >( mxTableObj
.get() );
1045 SdrModel
* pModel
= pTableObj
? pTableObj
->GetModel() : 0;
1047 if( !pTableObj
|| !pModel
|| !pArgs
|| (SfxItemState::SET
!= pArgs
->GetItemState(SID_TABLE_STYLE
, false)) )
1050 const SfxStringItem
* pArg
= dynamic_cast< const SfxStringItem
* >( &pArgs
->Get( SID_TABLE_STYLE
) );
1051 if( pArg
&& mxTable
.is() ) try
1053 Reference
< XStyleFamiliesSupplier
> xSFS( pModel
->getUnoModel(), UNO_QUERY_THROW
);
1054 Reference
< XNameAccess
> xFamilyNameAccess( xSFS
->getStyleFamilies(), UNO_QUERY_THROW
);
1055 const OUString
sFamilyName( "table" );
1056 Reference
< XNameAccess
> xTableFamilyAccess( xFamilyNameAccess
->getByName( sFamilyName
), UNO_QUERY_THROW
);
1058 if( xTableFamilyAccess
->hasByName( pArg
->GetValue() ) )
1060 // found table style with the same name
1061 Reference
< XIndexAccess
> xNewTableStyle( xTableFamilyAccess
->getByName( pArg
->GetValue() ), UNO_QUERY_THROW
);
1063 const bool bUndo
= pModel
->IsUndoEnabled();
1067 pModel
->BegUndo( ImpGetResStr(STR_TABLE_STYLE
) );
1068 pModel
->AddUndo( new TableStyleUndo( *pTableObj
) );
1071 pTableObj
->setTableStyle( xNewTableStyle
);
1073 const sal_Int32 nRowCount
= mxTable
->getRowCount();
1074 const sal_Int32 nColCount
= mxTable
->getColumnCount();
1075 for( sal_Int32 nRow
= 0; nRow
< nRowCount
; nRow
++ )
1077 for( sal_Int32 nCol
= 0; nCol
< nColCount
; nCol
++ ) try
1079 CellRef
xCell( dynamic_cast< Cell
* >( mxTable
->getCellByPosition( nCol
, nRow
).get() ) );
1082 SfxItemSet
aSet( xCell
->GetItemSet() );
1083 bool bChanges
= false;
1084 SfxStyleSheet
*pStyleSheet
= xCell
->GetStyleSheet();
1085 SAL_WARN_IF(!pStyleSheet
, "svx", "no stylesheet for table cell?");
1088 const SfxItemSet
& rStyleAttribs
= pStyleSheet
->GetItemSet();
1090 for ( sal_uInt16 nWhich
= SDRATTR_START
; nWhich
<= SDRATTR_TABLE_LAST
; nWhich
++ )
1092 if( (rStyleAttribs
.GetItemState( nWhich
) == SfxItemState::SET
) && (aSet
.GetItemState( nWhich
) == SfxItemState::SET
) )
1094 aSet
.ClearItem( nWhich
);
1105 xCell
->SetMergedItemSetAndBroadcast( aSet
, true );
1111 OSL_FAIL( "svx::SvxTableController::SetTableStyle(), exception caught!" );
1121 OSL_FAIL( "svx::SvxTableController::SetTableStyle(), exception caught!" );
1125 void SvxTableController::SetTableStyleSettings( const SfxItemSet
* pArgs
)
1127 SdrTableObj
* pTableObj
= dynamic_cast< sdr::table::SdrTableObj
* >( mxTableObj
.get() );
1128 SdrModel
* pModel
= pTableObj
? pTableObj
->GetModel() : 0;
1130 if( !pTableObj
|| !pModel
)
1133 TableStyleSettings
aSettings( pTableObj
->getTableStyleSettings() );
1135 const SfxPoolItem
*pPoolItem
=NULL
;
1137 if( (SfxItemState::SET
== pArgs
->GetItemState(ID_VAL_USEFIRSTROWSTYLE
, false,&pPoolItem
)) )
1138 aSettings
.mbUseFirstRow
= static_cast< const SfxBoolItem
* >(pPoolItem
)->GetValue();
1140 if( (SfxItemState::SET
== pArgs
->GetItemState(ID_VAL_USELASTROWSTYLE
, false,&pPoolItem
)) )
1141 aSettings
.mbUseLastRow
= static_cast< const SfxBoolItem
* >(pPoolItem
)->GetValue();
1143 if( (SfxItemState::SET
== pArgs
->GetItemState(ID_VAL_USEBANDINGROWSTYLE
, false,&pPoolItem
)) )
1144 aSettings
.mbUseRowBanding
= static_cast< const SfxBoolItem
* >(pPoolItem
)->GetValue();
1146 if( (SfxItemState::SET
== pArgs
->GetItemState(ID_VAL_USEFIRSTCOLUMNSTYLE
, false,&pPoolItem
)) )
1147 aSettings
.mbUseFirstColumn
= static_cast< const SfxBoolItem
* >(pPoolItem
)->GetValue();
1149 if( (SfxItemState::SET
== pArgs
->GetItemState(ID_VAL_USELASTCOLUMNSTYLE
, false,&pPoolItem
)) )
1150 aSettings
.mbUseLastColumn
= static_cast< const SfxBoolItem
* >(pPoolItem
)->GetValue();
1152 if( (SfxItemState::SET
== pArgs
->GetItemState(ID_VAL_USEBANDINGCOLUMNSTYLE
, false,&pPoolItem
)) )
1153 aSettings
.mbUseColumnBanding
= static_cast< const SfxBoolItem
* >(pPoolItem
)->GetValue();
1155 if( aSettings
== pTableObj
->getTableStyleSettings() )
1158 const bool bUndo
= pModel
->IsUndoEnabled();
1162 pModel
->BegUndo( ImpGetResStr(STR_TABLE_STYLE_SETTINGS
) );
1163 pModel
->AddUndo( new TableStyleUndo( *pTableObj
) );
1166 pTableObj
->setTableStyleSettings( aSettings
);
1172 void SvxTableController::SetVertical( sal_uInt16 nSId
)
1174 SdrTableObj
* pTableObj
= dynamic_cast< sdr::table::SdrTableObj
* >( mxTableObj
.get() );
1175 if( mxTable
.is() && pTableObj
)
1177 TableModelNotifyGuard
aGuard( mxTable
.get() );
1179 CellPos aStart
, aEnd
;
1180 getSelectedCells( aStart
, aEnd
);
1182 SdrTextVertAdjust eAdj
= SDRTEXTVERTADJUST_TOP
;
1186 case SID_TABLE_VERT_BOTTOM
:
1187 eAdj
= SDRTEXTVERTADJUST_BOTTOM
;
1189 case SID_TABLE_VERT_CENTER
:
1190 eAdj
= SDRTEXTVERTADJUST_CENTER
;
1192 //case SID_TABLE_VERT_NONE:
1197 SdrTextVertAdjustItem
aItem( eAdj
);
1199 for( sal_Int32 nRow
= aStart
.mnRow
; nRow
<= aEnd
.mnRow
; nRow
++ )
1201 for( sal_Int32 nCol
= aStart
.mnCol
; nCol
<= aEnd
.mnCol
; nCol
++ )
1203 CellRef
xCell( dynamic_cast< Cell
* >( mxTable
->getCellByPosition( nCol
, nRow
).get() ) );
1205 xCell
->SetMergedItem(aItem
);
1213 void SvxTableController::MergeMarkedCells()
1215 CellPos aStart
, aEnd
;
1216 getSelectedCells( aStart
, aEnd
);
1217 SdrTableObj
* pTableObj
= dynamic_cast< sdr::table::SdrTableObj
* >( mxTableObj
.get() );
1220 if( pTableObj
->IsTextEditActive() )
1221 mpView
->SdrEndTextEdit(true);
1223 TableModelNotifyGuard
aGuard( mxTable
.get() );
1224 MergeRange( aStart
.mnCol
, aStart
.mnRow
, aEnd
.mnCol
, aEnd
.mnRow
);
1228 void SvxTableController::SplitMarkedCells()
1232 CellPos aStart
, aEnd
;
1233 getSelectedCells( aStart
, aEnd
);
1235 SvxAbstractDialogFactory
* pFact
= SvxAbstractDialogFactory::Create();
1236 std::unique_ptr
< SvxAbstractSplittTableDialog
> xDlg( pFact
? pFact
->CreateSvxSplittTableDialog( NULL
, false, 99, 99 ) : 0 );
1237 if( xDlg
.get() && xDlg
->Execute() )
1239 const sal_Int32 nCount
= xDlg
->GetCount() - 1;
1243 getSelectedCells( aStart
, aEnd
);
1245 Reference
< XMergeableCellRange
> xRange( mxTable
->createCursorByRange( mxTable
->getCellRangeByPosition( aStart
.mnCol
, aStart
.mnRow
, aEnd
.mnCol
, aEnd
.mnRow
) ), UNO_QUERY_THROW
);
1247 const sal_Int32 nRowCount
= mxTable
->getRowCount();
1248 const sal_Int32 nColCount
= mxTable
->getColumnCount();
1251 SdrTableObj
* pTableObj
= dynamic_cast< SdrTableObj
* >( mxTableObj
.get() );
1254 if( pTableObj
->IsTextEditActive() )
1255 mpView
->SdrEndTextEdit(true);
1257 TableModelNotifyGuard
aGuard( mxTable
.get() );
1259 const bool bUndo
= mpModel
&& mpModel
->IsUndoEnabled();
1262 mpModel
->BegUndo( ImpGetResStr(STR_TABLE_SPLIT
) );
1263 mpModel
->AddUndo( mpModel
->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj
) );
1266 if( xDlg
->IsHorizontal() )
1268 xRange
->split( 0, nCount
);
1272 xRange
->split( nCount
, 0 );
1278 aEnd
.mnRow
+= mxTable
->getRowCount() - nRowCount
;
1279 aEnd
.mnCol
+= mxTable
->getColumnCount() - nColCount
;
1281 setSelectedCells( aStart
, aEnd
);
1286 void SvxTableController::DistributeColumns()
1288 SdrTableObj
* pTableObj
= dynamic_cast< SdrTableObj
* >( mxTableObj
.get() );
1291 const bool bUndo
= mpModel
&& mpModel
->IsUndoEnabled();
1294 mpModel
->BegUndo( ImpGetResStr(STR_TABLE_DISTRIBUTE_COLUMNS
) );
1295 mpModel
->AddUndo( mpModel
->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj
) );
1298 CellPos aStart
, aEnd
;
1299 getSelectedCells( aStart
, aEnd
);
1300 pTableObj
->DistributeColumns( aStart
.mnCol
, aEnd
.mnCol
);
1307 void SvxTableController::DistributeRows()
1309 SdrTableObj
* pTableObj
= dynamic_cast< SdrTableObj
* >( mxTableObj
.get() );
1312 const bool bUndo
= mpModel
&& mpModel
->IsUndoEnabled();
1315 mpModel
->BegUndo( ImpGetResStr(STR_TABLE_DISTRIBUTE_ROWS
) );
1316 mpModel
->AddUndo( mpModel
->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj
) );
1319 CellPos aStart
, aEnd
;
1320 getSelectedCells( aStart
, aEnd
);
1321 pTableObj
->DistributeRows( aStart
.mnRow
, aEnd
.mnRow
);
1328 bool SvxTableController::DeleteMarked()
1330 if( mbCellSelectionMode
)
1334 CellPos aStart
, aEnd
;
1335 getSelectedCells( aStart
, aEnd
);
1336 for( sal_Int32 nRow
= aStart
.mnRow
; nRow
<= aEnd
.mnRow
; nRow
++ )
1338 for( sal_Int32 nCol
= aStart
.mnCol
; nCol
<= aEnd
.mnCol
; nCol
++ )
1340 CellRef
xCell( dynamic_cast< Cell
* >( mxTable
->getCellByPosition( nCol
, nRow
).get() ) );
1342 xCell
->SetOutlinerParaObject( 0 );
1354 bool SvxTableController::GetStyleSheet( SfxStyleSheet
*& rpStyleSheet
) const
1356 if( hasSelectedCells() )
1362 SfxStyleSheet
* pRet
=0;
1365 CellPos aStart
, aEnd
;
1366 const_cast<SvxTableController
&>(*this).getSelectedCells( aStart
, aEnd
);
1368 for( sal_Int32 nRow
= aStart
.mnRow
; nRow
<= aEnd
.mnRow
; nRow
++ )
1370 for( sal_Int32 nCol
= aStart
.mnCol
; nCol
<= aEnd
.mnCol
; nCol
++ )
1372 CellRef
xCell( dynamic_cast< Cell
* >( mxTable
->getCellByPosition( nCol
, nRow
).get() ) );
1375 SfxStyleSheet
* pSS
=xCell
->GetStyleSheet();
1380 else if(pRet
!= pSS
)
1388 rpStyleSheet
= pRet
;
1395 bool SvxTableController::SetStyleSheet( SfxStyleSheet
* pStyleSheet
, bool bDontRemoveHardAttr
)
1397 if( hasSelectedCells() && (!pStyleSheet
|| pStyleSheet
->GetFamily() == SFX_STYLE_FAMILY_FRAME
) )
1401 CellPos aStart
, aEnd
;
1402 getSelectedCells( aStart
, aEnd
);
1404 for( sal_Int32 nRow
= aStart
.mnRow
; nRow
<= aEnd
.mnRow
; nRow
++ )
1406 for( sal_Int32 nCol
= aStart
.mnCol
; nCol
<= aEnd
.mnCol
; nCol
++ )
1408 CellRef
xCell( dynamic_cast< Cell
* >( mxTable
->getCellByPosition( nCol
, nRow
).get() ) );
1410 xCell
->SetStyleSheet(pStyleSheet
,bDontRemoveHardAttr
);
1425 bool SvxTableController::checkTableObject()
1427 return mxTableObj
.is();
1432 sal_uInt16
SvxTableController::getKeyboardAction( const KeyEvent
& rKEvt
, vcl::Window
* /*pWindow*/ )
1434 const bool bMod1
= rKEvt
.GetKeyCode().IsMod1(); // ctrl
1435 const bool bMod2
= rKEvt
.GetKeyCode().IsMod2(); // Alt
1437 const bool bTextEdit
= mpView
->IsTextEdit();
1439 sal_uInt16 nAction
= ACTION_HANDLED_BY_VIEW
;
1441 sdr::table::SdrTableObj
* pTableObj
= dynamic_cast< sdr::table::SdrTableObj
* >( mxTableObj
.get() );
1445 // handle special keys
1446 const sal_Int16 nCode
= rKEvt
.GetKeyCode().GetCode();
1449 case awt::Key::ESCAPE
: // handle escape
1453 // escape during text edit ends text edit
1454 nAction
= ACTION_STOP_TEXT_EDIT
;
1456 if( mbCellSelectionMode
)
1458 // escape with selected cells removes selection
1459 nAction
= ACTION_REMOVE_SELECTION
;
1463 case awt::Key::RETURN
: // handle return
1465 if( !bMod1
&& !bMod2
&& !bTextEdit
)
1467 // when not already editing, return starts text edit
1468 setSelectionStart( SdrTableObj::getFirstCell() );
1469 nAction
= ACTION_EDIT_CELL
;
1473 case awt::Key::F2
: // f2 toggles text edit
1475 if( bMod1
|| bMod2
) // f2 with modifiers is handled by the view
1478 else if( bTextEdit
)
1480 // f2 during text edit stops text edit
1481 nAction
= ACTION_STOP_TEXT_EDIT
;
1483 else if( mbCellSelectionMode
)
1485 // f2 with selected cells removes selection
1486 nAction
= ACTION_REMOVE_SELECTION
;
1490 // f2 with no selection and no text edit starts text edit
1491 setSelectionStart( SdrTableObj::getFirstCell() );
1492 nAction
= ACTION_EDIT_CELL
;
1496 case awt::Key::HOME
:
1497 case awt::Key::NUM7
:
1499 if( (bMod1
|| bMod2
) && (bTextEdit
|| mbCellSelectionMode
) )
1501 if( bMod1
&& !bMod2
)
1503 // ctrl + home jumps to first cell
1504 nAction
= ACTION_GOTO_FIRST_CELL
;
1506 else if( !bMod1
&& bMod2
)
1508 // alt + home jumps to first column
1509 nAction
= ACTION_GOTO_FIRST_COLUMN
;
1515 case awt::Key::NUM1
:
1517 if( (bMod1
|| bMod2
) && (bTextEdit
|| mbCellSelectionMode
) )
1519 if( bMod1
&& !bMod2
)
1521 // ctrl + end jumps to last cell
1522 nAction
= ACTION_GOTO_LAST_CELL
;
1524 else if( !bMod1
&& bMod2
)
1526 // alt + home jumps to last column
1527 nAction
= ACTION_GOTO_LAST_COLUMN
;
1535 if( bTextEdit
|| mbCellSelectionMode
)
1536 nAction
= ACTION_TAB
;
1541 case awt::Key::NUM8
:
1542 case awt::Key::DOWN
:
1543 case awt::Key::NUM2
:
1544 case awt::Key::LEFT
:
1545 case awt::Key::NUM4
:
1546 case awt::Key::RIGHT
:
1547 case awt::Key::NUM6
:
1549 bool bTextMove
= false;
1551 if( !bMod1
&& bMod2
)
1553 if( (nCode
== awt::Key::UP
) || (nCode
== awt::Key::NUM8
) )
1555 nAction
= ACTION_GOTO_LEFT_CELL
;
1557 else if( (nCode
== awt::Key::DOWN
) || (nCode
== awt::Key::NUM2
) )
1559 nAction
= ACTION_GOTO_RIGHT_CELL
;
1566 OutlinerView
* pOLV
= mpView
->GetTextEditOutlinerView();
1570 // during text edit, check if we navigate out of the cell
1571 ESelection aOldSelection
= pOLV
->GetSelection();
1572 pOLV
->PostKeyEvent(rKEvt
);
1573 bTextMove
= pOLV
&& ( aOldSelection
.IsEqual(pOLV
->GetSelection()) );
1576 nAction
= ACTION_NONE
;
1581 if( mbCellSelectionMode
|| bTextMove
)
1583 // no text edit, navigate in cells if selection active
1586 case awt::Key::LEFT
:
1587 case awt::Key::NUM4
:
1588 nAction
= ACTION_GOTO_LEFT_CELL
;
1590 case awt::Key::RIGHT
:
1591 case awt::Key::NUM6
:
1592 nAction
= ACTION_GOTO_RIGHT_CELL
;
1594 case awt::Key::DOWN
:
1595 case awt::Key::NUM2
:
1596 nAction
= ACTION_GOTO_DOWN_CELL
;
1599 case awt::Key::NUM8
:
1600 nAction
= ACTION_GOTO_UP_CELL
;
1606 case awt::Key::PAGEUP
:
1608 nAction
= ACTION_GOTO_FIRST_ROW
;
1611 case awt::Key::PAGEDOWN
:
1613 nAction
= ACTION_GOTO_LAST_ROW
;
1619 bool SvxTableController::executeAction( sal_uInt16 nAction
, bool bSelect
, vcl::Window
* pWindow
)
1621 sdr::table::SdrTableObj
* pTableObj
= dynamic_cast< sdr::table::SdrTableObj
* >( mxTableObj
.get() );
1627 case ACTION_GOTO_FIRST_CELL
:
1629 gotoCell( SdrTableObj::getFirstCell(), bSelect
, pWindow
, nAction
);
1633 case ACTION_GOTO_LEFT_CELL
:
1635 gotoCell( pTableObj
->getLeftCell( getSelectionEnd(), !bSelect
), bSelect
, pWindow
, nAction
);
1639 case ACTION_GOTO_RIGHT_CELL
:
1641 gotoCell( pTableObj
->getRightCell( getSelectionEnd(), !bSelect
), bSelect
, pWindow
, nAction
);
1645 case ACTION_GOTO_LAST_CELL
:
1647 gotoCell( pTableObj
->getLastCell(), bSelect
, pWindow
, nAction
);
1651 case ACTION_GOTO_FIRST_COLUMN
:
1653 CellPos
aPos( SdrTableObj::getFirstCell().mnCol
, getSelectionEnd().mnRow
);
1654 gotoCell( aPos
, bSelect
, pWindow
, nAction
);
1658 case ACTION_GOTO_LAST_COLUMN
:
1660 CellPos
aPos( pTableObj
->getLastCell().mnCol
, getSelectionEnd().mnRow
);
1661 gotoCell( aPos
, bSelect
, pWindow
, nAction
);
1665 case ACTION_GOTO_FIRST_ROW
:
1667 CellPos
aPos( getSelectionEnd().mnCol
, SdrTableObj::getFirstCell().mnRow
);
1668 gotoCell( aPos
, bSelect
, pWindow
, nAction
);
1672 case ACTION_GOTO_UP_CELL
:
1674 gotoCell( pTableObj
->getUpCell(getSelectionEnd(), !bSelect
), bSelect
, pWindow
, nAction
);
1678 case ACTION_GOTO_DOWN_CELL
:
1680 gotoCell( pTableObj
->getDownCell(getSelectionEnd(), !bSelect
), bSelect
, pWindow
, nAction
);
1684 case ACTION_GOTO_LAST_ROW
:
1686 CellPos
aPos( getSelectionEnd().mnCol
, pTableObj
->getLastCell().mnRow
);
1687 gotoCell( aPos
, bSelect
, pWindow
, nAction
);
1691 case ACTION_EDIT_CELL
:
1692 EditCell( getSelectionStart(), pWindow
, 0, nAction
);
1695 case ACTION_STOP_TEXT_EDIT
:
1699 case ACTION_REMOVE_SELECTION
:
1703 case ACTION_START_SELECTION
:
1704 StartSelection( getSelectionStart() );
1710 gotoCell( pTableObj
->getPreviousCell( getSelectionEnd(), true ), false, pWindow
, nAction
);
1713 CellPos
aSelectionEnd( getSelectionEnd() );
1714 CellPos
aNextCell( pTableObj
->getNextCell( aSelectionEnd
, true ) );
1715 if( aSelectionEnd
== aNextCell
)
1717 onInsert( SID_TABLE_INSERT_ROW
, 0 );
1718 aNextCell
= pTableObj
->getNextCell( aSelectionEnd
, true );
1720 gotoCell( aNextCell
, false, pWindow
, nAction
);
1726 return nAction
!= ACTION_HANDLED_BY_VIEW
;
1731 void SvxTableController::gotoCell( const CellPos
& rPos
, bool bSelect
, vcl::Window
* pWindow
, sal_uInt16 nAction
)
1733 if( mxTableObj
.is() && static_cast<SdrTableObj
*>(mxTableObj
.get())->IsTextEditActive() )
1734 mpView
->SdrEndTextEdit(true);
1738 maCursorLastPos
= rPos
;
1739 if( mxTableObj
.is() )
1740 static_cast< SdrTableObj
* >( mxTableObj
.get() )->setActiveCell( rPos
);
1742 if( !mbCellSelectionMode
)
1744 setSelectedCells( maCursorFirstPos
, rPos
);
1748 UpdateSelection( rPos
);
1754 EditCell( rPos
, pWindow
, 0, nAction
);
1760 const CellPos
& SvxTableController::getSelectionStart()
1762 checkCell( maCursorFirstPos
);
1763 return maCursorFirstPos
;
1768 void SvxTableController::setSelectionStart( const CellPos
& rPos
)
1770 maCursorFirstPos
= rPos
;
1775 const CellPos
& SvxTableController::getSelectionEnd()
1777 checkCell( maCursorLastPos
);
1778 return maCursorLastPos
;
1783 void SvxTableController::MergeRange( sal_Int32 nFirstCol
, sal_Int32 nFirstRow
, sal_Int32 nLastCol
, sal_Int32 nLastRow
)
1785 if( mxTable
.is() ) try
1787 Reference
< XMergeableCellRange
> xRange( mxTable
->createCursorByRange( mxTable
->getCellRangeByPosition( nFirstCol
, nFirstRow
,nLastCol
, nLastRow
) ), UNO_QUERY_THROW
);
1788 if( xRange
->isMergeable() )
1790 const bool bUndo
= mpModel
&& mpModel
->IsUndoEnabled();
1793 mpModel
->BegUndo( ImpGetResStr(STR_TABLE_MERGE
) );
1794 mpModel
->AddUndo( mpModel
->GetSdrUndoFactory().CreateUndoGeoObject(*mxTableObj
.get()) );
1805 DBG_ASSERT( false, "sdr::table::SvxTableController::MergeRange(), exception caught!" );
1813 void SvxTableController::checkCell( CellPos
& rPos
)
1815 if( mxTable
.is() ) try
1817 if( rPos
.mnCol
>= mxTable
->getColumnCount() )
1818 rPos
.mnCol
= mxTable
->getColumnCount()-1;
1820 if( rPos
.mnRow
>= mxTable
->getRowCount() )
1821 rPos
.mnRow
= mxTable
->getRowCount()-1;
1825 OSL_FAIL("sdr::table::SvxTableController::checkCell(), exception caught!" );
1831 void SvxTableController::findMergeOrigin( CellPos
& rPos
)
1833 if( mxTable
.is() ) try
1835 Reference
< XMergeableCell
> xCell( mxTable
->getCellByPosition( rPos
.mnCol
, rPos
.mnRow
), UNO_QUERY_THROW
);
1836 if( xCell
.is() && xCell
->isMerged() )
1838 ::findMergeOrigin( mxTable
, rPos
.mnCol
, rPos
.mnRow
, rPos
.mnCol
, rPos
.mnRow
);
1843 OSL_FAIL("sdr::table::SvxTableController::findMergeOrigin(), exception caught!" );
1849 void SvxTableController::EditCell( const CellPos
& rPos
, vcl::Window
* pWindow
, const awt::MouseEvent
* pMouseEvent
/*= 0*/, sal_uInt16 nAction
/*= ACTION_NONE */ )
1851 SdrPageView
* pPV
= mpView
->GetSdrPageView();
1853 sdr::table::SdrTableObj
* pTableObj
= dynamic_cast< sdr::table::SdrTableObj
* >( mxTableObj
.get() );
1854 if( pTableObj
&& pTableObj
->GetPage() == pPV
->GetPage() )
1856 bool bEmptyOutliner
= false;
1858 if(!pTableObj
->GetOutlinerParaObject() && mpView
->GetTextEditOutliner())
1860 ::Outliner
* pOutl
= mpView
->GetTextEditOutliner();
1861 sal_Int32 nParaAnz
= pOutl
->GetParagraphCount();
1862 Paragraph
* p1stPara
= pOutl
->GetParagraph( 0 );
1864 if(nParaAnz
==1 && p1stPara
)
1866 // Bei nur einem Pararaph
1867 if (pOutl
->GetText(p1stPara
).isEmpty())
1869 bEmptyOutliner
= true;
1874 CellPos
aPos( rPos
);
1875 findMergeOrigin( aPos
);
1877 if( pTableObj
!= mpView
->GetTextEditObject() || bEmptyOutliner
|| !pTableObj
->IsTextEditActive( aPos
) )
1879 if( pTableObj
->IsTextEditActive() )
1880 mpView
->SdrEndTextEdit(true);
1882 pTableObj
->setActiveCell( aPos
);
1884 // create new outliner, owner will be the SdrObjEditView
1885 SdrOutliner
* pOutl
= mpModel
? SdrMakeOutliner(OUTLINERMODE_OUTLINEOBJECT
, *mpModel
) : NULL
;
1886 if (pOutl
&& pTableObj
->IsVerticalWriting())
1887 pOutl
->SetVertical( true );
1889 if (mpView
->SdrBeginTextEdit(pTableObj
, pPV
, pWindow
, true, pOutl
))
1891 maCursorLastPos
= maCursorFirstPos
= rPos
;
1893 OutlinerView
* pOLV
= mpView
->GetTextEditOutlinerView();
1899 ::MouseEvent
aMEvt( *pMouseEvent
);
1902 SdrHitKind eHit
= mpView
->PickAnything(aMEvt
, SdrMouseEventKind::BUTTONDOWN
, aVEvt
);
1904 if (eHit
== SDRHIT_TEXTEDIT
)
1907 pOLV
->MouseButtonDown(aMEvt
);
1908 pOLV
->MouseMove(aMEvt
);
1909 pOLV
->MouseButtonUp(aMEvt
);
1910 // pOLV->MouseButtonDown(aMEvt);
1915 nAction
= ACTION_GOTO_LEFT_CELL
;
1921 // Move cursor to end of text
1922 ESelection aNewSelection
;
1924 const WritingMode eMode
= pTableObj
->GetWritingMode();
1925 if( ((nAction
== ACTION_GOTO_LEFT_CELL
) || (nAction
== ACTION_GOTO_RIGHT_CELL
)) && (eMode
!= WritingMode_TB_RL
) )
1927 const bool bLast
= ((nAction
== ACTION_GOTO_LEFT_CELL
) && (eMode
== WritingMode_LR_TB
)) ||
1928 ((nAction
== ACTION_GOTO_RIGHT_CELL
) && (eMode
== WritingMode_RL_TB
));
1931 aNewSelection
= ESelection(EE_PARA_NOT_FOUND
, EE_INDEX_NOT_FOUND
, EE_PARA_NOT_FOUND
, EE_INDEX_NOT_FOUND
);
1933 pOLV
->SetSelection(aNewSelection
);
1942 bool SvxTableController::StopTextEdit()
1944 if(mpView
->IsTextEdit())
1946 mpView
->SdrEndTextEdit();
1947 mpView
->SetCurrentObj(OBJ_TABLE
);
1948 mpView
->SetEditMode(SDREDITMODE_EDIT
);
1959 void SvxTableController::getSelectedCells( CellPos
& rFirst
, CellPos
& rLast
)
1961 if( mbCellSelectionMode
)
1963 checkCell( maCursorFirstPos
);
1964 checkCell( maCursorLastPos
);
1966 rFirst
.mnCol
= std::min( maCursorFirstPos
.mnCol
, maCursorLastPos
.mnCol
);
1967 rFirst
.mnRow
= std::min( maCursorFirstPos
.mnRow
, maCursorLastPos
.mnRow
);
1968 rLast
.mnCol
= std::max( maCursorFirstPos
.mnCol
, maCursorLastPos
.mnCol
);
1969 rLast
.mnRow
= std::max( maCursorFirstPos
.mnRow
, maCursorLastPos
.mnRow
);
1972 if( mxTable
.is() ) do
1975 for( sal_Int32 nRow
= rFirst
.mnRow
; nRow
<= rLast
.mnRow
&& !bExt
; nRow
++ )
1977 for( sal_Int32 nCol
= rFirst
.mnCol
; nCol
<= rLast
.mnCol
&& !bExt
; nCol
++ )
1979 Reference
< XMergeableCell
> xCell( mxTable
->getCellByPosition( nCol
, nRow
), UNO_QUERY
);
1983 if( xCell
->isMerged() )
1985 CellPos
aPos( nCol
, nRow
);
1986 findMergeOrigin( aPos
);
1987 if( (aPos
.mnCol
< rFirst
.mnCol
) || (aPos
.mnRow
< rFirst
.mnRow
) )
1989 rFirst
.mnCol
= std::min( rFirst
.mnCol
, aPos
.mnCol
);
1990 rFirst
.mnRow
= std::min( rFirst
.mnRow
, aPos
.mnRow
);
1996 if( ((nCol
+ xCell
->getColumnSpan() - 1) > rLast
.mnCol
) || (nRow
+ xCell
->getRowSpan() - 1 ) > rLast
.mnRow
)
1998 rLast
.mnCol
= std::max( rLast
.mnCol
, nCol
+ xCell
->getColumnSpan() - 1 );
1999 rLast
.mnRow
= std::max( rLast
.mnRow
, nRow
+ xCell
->getRowSpan() - 1 );
2008 else if( mpView
&& mpView
->IsTextEdit() )
2010 rFirst
= getSelectionStart();
2011 findMergeOrigin( rFirst
);
2016 Reference
< XMergeableCell
> xCell( mxTable
->getCellByPosition( rLast
.mnCol
, rLast
.mnRow
), UNO_QUERY
);
2019 rLast
.mnCol
+= xCell
->getColumnSpan() - 1;
2020 rLast
.mnRow
+= xCell
->getRowSpan() - 1;
2030 rLast
.mnRow
= mxTable
->getRowCount()-1;
2031 rLast
.mnCol
= mxTable
->getColumnCount()-1;
2043 void SvxTableController::StartSelection( const CellPos
& rPos
)
2046 mbCellSelectionMode
= true;
2047 maCursorLastPos
= maCursorFirstPos
= rPos
;
2048 mpView
->MarkListHasChanged();
2053 void SvxTableController::setSelectedCells( const CellPos
& rStart
, const CellPos
& rEnd
)
2056 mbCellSelectionMode
= true;
2057 maCursorFirstPos
= rStart
;
2058 UpdateSelection( rEnd
);
2063 void SvxTableController::UpdateSelection( const CellPos
& rPos
)
2065 maCursorLastPos
= rPos
;
2066 mpView
->MarkListHasChanged();
2071 void SvxTableController::clearSelection()
2078 void SvxTableController::selectAll()
2082 CellPos aPos1
, aPos2( mxTable
->getColumnCount()-1, mxTable
->getRowCount()-1 );
2083 if( (aPos2
.mnCol
>= 0) && (aPos2
.mnRow
>= 0) )
2085 setSelectedCells( aPos1
, aPos2
);
2092 void SvxTableController::RemoveSelection()
2094 if( mbCellSelectionMode
)
2096 mbCellSelectionMode
= false;
2097 mpView
->MarkListHasChanged();
2103 void SvxTableController::onTableModified()
2105 if( mnUpdateEvent
== 0 )
2106 mnUpdateEvent
= Application::PostUserEvent( LINK( this, SvxTableController
, UpdateHdl
) );
2110 void SvxTableController::updateSelectionOverlay()
2112 destroySelectionOverlay();
2113 if( mbCellSelectionMode
)
2115 sdr::table::SdrTableObj
* pTableObj
= dynamic_cast< sdr::table::SdrTableObj
* >( mxTableObj
.get() );
2118 sdr::overlay::OverlayObjectCell::RangeVector aRanges
;
2120 Rectangle aStartRect
, aEndRect
;
2121 CellPos aStart
,aEnd
;
2122 getSelectedCells( aStart
, aEnd
);
2123 pTableObj
->getCellBounds( aStart
, aStartRect
);
2125 basegfx::B2DRange
a2DRange( basegfx::B2DPoint(aStartRect
.Left(), aStartRect
.Top()) );
2126 a2DRange
.expand( basegfx::B2DPoint(aStartRect
.Right(), aStartRect
.Bottom()) );
2128 findMergeOrigin( aEnd
);
2129 pTableObj
->getCellBounds( aEnd
, aEndRect
);
2130 a2DRange
.expand( basegfx::B2DPoint(aEndRect
.Left(), aEndRect
.Top()) );
2131 a2DRange
.expand( basegfx::B2DPoint(aEndRect
.Right(), aEndRect
.Bottom()) );
2132 aRanges
.push_back( a2DRange
);
2134 ::Color
aHighlight( COL_BLUE
);
2135 OutputDevice
* pOutDev
= mpView
->GetFirstOutputDevice();
2137 aHighlight
= pOutDev
->GetSettings().GetStyleSettings().GetHighlightColor();
2139 const sal_uInt32 nCount
= mpView
->PaintWindowCount();
2140 for( sal_uInt32 nIndex
= 0; nIndex
< nCount
; nIndex
++ )
2142 SdrPaintWindow
* pPaintWindow
= mpView
->GetPaintWindow(nIndex
);
2145 rtl::Reference
< sdr::overlay::OverlayManager
> xOverlayManager
= pPaintWindow
->GetOverlayManager();
2146 if( xOverlayManager
.is() )
2148 // sdr::overlay::CellOverlayType eType = sdr::overlay::CELL_OVERLAY_INVERT;
2149 sdr::overlay::CellOverlayType eType
= sdr::overlay::CELL_OVERLAY_TRANSPARENT
;
2151 sdr::overlay::OverlayObjectCell
* pOverlay
= new sdr::overlay::OverlayObjectCell( eType
, aHighlight
, aRanges
);
2153 xOverlayManager
->add(*pOverlay
);
2154 mpSelectionOverlay
= new sdr::overlay::OverlayObjectList
;
2155 mpSelectionOverlay
->append(*pOverlay
);
2160 // If tiled rendering, emit callbacks for sdr table selection.
2161 if (pOutDev
&& pTableObj
->GetModel()->isTiledRendering())
2163 // Left edge of aStartRect.
2164 Rectangle
aSelectionStart(aStartRect
.Left(), aStartRect
.Top(), aStartRect
.Left(), aStartRect
.Bottom());
2165 // Right edge of aEndRect.
2166 Rectangle
aSelectionEnd(aEndRect
.Right(), aEndRect
.Top(), aEndRect
.Right(), aEndRect
.Bottom());
2167 Rectangle
aSelection(a2DRange
.getMinX(), a2DRange
.getMinY(), a2DRange
.getMaxX(), a2DRange
.getMaxY());
2169 if (pOutDev
->GetMapMode().GetMapUnit() == MAP_100TH_MM
)
2171 aSelectionStart
= OutputDevice::LogicToLogic(aSelectionStart
, MAP_100TH_MM
, MAP_TWIP
);
2172 aSelectionEnd
= OutputDevice::LogicToLogic(aSelectionEnd
, MAP_100TH_MM
, MAP_TWIP
);
2173 aSelection
= OutputDevice::LogicToLogic(aSelection
, MAP_100TH_MM
, MAP_TWIP
);
2176 pTableObj
->GetModel()->libreOfficeKitCallback(LOK_CALLBACK_TEXT_SELECTION_START
, aSelectionStart
.toString().getStr());
2177 pTableObj
->GetModel()->libreOfficeKitCallback(LOK_CALLBACK_TEXT_SELECTION_END
, aSelectionEnd
.toString().getStr());
2178 pTableObj
->GetModel()->libreOfficeKitCallback(LOK_CALLBACK_TEXT_SELECTION
, aSelection
.toString().getStr());
2186 void SvxTableController::destroySelectionOverlay()
2188 if( mpSelectionOverlay
)
2190 delete mpSelectionOverlay
;
2191 mpSelectionOverlay
= 0;
2193 if (mxTableObj
->GetModel()->isTiledRendering())
2195 // Clear the LOK text selection so far provided by this table.
2196 mxTableObj
->GetModel()->libreOfficeKitCallback(LOK_CALLBACK_TEXT_SELECTION_START
, "EMPTY");
2197 mxTableObj
->GetModel()->libreOfficeKitCallback(LOK_CALLBACK_TEXT_SELECTION_END
, "EMPTY");
2198 mxTableObj
->GetModel()->libreOfficeKitCallback(LOK_CALLBACK_TEXT_SELECTION
, "EMPTY");
2205 void SvxTableController::MergeAttrFromSelectedCells(SfxItemSet
& rAttr
, bool bOnlyHardAttr
) const
2209 CellPos aStart
, aEnd
;
2210 const_cast<SvxTableController
&>(*this).getSelectedCells( aStart
, aEnd
);
2212 for( sal_Int32 nRow
= aStart
.mnRow
; nRow
<= aEnd
.mnRow
; nRow
++ )
2214 for( sal_Int32 nCol
= aStart
.mnCol
; nCol
<= aEnd
.mnCol
; nCol
++ )
2216 CellRef
xCell( dynamic_cast< Cell
* >( mxTable
->getCellByPosition( nCol
, nRow
).get() ) );
2217 if( xCell
.is() && !xCell
->isMerged() )
2219 const SfxItemSet
& rSet
= xCell
->GetItemSet();
2220 SfxWhichIter
aIter(rSet
);
2221 sal_uInt16
nWhich(aIter
.FirstWhich());
2226 if(SfxItemState::DONTCARE
== rSet
.GetItemState(nWhich
, false))
2227 rAttr
.InvalidateItem(nWhich
);
2229 rAttr
.MergeValue(rSet
.Get(nWhich
), true);
2231 else if(SfxItemState::SET
== rSet
.GetItemState(nWhich
, false))
2233 const SfxPoolItem
& rItem
= rSet
.Get(nWhich
);
2234 rAttr
.MergeValue(rItem
, true);
2237 nWhich
= aIter
.NextWhich();
2247 const sal_uInt16 CELL_BEFORE
= 0x0001;
2248 const sal_uInt16 CELL_LEFT
= 0x0002;
2249 const sal_uInt16 CELL_RIGHT
= 0x0004;
2250 const sal_uInt16 CELL_AFTER
= 0x0008;
2252 const sal_uInt16 CELL_UPPER
= 0x0010;
2253 const sal_uInt16 CELL_TOP
= 0x0020;
2254 const sal_uInt16 CELL_BOTTOM
= 0x0040;
2255 const sal_uInt16 CELL_LOWER
= 0x0080;
2259 static void ImplSetLinePreserveColor( SvxBoxItem
& rNewFrame
, const SvxBorderLine
* pNew
, SvxBoxItemLine nLine
)
2263 const SvxBorderLine
* pOld
= rNewFrame
.GetLine(nLine
);
2266 SvxBorderLine
aNewLine( *pNew
);
2267 aNewLine
.SetColor( pOld
->GetColor() );
2268 rNewFrame
.SetLine( &aNewLine
, nLine
);
2272 rNewFrame
.SetLine( pNew
, nLine
);
2277 static void ImplApplyBoxItem( sal_uInt16 nCellFlags
, const SvxBoxItem
* pBoxItem
, const SvxBoxInfoItem
* pBoxInfoItem
, SvxBoxItem
& rNewFrame
)
2279 if( (nCellFlags
& (CELL_BEFORE
|CELL_AFTER
|CELL_UPPER
|CELL_LOWER
)) != 0 )
2281 // current cell is outside the selection
2283 if( (nCellFlags
& ( CELL_BEFORE
|CELL_AFTER
)) == 0 ) // check if its not nw or ne corner
2285 if( nCellFlags
& CELL_UPPER
)
2287 if( pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::TOP
) )
2288 rNewFrame
.SetLine(0, SvxBoxItemLine::BOTTOM
);
2290 else if( nCellFlags
& CELL_LOWER
)
2292 if( pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::BOTTOM
) )
2293 rNewFrame
.SetLine( 0, SvxBoxItemLine::TOP
);
2296 else if( (nCellFlags
& ( CELL_UPPER
|CELL_LOWER
)) == 0 ) // check if its not sw or se corner
2298 if( nCellFlags
& CELL_BEFORE
)
2300 if( pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::LEFT
) )
2301 rNewFrame
.SetLine( 0, SvxBoxItemLine::RIGHT
);
2303 else if( nCellFlags
& CELL_AFTER
)
2305 if( pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::RIGHT
) )
2306 rNewFrame
.SetLine( 0, SvxBoxItemLine::LEFT
);
2312 // current cell is inside the selection
2314 if( (nCellFlags
& CELL_LEFT
) ? pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::LEFT
) : pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::VERT
) )
2315 rNewFrame
.SetLine( (nCellFlags
& CELL_LEFT
) ? pBoxItem
->GetLeft() : pBoxInfoItem
->GetVert(), SvxBoxItemLine::LEFT
);
2317 if( (nCellFlags
& CELL_RIGHT
) ? pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::RIGHT
) : pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::VERT
) )
2318 rNewFrame
.SetLine( (nCellFlags
& CELL_RIGHT
) ? pBoxItem
->GetRight() : pBoxInfoItem
->GetVert(), SvxBoxItemLine::RIGHT
);
2320 if( (nCellFlags
& CELL_TOP
) ? pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::TOP
) : pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::HORI
) )
2321 rNewFrame
.SetLine( (nCellFlags
& CELL_TOP
) ? pBoxItem
->GetTop() : pBoxInfoItem
->GetHori(), SvxBoxItemLine::TOP
);
2323 if( (nCellFlags
& CELL_BOTTOM
) ? pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::BOTTOM
) : pBoxInfoItem
->IsValid(SvxBoxInfoItemValidFlags::HORI
) )
2324 rNewFrame
.SetLine( (nCellFlags
& CELL_BOTTOM
) ? pBoxItem
->GetBottom() : pBoxInfoItem
->GetHori(), SvxBoxItemLine::BOTTOM
);
2326 // apply distance to borders
2327 if( pBoxInfoItem
->IsValid( SvxBoxInfoItemValidFlags::DISTANCE
) )
2328 for( SvxBoxItemLine nLine
: o3tl::enumrange
<SvxBoxItemLine
>() )
2329 rNewFrame
.SetDistance( pBoxItem
->GetDistance( nLine
), nLine
);
2335 static void ImplSetLineColor( SvxBoxItem
& rNewFrame
, SvxBoxItemLine nLine
, const Color
& rColor
)
2337 const SvxBorderLine
* pSourceLine
= rNewFrame
.GetLine( nLine
);
2340 SvxBorderLine
aLine( *pSourceLine
);
2341 aLine
.SetColor( rColor
);
2342 rNewFrame
.SetLine( &aLine
, nLine
);
2348 static void ImplApplyLineColorItem( sal_uInt16 nCellFlags
, const SvxColorItem
* pLineColorItem
, SvxBoxItem
& rNewFrame
)
2350 const Color
aColor( pLineColorItem
->GetValue() );
2352 if( (nCellFlags
& (CELL_LOWER
|CELL_BEFORE
|CELL_AFTER
)) == 0 )
2353 ImplSetLineColor( rNewFrame
, SvxBoxItemLine::BOTTOM
, aColor
);
2355 if( (nCellFlags
& (CELL_UPPER
|CELL_BEFORE
|CELL_AFTER
)) == 0 )
2356 ImplSetLineColor( rNewFrame
, SvxBoxItemLine::TOP
, aColor
);
2358 if( (nCellFlags
& (CELL_UPPER
|CELL_LOWER
|CELL_AFTER
)) == 0 )
2359 ImplSetLineColor( rNewFrame
, SvxBoxItemLine::RIGHT
, aColor
);
2361 if( (nCellFlags
& (CELL_UPPER
|CELL_LOWER
|CELL_BEFORE
)) == 0 )
2362 ImplSetLineColor( rNewFrame
, SvxBoxItemLine::LEFT
, aColor
);
2367 static void ImplApplyBorderLineItem( sal_uInt16 nCellFlags
, const SvxBorderLine
* pBorderLineItem
, SvxBoxItem
& rNewFrame
)
2369 if( (nCellFlags
& ( CELL_BEFORE
|CELL_AFTER
|CELL_UPPER
|CELL_LOWER
)) != 0 )
2371 if( (nCellFlags
& ( CELL_BEFORE
|CELL_AFTER
)) == 0 ) // check if its not nw or ne corner
2373 if( nCellFlags
& CELL_UPPER
)
2375 if( rNewFrame
.GetBottom() )
2376 ImplSetLinePreserveColor( rNewFrame
, pBorderLineItem
, SvxBoxItemLine::BOTTOM
);
2378 else if( nCellFlags
& CELL_LOWER
)
2380 if( rNewFrame
.GetTop() )
2381 ImplSetLinePreserveColor( rNewFrame
, pBorderLineItem
, SvxBoxItemLine::TOP
);
2384 else if( (nCellFlags
& ( CELL_UPPER
|CELL_LOWER
)) == 0 ) // check if its not sw or se corner
2386 if( nCellFlags
& CELL_BEFORE
)
2388 if( rNewFrame
.GetRight() )
2389 ImplSetLinePreserveColor( rNewFrame
, pBorderLineItem
, SvxBoxItemLine::RIGHT
);
2391 else if( nCellFlags
& CELL_AFTER
)
2393 if( rNewFrame
.GetLeft() )
2394 ImplSetLinePreserveColor( rNewFrame
, pBorderLineItem
, SvxBoxItemLine::LEFT
);
2400 if( rNewFrame
.GetBottom() )
2401 ImplSetLinePreserveColor( rNewFrame
, pBorderLineItem
, SvxBoxItemLine::BOTTOM
);
2402 if( rNewFrame
.GetTop() )
2403 ImplSetLinePreserveColor( rNewFrame
, pBorderLineItem
, SvxBoxItemLine::TOP
);
2404 if( rNewFrame
.GetRight() )
2405 ImplSetLinePreserveColor( rNewFrame
, pBorderLineItem
, SvxBoxItemLine::RIGHT
);
2406 if( rNewFrame
.GetLeft() )
2407 ImplSetLinePreserveColor( rNewFrame
, pBorderLineItem
, SvxBoxItemLine::LEFT
);
2413 void SvxTableController::ApplyBorderAttr( const SfxItemSet
& rAttr
)
2417 const sal_Int32 nRowCount
= mxTable
->getRowCount();
2418 const sal_Int32 nColCount
= mxTable
->getColumnCount();
2419 if( nRowCount
&& nColCount
)
2421 const SvxBoxItem
* pBoxItem
= 0;
2422 if(SfxItemState::SET
== rAttr
.GetItemState(SDRATTR_TABLE_BORDER
, false) )
2423 pBoxItem
= dynamic_cast< const SvxBoxItem
* >( &rAttr
.Get( SDRATTR_TABLE_BORDER
) );
2425 const SvxBoxInfoItem
* pBoxInfoItem
= 0;
2426 if(SfxItemState::SET
== rAttr
.GetItemState(SDRATTR_TABLE_BORDER_INNER
, false) )
2427 pBoxInfoItem
= dynamic_cast< const SvxBoxInfoItem
* >( &rAttr
.Get( SDRATTR_TABLE_BORDER_INNER
) );
2429 const SvxColorItem
* pLineColorItem
= 0;
2430 if(SfxItemState::SET
== rAttr
.GetItemState(SID_FRAME_LINECOLOR
, false) )
2431 pLineColorItem
= dynamic_cast< const SvxColorItem
* >( &rAttr
.Get( SID_FRAME_LINECOLOR
) );
2433 const SvxBorderLine
* pBorderLineItem
= 0;
2434 if(SfxItemState::SET
== rAttr
.GetItemState(SID_FRAME_LINESTYLE
, false) )
2435 pBorderLineItem
= static_cast<const SvxLineItem
&>(rAttr
.Get( SID_FRAME_LINESTYLE
)).GetLine();
2437 if( pBoxInfoItem
&& !pBoxItem
)
2439 const static SvxBoxItem
gaEmptyBoxItem( SDRATTR_TABLE_BORDER
);
2440 pBoxItem
= &gaEmptyBoxItem
;
2442 else if( pBoxItem
&& !pBoxInfoItem
)
2444 const static SvxBoxInfoItem
gaEmptyBoxInfoItem( SDRATTR_TABLE_BORDER_INNER
);
2445 pBoxInfoItem
= &gaEmptyBoxInfoItem
;
2448 CellPos aStart
, aEnd
;
2449 getSelectedCells( aStart
, aEnd
);
2451 const sal_Int32 nLastRow
= std::min( aEnd
.mnRow
+ 2, nRowCount
);
2452 const sal_Int32 nLastCol
= std::min( aEnd
.mnCol
+ 2, nColCount
);
2454 for( sal_Int32 nRow
= std::max( aStart
.mnRow
- 1, (sal_Int32
)0 ); nRow
< nLastRow
; nRow
++ )
2456 sal_uInt16 nRowFlags
= 0;
2457 nRowFlags
|= (nRow
== aStart
.mnRow
) ? CELL_TOP
: 0;
2458 nRowFlags
|= (nRow
== aEnd
.mnRow
) ? CELL_BOTTOM
: 0;
2459 nRowFlags
|= (nRow
< aStart
.mnRow
) ? CELL_UPPER
: 0;
2460 nRowFlags
|= (nRow
> aEnd
.mnRow
) ? CELL_LOWER
: 0;
2462 for( sal_Int32 nCol
= std::max( aStart
.mnCol
- 1, (sal_Int32
)0 ); nCol
< nLastCol
; nCol
++ )
2464 CellRef
xCell( dynamic_cast< Cell
* >( mxTable
->getCellByPosition( nCol
, nRow
).get() ) );
2468 const SfxItemSet
& rSet
= xCell
->GetItemSet();
2469 const SvxBoxItem
* pOldOuter
= static_cast<const SvxBoxItem
*>(&rSet
.Get( SDRATTR_TABLE_BORDER
));
2471 SvxBoxItem
aNewFrame( *pOldOuter
);
2473 sal_uInt16 nCellFlags
= nRowFlags
;
2474 nCellFlags
|= (nCol
== aStart
.mnCol
) ? CELL_LEFT
: 0;
2475 nCellFlags
|= (nCol
== aEnd
.mnCol
) ? CELL_RIGHT
: 0;
2476 nCellFlags
|= (nCol
< aStart
.mnCol
) ? CELL_BEFORE
: 0;
2477 nCellFlags
|= (nCol
> aEnd
.mnCol
) ? CELL_AFTER
: 0;
2479 if( pBoxItem
&& pBoxInfoItem
)
2480 ImplApplyBoxItem( nCellFlags
, pBoxItem
, pBoxInfoItem
, aNewFrame
);
2482 if( pLineColorItem
)
2483 ImplApplyLineColorItem( nCellFlags
, pLineColorItem
, aNewFrame
);
2485 if( pBorderLineItem
)
2486 ImplApplyBorderLineItem( nCellFlags
, pBorderLineItem
, aNewFrame
);
2488 if (aNewFrame
!= *pOldOuter
)
2490 SfxItemSet
aAttr(*rSet
.GetPool(), rSet
.GetRanges());
2491 aAttr
.Put(aNewFrame
);
2492 xCell
->SetMergedItemSetAndBroadcast( aAttr
, false );
2502 void SvxTableController::UpdateTableShape()
2504 SdrObject
* pTableObj
= mxTableObj
.get();
2507 pTableObj
->ActionChanged();
2508 pTableObj
->BroadcastObjectChange();
2510 updateSelectionOverlay();
2516 void SvxTableController::SetAttrToSelectedCells(const SfxItemSet
& rAttr
, bool bReplaceAll
)
2520 const bool bUndo
= mpModel
&& mpModel
->IsUndoEnabled();
2523 mpModel
->BegUndo( ImpGetResStr(STR_TABLE_NUMFORMAT
) );
2525 CellPos aStart
, aEnd
;
2526 getSelectedCells( aStart
, aEnd
);
2528 SfxItemSet
aAttr(*rAttr
.GetPool(), rAttr
.GetRanges());
2529 aAttr
.Put(rAttr
, true);
2531 const bool bFrame
= (rAttr
.GetItemState( SDRATTR_TABLE_BORDER
) == SfxItemState::SET
) || (rAttr
.GetItemState( SDRATTR_TABLE_BORDER_INNER
) == SfxItemState::SET
);
2535 aAttr
.ClearItem( SDRATTR_TABLE_BORDER
);
2536 aAttr
.ClearItem( SDRATTR_TABLE_BORDER_INNER
);
2539 for( sal_Int32 nRow
= aStart
.mnRow
; nRow
<= aEnd
.mnRow
; nRow
++ )
2541 for( sal_Int32 nCol
= aStart
.mnCol
; nCol
<= aEnd
.mnCol
; nCol
++ )
2543 CellRef
xCell( dynamic_cast< Cell
* >( mxTable
->getCellByPosition( nCol
, nRow
).get() ) );
2548 xCell
->SetMergedItemSetAndBroadcast(aAttr
, bReplaceAll
);
2555 ApplyBorderAttr( rAttr
);
2568 bool SvxTableController::GetAttributes(SfxItemSet
& rTargetSet
, bool bOnlyHardAttr
) const
2570 if( mxTableObj
.is() && hasSelectedCells() )
2572 MergeAttrFromSelectedCells( rTargetSet
, bOnlyHardAttr
);
2574 if( mpView
->IsTextEdit() )
2576 if( mxTableObj
->GetOutlinerParaObject() )
2577 rTargetSet
.Put( SvxScriptTypeItem( mxTableObj
->GetOutlinerParaObject()->GetTextObject().GetScriptType() ) );
2579 OutlinerView
* pTextEditOutlinerView
= mpView
->GetTextEditOutlinerView();
2580 if(pTextEditOutlinerView
)
2582 // FALSE= InvalidItems nicht al Default, sondern als "Loecher" betrachten
2583 rTargetSet
.Put(pTextEditOutlinerView
->GetAttribs(), false);
2584 rTargetSet
.Put( SvxScriptTypeItem( pTextEditOutlinerView
->GetSelectedScriptType() ) );
2598 bool SvxTableController::SetAttributes(const SfxItemSet
& rSet
, bool bReplaceAll
)
2600 if( mbCellSelectionMode
|| mpView
->IsTextEdit() )
2602 SetAttrToSelectedCells( rSet
, bReplaceAll
);
2610 bool SvxTableController::GetMarkedObjModel( SdrPage
* pNewPage
)
2612 if( mxTableObj
.is() && mbCellSelectionMode
&& pNewPage
) try
2614 sdr::table::SdrTableObj
& rTableObj
= *static_cast< sdr::table::SdrTableObj
* >( mxTableObj
.get() );
2616 CellPos aStart
, aEnd
;
2617 getSelectedCells( aStart
, aEnd
);
2619 SdrTableObj
* pNewTableObj
= rTableObj
.CloneRange( aStart
, aEnd
);
2621 pNewTableObj
->SetPage( pNewPage
);
2622 pNewTableObj
->SetModel( pNewPage
->GetModel() );
2624 SdrInsertReason
aReason(SDRREASON_VIEWCALL
);
2625 pNewPage
->InsertObject(pNewTableObj
, SAL_MAX_SIZE
, &aReason
);
2631 OSL_FAIL( "svx::SvxTableController::GetMarkedObjModel(), exception caught!" );
2638 bool SvxTableController::PasteObjModel( const SdrModel
& rModel
)
2640 if( mxTableObj
.is() && mpView
&& (rModel
.GetPageCount() >= 1) )
2642 const SdrPage
* pPastePage
= rModel
.GetPage(0);
2643 if( pPastePage
&& pPastePage
->GetObjCount() == 1 )
2645 SdrTableObj
* pPasteTableObj
= dynamic_cast< SdrTableObj
* >( pPastePage
->GetObj(0) );
2646 if( pPasteTableObj
)
2648 return PasteObject( pPasteTableObj
);
2658 bool SvxTableController::PasteObject( SdrTableObj
* pPasteTableObj
)
2660 if( !pPasteTableObj
)
2663 Reference
< XTable
> xPasteTable( pPasteTableObj
->getTable() );
2664 if( !xPasteTable
.is() )
2670 sal_Int32 nPasteColumns
= xPasteTable
->getColumnCount();
2671 sal_Int32 nPasteRows
= xPasteTable
->getRowCount();
2673 CellPos aStart
, aEnd
;
2674 getSelectedCells( aStart
, aEnd
);
2676 if( mpView
->IsTextEdit() )
2677 mpView
->SdrEndTextEdit(true);
2679 sal_Int32 nColumns
= mxTable
->getColumnCount();
2680 sal_Int32 nRows
= mxTable
->getRowCount();
2682 const sal_Int32 nMissing
= nPasteRows
- ( nRows
- aStart
.mnRow
);
2685 Reference
< XTableRows
> xRows( mxTable
->getRows() );
2686 xRows
->insertByIndex( nRows
, nMissing
);
2687 nRows
= mxTable
->getRowCount();
2690 nPasteRows
= std::min( nPasteRows
, nRows
- aStart
.mnRow
);
2691 nPasteColumns
= std::min( nPasteColumns
, nColumns
- aStart
.mnCol
);
2693 // copy cell contents
2694 for( sal_Int32 nRow
= 0; nRow
< nPasteRows
; ++nRow
)
2696 for( sal_Int32 nCol
= 0; nCol
< nPasteColumns
; ++nCol
)
2698 CellRef
xTargetCell( dynamic_cast< Cell
* >( mxTable
->getCellByPosition( aStart
.mnCol
+ nCol
, aStart
.mnRow
+ nRow
).get() ) );
2699 if( xTargetCell
.is() && !xTargetCell
->isMerged() )
2701 xTargetCell
->AddUndo();
2702 xTargetCell
->cloneFrom( dynamic_cast< Cell
* >( xPasteTable
->getCellByPosition( nCol
, nRow
).get() ) );
2703 nCol
+= xTargetCell
->getColumnSpan() - 1;
2713 bool SvxTableController::TakeFormatPaintBrush( std::shared_ptr
< SfxItemSet
>& /*rFormatSet*/ )
2715 // SdrView::TakeFormatPaintBrush() is enough
2719 bool SvxTableController::ApplyFormatPaintBrush( SfxItemSet
& rFormatSet
, bool bNoCharacterFormats
, bool bNoParagraphFormats
)
2721 if( mbCellSelectionMode
)
2723 SdrTextObj
* pTableObj
= dynamic_cast<SdrTextObj
*>( mxTableObj
.get() );
2727 const bool bUndo
= mpModel
&& mpModel
->IsUndoEnabled();
2730 mpModel
->BegUndo( ImpGetResStr(STR_TABLE_NUMFORMAT
) );
2732 CellPos aStart
, aEnd
;
2733 getSelectedCells( aStart
, aEnd
);
2735 SfxItemSet
aAttr(*rFormatSet
.GetPool(), rFormatSet
.GetRanges());
2736 aAttr
.Put(rFormatSet
, true);
2738 const bool bFrame
= (rFormatSet
.GetItemState( SDRATTR_TABLE_BORDER
) == SfxItemState::SET
) || (rFormatSet
.GetItemState( SDRATTR_TABLE_BORDER_INNER
) == SfxItemState::SET
);
2742 aAttr
.ClearItem( SDRATTR_TABLE_BORDER
);
2743 aAttr
.ClearItem( SDRATTR_TABLE_BORDER_INNER
);
2746 const sal_uInt16
* pRanges
= rFormatSet
.GetRanges();
2747 bool bTextOnly
= true;
2751 if( (*pRanges
!= EE_PARA_START
) && (*pRanges
!= EE_CHAR_START
) )
2759 const bool bReplaceAll
= false;
2760 for( sal_Int32 nRow
= aStart
.mnRow
; nRow
<= aEnd
.mnRow
; nRow
++ )
2762 for( sal_Int32 nCol
= aStart
.mnCol
; nCol
<= aEnd
.mnCol
; nCol
++ )
2764 CellRef
xCell( dynamic_cast< Cell
* >( mxTable
->getCellByPosition( nCol
, nRow
).get() ) );
2770 xCell
->SetMergedItemSetAndBroadcast(aAttr
, bReplaceAll
);
2772 SdrText
* pText
= static_cast< SdrText
* >( xCell
.get() );
2773 SdrObjEditView::ApplyFormatPaintBrushToText( rFormatSet
, *pTableObj
, pText
, bNoCharacterFormats
, bNoParagraphFormats
);
2780 ApplyBorderAttr( rFormatSet
);
2797 IMPL_LINK_NOARG(SvxTableController
, UpdateHdl
)
2801 if( mbCellSelectionMode
)
2803 CellPos
aStart( maCursorFirstPos
);
2804 CellPos
aEnd( maCursorLastPos
);
2807 if( aStart
!= maCursorFirstPos
|| aEnd
!= maCursorLastPos
)
2809 setSelectedCells( aStart
, aEnd
);
2812 updateSelectionOverlay();
2822 LinesState(SvxBoxItem
& rBoxItem_
, SvxBoxInfoItem
& rBoxInfoItem_
)
2823 : rBoxItem(rBoxItem_
)
2824 , rBoxInfoItem(rBoxInfoItem_
)
2825 , bDistanceIndeterminate(false)
2827 aBorderSet
.fill(false);
2828 aInnerLineSet
.fill(false);
2829 aBorderIndeterminate
.fill(false);
2830 aInnerLineIndeterminate
.fill(false);
2831 aDistanceSet
.fill(false);
2835 SvxBoxItem
& rBoxItem
;
2836 SvxBoxInfoItem
& rBoxInfoItem
;
2837 o3tl::enumarray
<SvxBoxItemLine
, bool> aBorderSet
;
2838 o3tl::enumarray
<SvxBoxInfoItemLine
, bool> aInnerLineSet
;
2839 o3tl::enumarray
<SvxBoxItemLine
, bool> aBorderIndeterminate
;
2840 o3tl::enumarray
<SvxBoxInfoItemLine
, bool> aInnerLineIndeterminate
;
2841 o3tl::enumarray
<SvxBoxItemLine
, bool> aDistanceSet
;
2842 o3tl::enumarray
<SvxBoxItemLine
, sal_uInt16
> aDistance
;
2843 bool bDistanceIndeterminate
;
2846 class BoxItemWrapper
2849 BoxItemWrapper(SvxBoxItem
& rBoxItem
, SvxBoxInfoItem
& rBoxInfoItem
, SvxBoxItemLine nBorderLine
, SvxBoxInfoItemLine nInnerLine
, bool bBorder
);
2851 const SvxBorderLine
* getLine() const;
2852 void setLine(const SvxBorderLine
* pLine
);
2855 SvxBoxItem
& m_rBoxItem
;
2856 SvxBoxInfoItem
& m_rBoxInfoItem
;
2857 const SvxBoxItemLine m_nBorderLine
;
2858 const SvxBoxInfoItemLine m_nInnerLine
;
2859 const bool m_bBorder
;
2862 BoxItemWrapper::BoxItemWrapper(
2863 SvxBoxItem
& rBoxItem
, SvxBoxInfoItem
& rBoxInfoItem
,
2864 const SvxBoxItemLine nBorderLine
, const SvxBoxInfoItemLine nInnerLine
, const bool bBorder
)
2865 : m_rBoxItem(rBoxItem
)
2866 , m_rBoxInfoItem(rBoxInfoItem
)
2867 , m_nBorderLine(nBorderLine
)
2868 , m_nInnerLine(nInnerLine
)
2869 , m_bBorder(bBorder
)
2873 const SvxBorderLine
* BoxItemWrapper::getLine() const
2876 return m_rBoxItem
.GetLine(m_nBorderLine
);
2878 return (m_nInnerLine
== SvxBoxInfoItemLine::HORI
) ? m_rBoxInfoItem
.GetHori() : m_rBoxInfoItem
.GetVert();
2881 void BoxItemWrapper::setLine(const SvxBorderLine
* pLine
)
2884 m_rBoxItem
.SetLine(pLine
, m_nBorderLine
);
2886 m_rBoxInfoItem
.SetLine(pLine
, m_nInnerLine
);
2889 void lcl_MergeBorderLine(
2890 LinesState
& rLinesState
, const SvxBorderLine
* const pLine
, const SvxBoxItemLine nLine
,
2891 SvxBoxInfoItemValidFlags nValidFlag
, const bool bBorder
= true)
2893 const SvxBoxInfoItemLine
nInnerLine(bBorder
? SvxBoxInfoItemLine::HORI
: ((nValidFlag
& SvxBoxInfoItemValidFlags::HORI
) ? SvxBoxInfoItemLine::HORI
: SvxBoxInfoItemLine::VERT
));
2894 BoxItemWrapper
aBoxItem(rLinesState
.rBoxItem
, rLinesState
.rBoxInfoItem
, nLine
, nInnerLine
, bBorder
);
2895 bool& rbSet(bBorder
? rLinesState
.aBorderSet
[nLine
] : rLinesState
.aInnerLineSet
[nInnerLine
]);
2899 bool& rbIndeterminate(bBorder
? rLinesState
.aBorderIndeterminate
[nLine
] : rLinesState
.aInnerLineIndeterminate
[nInnerLine
]);
2900 if (!rbIndeterminate
)
2902 const SvxBorderLine
* const pMergedLine(aBoxItem
.getLine());
2903 if ((pLine
&& !pMergedLine
) || (!pLine
&& pMergedLine
) || (pLine
&& (*pLine
!= *pMergedLine
)))
2905 aBoxItem
.setLine(0);
2906 rbIndeterminate
= true;
2912 aBoxItem
.setLine(pLine
);
2917 void lcl_MergeBorderOrInnerLine(
2918 LinesState
& rLinesState
, const SvxBorderLine
* const pLine
, const SvxBoxItemLine nLine
,
2919 SvxBoxInfoItemValidFlags nValidFlag
, const bool bBorder
)
2922 lcl_MergeBorderLine(rLinesState
, pLine
, nLine
, nValidFlag
);
2925 const bool bVertical
= (nLine
== SvxBoxItemLine::LEFT
) || (nLine
== SvxBoxItemLine::RIGHT
);
2926 lcl_MergeBorderLine(rLinesState
, pLine
, nLine
, bVertical
? SvxBoxInfoItemValidFlags::VERT
: SvxBoxInfoItemValidFlags::HORI
, false);
2930 void lcl_MergeDistance(
2931 LinesState
& rLinesState
, const SvxBoxItemLine nIndex
, const sal_uInt16 nDistance
)
2933 if (rLinesState
.aDistanceSet
[nIndex
])
2935 if (!rLinesState
.bDistanceIndeterminate
)
2936 rLinesState
.bDistanceIndeterminate
= nDistance
!= rLinesState
.aDistance
[nIndex
];
2940 rLinesState
.aDistance
[nIndex
] = nDistance
;
2941 rLinesState
.aDistanceSet
[nIndex
] = true;
2945 void lcl_MergeCommonBorderAttr(LinesState
& rLinesState
, const SvxBoxItem
& rCellBoxItem
, const sal_Int32 nCellFlags
)
2947 if( (nCellFlags
& (CELL_BEFORE
|CELL_AFTER
|CELL_UPPER
|CELL_LOWER
)) != 0 )
2949 // current cell is outside the selection
2951 if( (nCellFlags
& ( CELL_BEFORE
|CELL_AFTER
)) == 0 ) // check if its not nw or ne corner
2953 if( nCellFlags
& CELL_UPPER
)
2954 lcl_MergeBorderLine(rLinesState
, rCellBoxItem
.GetBottom(), SvxBoxItemLine::TOP
, SvxBoxInfoItemValidFlags::TOP
);
2955 else if( nCellFlags
& CELL_LOWER
)
2956 lcl_MergeBorderLine(rLinesState
, rCellBoxItem
.GetTop(), SvxBoxItemLine::BOTTOM
, SvxBoxInfoItemValidFlags::BOTTOM
);
2958 else if( (nCellFlags
& ( CELL_UPPER
|CELL_LOWER
)) == 0 ) // check if its not sw or se corner
2960 if( nCellFlags
& CELL_BEFORE
)
2961 lcl_MergeBorderLine(rLinesState
, rCellBoxItem
.GetRight(), SvxBoxItemLine::LEFT
, SvxBoxInfoItemValidFlags::LEFT
);
2962 else if( nCellFlags
& CELL_AFTER
)
2963 lcl_MergeBorderLine(rLinesState
, rCellBoxItem
.GetLeft(), SvxBoxItemLine::RIGHT
, SvxBoxInfoItemValidFlags::RIGHT
);
2966 // NOTE: inner distances for cells outside the selected range
2967 // are not relevant -> we ignore them.
2971 // current cell is inside the selection
2973 lcl_MergeBorderOrInnerLine(rLinesState
, rCellBoxItem
.GetTop(), SvxBoxItemLine::TOP
, SvxBoxInfoItemValidFlags::TOP
, (nCellFlags
& CELL_TOP
) != 0);
2974 lcl_MergeBorderOrInnerLine(rLinesState
, rCellBoxItem
.GetBottom(), SvxBoxItemLine::BOTTOM
, SvxBoxInfoItemValidFlags::BOTTOM
, (nCellFlags
& CELL_BOTTOM
) != 0);
2975 lcl_MergeBorderOrInnerLine(rLinesState
, rCellBoxItem
.GetLeft(), SvxBoxItemLine::LEFT
, SvxBoxInfoItemValidFlags::LEFT
, (nCellFlags
& CELL_LEFT
) != 0);
2976 lcl_MergeBorderOrInnerLine(rLinesState
, rCellBoxItem
.GetRight(), SvxBoxItemLine::RIGHT
, SvxBoxInfoItemValidFlags::RIGHT
, (nCellFlags
& CELL_RIGHT
) != 0);
2978 lcl_MergeDistance(rLinesState
, SvxBoxItemLine::TOP
, rCellBoxItem
.GetDistance(SvxBoxItemLine::TOP
));
2979 lcl_MergeDistance(rLinesState
, SvxBoxItemLine::BOTTOM
, rCellBoxItem
.GetDistance(SvxBoxItemLine::BOTTOM
));
2980 lcl_MergeDistance(rLinesState
, SvxBoxItemLine::LEFT
, rCellBoxItem
.GetDistance(SvxBoxItemLine::LEFT
));
2981 lcl_MergeDistance(rLinesState
, SvxBoxItemLine::RIGHT
, rCellBoxItem
.GetDistance(SvxBoxItemLine::RIGHT
));
2987 void SvxTableController::FillCommonBorderAttrFromSelectedCells( SvxBoxItem
& rBoxItem
, SvxBoxInfoItem
& rBoxInfoItem
) const
2991 const sal_Int32 nRowCount
= mxTable
->getRowCount();
2992 const sal_Int32 nColCount
= mxTable
->getColumnCount();
2993 if( nRowCount
&& nColCount
)
2995 CellPos aStart
, aEnd
;
2996 const_cast< SvxTableController
* >( this )->getSelectedCells( aStart
, aEnd
);
2998 // We are adding one more row/column around the block of selected cells.
2999 // We will be checking the adjoining border of these too.
3000 const sal_Int32 nLastRow
= std::min( aEnd
.mnRow
+ 2, nRowCount
);
3001 const sal_Int32 nLastCol
= std::min( aEnd
.mnCol
+ 2, nColCount
);
3003 rBoxInfoItem
.SetValid( SvxBoxInfoItemValidFlags::ALL
, false );
3004 LinesState
aLinesState( rBoxItem
, rBoxInfoItem
);
3006 /* Here we go through all the selected cells (enhanced by
3007 * the adjoining row/column on each side) and determine the
3008 * lines for presentation. The algorithm is simple:
3009 * 1. if a border or inner line is set (or unset) in all
3010 * cells to the same value, it will be used.
3011 * 2. if a border or inner line is set only in some cells,
3012 * it will be set to indeterminate state (SetValid() on
3015 for( sal_Int32 nRow
= std::max( aStart
.mnRow
- 1, (sal_Int32
)0 ); nRow
< nLastRow
; nRow
++ )
3017 sal_uInt16 nRowFlags
= 0;
3018 nRowFlags
|= (nRow
== aStart
.mnRow
) ? CELL_TOP
: 0;
3019 nRowFlags
|= (nRow
== aEnd
.mnRow
) ? CELL_BOTTOM
: 0;
3020 nRowFlags
|= (nRow
< aStart
.mnRow
) ? CELL_UPPER
: 0;
3021 nRowFlags
|= (nRow
> aEnd
.mnRow
) ? CELL_LOWER
: 0;
3023 for( sal_Int32 nCol
= std::max( aStart
.mnCol
- 1, (sal_Int32
)0 ); nCol
< nLastCol
; nCol
++ )
3025 CellRef
xCell( dynamic_cast< Cell
* >( mxTable
->getCellByPosition( nCol
, nRow
).get() ) );
3029 sal_uInt16 nCellFlags
= nRowFlags
;
3030 nCellFlags
|= (nCol
== aStart
.mnCol
) ? CELL_LEFT
: 0;
3031 nCellFlags
|= (nCol
== aEnd
.mnCol
) ? CELL_RIGHT
: 0;
3032 nCellFlags
|= (nCol
< aStart
.mnCol
) ? CELL_BEFORE
: 0;
3033 nCellFlags
|= (nCol
> aEnd
.mnCol
) ? CELL_AFTER
: 0;
3035 const SfxItemSet
& rSet
= xCell
->GetItemSet();
3036 SvxBoxItem
aCellBoxItem(mergeDrawinglayerTextDistancesAndSvxBoxItem(rSet
));
3037 lcl_MergeCommonBorderAttr( aLinesState
, aCellBoxItem
, nCellFlags
);
3041 if (!aLinesState
.aBorderIndeterminate
[SvxBoxItemLine::TOP
])
3042 aLinesState
.rBoxInfoItem
.SetValid(SvxBoxInfoItemValidFlags::TOP
);
3043 if (!aLinesState
.aBorderIndeterminate
[SvxBoxItemLine::BOTTOM
])
3044 aLinesState
.rBoxInfoItem
.SetValid(SvxBoxInfoItemValidFlags::BOTTOM
);
3045 if (!aLinesState
.aBorderIndeterminate
[SvxBoxItemLine::LEFT
])
3046 aLinesState
.rBoxInfoItem
.SetValid(SvxBoxInfoItemValidFlags::LEFT
);
3047 if (!aLinesState
.aBorderIndeterminate
[SvxBoxItemLine::RIGHT
])
3048 aLinesState
.rBoxInfoItem
.SetValid(SvxBoxInfoItemValidFlags::RIGHT
);
3049 if (!aLinesState
.aInnerLineIndeterminate
[SvxBoxInfoItemLine::HORI
])
3050 aLinesState
.rBoxInfoItem
.SetValid(SvxBoxInfoItemValidFlags::HORI
);
3051 if (!aLinesState
.aInnerLineIndeterminate
[SvxBoxInfoItemLine::VERT
])
3052 aLinesState
.rBoxInfoItem
.SetValid(SvxBoxInfoItemValidFlags::VERT
);
3054 if (!aLinesState
.bDistanceIndeterminate
)
3056 if (aLinesState
.aDistanceSet
[SvxBoxItemLine::TOP
])
3057 aLinesState
.rBoxItem
.SetDistance(aLinesState
.aDistance
[SvxBoxItemLine::TOP
], SvxBoxItemLine::TOP
);
3058 if (aLinesState
.aDistanceSet
[SvxBoxItemLine::BOTTOM
])
3059 aLinesState
.rBoxItem
.SetDistance(aLinesState
.aDistance
[SvxBoxItemLine::BOTTOM
], SvxBoxItemLine::BOTTOM
);
3060 if (aLinesState
.aDistanceSet
[SvxBoxItemLine::LEFT
])
3061 aLinesState
.rBoxItem
.SetDistance(aLinesState
.aDistance
[SvxBoxItemLine::LEFT
], SvxBoxItemLine::LEFT
);
3062 if (aLinesState
.aDistanceSet
[SvxBoxItemLine::RIGHT
])
3063 aLinesState
.rBoxItem
.SetDistance(aLinesState
.aDistance
[SvxBoxItemLine::RIGHT
], SvxBoxItemLine::RIGHT
);
3064 aLinesState
.rBoxInfoItem
.SetValid(SvxBoxInfoItemValidFlags::DISTANCE
);
3070 bool SvxTableController::selectRow( sal_Int32 row
)
3074 CellPos
aStart( 0, row
), aEnd( mxTable
->getColumnCount() - 1, row
);
3075 StartSelection( aEnd
);
3076 gotoCell( aStart
, true, 0 );
3080 bool SvxTableController::selectColumn( sal_Int32 column
)
3084 CellPos
aStart( column
, 0 ), aEnd( column
, mxTable
->getRowCount() - 1 );
3085 StartSelection( aEnd
);
3086 gotoCell( aStart
, true, 0 );
3090 bool SvxTableController::deselectRow( sal_Int32 row
)
3094 CellPos
aStart( 0, row
), aEnd( mxTable
->getColumnCount() - 1, row
);
3095 StartSelection( aEnd
);
3096 gotoCell( aStart
, false, 0 );
3100 bool SvxTableController::deselectColumn( sal_Int32 column
)
3104 CellPos
aStart( column
, 0 ), aEnd( column
, mxTable
->getRowCount() - 1 );
3105 StartSelection( aEnd
);
3106 gotoCell( aStart
, false, 0 );
3110 bool SvxTableController::isRowSelected( sal_Int32 nRow
)
3112 if( hasSelectedCells() )
3114 CellPos aFirstPos
, aLastPos
;
3115 getSelectedCells( aFirstPos
, aLastPos
);
3116 if( (aFirstPos
.mnCol
== 0) && (nRow
>= aFirstPos
.mnRow
&& nRow
<= aLastPos
.mnRow
) && (mxTable
->getColumnCount() - 1 == aLastPos
.mnCol
) )
3122 bool SvxTableController::isColumnSelected( sal_Int32 nColumn
)
3124 if( hasSelectedCells() )
3126 CellPos aFirstPos
, aLastPos
;
3127 getSelectedCells( aFirstPos
, aLastPos
);
3128 if( (aFirstPos
.mnRow
== 0) && (nColumn
>= aFirstPos
.mnCol
&& nColumn
<= aLastPos
.mnCol
) && (mxTable
->getRowCount() - 1 == aLastPos
.mnRow
) )
3134 bool SvxTableController::isRowHeader()
3136 SdrTableObj
* pTableObj
= dynamic_cast< sdr::table::SdrTableObj
* >( mxTableObj
.get() );
3137 SdrModel
* pModel
= pTableObj
? pTableObj
->GetModel() : 0;
3139 if( !pTableObj
|| !pModel
)
3142 TableStyleSettings
aSettings( pTableObj
->getTableStyleSettings() );
3144 return aSettings
.mbUseFirstRow
;
3147 bool SvxTableController::isColumnHeader()
3149 SdrTableObj
* pTableObj
= dynamic_cast< sdr::table::SdrTableObj
* >( mxTableObj
.get() );
3150 SdrModel
* pModel
= pTableObj
? pTableObj
->GetModel() : 0;
3152 if( !pTableObj
|| !pModel
)
3155 TableStyleSettings
aSettings( pTableObj
->getTableStyleSettings() );
3157 return aSettings
.mbUseFirstColumn
;
3160 bool SvxTableController::setCursorLogicPosition(const Point
& rPosition
, bool bPoint
)
3162 if (mxTableObj
->GetObjIdentifier() != OBJ_TABLE
)
3165 SdrTableObj
* pTableObj
= static_cast<SdrTableObj
*>(mxTableObj
.get());
3167 if (pTableObj
->CheckTableHit(rPosition
, aCellPos
.mnCol
, aCellPos
.mnRow
, 0) != SDRTABLEHIT_NONE
)
3169 // Position is a table cell.
3170 if (mbCellSelectionMode
)
3172 // We have a table selection already: adjust the point or the mark.
3174 setSelectedCells(maCursorFirstPos
, aCellPos
);
3176 setSelectedCells(aCellPos
, maCursorLastPos
);
3179 else if (aCellPos
!= maMouseDownPos
)
3181 // No selection, but rPosition is at an other cell: start table selection.
3182 StartSelection(maMouseDownPos
);
3183 // Update graphic selection, should be hidden now.
3184 mpView
->AdjustMarkHdl();
3193 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */