LibreOffice Module svx (master) 1
tablecontroller.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <algorithm>
21
23#include <tablemodel.hxx>
24
25#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
26#include <com/sun/star/container/XIndexAccess.hpp>
27
28#include <com/sun/star/beans/XPropertySet.hpp>
29#include <com/sun/star/table/XMergeableCellRange.hpp>
30#include <com/sun/star/table/XMergeableCell.hpp>
31
32#include <sal/config.h>
33#include <sal/log.hxx>
34
35#include <vcl/svapp.hxx>
36#include <vcl/settings.hxx>
37#include <vcl/window.hxx>
38
39#include <svl/whiter.hxx>
40#include <svl/stritem.hxx>
41
42#include <sfx2/request.hxx>
43
44#include <svx/svdotable.hxx>
47#include <svx/svxids.hrc>
48#include <svx/svdoutl.hxx>
49#include <svx/svdpagv.hxx>
50#include <svx/svdetc.hxx>
52#include <svx/svdmodel.hxx>
54#include <svx/svxdlg.hxx>
55#include <editeng/boxitem.hxx>
56#include <cell.hxx>
58#include <editeng/colritem.hxx>
59#include <editeng/lineitem.hxx>
60#include <svx/strings.hrc>
61#include <svx/dialmgr.hxx>
62#include <svx/svdpage.hxx>
63#include <svx/sdmetitm.hxx>
64#include <svx/sdtditm.hxx>
65#include "tableundo.hxx"
66#include "tablelayouter.hxx"
67#include <LibreOfficeKit/LibreOfficeKitEnums.h>
68#include <memory>
69#include <o3tl/enumarray.hxx>
70#include <o3tl/enumrange.hxx>
72#include <comphelper/lok.hxx>
73#include <sfx2/viewsh.hxx>
74#include <editeng/editview.hxx>
77
78using ::editeng::SvxBorderLine;
79using namespace sdr::table;
80using namespace ::com::sun::star;
81using namespace ::com::sun::star::uno;
82using namespace ::com::sun::star::table;
83using namespace ::com::sun::star::beans;
84using namespace ::com::sun::star::container;
85using namespace ::com::sun::star::text;
86using namespace ::com::sun::star::style;
87
88namespace {
89
90enum class CellPosFlag // signals the relative position of a cell to a selection
91{
92 NONE = 0x0000, // not set or inside
93 // row
94 Before = 0x0001,
95 Left = 0x0002,
96 Right = 0x0004,
97 After = 0x0008,
98 // column
99 Upper = 0x0010,
100 Top = 0x0020,
101 Bottom = 0x0040,
102 Lower = 0x0080
103};
104
105}
106
107namespace o3tl
108{ template<> struct typed_flags<CellPosFlag> : is_typed_flags<CellPosFlag, 0xff> {}; }
109
110namespace sdr::table {
111
112namespace {
113
114class SvxTableControllerModifyListener : public ::cppu::WeakImplHelper< css::util::XModifyListener >
115{
116public:
117 explicit SvxTableControllerModifyListener( SvxTableController* pController )
118 : mpController( pController ) {}
119
120 // XModifyListener
121 virtual void SAL_CALL modified( const css::lang::EventObject& aEvent ) override;
122
123 // XEventListener
124 virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
125
127};
128
129}
130
131// XModifyListener
132
133
134void SAL_CALL SvxTableControllerModifyListener::modified( const css::lang::EventObject& )
135{
136 if( mpController )
138}
139
140
141// XEventListener
142
143
144void SAL_CALL SvxTableControllerModifyListener::disposing( const css::lang::EventObject& )
145{
146 mpController = nullptr;
147}
148
149
150
151
153 SdrView& rView,
154 const SdrTableObj& rObj,
155 const rtl::Reference< sdr::SelectionController >& xRefController )
156{
157 return SvxTableController::create(rView, rObj, xRefController);
158}
159
160
162 SdrView& rView,
163 const SdrTableObj& rObj,
164 const rtl::Reference< sdr::SelectionController >& xRefController )
165{
166 if( xRefController.is() )
167 {
168 SvxTableController* pController = dynamic_cast< SvxTableController* >( xRefController.get() );
169
170 if(pController && (pController->mxTableObj.get() == &rObj) && (&pController->mrView == &rView))
171 {
172 return xRefController;
173 }
174 }
175
176 return new SvxTableController(rView, rObj);
177}
178
179
181 SdrView& rView,
182 const SdrTableObj& rObj)
183: mbCellSelectionMode(false)
184 ,mbHasJustMerged(false)
185 ,mbLeftButtonDown(false)
186 ,mrView(rView)
187 ,mxTableObj(const_cast< SdrTableObj* >(&rObj))
188 ,mnUpdateEvent( nullptr )
189{
192
193 Reference< XTable > xTable( mxTableObj.get()->getTable() );
194 if( xTable.is() )
195 {
196 mxModifyListener = new SvxTableControllerModifyListener( this );
197 xTable->addModifyListener( mxModifyListener );
198
199 mxTable.set( dynamic_cast< TableModel* >( xTable.get() ) );
200 }
201}
202
204{
205 if( mnUpdateEvent )
206 {
208 }
209
210 if( mxModifyListener.is() && mxTableObj.get() )
211 {
212 Reference< XTable > xTable( mxTableObj.get()->getTable() );
213 if( xTable.is() )
214 {
215 xTable->removeModifyListener( mxModifyListener );
216 mxModifyListener.clear();
217 }
218 }
219}
220
222{
223 if(!checkTableObject())
224 return false;
225
226 SdrTableObj& rTableObj(*mxTableObj.get());
227 SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
228
229 // check if we are read only
230 if( rModel.IsReadOnly())
231 {
232 switch( rKEvt.GetKeyCode().GetCode() )
233 {
234 case awt::Key::DOWN:
235 case awt::Key::UP:
236 case awt::Key::LEFT:
237 case awt::Key::RIGHT:
238 case awt::Key::TAB:
239 case awt::Key::HOME:
240 case awt::Key::END:
241 case awt::Key::NUM2:
242 case awt::Key::NUM4:
243 case awt::Key::NUM6:
244 case awt::Key::NUM8:
245 case awt::Key::ESCAPE:
246 case awt::Key::F2:
247 break;
248 default:
249 // tell the view we eat the event, no further processing needed
250 return true;
251 }
252 }
253
254 TblAction nAction = getKeyboardAction(rKEvt);
255
256 return executeAction( nAction, rKEvt.GetKeyCode().IsShift(), pWindow );
257}
258
259namespace {
260
261Point pixelToLogic(const Point& rPoint, vcl::Window const * pWindow)
262{
263 if (!pWindow)
264 return rPoint;
265
266 return pWindow->PixelToLogic(rPoint);
267}
268
269}
270
272{
273 if (comphelper::LibreOfficeKit::isActive() && !pWindow)
274 {
275 // Tiled rendering: get the window that has the disabled map mode.
276 if (OutputDevice* pOutputDevice = mrView.GetFirstOutputDevice())
277 {
278 if (pOutputDevice->GetOutDevType() == OUTDEV_WINDOW)
279 pWindow = pOutputDevice->GetOwnerWindow();
280 }
281 }
282
283 if( !pWindow || !checkTableObject() )
284 return false;
285
286 SdrViewEvent aVEvt;
288 return false;
289
290 TableHitKind eHit = mxTableObj.get()->CheckTableHit(pixelToLogic(rMEvt.GetPosPixel(), pWindow), maMouseDownPos.mnCol, maMouseDownPos.mnRow);
291
292 mbLeftButtonDown = (rMEvt.GetClicks() == 1) && rMEvt.IsLeft();
293
294 if( eHit == TableHitKind::Cell )
295 {
297 return true;
298 }
299
300 if( rMEvt.IsRight() && eHit != TableHitKind::NONE )
301 return true; // right click will become context menu
302
303 // for cell selection with the mouse remember our first hit
304 if( mbLeftButtonDown )
305 {
307
308 SdrHdl* pHdl = mrView.PickHandle(pixelToLogic(rMEvt.GetPosPixel(), pWindow));
309
310 if( pHdl )
311 {
312 mbLeftButtonDown = false;
313 }
314 else
315 {
317
318 if (!pTableObj || eHit == TableHitKind::NONE)
319 {
320 mbLeftButtonDown = false;
321 }
322 }
323 }
324
325 if (comphelper::LibreOfficeKit::isActive() && rMEvt.GetClicks() == 2 && rMEvt.IsLeft() && eHit == TableHitKind::CellTextArea)
326 {
327 bool bEmptyOutliner = false;
328 if (Outliner* pOutliner = mrView.GetTextEditOutliner())
329 {
330 if (pOutliner->GetParagraphCount() == 1)
331 {
332 if (Paragraph* pParagraph = pOutliner->GetParagraph(0))
333 bEmptyOutliner = pOutliner->GetText(pParagraph).isEmpty();
334 }
335 }
336 if (bEmptyOutliner)
337 {
338 // Tiled rendering: a left double-click in an empty cell: select it.
341 // Update graphic selection, should be hidden now.
343 return true;
344 }
345 }
346
347 return false;
348}
349
350
352{
353 if( !checkTableObject() )
354 return false;
355
356 mbLeftButtonDown = false;
357
358 return rMEvt.GetClicks() == 2;
359}
360
361
363{
364 if( !checkTableObject() )
365 return false;
366
367 rtl::Reference<SdrTableObj> pTableObj = mxTableObj.get();
368 CellPos aPos;
369 if (mbLeftButtonDown && pTableObj && pTableObj->CheckTableHit(pixelToLogic(rMEvt.GetPosPixel(), pWindow), aPos.mnCol, aPos.mnRow ) != TableHitKind::NONE)
370 {
371 if(aPos != maMouseDownPos)
372 {
374 {
376 return true;
377 }
378 else
379 {
381 }
382 }
383 else if( mbCellSelectionMode )
384 {
385 UpdateSelection( aPos );
386 return true;
387 }
388 }
389 return false;
390}
391
392
394{
395 bool bSelected = false;
396
397 rtl::Reference<SdrTableObj> pTableObj = mxTableObj.get();
398 if( pTableObj && pTableObj->IsTextEditActive() )
399 {
400 pTableObj->getActiveCellPos( maCursorFirstPos );
402 mbCellSelectionMode = false;
403 }
404 else
405 {
406 const SdrMarkList& rMarkList= mrView.GetMarkedObjectList();
407 if( rMarkList.GetMarkCount() == 1 )
408 bSelected = mxTableObj.get().get() == rMarkList.GetMark(0)->GetMarkedSdrObj();
409 }
410
411 if( bSelected )
412 {
414 }
415 else
416 {
418 }
419}
421{
423 if ( pTableObj && !pTableObj->IsTextEditActive())
424 {
425 selectAll();
426 }
427}
428
429
431{
432 if(!mxTable.is() || !mxTableObj.get().is())
433 return;
434
435 SdrTableObj& rTableObj(*mxTableObj.get());
436 SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
437 std::optional<SfxItemSet> oSet;
438 bool bVertDone(false);
439
440 // Iterate over all requested items in the set.
441 SfxWhichIter aIter( rSet );
442 sal_uInt16 nWhich = aIter.FirstWhich();
443 while (nWhich)
444 {
445 switch (nWhich)
446 {
447 case SID_TABLE_VERT_BOTTOM:
448 case SID_TABLE_VERT_CENTER:
449 case SID_TABLE_VERT_NONE:
450 {
451 if(!bVertDone)
452 {
453 if (!oSet)
454 {
455 oSet.emplace(rModel.GetItemPool());
456 MergeAttrFromSelectedCells(*oSet, false);
457 }
458
460
461 if (oSet->GetItemState( SDRATTR_TEXT_VERTADJUST ) != SfxItemState::DONTCARE)
462 eAdj = oSet->Get(SDRATTR_TEXT_VERTADJUST).GetValue();
463
464 rSet.Put(SfxBoolItem(SID_TABLE_VERT_BOTTOM, eAdj == SDRTEXTVERTADJUST_BOTTOM));
465 rSet.Put(SfxBoolItem(SID_TABLE_VERT_CENTER, eAdj == SDRTEXTVERTADJUST_CENTER));
466 rSet.Put(SfxBoolItem(SID_TABLE_VERT_NONE, eAdj == SDRTEXTVERTADJUST_TOP));
467 bVertDone = true;
468 }
469 break;
470 }
471 case SID_TABLE_DELETE_ROW:
472 if( !mxTable.is() || !hasSelectedCells() || (!comphelper::LibreOfficeKit::isActive() && mxTable->getRowCount() <= 1) )
473 rSet.DisableItem(SID_TABLE_DELETE_ROW);
474 break;
475 case SID_TABLE_DELETE_COL:
476 if( !mxTable.is() || !hasSelectedCells() || (!comphelper::LibreOfficeKit::isActive() && mxTable->getColumnCount() <= 1) )
477 rSet.DisableItem(SID_TABLE_DELETE_COL);
478 break;
479 case SID_TABLE_DELETE_TABLE:
480 if( !mxTable.is() )
481 rSet.DisableItem(SID_TABLE_DELETE_TABLE);
482 break;
483 case SID_TABLE_MERGE_CELLS:
484 if( !mxTable.is() || !hasSelectedCells() )
485 rSet.DisableItem(SID_TABLE_MERGE_CELLS);
486 break;
487 case SID_TABLE_SPLIT_CELLS:
488 if( !hasSelectedCells() || !mxTable.is() )
489 rSet.DisableItem(SID_TABLE_SPLIT_CELLS);
490 break;
491
492 case SID_TABLE_OPTIMAL_ROW_HEIGHT:
493 case SID_TABLE_DISTRIBUTE_COLUMNS:
494 case SID_TABLE_DISTRIBUTE_ROWS:
495 {
496 bool bDistributeColumns = false;
497 bool bDistributeRows = false;
498 if( mxTable.is() )
499 {
500 CellPos aStart, aEnd;
501 getSelectedCells( aStart, aEnd );
502
503 bDistributeColumns = aStart.mnCol != aEnd.mnCol;
504 bDistributeRows = aStart.mnRow != aEnd.mnRow;
505 }
506 if( !bDistributeColumns )
507 rSet.DisableItem(SID_TABLE_DISTRIBUTE_COLUMNS);
508 if( !bDistributeRows )
509 {
510 rSet.DisableItem(SID_TABLE_OPTIMAL_ROW_HEIGHT);
511 rSet.DisableItem(SID_TABLE_DISTRIBUTE_ROWS);
512 }
513 break;
514 }
515
516 default:
517 break;
518 }
519 nWhich = aIter.NextWhich();
520 }
521}
522
523
524void SvxTableController::onInsert( sal_uInt16 nSId, const SfxItemSet* pArgs )
525{
526 if(!checkTableObject())
527 return;
528
529 SdrTableObj& rTableObj(*mxTableObj.get());
530 SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
531 bool bInsertAfter = true;
532 sal_uInt16 nCount = 0;
533
534 if( pArgs )
535 {
536 const SfxPoolItem* pItem = nullptr;
537 pArgs->GetItemState(nSId, false, &pItem);
538 if (pItem)
539 {
540 nCount = static_cast<const SfxInt16Item*>(pItem)->GetValue();
541 if(const SfxBoolItem* pItem2 = pArgs->GetItemIfSet(SID_TABLE_PARAM_INSERT_AFTER))
542 bInsertAfter = pItem2->GetValue();
543 }
544 }
545
546 CellPos aStart, aEnd;
547 if( hasSelectedCells() )
548 {
549 getSelectedCells( aStart, aEnd );
550 }
551 else
552 {
553 if( bInsertAfter )
554 {
555 aStart.mnCol = mxTable->getColumnCount() - 1;
556 aStart.mnRow = mxTable->getRowCount() - 1;
557 aEnd = aStart;
558 }
559 }
560
561 if( rTableObj.IsTextEditActive() )
563
565
566 static constexpr OUStringLiteral sSize( u"Size" );
567 const bool bUndo(rModel.IsUndoEnabled());
568
569 switch( nSId )
570 {
571 case SID_TABLE_INSERT_COL:
572 {
573 TableModelNotifyGuard aGuard( mxTable.get() );
574
575 if( bUndo )
576 {
577 rModel.BegUndo( SvxResId(STR_TABLE_INSCOL) );
578 rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoGeoObject(rTableObj));
579 }
580
581 Reference< XTableColumns > xCols( mxTable->getColumns() );
582 const sal_Int32 nNewColumns = (nCount == 0) ? (aEnd.mnCol - aStart.mnCol + 1) : nCount;
583 const sal_Int32 nNewStartColumn = aEnd.mnCol + (bInsertAfter ? 1 : 0);
584 xCols->insertByIndex( nNewStartColumn, nNewColumns );
585
586 for( sal_Int32 nOffset = 0; nOffset < nNewColumns; nOffset++ )
587 {
588 // Resolves fdo#61540
589 // On Insert before, the reference column whose size is going to be
590 // used for newly created column(s) is wrong. As the new columns are
591 // inserted before the reference column, the reference column moved
592 // to the new position by no., of new columns i.e (earlier+newcolumns).
593 Reference< XPropertySet >(xCols->getByIndex(nNewStartColumn+nOffset), UNO_QUERY_THROW )->
594 setPropertyValue( sSize,
595 Reference< XPropertySet >(xCols->getByIndex( bInsertAfter?nNewStartColumn-1:nNewStartColumn+nNewColumns ), UNO_QUERY_THROW )->
596 getPropertyValue( sSize ) );
597 }
598
599 // Copy cell properties
600 sal_Int32 nPropSrcCol = (bInsertAfter ? aEnd.mnCol : aStart.mnCol + nNewColumns);
601 sal_Int32 nRowSpan = 0;
602 bool bNewSpan = false;
603
604 for( sal_Int32 nRow = 0; nRow < mxTable->getRowCount(); ++nRow )
605 {
606 CellRef xSourceCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nPropSrcCol, nRow ).get() ) );
607
608 // When we insert new COLUMNs, we want to copy ROW spans.
609 if (xSourceCell.is() && nRowSpan == 0)
610 {
611 // we are not in a span yet. Let's find out if the current cell is in a span.
612 sal_Int32 nColSpan = sal_Int32();
613 sal_Int32 nSpanInfoCol = sal_Int32();
614
615 if( xSourceCell->getRowSpan() > 1 )
616 {
617 // The current cell is the top-left cell in a span.
618 // Get the span info and propagate it to the target.
619 nRowSpan = xSourceCell->getRowSpan();
620 nColSpan = xSourceCell->getColumnSpan();
621 nSpanInfoCol = nPropSrcCol;
622 }
623 else if( xSourceCell->isMerged() )
624 {
625 // The current cell is a middle cell in a 2D span.
626 // Look for the top-left cell in the span.
627 for( nSpanInfoCol = nPropSrcCol - 1; nSpanInfoCol >= 0; --nSpanInfoCol )
628 {
629 CellRef xMergeInfoCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nSpanInfoCol, nRow ).get() ) );
630 if (xMergeInfoCell.is() && !xMergeInfoCell->isMerged())
631 {
632 nRowSpan = xMergeInfoCell->getRowSpan();
633 nColSpan = xMergeInfoCell->getColumnSpan();
634 break;
635 }
636 }
637 if( nRowSpan == 1 )
638 nRowSpan = 0;
639 }
640
641 // The target columns are outside the span; Start a new span.
642 if( nRowSpan > 0 && ( nNewStartColumn < nSpanInfoCol || nSpanInfoCol + nColSpan <= nNewStartColumn ) )
643 bNewSpan = true;
644 }
645
646 // Now copy the properties from the source to the targets
647 for( sal_Int32 nOffset = 0; nOffset < nNewColumns; nOffset++ )
648 {
649 CellRef xTargetCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nNewStartColumn + nOffset, nRow ).get() ) );
650 if( xTargetCell.is() )
651 {
652 if( nRowSpan > 0 )
653 {
654 if( bNewSpan )
655 xTargetCell->merge( 1, nRowSpan );
656 else
657 xTargetCell->setMerged();
658 }
659 xTargetCell->copyFormatFrom( xSourceCell );
660 }
661 }
662
663 if( nRowSpan > 0 )
664 {
665 --nRowSpan;
666 bNewSpan = false;
667 }
668 }
669
670 if( bUndo )
671 rModel.EndUndo();
672
673 aStart.mnCol = nNewStartColumn;
674 aStart.mnRow = 0;
675 aEnd.mnCol = aStart.mnCol + nNewColumns - 1;
676 aEnd.mnRow = mxTable->getRowCount() - 1;
677 break;
678 }
679
680 case SID_TABLE_INSERT_ROW:
681 {
682 TableModelNotifyGuard aGuard( mxTable.get() );
683
684 if( bUndo )
685 {
686 rModel.BegUndo( SvxResId(STR_TABLE_INSROW ) );
687 rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoGeoObject(rTableObj));
688 }
689
690 Reference< XTableRows > xRows( mxTable->getRows() );
691 const sal_Int32 nNewRows = (nCount == 0) ? (aEnd.mnRow - aStart.mnRow + 1) : nCount;
692 const sal_Int32 nNewRowStart = aEnd.mnRow + (bInsertAfter ? 1 : 0);
693 xRows->insertByIndex( nNewRowStart, nNewRows );
694
695 for( sal_Int32 nOffset = 0; nOffset < nNewRows; nOffset++ )
696 {
697 Reference< XPropertySet >( xRows->getByIndex( aEnd.mnRow + nOffset + 1 ), UNO_QUERY_THROW )->
698 setPropertyValue( sSize,
699 Reference< XPropertySet >( xRows->getByIndex( aStart.mnRow + nOffset ), UNO_QUERY_THROW )->
700 getPropertyValue( sSize ) );
701 }
702
703 // Copy the cell properties
704 sal_Int32 nPropSrcRow = (bInsertAfter ? aEnd.mnRow : aStart.mnRow + nNewRows);
705 sal_Int32 nColSpan = 0;
706 bool bNewSpan = false;
707
708 for( sal_Int32 nCol = 0; nCol < mxTable->getColumnCount(); ++nCol )
709 {
710 CellRef xSourceCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nPropSrcRow ).get() ) );
711
712 if (!xSourceCell.is())
713 continue;
714
715 // When we insert new ROWs, we want to copy COLUMN spans.
716 if( nColSpan == 0 )
717 {
718 // we are not in a span yet. Let's find out if the current cell is in a span.
719 sal_Int32 nRowSpan = sal_Int32();
720 sal_Int32 nSpanInfoRow = sal_Int32();
721
722 if( xSourceCell->getColumnSpan() > 1 )
723 {
724 // The current cell is the top-left cell in a span.
725 // Get the span info and propagate it to the target.
726 nColSpan = xSourceCell->getColumnSpan();
727 nRowSpan = xSourceCell->getRowSpan();
728 nSpanInfoRow = nPropSrcRow;
729 }
730 else if( xSourceCell->isMerged() )
731 {
732 // The current cell is a middle cell in a 2D span.
733 // Look for the top-left cell in the span.
734 for( nSpanInfoRow = nPropSrcRow - 1; nSpanInfoRow >= 0; --nSpanInfoRow )
735 {
736 CellRef xMergeInfoCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nSpanInfoRow ).get() ) );
737 if (xMergeInfoCell.is() && !xMergeInfoCell->isMerged())
738 {
739 nColSpan = xMergeInfoCell->getColumnSpan();
740 nRowSpan = xMergeInfoCell->getRowSpan();
741 break;
742 }
743 }
744 if( nColSpan == 1 )
745 nColSpan = 0;
746 }
747
748 // Inserted rows are outside the span; Start a new span.
749 if( nColSpan > 0 && ( nNewRowStart < nSpanInfoRow || nSpanInfoRow + nRowSpan <= nNewRowStart ) )
750 bNewSpan = true;
751 }
752
753 // Now copy the properties from the source to the targets
754 for( sal_Int32 nOffset = 0; nOffset < nNewRows; ++nOffset )
755 {
756 CellRef xTargetCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nNewRowStart + nOffset ).get() ) );
757 if( xTargetCell.is() )
758 {
759 if( nColSpan > 0 )
760 {
761 if( bNewSpan )
762 xTargetCell->merge( nColSpan, 1 );
763 else
764 xTargetCell->setMerged();
765 }
766 xTargetCell->copyFormatFrom( xSourceCell );
767 }
768 }
769
770 if( nColSpan > 0 )
771 {
772 --nColSpan;
773 bNewSpan = false;
774 }
775 }
776
777 if( bUndo )
778 rModel.EndUndo();
779
780 aStart.mnCol = 0;
781 aStart.mnRow = nNewRowStart;
782 aEnd.mnCol = mxTable->getColumnCount() - 1;
783 aEnd.mnRow = aStart.mnRow + nNewRows - 1;
784 break;
785 }
786 }
787
788 StartSelection( aStart );
789 UpdateSelection( aEnd );
790}
791
792
793void SvxTableController::onDelete( sal_uInt16 nSId )
794{
796 if( !pTableObj || !mxTable.is() )
797 return;
798
799 if( nSId == SID_TABLE_DELETE_TABLE )
800 {
801 if( pTableObj->IsTextEditActive() )
803
805 }
806 else if( hasSelectedCells() )
807 {
808 CellPos aStart, aEnd;
809 getSelectedCells( aStart, aEnd );
810
811 if( pTableObj->IsTextEditActive() )
813
815
816 bool bDeleteTable = false;
817 switch( nSId )
818 {
819 case SID_TABLE_DELETE_COL:
820 {
821 const sal_Int32 nRemovedColumns = aEnd.mnCol - aStart.mnCol + 1;
822 if( nRemovedColumns == mxTable->getColumnCount() )
823 {
824 bDeleteTable = true;
825 }
826 else
827 {
828 Reference< XTableColumns > xCols( mxTable->getColumns() );
829 xCols->removeByIndex( aStart.mnCol, nRemovedColumns );
830 EditCell(aStart, nullptr, TblAction::NONE);
831 }
832 break;
833 }
834
835 case SID_TABLE_DELETE_ROW:
836 {
837 const sal_Int32 nRemovedRows = aEnd.mnRow - aStart.mnRow + 1;
838 if( nRemovedRows == mxTable->getRowCount() )
839 {
840 bDeleteTable = true;
841 }
842 else
843 {
844 Reference< XTableRows > xRows( mxTable->getRows() );
845 xRows->removeByIndex( aStart.mnRow, nRemovedRows );
846 EditCell(aStart, nullptr, TblAction::NONE);
847 }
848 break;
849 }
850 }
851
852 if( bDeleteTable )
854 else
856 }
857}
858
859
860void SvxTableController::onSelect( sal_uInt16 nSId )
861{
862 if( !mxTable.is() )
863 return;
864
865 const sal_Int32 nRowCount = mxTable->getRowCount();
866 const sal_Int32 nColCount = mxTable->getColumnCount();
867 if( !(nRowCount && nColCount) )
868 return;
869
870 CellPos aStart, aEnd;
871 getSelectedCells( aStart, aEnd );
872
873 switch( nSId )
874 {
875 case SID_TABLE_SELECT_ALL:
876 aEnd.mnCol = 0; aEnd.mnRow = 0;
877 aStart.mnCol = nColCount - 1; aStart.mnRow = nRowCount - 1;
878 break;
879 case SID_TABLE_SELECT_COL:
880 aEnd.mnRow = nRowCount - 1;
881 aStart.mnRow = 0;
882 break;
883 case SID_TABLE_SELECT_ROW:
884 aEnd.mnCol = nColCount - 1;
885 aStart.mnCol = 0;
886 break;
887 }
888
889 StartSelection( aEnd );
890 gotoCell( aStart, true, nullptr );
891}
892
894{
895 // merge drawing layer text distance items into SvxBoxItem used by the dialog
896 SvxBoxItem aBoxItem( rAttrSet.Get( SDRATTR_TABLE_BORDER ) );
897 aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( rAttrSet.Get(SDRATTR_TEXT_LEFTDIST).GetValue()), SvxBoxItemLine::LEFT );
898 aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( rAttrSet.Get(SDRATTR_TEXT_RIGHTDIST).GetValue()), SvxBoxItemLine::RIGHT );
899 aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( rAttrSet.Get(SDRATTR_TEXT_UPPERDIST).GetValue()), SvxBoxItemLine::TOP );
900 aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( rAttrSet.Get(SDRATTR_TEXT_LOWERDIST).GetValue()), SvxBoxItemLine::BOTTOM );
901 return aBoxItem;
902}
903
905{
906 const SvxBoxItem* pNewItem( rAttrSet.GetItemIfSet( SDRATTR_TABLE_BORDER ) );
907 if ( !pNewItem )
908 return;
909
910 if( pNewItem->GetDistance( SvxBoxItemLine::LEFT ) != pOriginalItem.GetDistance( SvxBoxItemLine::LEFT ) )
911 rAttrSet.Put(makeSdrTextLeftDistItem( pNewItem->GetDistance( SvxBoxItemLine::LEFT ) ) );
912
913 if( pNewItem->GetDistance( SvxBoxItemLine::RIGHT ) != pOriginalItem.GetDistance( SvxBoxItemLine::RIGHT ) )
914 rAttrSet.Put(makeSdrTextRightDistItem( pNewItem->GetDistance( SvxBoxItemLine::RIGHT ) ) );
915
916 if( pNewItem->GetDistance( SvxBoxItemLine::TOP ) != pOriginalItem.GetDistance( SvxBoxItemLine::TOP ) )
917 rAttrSet.Put(makeSdrTextUpperDistItem( pNewItem->GetDistance( SvxBoxItemLine::TOP ) ) );
918
919 if( pNewItem->GetDistance( SvxBoxItemLine::BOTTOM ) != pOriginalItem.GetDistance( SvxBoxItemLine::BOTTOM ) )
920 rAttrSet.Put(makeSdrTextLowerDistItem( pNewItem->GetDistance( SvxBoxItemLine::BOTTOM ) ) );
921}
922
924{
925 if(!mxTableObj.get().is())
926 return;
927
928 SdrTableObj& rTableObj(*mxTableObj.get());
929 SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
930 const SfxItemSet* pArgs = rReq.GetArgs();
931
932 if(pArgs)
933 return;
934
935 SfxItemSet aNewAttr(rModel.GetItemPool());
936
937 // merge drawing layer text distance items into SvxBoxItem used by the dialog
938 auto xBoxItem(std::make_shared<SvxBoxItem>(TextDistancesToSvxBoxItem(aNewAttr)));
939 auto xBoxInfoItem(std::make_shared<SvxBoxInfoItem>(aNewAttr.Get(SDRATTR_TABLE_BORDER_INNER)));
940
941 MergeAttrFromSelectedCells(aNewAttr, false);
942 FillCommonBorderAttrFromSelectedCells(*xBoxItem, *xBoxInfoItem);
943 aNewAttr.Put(*xBoxItem);
944 aNewAttr.Put(*xBoxInfoItem);
945
946 // Fill in shadow properties.
947 const SfxItemSet& rTableItemSet = rTableObj.GetMergedItemSet();
948 for (sal_uInt16 nWhich = SDRATTR_SHADOW_FIRST; nWhich <= SDRATTR_SHADOW_LAST; ++nWhich)
949 {
950 if (rTableItemSet.GetItemState(nWhich, false) != SfxItemState::SET)
951 {
952 continue;
953 }
954
955 aNewAttr.Put(rTableItemSet.Get(nWhich));
956 }
957
960 rReq.GetFrameWeld(),
961 aNewAttr,
962 rModel, false) );
963
964 // Even Cancel Button is returning positive(101) value,
965 xDlg->StartExecuteAsync([xDlg, this, xBoxItem, xBoxInfoItem](int nResult){
966 if (nResult == RET_OK)
967 {
968 SfxItemSet aNewSet(*(xDlg->GetOutputItemSet()));
969
970 //Only properties that were unchanged by the dialog appear in this
971 //itemset. We had constructed these two properties from other
972 //ones, so if they were not changed, then forcible set them back to
973 //their originals in the new result set so we can decompose that
974 //unchanged state back to their input properties
975 if (aNewSet.GetItemState(SDRATTR_TABLE_BORDER, false) != SfxItemState::SET)
976 {
977 aNewSet.Put(*xBoxItem);
978 }
979 if (aNewSet.GetItemState(SDRATTR_TABLE_BORDER_INNER, false) != SfxItemState::SET)
980 {
981 aNewSet.Put(*xBoxInfoItem);
982 }
983
984 SvxBoxItemToTextDistances(*xBoxItem, aNewSet);
985
986 if (checkTableObject() && mxTable.is())
987 {
988 // Create a single undo action when applying the result of the dialog.
989 SdrTableObj& rTableObject(*mxTableObj.get());
990 SdrModel& rSdrModel(rTableObject.getSdrModelFromSdrObject());
991 bool bUndo = rSdrModel.IsUndoEnabled() && !mrView.IsTextEdit();
992 if (bUndo)
993 {
994 rSdrModel.BegUndo(SvxResId(STR_TABLE_NUMFORMAT));
995 }
996
997 this->SetAttrToSelectedCells(aNewSet, false);
998
999 this->SetAttrToSelectedShape(aNewSet);
1000
1001 if (bUndo)
1002 {
1003 rSdrModel.EndUndo();
1004 }
1005 }
1006 }
1007
1008 xDlg->disposeOnce();
1009 });
1010}
1011
1013{
1014 const sal_uInt16 nSId = rReq.GetSlot();
1015 switch( nSId )
1016 {
1017 case SID_TABLE_INSERT_ROW:
1018 case SID_TABLE_INSERT_COL:
1019 onInsert( nSId, rReq.GetArgs() );
1020 break;
1021 case SID_TABLE_DELETE_ROW:
1022 case SID_TABLE_DELETE_COL:
1023 case SID_TABLE_DELETE_TABLE:
1024 onDelete( nSId );
1025 break;
1026 case SID_TABLE_SELECT_ALL:
1027 case SID_TABLE_SELECT_COL:
1028 case SID_TABLE_SELECT_ROW:
1029 onSelect( nSId );
1030 break;
1031 case SID_FORMAT_TABLE_DLG:
1032 onFormatTable( rReq );
1033 break;
1034
1035 case SID_FRAME_LINESTYLE:
1036 case SID_FRAME_LINECOLOR:
1037 case SID_ATTR_BORDER:
1038 {
1039 const SfxItemSet* pArgs = rReq.GetArgs();
1040 if( pArgs )
1041 ApplyBorderAttr( *pArgs );
1042 }
1043 break;
1044
1045 case SID_ATTR_FILL_STYLE:
1046 {
1047 const SfxItemSet* pArgs = rReq.GetArgs();
1048 if( pArgs )
1049 SetAttributes( *pArgs, false );
1050 }
1051 break;
1052
1053 case SID_TABLE_MERGE_CELLS:
1055 break;
1056
1057 case SID_TABLE_SPLIT_CELLS:
1058 SplitMarkedCells(rReq);
1059 break;
1060
1061 case SID_TABLE_MINIMAL_COLUMN_WIDTH:
1062 DistributeColumns(/*bOptimize=*/true, /*bMinimize=*/true);
1063 break;
1064
1065 case SID_TABLE_OPTIMAL_COLUMN_WIDTH:
1066 DistributeColumns(/*bOptimize=*/true, /*bMinimize=*/false);
1067 break;
1068
1069 case SID_TABLE_DISTRIBUTE_COLUMNS:
1070 DistributeColumns(/*bOptimize=*/false, /*bMinimize=*/false);
1071 break;
1072
1073 case SID_TABLE_MINIMAL_ROW_HEIGHT:
1074 DistributeRows(/*bOptimize=*/true, /*bMinimize=*/true);
1075 break;
1076
1077 case SID_TABLE_OPTIMAL_ROW_HEIGHT:
1078 DistributeRows(/*bOptimize=*/true, /*bMinimize=*/false);
1079 break;
1080
1081 case SID_TABLE_DISTRIBUTE_ROWS:
1082 DistributeRows(/*bOptimize=*/false, /*bMinimize=*/false);
1083 break;
1084
1085 case SID_TABLE_VERT_BOTTOM:
1086 case SID_TABLE_VERT_CENTER:
1087 case SID_TABLE_VERT_NONE:
1088 SetVertical( nSId );
1089 break;
1090
1091 case SID_AUTOFORMAT:
1092 case SID_TABLE_SORT_DIALOG:
1093 case SID_TABLE_AUTOSUM:
1094 default:
1095 break;
1096
1097 case SID_TABLE_STYLE:
1098 SetTableStyle( rReq.GetArgs() );
1099 break;
1100
1101 case SID_TABLE_STYLE_SETTINGS:
1103 break;
1104 case SID_TABLE_CHANGE_CURRENT_BORDER_POSITION:
1105 changeTableEdge(rReq);
1106 break;
1107 }
1108}
1109
1111{
1112 if(!checkTableObject())
1113 return;
1114
1115 SdrTableObj& rTableObj(*mxTableObj.get());
1116 SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
1117
1118 if(!pArgs || (SfxItemState::SET != pArgs->GetItemState(SID_TABLE_STYLE, false)))
1119 return;
1120
1121 const SfxStringItem* pArg = &pArgs->Get( SID_TABLE_STYLE );
1122 if( !(pArg && mxTable.is()) )
1123 return;
1124
1125 try
1126 {
1127 Reference< XStyleFamiliesSupplier > xSFS( rModel.getUnoModel(), UNO_QUERY_THROW );
1128 Reference< XNameAccess > xFamilyNameAccess( xSFS->getStyleFamilies(), UNO_SET_THROW );
1129 Reference< XNameAccess > xTableFamilyAccess( xFamilyNameAccess->getByName( "table" ), UNO_QUERY_THROW );
1130
1131 if( xTableFamilyAccess->hasByName( pArg->GetValue() ) )
1132 {
1133 // found table style with the same name
1134 Reference< XIndexAccess > xNewTableStyle( xTableFamilyAccess->getByName( pArg->GetValue() ), UNO_QUERY_THROW );
1135
1136 const bool bUndo = rModel.IsUndoEnabled();
1137
1138 if( bUndo )
1139 {
1140 rModel.BegUndo(SvxResId(STR_TABLE_STYLE));
1141 rModel.AddUndo(std::make_unique<TableStyleUndo>(rTableObj));
1142 }
1143
1144 rTableObj.setTableStyle( xNewTableStyle );
1145
1146 const sal_Int32 nRowCount = mxTable->getRowCount();
1147 const sal_Int32 nColCount = mxTable->getColumnCount();
1148 for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ )
1149 {
1150 for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ ) try
1151 {
1152 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
1153 if( xCell.is() )
1154 {
1155 SfxItemSet aSet( xCell->GetItemSet() );
1156 bool bChanges = false;
1157 SfxStyleSheet *pStyleSheet = xCell->GetStyleSheet();
1158 SAL_WARN_IF(!pStyleSheet, "svx", "no stylesheet for table cell?");
1159 if (pStyleSheet)
1160 {
1161 const SfxItemSet& rStyleAttribs = pStyleSheet->GetItemSet();
1162
1163 for ( sal_uInt16 nWhich = SDRATTR_START; nWhich <= SDRATTR_TABLE_LAST; nWhich++ )
1164 {
1165 if( (rStyleAttribs.GetItemState( nWhich ) == SfxItemState::SET) && (aSet.GetItemState( nWhich ) == SfxItemState::SET) )
1166 {
1167 aSet.ClearItem( nWhich );
1168 bChanges = true;
1169 }
1170 }
1171 }
1172
1173 if( bChanges )
1174 {
1175 if( bUndo )
1176 xCell->AddUndo();
1177
1178 xCell->SetMergedItemSetAndBroadcast( aSet, true );
1179 }
1180 }
1181 }
1182 catch( Exception& )
1183 {
1184 TOOLS_WARN_EXCEPTION("svx.table", "");
1185 }
1186 }
1187
1188 if( bUndo )
1189 rModel.EndUndo();
1190 }
1191 }
1192 catch( Exception& )
1193 {
1194 TOOLS_WARN_EXCEPTION("svx.table", "");
1195 }
1196}
1197
1199{
1200 if(!checkTableObject())
1201 return;
1202
1203 SdrTableObj& rTableObj(*mxTableObj.get());
1204 SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
1205
1206 TableStyleSettings aSettings(rTableObj.getTableStyleSettings() );
1207 const SfxBoolItem *pPoolItem=nullptr;
1208
1209 if( (pPoolItem = pArgs->GetItemIfSet(ID_VAL_USEFIRSTROWSTYLE, false)) )
1210 aSettings.mbUseFirstRow = pPoolItem->GetValue();
1211
1212 if( (pPoolItem = pArgs->GetItemIfSet(ID_VAL_USELASTROWSTYLE, false)) )
1213 aSettings.mbUseLastRow = pPoolItem->GetValue();
1214
1215 if( (pPoolItem = pArgs->GetItemIfSet(ID_VAL_USEBANDINGROWSTYLE, false)) )
1216 aSettings.mbUseRowBanding = pPoolItem->GetValue();
1217
1218 if( (pPoolItem = pArgs->GetItemIfSet(ID_VAL_USEFIRSTCOLUMNSTYLE, false)) )
1219 aSettings.mbUseFirstColumn = pPoolItem->GetValue();
1220
1221 if( (pPoolItem = pArgs->GetItemIfSet(ID_VAL_USELASTCOLUMNSTYLE, false)) )
1222 aSettings.mbUseLastColumn = pPoolItem->GetValue();
1223
1224 if( (pPoolItem = pArgs->GetItemIfSet(ID_VAL_USEBANDINGCOLUMNSTYLE, false)) )
1225 aSettings.mbUseColumnBanding = pPoolItem->GetValue();
1226
1227 if( aSettings == rTableObj.getTableStyleSettings() )
1228 return;
1229
1230 const bool bUndo(rModel.IsUndoEnabled());
1231
1232 if( bUndo )
1233 {
1234 rModel.BegUndo( SvxResId(STR_TABLE_STYLE_SETTINGS) );
1235 rModel.AddUndo(std::make_unique<TableStyleUndo>(rTableObj));
1236 }
1237
1238 rTableObj.setTableStyleSettings( aSettings );
1239
1240 if( bUndo )
1241 rModel.EndUndo();
1242}
1243
1244void SvxTableController::SetVertical( sal_uInt16 nSId )
1245{
1246 if(!checkTableObject())
1247 return;
1248
1249 SdrTableObj& rTableObj(*mxTableObj.get());
1250 SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
1251
1252 TableModelNotifyGuard aGuard( mxTable.get() );
1253 const bool bUndo(rModel.IsUndoEnabled());
1254
1255 if (bUndo)
1256 {
1257 rModel.BegUndo(SvxResId(STR_TABLE_NUMFORMAT));
1258 rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoAttrObject(rTableObj));
1259 }
1260
1261 CellPos aStart, aEnd;
1262 getSelectedCells( aStart, aEnd );
1263
1265
1266 switch( nSId )
1267 {
1268 case SID_TABLE_VERT_BOTTOM:
1270 break;
1271 case SID_TABLE_VERT_CENTER:
1273 break;
1274 //case SID_TABLE_VERT_NONE:
1275 default:
1276 break;
1277 }
1278
1279 SdrTextVertAdjustItem aItem( eAdj );
1280
1281 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
1282 {
1283 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
1284 {
1285 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
1286 if( xCell.is() )
1287 {
1288 if (bUndo)
1289 xCell->AddUndo();
1290 SfxItemSet aSet(xCell->GetItemSet());
1291 aSet.Put(aItem);
1292 xCell->SetMergedItemSetAndBroadcast(aSet, /*bClearAllItems=*/false);
1293 }
1294 }
1295 }
1296
1298
1299 if (bUndo)
1300 rModel.EndUndo();
1301}
1302
1304{
1305 CellPos aStart, aEnd;
1306 getSelectedCells( aStart, aEnd );
1307 rtl::Reference<SdrTableObj> pTableObj = mxTableObj.get();
1308 if( pTableObj )
1309 {
1310 if( pTableObj->IsTextEditActive() )
1311 mrView.SdrEndTextEdit(true);
1312
1313 TableModelNotifyGuard aGuard( mxTable.get() );
1314 MergeRange( aStart.mnCol, aStart.mnRow, aEnd.mnCol, aEnd.mnRow );
1315 }
1316}
1317
1319{
1320 if(!checkTableObject() || !mxTable.is())
1321 return;
1322
1325
1326 xDlg->StartExecuteAsync([xDlg, this](int) {
1327 const sal_Int32 nCount = xDlg->GetCount() - 1;
1328
1329 if( nCount < 1 )
1330 return;
1331
1332 CellPos aStart, aEnd;
1333 getSelectedCells( aStart, aEnd );
1334 Reference< XMergeableCellRange > xRange( mxTable->createCursorByRange( mxTable->getCellRangeByPosition( aStart.mnCol, aStart.mnRow, aEnd.mnCol, aEnd.mnRow ) ), UNO_QUERY_THROW );
1335 const sal_Int32 nRowCount = mxTable->getRowCount();
1336 const sal_Int32 nColCount = mxTable->getColumnCount();
1337 SdrTableObj& rTableObj(*mxTableObj.get());
1338
1339 if( rTableObj.IsTextEditActive() )
1340 mrView.SdrEndTextEdit(true);
1341
1342 TableModelNotifyGuard aGuard( mxTable.get() );
1343 SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
1344 const bool bUndo(rModel.IsUndoEnabled());
1345
1346 if( bUndo )
1347 {
1348 rModel.BegUndo( SvxResId(STR_TABLE_SPLIT) );
1349 rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoGeoObject(rTableObj));
1350 }
1351
1352 if( xDlg->IsHorizontal() )
1353 {
1354 xRange->split( 0, nCount );
1355 }
1356 else
1357 {
1358 xRange->split( nCount, 0 );
1359 }
1360
1361 if( bUndo )
1362 rModel.EndUndo();
1363
1364 aEnd.mnRow += mxTable->getRowCount() - nRowCount;
1365 aEnd.mnCol += mxTable->getColumnCount() - nColCount;
1366
1367 setSelectedCells( aStart, aEnd );
1368
1369 xDlg->disposeOnce();
1370 });
1371}
1372
1373void SvxTableController::DistributeColumns(const bool bOptimize, const bool bMinimize)
1374{
1375 if(!checkTableObject())
1376 return;
1377
1378 SdrTableObj& rTableObj(*mxTableObj.get());
1379 SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
1380 const bool bUndo(rModel.IsUndoEnabled());
1381
1382 if( bUndo )
1383 {
1384 rModel.BegUndo( SvxResId(STR_TABLE_DISTRIBUTE_COLUMNS) );
1385 rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoGeoObject(rTableObj));
1386 }
1387
1388 CellPos aStart, aEnd;
1389 getSelectedCells( aStart, aEnd );
1390 rTableObj.DistributeColumns( aStart.mnCol, aEnd.mnCol, bOptimize, bMinimize );
1391
1392 if( bUndo )
1393 rModel.EndUndo();
1394}
1395
1396void SvxTableController::DistributeRows(const bool bOptimize, const bool bMinimize)
1397{
1398 if(!checkTableObject())
1399 return;
1400
1401 SdrTableObj& rTableObj(*mxTableObj.get());
1402 SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
1403 const bool bUndo(rModel.IsUndoEnabled());
1404
1405 if( bUndo )
1406 {
1407 rModel.BegUndo( SvxResId(STR_TABLE_DISTRIBUTE_ROWS) );
1408 rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoGeoObject(rTableObj));
1409 }
1410
1411 CellPos aStart, aEnd;
1412 getSelectedCells( aStart, aEnd );
1413 rTableObj.DistributeRows( aStart.mnRow, aEnd.mnRow, bOptimize, bMinimize );
1414
1415 if( bUndo )
1416 rModel.EndUndo();
1417}
1418
1420{
1421 return mbCellSelectionMode && mxTable.is();
1422}
1423
1425{
1426 if(!checkTableObject() || !HasMarked())
1427 return false;
1428
1429 SdrTableObj& rTableObj(*mxTableObj.get());
1430 SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
1431 const bool bUndo(rModel.IsUndoEnabled());
1432 bool bDeleteTable = false;
1433
1434 if (bUndo)
1435 rModel.BegUndo(SvxResId(STR_TABLE_DELETE_CELL_CONTENTS));
1436
1437 CellPos aStart, aEnd;
1438 getSelectedCells( aStart, aEnd );
1439 const sal_Int32 nRemovedColumns = aEnd.mnCol - aStart.mnCol + 1;
1440 const sal_Int32 nRemovedRows = aEnd.mnRow - aStart.mnRow + 1;
1441 if( nRemovedColumns == mxTable->getColumnCount() && nRemovedRows == mxTable->getRowCount())
1442 {
1443 bDeleteTable = true;
1444 }
1445 else
1446 {
1447 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
1448 {
1449 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
1450 {
1451 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
1452 if (xCell.is() && xCell->hasText())
1453 {
1454 if (bUndo)
1455 xCell->AddUndo();
1456 xCell->SetOutlinerParaObject(std::nullopt);
1457 }
1458 }
1459 }
1460 }
1461
1462 if (bDeleteTable)
1464
1465 if (bUndo)
1466 rModel.EndUndo();
1467
1468 if (!bDeleteTable)
1470 return true;
1471}
1472
1474{
1475 if( hasSelectedCells() )
1476 {
1477 rpStyleSheet = nullptr;
1478
1479 if( mxTable.is() )
1480 {
1481 SfxStyleSheet* pRet=nullptr;
1482 bool b1st=true;
1483
1484 CellPos aStart, aEnd;
1485 const_cast<SvxTableController&>(*this).getSelectedCells( aStart, aEnd );
1486
1487 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
1488 {
1489 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
1490 {
1491 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
1492 if( xCell.is() )
1493 {
1494 SfxStyleSheet* pSS=xCell->GetStyleSheet();
1495 if(b1st)
1496 {
1497 pRet=pSS;
1498 }
1499 else if(pRet != pSS)
1500 {
1501 return true;
1502 }
1503 b1st=false;
1504 }
1505 }
1506 }
1507 rpStyleSheet = pRet;
1508 return true;
1509 }
1510 }
1511 return false;
1512}
1513
1514bool SvxTableController::SetStyleSheet( SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr )
1515{
1516 if( hasSelectedCells() && (!pStyleSheet || pStyleSheet->GetFamily() == SfxStyleFamily::Frame) )
1517 {
1518 if( mxTable.is() )
1519 {
1520 CellPos aStart, aEnd;
1521 getSelectedCells( aStart, aEnd );
1522
1523 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
1524 {
1525 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
1526 {
1527 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
1528 if( xCell.is() )
1529 xCell->SetStyleSheet(pStyleSheet,bDontRemoveHardAttr);
1530 }
1531 }
1532
1534 return true;
1535 }
1536 }
1537 return false;
1538}
1539
1541{
1542 if (!checkTableObject())
1543 return;
1544
1545 const auto* pType = rReq.GetArg<SfxStringItem>(SID_TABLE_BORDER_TYPE);
1546 const auto* pIndex = rReq.GetArg<SfxUInt16Item>(SID_TABLE_BORDER_INDEX);
1547 const auto* pOffset = rReq.GetArg<SfxInt32Item>(SID_TABLE_BORDER_OFFSET);
1548
1549 if (!(pType && pIndex && pOffset))
1550 return;
1551
1552 const OUString sType = pType->GetValue();
1553 const sal_uInt16 nIndex = pIndex->GetValue();
1554 const sal_Int32 nOffset = convertTwipToMm100(pOffset->GetValue());
1555
1556 SdrTableObj& rTableObj(*mxTableObj.get());
1557
1558 sal_Int32 nEdgeIndex = -1;
1559 bool bHorizontal = sType.startsWith("row");
1560
1561 if (sType == "column-left" || sType == "row-left")
1562 {
1563 nEdgeIndex = 0;
1564 }
1565 else if (sType == "column-right")
1566 {
1567 // Number of edges = number of columns + 1
1568 nEdgeIndex = rTableObj.getColumnCount();
1569 }
1570 else if (sType == "row-right")
1571 {
1572 // Number of edges = number of rows + 1
1573 nEdgeIndex = rTableObj.getRowCount();
1574 }
1575 else if (sType == "column-middle" || sType == "row-middle")
1576 {
1577 nEdgeIndex = nIndex + 1;
1578 }
1579
1580 if (nEdgeIndex < 0)
1581 return;
1582
1583 TableModelNotifyGuard aGuard(mxTable.get());
1584 SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
1585 const bool bUndo(rModel.IsUndoEnabled());
1586 if (bUndo)
1587 {
1588 auto pUndoObject = rModel.GetSdrUndoFactory().CreateUndoGeoObject(rTableObj);
1589 rModel.BegUndo(pUndoObject->GetComment());
1590
1591 auto* pGeoUndo = static_cast<SdrUndoGeoObj*>(pUndoObject.get());
1592 if (pGeoUndo)
1593 pGeoUndo->SetSkipChangeLayout(true);
1594
1595 rModel.AddUndo(std::move(pUndoObject));
1596 }
1597 tools::Rectangle aBoundRect;
1598 if (rTableObj.GetUserCall())
1599 aBoundRect = rTableObj.GetLastBoundRect();
1600 rTableObj.changeEdge(bHorizontal, nEdgeIndex, nOffset);
1601 rTableObj.SetChanged();
1602 rTableObj.SendUserCall(SdrUserCallType::Resize, aBoundRect);
1603 if (bUndo)
1604 rModel.EndUndo();
1605}
1606
1607// internals
1608
1609
1611{
1612 return mxTableObj.get().is();
1613}
1614
1615
1617{
1618 const bool bMod1 = rKEvt.GetKeyCode().IsMod1(); // ctrl
1619 const bool bMod2 = rKEvt.GetKeyCode().IsMod2(); // Alt
1620 const bool bTextEdit = mrView.IsTextEdit();
1621
1623
1625 if( !pTableObj )
1626 return nAction;
1627
1628 // handle special keys
1629 const sal_Int16 nCode = rKEvt.GetKeyCode().GetCode();
1630 switch( nCode )
1631 {
1632 case awt::Key::ESCAPE: // handle escape
1633 {
1634 if( bTextEdit )
1635 {
1636 // escape during text edit ends text edit
1637 nAction = TblAction::StopTextEdit;
1638 }
1640 {
1641 // escape with selected cells removes selection
1643 }
1644 break;
1645 }
1646 case awt::Key::RETURN: // handle return
1647 {
1648 if( !bMod1 && !bMod2 && !bTextEdit )
1649 {
1650 // when not already editing, return starts text edit
1652 nAction = TblAction::EditCell;
1653 }
1654 break;
1655 }
1656 case awt::Key::F2: // f2 toggles text edit
1657 {
1658 if( bMod1 || bMod2 ) // f2 with modifiers is handled by the view
1659 {
1660 }
1661 else if( bTextEdit )
1662 {
1663 // f2 during text edit stops text edit
1664 nAction = TblAction::StopTextEdit;
1665 }
1666 else if( mbCellSelectionMode )
1667 {
1668 // f2 with selected cells removes selection
1670 }
1671 else
1672 {
1673 // f2 with no selection and no text edit starts text edit
1675 nAction = TblAction::EditCell;
1676 }
1677 break;
1678 }
1679 case awt::Key::HOME:
1680 case awt::Key::NUM7:
1681 {
1682 if( (bMod1 || bMod2) && (bTextEdit || mbCellSelectionMode) )
1683 {
1684 if( bMod1 && !bMod2 )
1685 {
1686 // ctrl + home jumps to first cell
1687 nAction = TblAction::GotoFirstCell;
1688 }
1689 else if( !bMod1 && bMod2 )
1690 {
1691 // alt + home jumps to first column
1693 }
1694 }
1695 break;
1696 }
1697 case awt::Key::END:
1698 case awt::Key::NUM1:
1699 {
1700 if( (bMod1 || bMod2) && (bTextEdit || mbCellSelectionMode) )
1701 {
1702 if( bMod1 && !bMod2 )
1703 {
1704 // ctrl + end jumps to last cell
1705 nAction = TblAction::GotoLastCell;
1706 }
1707 else if( !bMod1 && bMod2 )
1708 {
1709 // alt + home jumps to last column
1710 nAction = TblAction::GotoLastColumn;
1711 }
1712 }
1713 break;
1714 }
1715
1716 case awt::Key::TAB:
1717 {
1718 if( bTextEdit || mbCellSelectionMode )
1719 nAction = TblAction::Tab;
1720 break;
1721 }
1722
1723 case awt::Key::UP:
1724 case awt::Key::NUM8:
1725 case awt::Key::DOWN:
1726 case awt::Key::NUM2:
1727 case awt::Key::LEFT:
1728 case awt::Key::NUM4:
1729 case awt::Key::RIGHT:
1730 case awt::Key::NUM6:
1731 {
1732
1733 if( !bMod1 && bMod2 )
1734 {
1735 if(bTextEdit || mbCellSelectionMode)
1736 {
1737 if( (nCode == awt::Key::UP) || (nCode == awt::Key::NUM8) )
1738 {
1739 nAction = TblAction::GotoLeftCell;
1740 break;
1741 }
1742 else if( (nCode == awt::Key::DOWN) || (nCode == awt::Key::NUM2) )
1743 {
1744 nAction = TblAction::GotoRightCell;
1745 break;
1746 }
1747 }
1748 }
1749
1750 bool bTextMove = false;
1752 if( pOLV )
1753 {
1755 // during text edit, check if we navigate out of the cell
1756 ESelection aOldSelection = pOLV->GetSelection();
1757 pOLV->PostKeyEvent(rKEvt);
1758 bTextMove = aOldSelection == pOLV->GetSelection();
1759 if( !bTextMove )
1760 {
1761 nAction = TblAction::NONE;
1762 }
1763 }
1764
1765 if( mbCellSelectionMode || bTextMove )
1766 {
1767 // no text edit, navigate in cells if selection active
1768 switch( nCode )
1769 {
1770 case awt::Key::LEFT:
1771 case awt::Key::NUM4:
1772 nAction = TblAction::GotoLeftCell;
1773 break;
1774 case awt::Key::RIGHT:
1775 case awt::Key::NUM6:
1776 nAction = TblAction::GotoRightCell;
1777 break;
1778 case awt::Key::DOWN:
1779 case awt::Key::NUM2:
1780 nAction = TblAction::GotoDownCell;
1781 break;
1782 case awt::Key::UP:
1783 case awt::Key::NUM8:
1784 nAction = TblAction::GotoUpCell;
1785 break;
1786 }
1787 }
1788 break;
1789 }
1790 case awt::Key::PAGEUP:
1791 if( bMod2 )
1792 nAction = TblAction::GotoFirstRow;
1793 break;
1794
1795 case awt::Key::PAGEDOWN:
1796 if( bMod2 )
1797 nAction = TblAction::GotoLastRow;
1798 break;
1799 }
1800 return nAction;
1801}
1802
1803bool SvxTableController::executeAction(TblAction nAction, bool bSelect, vcl::Window* pWindow)
1804{
1806 if( !pTableObj )
1807 return false;
1808
1809 switch( nAction )
1810 {
1812 {
1813 gotoCell( SdrTableObj::getFirstCell(), bSelect, pWindow, nAction );
1814 break;
1815 }
1816
1818 {
1819 gotoCell( pTableObj->getLeftCell( getSelectionEnd(), !bSelect ), bSelect, pWindow, nAction );
1820 break;
1821 }
1822
1824 {
1825 gotoCell( pTableObj->getRightCell( getSelectionEnd(), !bSelect ), bSelect, pWindow, nAction);
1826 break;
1827 }
1828
1830 {
1831 gotoCell( pTableObj->getLastCell(), bSelect, pWindow, nAction );
1832 break;
1833 }
1834
1836 {
1838 gotoCell( aPos, bSelect, pWindow, nAction );
1839 break;
1840 }
1841
1843 {
1844 CellPos aPos( pTableObj->getLastCell().mnCol, getSelectionEnd().mnRow );
1845 gotoCell( aPos, bSelect, pWindow, nAction );
1846 break;
1847 }
1848
1850 {
1852 gotoCell( aPos, bSelect, pWindow, nAction );
1853 break;
1854 }
1855
1857 {
1858 gotoCell( pTableObj->getUpCell(getSelectionEnd(), !bSelect), bSelect, pWindow, nAction );
1859 break;
1860 }
1861
1863 {
1864 gotoCell( pTableObj->getDownCell(getSelectionEnd(), !bSelect), bSelect, pWindow, nAction );
1865 break;
1866 }
1867
1869 {
1870 CellPos aPos( getSelectionEnd().mnCol, pTableObj->getLastCell().mnRow );
1871 gotoCell( aPos, bSelect, pWindow, nAction );
1872 break;
1873 }
1874
1876 EditCell( getSelectionStart(), pWindow, nAction );
1877 break;
1878
1880 StopTextEdit();
1881 break;
1882
1885 break;
1886
1887 case TblAction::Tab:
1888 {
1889 if( bSelect )
1890 gotoCell( pTableObj->getPreviousCell( getSelectionEnd(), true ), false, pWindow, nAction );
1891 else
1892 {
1893 CellPos aSelectionEnd( getSelectionEnd() );
1894 CellPos aNextCell( pTableObj->getNextCell( aSelectionEnd, true ) );
1895 if( aSelectionEnd == aNextCell )
1896 {
1897 onInsert( SID_TABLE_INSERT_ROW );
1898 aNextCell = pTableObj->getNextCell( aSelectionEnd, true );
1899 }
1900 gotoCell( aNextCell, false, pWindow, nAction );
1901 }
1902 break;
1903 }
1904 default:
1905 break;
1906 }
1907
1908 return nAction != TblAction::HandledByView;
1909}
1910
1911
1912void SvxTableController::gotoCell(const CellPos& rPos, bool bSelect, vcl::Window* pWindow, TblAction nAction /*= TblAction::NONE */)
1913{
1914 auto pTable = mxTableObj.get();
1915 if( pTable && pTable->IsTextEditActive() )
1916 mrView.SdrEndTextEdit(true);
1917
1918 if( bSelect )
1919 {
1920 maCursorLastPos = rPos;
1921 if( pTable )
1922 pTable->setActiveCell( rPos );
1923
1924 if( !mbCellSelectionMode )
1925 {
1927 }
1928 else
1929 {
1930 UpdateSelection( rPos );
1931 }
1932 }
1933 else
1934 {
1936 EditCell( rPos, pWindow, nAction );
1937 }
1938}
1939
1940
1942{
1944 return maCursorFirstPos;
1945}
1946
1947
1949{
1950 maCursorFirstPos = rPos;
1951}
1952
1953
1955{
1957 return maCursorLastPos;
1958}
1959
1960
1961void SvxTableController::MergeRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow )
1962{
1963 if(!checkTableObject() || !mxTable.is())
1964 return;
1965
1966 try
1967 {
1968 Reference< XMergeableCellRange > xRange( mxTable->createCursorByRange( mxTable->getCellRangeByPosition( nFirstCol, nFirstRow,nLastCol, nLastRow ) ), UNO_QUERY_THROW );
1969
1970 if( xRange->isMergeable() )
1971 {
1972 SdrTableObj& rTableObj(*mxTableObj.get());
1973 SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
1974 const bool bUndo(rModel.IsUndoEnabled());
1975
1976 if( bUndo )
1977 {
1978 rModel.BegUndo( SvxResId(STR_TABLE_MERGE) );
1979 rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoGeoObject(rTableObj));
1980 }
1981
1982 xRange->merge();
1983 mbHasJustMerged = true;
1985
1986 if( bUndo )
1987 rModel.EndUndo();
1988 }
1989 }
1990 catch( Exception& )
1991 {
1992 TOOLS_WARN_EXCEPTION( "svx.table", "" );
1993 }
1994}
1995
1996
1998{
1999 if( !mxTable.is() )
2000 return;
2001
2002 try
2003 {
2004 if( rPos.mnCol >= mxTable->getColumnCount() )
2005 rPos.mnCol = mxTable->getColumnCount()-1;
2006
2007 if( rPos.mnRow >= mxTable->getRowCount() )
2008 rPos.mnRow = mxTable->getRowCount()-1;
2009 }
2010 catch( Exception& )
2011 {
2012 TOOLS_WARN_EXCEPTION("svx.table", "");
2013 }
2014}
2015
2016
2018{
2019 if( !mxTable.is() )
2020 return;
2021
2022 try
2023 {
2024 Reference< XMergeableCell > xCell( mxTable->getCellByPosition( rPos.mnCol, rPos.mnRow ), UNO_QUERY_THROW );
2025 if( xCell->isMerged() )
2026 {
2027 ::findMergeOrigin( mxTable, rPos.mnCol, rPos.mnRow, rPos.mnCol, rPos.mnRow );
2028 }
2029 }
2030 catch( Exception& )
2031 {
2032 TOOLS_WARN_EXCEPTION("svx.table", "");
2033 }
2034}
2035
2036
2037void SvxTableController::EditCell(const CellPos& rPos, vcl::Window* pWindow, TblAction nAction /*= TblAction::NONE */)
2038{
2040
2041 if(nullptr == pPV || !checkTableObject())
2042 return;
2043
2044 SdrTableObj& rTableObj(*mxTableObj.get());
2045
2046 if(rTableObj.getSdrPageFromSdrObject() != pPV->GetPage())
2047 return;
2048
2049 bool bEmptyOutliner = false;
2050
2052 {
2054 sal_Int32 nParaCnt = pOutl->GetParagraphCount();
2055 Paragraph* p1stPara = pOutl->GetParagraph( 0 );
2056
2057 if(nParaCnt==1 && p1stPara)
2058 {
2059 // with only one paragraph
2060 if (pOutl->GetText(p1stPara).isEmpty())
2061 {
2062 bEmptyOutliner = true;
2063 }
2064 }
2065 }
2066
2067 CellPos aPos( rPos );
2068 findMergeOrigin( aPos );
2069
2070 if( &rTableObj == mrView.GetTextEditObject() && !bEmptyOutliner && rTableObj.IsTextEditActive( aPos ) )
2071 return;
2072
2073 if( rTableObj.IsTextEditActive() )
2074 mrView.SdrEndTextEdit(true);
2075
2076 rTableObj.setActiveCell( aPos );
2077
2078 // create new outliner, owner will be the SdrObjEditView
2079 SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
2080 std::unique_ptr<SdrOutliner> pOutl(SdrMakeOutliner(OutlinerMode::OutlineObject, rModel));
2081
2082 if (pOutl && rTableObj.IsVerticalWriting())
2083 pOutl->SetVertical( true );
2084
2085 if (!mrView.SdrBeginTextEdit(&rTableObj, pPV, pWindow, true, pOutl.release()))
2086 return;
2087
2089
2091
2092 // Move cursor to end of text
2094
2095 const WritingMode eMode = rTableObj.GetWritingMode();
2096 if (((nAction == TblAction::GotoLeftCell) || (nAction == TblAction::GotoRightCell)) && (eMode != WritingMode_TB_RL))
2097 {
2098 const bool bLast = ((nAction == TblAction::GotoLeftCell) && (eMode == WritingMode_LR_TB)) ||
2099 ((nAction == TblAction::GotoRightCell) && (eMode == WritingMode_RL_TB));
2100
2101 if( bLast )
2103 }
2105}
2106
2107
2109{
2110 if(mrView.IsTextEdit())
2111 {
2115 }
2116}
2117
2118
2120{
2122 {
2125
2126 rFirst.mnCol = std::min( maCursorFirstPos.mnCol, maCursorLastPos.mnCol );
2127 rFirst.mnRow = std::min( maCursorFirstPos.mnRow, maCursorLastPos.mnRow );
2128 rLast.mnCol = std::max( maCursorFirstPos.mnCol, maCursorLastPos.mnCol );
2129 rLast.mnRow = std::max( maCursorFirstPos.mnRow, maCursorLastPos.mnRow );
2130
2131 if( !mxTable.is() )
2132 return;
2133
2134 bool bExt = false;
2135 do
2136 {
2137 bExt = false;
2138 for( sal_Int32 nRow = rFirst.mnRow; nRow <= rLast.mnRow && !bExt; nRow++ )
2139 {
2140 for( sal_Int32 nCol = rFirst.mnCol; nCol <= rLast.mnCol && !bExt; nCol++ )
2141 {
2142 Reference< XMergeableCell > xCell( mxTable->getCellByPosition( nCol, nRow ), UNO_QUERY );
2143 if( !xCell.is() )
2144 continue;
2145
2146 if( xCell->isMerged() )
2147 {
2148 CellPos aPos( nCol, nRow );
2149 findMergeOrigin( aPos );
2150 if( (aPos.mnCol < rFirst.mnCol) || (aPos.mnRow < rFirst.mnRow) )
2151 {
2152 rFirst.mnCol = std::min( rFirst.mnCol, aPos.mnCol );
2153 rFirst.mnRow = std::min( rFirst.mnRow, aPos.mnRow );
2154 bExt = true;
2155 }
2156 }
2157 else
2158 {
2159 if( ((nCol + xCell->getColumnSpan() - 1) > rLast.mnCol) || (nRow + xCell->getRowSpan() - 1 ) > rLast.mnRow )
2160 {
2161 rLast.mnCol = std::max( rLast.mnCol, nCol + xCell->getColumnSpan() - 1 );
2162 rLast.mnRow = std::max( rLast.mnRow, nRow + xCell->getRowSpan() - 1 );
2163 bExt = true;
2164 }
2165 }
2166 }
2167 }
2168 }
2169 while(bExt);
2170 }
2171 else if(mrView.IsTextEdit())
2172 {
2173 rFirst = getSelectionStart();
2174 findMergeOrigin( rFirst );
2175 rLast = rFirst;
2176
2177 if( mxTable.is() )
2178 {
2179 Reference< XMergeableCell > xCell( mxTable->getCellByPosition( rLast.mnCol, rLast.mnRow ), UNO_QUERY );
2180 if( xCell.is() )
2181 {
2182 rLast.mnCol += xCell->getColumnSpan() - 1;
2183 rLast.mnRow += xCell->getRowSpan() - 1;
2184 }
2185 }
2186 }
2187 else
2188 {
2189 rFirst.mnCol = 0;
2190 rFirst.mnRow = 0;
2191 if( mxTable.is() )
2192 {
2193 rLast.mnRow = mxTable->getRowCount()-1;
2194 rLast.mnCol = mxTable->getColumnCount()-1;
2195 }
2196 else
2197 {
2198 rLast.mnRow = 0;
2199 rLast.mnCol = 0;
2200 }
2201 }
2202}
2203
2204
2206{
2207 StopTextEdit();
2208 mbCellSelectionMode = true;
2211}
2212
2213
2214void SvxTableController::setSelectedCells( const CellPos& rStart, const CellPos& rEnd )
2215{
2216 StopTextEdit();
2217 mbCellSelectionMode = true;
2218 maCursorFirstPos = rStart;
2219 UpdateSelection( rEnd );
2220}
2221
2222
2223bool SvxTableController::ChangeFontSize(bool bGrow, const FontList* pFontList)
2224{
2225 if(!checkTableObject() || !mxTable.is())
2226 return false;
2227
2228 SdrTableObj& rTableObj(*mxTableObj.get());
2229 SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
2230
2231 if (mrView.IsTextEdit())
2232 return true;
2233
2234 CellPos aStart, aEnd;
2235
2236 if(hasSelectedCells())
2237 {
2238 getSelectedCells(aStart, aEnd);
2239 }
2240 else
2241 {
2242 aStart.mnRow = 0;
2243 aStart.mnCol = 0;
2244 aEnd.mnRow = mxTable->getRowCount() - 1;
2245 aEnd.mnCol = mxTable->getColumnCount() - 1;
2246 }
2247
2248 for (sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++)
2249 {
2250 for (sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++)
2251 {
2252 CellRef xCell(dynamic_cast< Cell* >(mxTable->getCellByPosition(nCol, nRow).get()));
2253 if (xCell.is())
2254 {
2255 if (rModel.IsUndoEnabled())
2256 xCell->AddUndo();
2257
2258 SfxItemSet aCellSet(xCell->GetItemSet());
2259 if (EditView::ChangeFontSize(bGrow, aCellSet, pFontList))
2260 {
2261 xCell->SetMergedItemSetAndBroadcast(aCellSet, false);
2262 }
2263 }
2264 }
2265 }
2266
2268
2269 return true;
2270}
2271
2272
2274{
2275 maCursorLastPos = rPos;
2277}
2278
2279
2281{
2283}
2284
2285
2287{
2288 if( mxTable.is() )
2289 {
2290 CellPos aPos2( mxTable->getColumnCount()-1, mxTable->getRowCount()-1 );
2291 if( (aPos2.mnCol >= 0) && (aPos2.mnRow >= 0) )
2292 {
2293 CellPos aPos1;
2294 setSelectedCells( aPos1, aPos2 );
2295 }
2296 }
2297}
2298
2299
2301{
2303 {
2304 mbCellSelectionMode = false;
2306 }
2307}
2308
2309
2311{
2312 if( mnUpdateEvent == nullptr )
2314}
2315
2316
2318{
2319 // There is no need to update selection overlay after merging cells
2320 // since the selection overlay should remain the same
2321 if ( mbHasJustMerged )
2322 return;
2323
2325 if( !mbCellSelectionMode )
2326 return;
2327
2329 if( !pTableObj )
2330 return;
2331
2333
2334 tools::Rectangle aStartRect, aEndRect;
2335 CellPos aStart,aEnd;
2336 getSelectedCells( aStart, aEnd );
2337 pTableObj->getCellBounds( aStart, aStartRect );
2338
2339 basegfx::B2DRange a2DRange( basegfx::B2DPoint(aStartRect.Left(), aStartRect.Top()) );
2340 a2DRange.expand( basegfx::B2DPoint(aStartRect.Right(), aStartRect.Bottom()) );
2341
2342 findMergeOrigin( aEnd );
2343 pTableObj->getCellBounds( aEnd, aEndRect );
2344 a2DRange.expand( basegfx::B2DPoint(aEndRect.Left(), aEndRect.Top()) );
2345 a2DRange.expand( basegfx::B2DPoint(aEndRect.Right(), aEndRect.Bottom()) );
2346 aRanges.push_back( a2DRange );
2347
2348 ::Color aHighlight( COL_BLUE );
2350 if( pOutDev )
2351 aHighlight = pOutDev->GetSettings().GetStyleSettings().GetHighlightColor();
2352
2353 const sal_uInt32 nCount = mrView.PaintWindowCount();
2354 for( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ )
2355 {
2356 SdrPaintWindow* pPaintWindow = mrView.GetPaintWindow(nIndex);
2357 if( pPaintWindow )
2358 {
2359 const rtl::Reference < sdr::overlay::OverlayManager >& xOverlayManager = pPaintWindow->GetOverlayManager();
2360 if( xOverlayManager.is() )
2361 {
2362 std::unique_ptr<sdr::overlay::OverlayObjectCell> pOverlay(new sdr::overlay::OverlayObjectCell( aHighlight, std::vector(aRanges) ));
2363
2364 xOverlayManager->add(*pOverlay);
2365 mpSelectionOverlay.emplace();
2366 mpSelectionOverlay->append(std::move(pOverlay));
2367 }
2368 }
2369 }
2370
2371 // If tiled rendering, emit callbacks for sdr table selection.
2372 if (!(pOutDev && comphelper::LibreOfficeKit::isActive()))
2373 return;
2374
2375 tools::Rectangle aSelection(a2DRange.getMinX(), a2DRange.getMinY(), a2DRange.getMaxX(), a2DRange.getMaxY());
2376
2377 if (pOutDev->GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
2378 aSelection = o3tl::toTwips(aSelection, o3tl::Length::mm100);
2379
2380 if(SfxViewShell* pViewShell = SfxViewShell::Current())
2381 {
2382 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_SELECTION_AREA, aSelection.toString());
2383 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, aSelection.toString());
2384 }
2385}
2386
2387
2389{
2390 if( !mpSelectionOverlay )
2391 return;
2392
2393 mpSelectionOverlay.reset();
2394
2396 {
2397 // Clear the LOK text selection so far provided by this table.
2398 if(SfxViewShell* pViewShell = SfxViewShell::Current())
2399 {
2400 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_SELECTION_AREA, "EMPTY");
2401 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION_START, "EMPTY");
2402 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION_END, "EMPTY");
2403 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, "EMPTY");
2404 }
2405 }
2406}
2407
2408
2410{
2411 if( !mxTable.is() )
2412 return;
2413
2414 CellPos aStart, aEnd;
2415 const_cast<SvxTableController&>(*this).getSelectedCells( aStart, aEnd );
2416
2417 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
2418 {
2419 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
2420 {
2421 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
2422 if( xCell.is() && !xCell->isMerged() )
2423 {
2424 const SfxItemSet& rSet = xCell->GetItemSet();
2425 SfxWhichIter aIter(rSet);
2426 sal_uInt16 nWhich(aIter.FirstWhich());
2427 while(nWhich)
2428 {
2429 SfxItemState nState = aIter.GetItemState(false);
2430 if(!bOnlyHardAttr)
2431 {
2432 if(SfxItemState::DONTCARE == nState)
2433 rAttr.InvalidateItem(nWhich);
2434 else
2435 rAttr.MergeValue(rSet.Get(nWhich), true);
2436 }
2437 else if(SfxItemState::SET == nState)
2438 {
2439 const SfxPoolItem& rItem = rSet.Get(nWhich);
2440 rAttr.MergeValue(rItem, true);
2441 }
2442
2443 nWhich = aIter.NextWhich();
2444 }
2445 }
2446 }
2447 }
2448}
2449
2450
2451static void ImplSetLinePreserveColor( SvxBoxItem& rNewFrame, const SvxBorderLine* pNew, SvxBoxItemLine nLine )
2452{
2453 if( pNew )
2454 {
2455 const SvxBorderLine* pOld = rNewFrame.GetLine(nLine);
2456 if( pOld )
2457 {
2458 SvxBorderLine aNewLine( *pNew );
2459 aNewLine.SetColor( pOld->GetColor() );
2460 rNewFrame.SetLine( &aNewLine, nLine );
2461 return;
2462 }
2463 }
2464 rNewFrame.SetLine( pNew, nLine );
2465}
2466
2467
2468static void ImplApplyBoxItem( CellPosFlag nCellPosFlags, const SvxBoxItem* pBoxItem, const SvxBoxInfoItem* pBoxInfoItem, SvxBoxItem& rNewFrame )
2469{
2470 if (nCellPosFlags & (CellPosFlag::Before|CellPosFlag::After|CellPosFlag::Upper|CellPosFlag::Lower))
2471 {
2472 // current cell is outside the selection
2473
2474 if (!(nCellPosFlags & (CellPosFlag::Before|CellPosFlag::After))) // check if it's not any corner
2475 {
2476 if (nCellPosFlags & CellPosFlag::Upper)
2477 {
2478 if( pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::TOP) )
2479 rNewFrame.SetLine(nullptr, SvxBoxItemLine::BOTTOM );
2480 }
2481 else if (nCellPosFlags & CellPosFlag::Lower)
2482 {
2483 if( pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::BOTTOM) )
2484 rNewFrame.SetLine( nullptr, SvxBoxItemLine::TOP );
2485 }
2486 }
2487 else if (!(nCellPosFlags & (CellPosFlag::Upper|CellPosFlag::Lower))) // check if it's not any corner
2488 {
2489 if (nCellPosFlags & CellPosFlag::Before)
2490 {
2491 if( pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::LEFT) )
2492 rNewFrame.SetLine( nullptr, SvxBoxItemLine::RIGHT );
2493 }
2494 else if (nCellPosFlags & CellPosFlag::After)
2495 {
2496 if( pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) )
2497 rNewFrame.SetLine( nullptr, SvxBoxItemLine::LEFT );
2498 }
2499 }
2500 }
2501 else
2502 {
2503 // current cell is inside the selection
2504
2505 if ((nCellPosFlags & CellPosFlag::Left) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::LEFT)
2506 : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT))
2507 rNewFrame.SetLine( (nCellPosFlags & CellPosFlag::Left) ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(), SvxBoxItemLine::LEFT );
2508
2509 if( (nCellPosFlags & CellPosFlag::Right) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) )
2510 rNewFrame.SetLine( (nCellPosFlags & CellPosFlag::Right) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(), SvxBoxItemLine::RIGHT );
2511
2512 if( (nCellPosFlags & CellPosFlag::Top) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::TOP) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::HORI) )
2513 rNewFrame.SetLine( (nCellPosFlags & CellPosFlag::Top) ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(), SvxBoxItemLine::TOP );
2514
2515 if( (nCellPosFlags & CellPosFlag::Bottom) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::BOTTOM) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::HORI) )
2516 rNewFrame.SetLine( (nCellPosFlags & CellPosFlag::Bottom) ? pBoxItem->GetBottom() : pBoxInfoItem->GetHori(), SvxBoxItemLine::BOTTOM );
2517
2518 // apply distance to borders
2519 if( pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::DISTANCE ) )
2521 rNewFrame.SetDistance( pBoxItem->GetDistance( nLine ), nLine );
2522 }
2523}
2524
2525
2526static void ImplSetLineColor( SvxBoxItem& rNewFrame, SvxBoxItemLine nLine, const Color& rColor )
2527{
2528 const SvxBorderLine* pSourceLine = rNewFrame.GetLine( nLine );
2529 if( pSourceLine )
2530 {
2531 SvxBorderLine aLine( *pSourceLine );
2532 aLine.SetColor( rColor );
2533 rNewFrame.SetLine( &aLine, nLine );
2534 }
2535}
2536
2537
2538static void ImplApplyLineColorItem( CellPosFlag nCellPosFlags, const SvxColorItem* pLineColorItem, SvxBoxItem& rNewFrame )
2539{
2540 const Color aColor( pLineColorItem->GetValue() );
2541
2542 if (!(nCellPosFlags & (CellPosFlag::Lower|CellPosFlag::Before|CellPosFlag::After)))
2543 ImplSetLineColor( rNewFrame, SvxBoxItemLine::BOTTOM, aColor );
2544
2545 if (!(nCellPosFlags & (CellPosFlag::Upper|CellPosFlag::Before|CellPosFlag::After)))
2546 ImplSetLineColor( rNewFrame, SvxBoxItemLine::TOP, aColor );
2547
2548 if (!(nCellPosFlags & (CellPosFlag::Upper|CellPosFlag::Lower|CellPosFlag::After)))
2549 ImplSetLineColor( rNewFrame, SvxBoxItemLine::RIGHT, aColor );
2550
2551 if (!(nCellPosFlags & (CellPosFlag::Upper|CellPosFlag::Lower|CellPosFlag::Before)))
2552 ImplSetLineColor( rNewFrame, SvxBoxItemLine::LEFT, aColor );
2553}
2554
2555
2556static void ImplApplyBorderLineItem( CellPosFlag nCellPosFlags, const SvxBorderLine* pBorderLineItem, SvxBoxItem& rNewFrame )
2557{
2558 if (nCellPosFlags & (CellPosFlag::Before|CellPosFlag::After|CellPosFlag::Upper|CellPosFlag::Lower))
2559 {
2560 if (!(nCellPosFlags & (CellPosFlag::Before|CellPosFlag::After))) // check if it's not any corner
2561 {
2562 if (nCellPosFlags & CellPosFlag::Upper)
2563 {
2564 if( rNewFrame.GetBottom() )
2565 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, SvxBoxItemLine::BOTTOM );
2566 }
2567 else if (nCellPosFlags & CellPosFlag::Lower)
2568 {
2569 if( rNewFrame.GetTop() )
2570 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, SvxBoxItemLine::TOP );
2571 }
2572 }
2573 else if (!(nCellPosFlags & (CellPosFlag::Upper|CellPosFlag::Lower))) // check if it's not any corner
2574 {
2575 if (nCellPosFlags & CellPosFlag::Before)
2576 {
2577 if( rNewFrame.GetRight() )
2578 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, SvxBoxItemLine::RIGHT );
2579 }
2580 else if (nCellPosFlags & CellPosFlag::After)
2581 {
2582 if( rNewFrame.GetLeft() )
2583 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, SvxBoxItemLine::LEFT );
2584 }
2585 }
2586 }
2587 else
2588 {
2589 if( rNewFrame.GetBottom() )
2590 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, SvxBoxItemLine::BOTTOM );
2591 if( rNewFrame.GetTop() )
2592 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, SvxBoxItemLine::TOP );
2593 if( rNewFrame.GetRight() )
2594 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, SvxBoxItemLine::RIGHT );
2595 if( rNewFrame.GetLeft() )
2596 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, SvxBoxItemLine::LEFT );
2597 }
2598}
2599
2600
2602{
2603 if( !mxTable.is() )
2604 return;
2605
2606 const sal_Int32 nRowCount = mxTable->getRowCount();
2607 const sal_Int32 nColCount = mxTable->getColumnCount();
2608 if( !(nRowCount && nColCount) )
2609 return;
2610
2611 const SvxBoxItem* pBoxItem = nullptr;
2612 if(SfxItemState::SET == rAttr.GetItemState(SDRATTR_TABLE_BORDER, false) )
2613 pBoxItem = &rAttr.Get( SDRATTR_TABLE_BORDER );
2614
2615 const SvxBoxInfoItem* pBoxInfoItem = nullptr;
2616 if(SfxItemState::SET == rAttr.GetItemState(SDRATTR_TABLE_BORDER_INNER, false) )
2617 pBoxInfoItem = &rAttr.Get( SDRATTR_TABLE_BORDER_INNER );
2618
2619 const SvxColorItem* pLineColorItem = nullptr;
2620 if(SfxItemState::SET == rAttr.GetItemState(SID_FRAME_LINECOLOR, false) )
2621 pLineColorItem = &rAttr.Get( SID_FRAME_LINECOLOR );
2622
2623 const SvxBorderLine* pBorderLineItem = nullptr;
2624 if(SfxItemState::SET == rAttr.GetItemState(SID_FRAME_LINESTYLE, false) )
2625 pBorderLineItem = rAttr.Get( SID_FRAME_LINESTYLE ).GetLine();
2626
2627 if( pBoxInfoItem && !pBoxItem )
2628 {
2629 const static SvxBoxItem gaEmptyBoxItem( SDRATTR_TABLE_BORDER );
2630 pBoxItem = &gaEmptyBoxItem;
2631 }
2632 else if( pBoxItem && !pBoxInfoItem )
2633 {
2634 const static SvxBoxInfoItem gaEmptyBoxInfoItem( SDRATTR_TABLE_BORDER_INNER );
2635 pBoxInfoItem = &gaEmptyBoxInfoItem;
2636 }
2637
2638 CellPos aStart, aEnd;
2639 getSelectedCells( aStart, aEnd );
2640
2641 const sal_Int32 nLastRow = std::min( aEnd.mnRow + 2, nRowCount );
2642 const sal_Int32 nLastCol = std::min( aEnd.mnCol + 2, nColCount );
2643
2644 for( sal_Int32 nRow = std::max( aStart.mnRow - 1, sal_Int32(0) ); nRow < nLastRow; nRow++ )
2645 {
2646 CellPosFlag nRowFlags = CellPosFlag::NONE;
2647 nRowFlags |= (nRow == aStart.mnRow) ? CellPosFlag::Top : CellPosFlag::NONE;
2648 nRowFlags |= (nRow == aEnd.mnRow) ? CellPosFlag::Bottom : CellPosFlag::NONE;
2649 nRowFlags |= (nRow < aStart.mnRow) ? CellPosFlag::Upper : CellPosFlag::NONE;
2650 nRowFlags |= (nRow > aEnd.mnRow) ? CellPosFlag::Lower : CellPosFlag::NONE;
2651
2652 for( sal_Int32 nCol = std::max( aStart.mnCol - 1, sal_Int32(0) ); nCol < nLastCol; nCol++ )
2653 {
2654 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
2655 if( !xCell.is() )
2656 continue;
2657
2658 const SfxItemSet& rSet = xCell->GetItemSet();
2659 const SvxBoxItem* pOldOuter = &rSet.Get( SDRATTR_TABLE_BORDER );
2660
2661 SvxBoxItem aNewFrame( *pOldOuter );
2662
2663 CellPosFlag nCellPosFlags = nRowFlags;
2664 nCellPosFlags |= (nCol == aStart.mnCol) ? CellPosFlag::Left : CellPosFlag::NONE;
2665 nCellPosFlags |= (nCol == aEnd.mnCol) ? CellPosFlag::Right : CellPosFlag::NONE;
2666 nCellPosFlags |= (nCol < aStart.mnCol) ? CellPosFlag::Before : CellPosFlag::NONE;
2667 nCellPosFlags |= (nCol > aEnd.mnCol) ? CellPosFlag::After : CellPosFlag::NONE;
2668
2669 if( pBoxItem && pBoxInfoItem )
2670 ImplApplyBoxItem( nCellPosFlags, pBoxItem, pBoxInfoItem, aNewFrame );
2671
2672 if( pLineColorItem )
2673 ImplApplyLineColorItem( nCellPosFlags, pLineColorItem, aNewFrame );
2674
2675 if( pBorderLineItem )
2676 ImplApplyBorderLineItem( nCellPosFlags, pBorderLineItem, aNewFrame );
2677
2678 if (aNewFrame != *pOldOuter)
2679 {
2680 SfxItemSet aAttr(*rSet.GetPool(), rSet.GetRanges());
2681 aAttr.Put(aNewFrame);
2682 xCell->SetMergedItemSetAndBroadcast( aAttr, false );
2683 }
2684 }
2685 }
2686}
2687
2688
2690{
2691 rtl::Reference<SdrObject> pTableObj = mxTableObj.get();
2692 if( pTableObj )
2693 {
2694 pTableObj->ActionChanged();
2695 pTableObj->BroadcastObjectChange();
2696 }
2698}
2699
2700
2701void SvxTableController::SetAttrToSelectedCells(const SfxItemSet& rAttr, bool bReplaceAll)
2702{
2703 if(!checkTableObject() || !mxTable.is())
2704 return;
2705
2706 SdrTableObj& rTableObj(*mxTableObj.get());
2707 SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
2708 const bool bUndo(rModel.IsUndoEnabled());
2709
2710 if( bUndo )
2711 rModel.BegUndo( SvxResId(STR_TABLE_NUMFORMAT) );
2712
2713 CellPos aStart, aEnd;
2714 getSelectedCells( aStart, aEnd );
2715
2716 SfxItemSet aAttr(*rAttr.GetPool(), rAttr.GetRanges());
2717 aAttr.Put(rAttr);
2718
2719 const bool bFrame = (rAttr.GetItemState( SDRATTR_TABLE_BORDER ) == SfxItemState::SET) || (rAttr.GetItemState( SDRATTR_TABLE_BORDER_INNER ) == SfxItemState::SET);
2720
2721 if( bFrame )
2722 {
2725 }
2726
2727 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
2728 {
2729 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
2730 {
2731 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
2732 if( xCell.is() )
2733 {
2734 if( bUndo )
2735 xCell->AddUndo();
2736 xCell->SetMergedItemSetAndBroadcast(aAttr, bReplaceAll);
2737 }
2738 }
2739 }
2740
2741 if( bFrame )
2742 {
2743 ApplyBorderAttr( rAttr );
2744 }
2745
2747
2748 if( bUndo )
2749 rModel.EndUndo();
2750}
2751
2753{
2754 if (!checkTableObject() || !mxTable.is())
2755 return;
2756
2757 // Filter out non-shadow items from rAttr.
2759 aSet.Put(rAttr);
2760
2761 if (!aSet.Count())
2762 {
2763 // If there are no items to be applied on the shape, then don't set anything, it would
2764 // terminate text edit without a good reason, which affects undo/redo.
2765 return;
2766 }
2767
2768 // Set shadow items on the marked shape.
2769 mrView.SetAttrToMarked(aSet, /*bReplaceAll=*/false);
2770}
2771
2772bool SvxTableController::GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const
2773{
2774 if( mxTableObj.get().is() && hasSelectedCells() )
2775 {
2776 MergeAttrFromSelectedCells( rTargetSet, bOnlyHardAttr );
2777
2778 if( mrView.IsTextEdit() )
2779 {
2780 OutlinerView* pTextEditOutlinerView = mrView.GetTextEditOutlinerView();
2781 if(pTextEditOutlinerView)
2782 {
2783 // FALSE= consider InvalidItems not as the default, but as "holes"
2784 rTargetSet.Put(pTextEditOutlinerView->GetAttribs(), false);
2785 }
2786 }
2787
2788 return true;
2789 }
2790 else
2791 {
2792 return false;
2793 }
2794}
2795
2796
2797bool SvxTableController::SetAttributes(const SfxItemSet& rSet, bool bReplaceAll)
2798{
2800 {
2801 SetAttrToSelectedCells( rSet, bReplaceAll );
2802 return true;
2803 }
2804 return false;
2805}
2806
2808{
2810 sdr::table::SdrTableObj* pCurrentSdrTableObj(GetTableObj());
2811
2812 if(nullptr == pCurrentSdrTableObj)
2813 {
2814 return pRetval;
2815 }
2816
2817 if(!mxTableObj.get().is())
2818 {
2819 return pRetval;
2820 }
2821
2822 // get selection and create full selection
2823 CellPos aStart, aEnd;
2824 const CellPos aFullStart, aFullEnd(mxTable->getColumnCount()-1, mxTable->getRowCount()-1);
2825
2826 getSelectedCells(aStart, aEnd);
2827
2828 // compare to see if we have a partial selection
2829 if(aStart != aFullStart || aEnd != aFullEnd)
2830 {
2831 // create full clone
2832 pRetval = SdrObject::Clone(*pCurrentSdrTableObj, rTargetModel);
2833
2834 // limit SdrObject's TableModel to partial selection
2835 pRetval->CropTableModelToSelection(aStart, aEnd);
2836 }
2837
2838 return pRetval;
2839}
2840
2842{
2843 if( mxTableObj.get().is() && (rModel.GetPageCount() >= 1) )
2844 {
2845 const SdrPage* pPastePage = rModel.GetPage(0);
2846 if( pPastePage && pPastePage->GetObjCount() == 1 )
2847 {
2848 SdrTableObj* pPasteTableObj = dynamic_cast< SdrTableObj* >( pPastePage->GetObj(0) );
2849 if( pPasteTableObj )
2850 {
2851 return PasteObject( pPasteTableObj );
2852 }
2853 }
2854 }
2855
2856 return false;
2857}
2858
2859
2860bool SvxTableController::PasteObject( SdrTableObj const * pPasteTableObj )
2861{
2862 if( !pPasteTableObj )
2863 return false;
2864
2865 Reference< XTable > xPasteTable( pPasteTableObj->getTable() );
2866 if( !xPasteTable.is() )
2867 return false;
2868
2869 if( !mxTable.is() )
2870 return false;
2871
2872 sal_Int32 nPasteColumns = xPasteTable->getColumnCount();
2873 sal_Int32 nPasteRows = xPasteTable->getRowCount();
2874
2875 CellPos aStart, aEnd;
2876 getSelectedCells( aStart, aEnd );
2877
2878 if( mrView.IsTextEdit() )
2879 mrView.SdrEndTextEdit(true);
2880
2881 sal_Int32 nColumns = mxTable->getColumnCount();
2882 sal_Int32 nRows = mxTable->getRowCount();
2883
2884 const sal_Int32 nMissing = nPasteRows - ( nRows - aStart.mnRow );
2885 if( nMissing > 0 )
2886 {
2887 Reference< XTableRows > xRows( mxTable->getRows() );
2888 xRows->insertByIndex( nRows, nMissing );
2889 nRows = mxTable->getRowCount();
2890 }
2891
2892 nPasteRows = std::min( nPasteRows, nRows - aStart.mnRow );
2893 nPasteColumns = std::min( nPasteColumns, nColumns - aStart.mnCol );
2894
2895 // copy cell contents
2896 for( sal_Int32 nRow = 0; nRow < nPasteRows; ++nRow )
2897 {
2898 for( sal_Int32 nCol = 0, nTargetCol = aStart.mnCol; nCol < nPasteColumns; ++nCol )
2899 {
2900 CellRef xTargetCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nTargetCol, aStart.mnRow + nRow ).get() ) );
2901 if( xTargetCell.is() && !xTargetCell->isMerged() )
2902 {
2903 CellRef xSourceCell(dynamic_cast<Cell*>(xPasteTable->getCellByPosition(nCol, nRow).get()));
2904 if (xSourceCell.is())
2905 {
2906 xTargetCell->AddUndo();
2907 // Prevent cell span exceeding the pasting range.
2908 if (nColumns < nTargetCol + xSourceCell->getColumnSpan())
2909 xTargetCell->replaceContentAndFormatting(xSourceCell);
2910 else
2911 xTargetCell->cloneFrom(xSourceCell);
2912
2913 nCol += xSourceCell->getColumnSpan() - 1;
2914 nTargetCol += xTargetCell->getColumnSpan();
2915 }
2916 }
2917 }
2918 }
2919
2921
2922 return true;
2923}
2924
2925bool SvxTableController::ApplyFormatPaintBrush( SfxItemSet& rFormatSet, bool bNoCharacterFormats, bool bNoParagraphFormats )
2926{
2928 {
2929 return false;
2930 }
2931
2932 if(!checkTableObject())
2933 return false;
2934
2935 SdrTableObj& rTableObj(*mxTableObj.get());
2936 SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
2937 const bool bUndo(rModel.IsUndoEnabled());
2938
2939 if( bUndo )
2940 rModel.BegUndo(SvxResId(STR_TABLE_NUMFORMAT));
2941
2942 CellPos aStart, aEnd;
2943 getSelectedCells( aStart, aEnd );
2944 const bool bFrame = (rFormatSet.GetItemState( SDRATTR_TABLE_BORDER ) == SfxItemState::SET) || (rFormatSet.GetItemState( SDRATTR_TABLE_BORDER_INNER ) == SfxItemState::SET);
2945
2946 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
2947 {
2948 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
2949 {
2950 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
2951 if( xCell.is() )
2952 {
2953 if (bUndo)
2954 xCell->AddUndo();
2955 SdrText* pText = xCell.get();
2956 SdrObjEditView::ApplyFormatPaintBrushToText( rFormatSet, rTableObj, pText, bNoCharacterFormats, bNoParagraphFormats );
2957 }
2958 }
2959 }
2960
2961 if( bFrame )
2962 {
2963 ApplyBorderAttr( rFormatSet );
2964 }
2965
2967
2968 if( bUndo )
2969 rModel.EndUndo();
2970
2971 return true;
2972}
2973
2974
2975IMPL_LINK_NOARG(SvxTableController, UpdateHdl, void*, void)
2976{
2977 mnUpdateEvent = nullptr;
2978
2979 if( mbCellSelectionMode )
2980 {
2981 CellPos aStart( maCursorFirstPos );
2982 CellPos aEnd( maCursorLastPos );
2983 checkCell(aStart);
2984 checkCell(aEnd);
2985 if( aStart != maCursorFirstPos || aEnd != maCursorLastPos )
2986 {
2987 setSelectedCells( aStart, aEnd );
2988 }
2989 }
2990
2991 updateSelectionOverlay();
2992 mbHasJustMerged = false;
2993}
2994
2995namespace
2996{
2997
2998struct LinesState
2999{
3000 LinesState(SvxBoxItem& rBoxItem_, SvxBoxInfoItem& rBoxInfoItem_)
3001 : rBoxItem(rBoxItem_)
3002 , rBoxInfoItem(rBoxInfoItem_)
3003 , bDistanceIndeterminate(false)
3004 {
3005 aBorderSet.fill(false);
3006 aInnerLineSet.fill(false);
3007 aBorderIndeterminate.fill(false);
3008 aInnerLineIndeterminate.fill(false);
3009 aDistanceSet.fill(false);
3010 aDistance.fill(0);
3011 }
3012
3022};
3023
3024class BoxItemWrapper
3025{
3026public:
3027 BoxItemWrapper(SvxBoxItem& rBoxItem, SvxBoxInfoItem& rBoxInfoItem, SvxBoxItemLine nBorderLine, SvxBoxInfoItemLine nInnerLine, bool bBorder);
3028
3029 const SvxBorderLine* getLine() const;
3030 void setLine(const SvxBorderLine* pLine);
3031
3032private:
3037 const bool m_bBorder;
3038};
3039
3040BoxItemWrapper::BoxItemWrapper(
3042 const SvxBoxItemLine nBorderLine, const SvxBoxInfoItemLine nInnerLine, const bool bBorder)
3045 , m_nBorderLine(nBorderLine)
3046 , m_nInnerLine(nInnerLine)
3047 , m_bBorder(bBorder)
3048{
3049}
3050
3051const SvxBorderLine* BoxItemWrapper::getLine() const
3052{
3053 if (m_bBorder)
3055 else
3056 return (m_nInnerLine == SvxBoxInfoItemLine::HORI) ? m_rBoxInfoItem.GetHori() : m_rBoxInfoItem.GetVert();
3057}
3058
3059void BoxItemWrapper::setLine(const SvxBorderLine* pLine)
3060{
3061 if (m_bBorder)
3063 else
3065}
3066
3067void lcl_MergeBorderLine(
3068 LinesState& rLinesState, const SvxBorderLine* const pLine, const SvxBoxItemLine nLine,
3069 SvxBoxInfoItemValidFlags nValidFlag, const bool bBorder = true)
3070{
3071 const SvxBoxInfoItemLine nInnerLine(bBorder ? SvxBoxInfoItemLine::HORI : ((nValidFlag & SvxBoxInfoItemValidFlags::HORI) ? SvxBoxInfoItemLine::HORI : SvxBoxInfoItemLine::VERT));
3072 BoxItemWrapper aBoxItem(rLinesState.rBoxItem, rLinesState.rBoxInfoItem, nLine, nInnerLine, bBorder);
3073 bool& rbSet(bBorder ? rLinesState.aBorderSet[nLine] : rLinesState.aInnerLineSet[nInnerLine]);
3074
3075 if (rbSet)
3076 {
3077 bool& rbIndeterminate(bBorder ? rLinesState.aBorderIndeterminate[nLine] : rLinesState.aInnerLineIndeterminate[nInnerLine]);
3078 if (!rbIndeterminate)
3079 {
3080 const SvxBorderLine* const pMergedLine(aBoxItem.getLine());
3081 if ((pLine && !pMergedLine) || (!pLine && pMergedLine) || (pLine && (*pLine != *pMergedLine)))
3082 {
3083 aBoxItem.setLine(nullptr);
3084 rbIndeterminate = true;
3085 }
3086 }
3087 }
3088 else
3089 {
3090 aBoxItem.setLine(pLine);
3091 rbSet = true;
3092 }
3093}
3094
3095void lcl_MergeBorderOrInnerLine(
3096 LinesState& rLinesState, const SvxBorderLine* const pLine, const SvxBoxItemLine nLine,
3097 SvxBoxInfoItemValidFlags nValidFlag, const bool bBorder)
3098{
3099 if (bBorder)
3100 lcl_MergeBorderLine(rLinesState, pLine, nLine, nValidFlag);
3101 else
3102 {
3103 const bool bVertical = (nLine == SvxBoxItemLine::LEFT) || (nLine == SvxBoxItemLine::RIGHT);
3104 lcl_MergeBorderLine(rLinesState, pLine, nLine, bVertical ? SvxBoxInfoItemValidFlags::VERT : SvxBoxInfoItemValidFlags::HORI, false);
3105 }
3106}
3107
3108void lcl_MergeDistance(
3109 LinesState& rLinesState, const SvxBoxItemLine nIndex, const sal_uInt16 nDistance)
3110{
3111 if (rLinesState.aDistanceSet[nIndex])
3112 {
3113 if (!rLinesState.bDistanceIndeterminate)
3114 rLinesState.bDistanceIndeterminate = nDistance != rLinesState.aDistance[nIndex];
3115 }
3116 else
3117 {
3118 rLinesState.aDistance[nIndex] = nDistance;
3119 rLinesState.aDistanceSet[nIndex] = true;
3120 }
3121}
3122
3123void lcl_MergeCommonBorderAttr(LinesState& rLinesState, const SvxBoxItem& rCellBoxItem, const CellPosFlag nCellPosFlags)
3124{
3125 if (nCellPosFlags & (CellPosFlag::Before|CellPosFlag::After|CellPosFlag::Upper|CellPosFlag::Lower))
3126 {
3127 // current cell is outside the selection
3128
3129 if (!(nCellPosFlags & (CellPosFlag::Before|CellPosFlag::After))) // check if it's not any corner
3130 {
3131 if (nCellPosFlags & CellPosFlag::Upper)
3132 lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetBottom(), SvxBoxItemLine::TOP, SvxBoxInfoItemValidFlags::TOP);
3133 else if (nCellPosFlags & CellPosFlag::Lower)
3134 lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetTop(), SvxBoxItemLine::BOTTOM, SvxBoxInfoItemValidFlags::BOTTOM);
3135 }
3136 else if (!(nCellPosFlags & (CellPosFlag::Upper|CellPosFlag::Lower))) // check if it's not any corner
3137 {
3138 if (nCellPosFlags & CellPosFlag::Before)
3139 lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetRight(), SvxBoxItemLine::LEFT, SvxBoxInfoItemValidFlags::LEFT);
3140 else if (nCellPosFlags & CellPosFlag::After)
3141 lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetLeft(), SvxBoxItemLine::RIGHT, SvxBoxInfoItemValidFlags::RIGHT);
3142 }
3143
3144 // NOTE: inner distances for cells outside the selected range
3145 // are not relevant -> we ignore them.
3146 }
3147 else
3148 {
3149 // current cell is inside the selection
3150
3151 lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetTop(), SvxBoxItemLine::TOP, SvxBoxInfoItemValidFlags::TOP, static_cast<bool>(nCellPosFlags & CellPosFlag::Top));
3152 lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetBottom(), SvxBoxItemLine::BOTTOM, SvxBoxInfoItemValidFlags::BOTTOM, static_cast<bool>(nCellPosFlags & CellPosFlag::Bottom));
3153 lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetLeft(), SvxBoxItemLine::LEFT, SvxBoxInfoItemValidFlags::LEFT, static_cast<bool>(nCellPosFlags & CellPosFlag::Left));
3154 lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetRight(), SvxBoxItemLine::RIGHT, SvxBoxInfoItemValidFlags::RIGHT, static_cast<bool>(nCellPosFlags & CellPosFlag::Right));
3155
3156 lcl_MergeDistance(rLinesState, SvxBoxItemLine::TOP, rCellBoxItem.GetDistance(SvxBoxItemLine::TOP));
3157 lcl_MergeDistance(rLinesState, SvxBoxItemLine::BOTTOM, rCellBoxItem.GetDistance(SvxBoxItemLine::BOTTOM));
3158 lcl_MergeDistance(rLinesState, SvxBoxItemLine::LEFT, rCellBoxItem.GetDistance(SvxBoxItemLine::LEFT));
3159 lcl_MergeDistance(rLinesState, SvxBoxItemLine::RIGHT, rCellBoxItem.GetDistance(SvxBoxItemLine::RIGHT));
3160 }
3161}
3162
3163}
3164
3165void SvxTableController::FillCommonBorderAttrFromSelectedCells( SvxBoxItem& rBoxItem, SvxBoxInfoItem& rBoxInfoItem ) const
3166{
3167 if( !mxTable.is() )
3168 return;
3169
3170 const sal_Int32 nRowCount = mxTable->getRowCount();
3171 const sal_Int32 nColCount = mxTable->getColumnCount();
3172 if( !(nRowCount && nColCount) )
3173 return;
3174
3175 CellPos aStart, aEnd;
3176 const_cast< SvxTableController* >( this )->getSelectedCells( aStart, aEnd );
3177
3178 // We are adding one more row/column around the block of selected cells.
3179 // We will be checking the adjoining border of these too.
3180 const sal_Int32 nLastRow = std::min( aEnd.mnRow + 2, nRowCount );
3181 const sal_Int32 nLastCol = std::min( aEnd.mnCol + 2, nColCount );
3182
3183 rBoxInfoItem.SetValid( SvxBoxInfoItemValidFlags::ALL, false );
3184 LinesState aLinesState( rBoxItem, rBoxInfoItem );
3185
3186 /* Here we go through all the selected cells (enhanced by
3187 * the adjoining row/column on each side) and determine the
3188 * lines for presentation. The algorithm is simple:
3189 * 1. if a border or inner line is set (or unset) in all
3190 * cells to the same value, it will be used.
3191 * 2. if a border or inner line is set only in some cells,
3192 * it will be set to indeterminate state (SetValid() on
3193 * rBoxInfoItem).
3194 */
3195 for( sal_Int32 nRow = std::max( aStart.mnRow - 1, sal_Int32(0) ); nRow < nLastRow; nRow++ )
3196 {
3197 CellPosFlag nRowFlags = CellPosFlag::NONE;
3198 nRowFlags |= (nRow == aStart.mnRow) ? CellPosFlag::Top : CellPosFlag::NONE;
3199 nRowFlags |= (nRow == aEnd.mnRow) ? CellPosFlag::Bottom : CellPosFlag::NONE;
3200 nRowFlags |= (nRow < aStart.mnRow) ? CellPosFlag::Upper : CellPosFlag::NONE;
3201 nRowFlags |= (nRow > aEnd.mnRow) ? CellPosFlag::Lower : CellPosFlag::NONE;
3202
3203 for( sal_Int32 nCol = std::max( aStart.mnCol - 1, sal_Int32(0) ); nCol < nLastCol; nCol++ )
3204 {
3205 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
3206 if( !xCell.is() )
3207 continue;
3208
3209 CellPosFlag nCellPosFlags = nRowFlags;
3210 nCellPosFlags |= (nCol == aStart.mnCol) ? CellPosFlag::Left : CellPosFlag::NONE;
3211 nCellPosFlags |= (nCol == aEnd.mnCol) ? CellPosFlag::Right : CellPosFlag::NONE;
3212 nCellPosFlags |= (nCol < aStart.mnCol) ? CellPosFlag::Before : CellPosFlag::NONE;
3213 nCellPosFlags |= (nCol > aEnd.mnCol) ? CellPosFlag::After : CellPosFlag::NONE;
3214
3215 const SfxItemSet& rSet = xCell->GetItemSet();
3217 lcl_MergeCommonBorderAttr( aLinesState, aCellBoxItem, nCellPosFlags );
3218 }
3219 }
3220
3221 if (!aLinesState.aBorderIndeterminate[SvxBoxItemLine::TOP])
3222 aLinesState.rBoxInfoItem.SetValid(SvxBoxInfoItemValidFlags::TOP);
3223 if (!aLinesState.aBorderIndeterminate[SvxBoxItemLine::BOTTOM])
3224 aLinesState.rBoxInfoItem.SetValid(SvxBoxInfoItemValidFlags::BOTTOM);
3225 if (!aLinesState.aBorderIndeterminate[SvxBoxItemLine::LEFT])
3226 aLinesState.rBoxInfoItem.SetValid(SvxBoxInfoItemValidFlags::LEFT);
3227 if (!aLinesState.aBorderIndeterminate[SvxBoxItemLine::RIGHT])
3228 aLinesState.rBoxInfoItem.SetValid(SvxBoxInfoItemValidFlags::RIGHT);
3229 if (!aLinesState.aInnerLineIndeterminate[SvxBoxInfoItemLine::HORI])
3230 aLinesState.rBoxInfoItem.SetValid(SvxBoxInfoItemValidFlags::HORI);
3231 if (!aLinesState.aInnerLineIndeterminate[SvxBoxInfoItemLine::VERT])
3232 aLinesState.rBoxInfoItem.SetValid(SvxBoxInfoItemValidFlags::VERT);
3233
3234 if (!aLinesState.bDistanceIndeterminate)
3235 {
3236 if (aLinesState.aDistanceSet[SvxBoxItemLine::TOP])
3237 aLinesState.rBoxItem.SetDistance(aLinesState.aDistance[SvxBoxItemLine::TOP], SvxBoxItemLine::TOP);
3238 if (aLinesState.aDistanceSet[SvxBoxItemLine::BOTTOM])
3239 aLinesState.rBoxItem.SetDistance(aLinesState.aDistance[SvxBoxItemLine::BOTTOM], SvxBoxItemLine::BOTTOM);
3240 if (aLinesState.aDistanceSet[SvxBoxItemLine::LEFT])
3241 aLinesState.rBoxItem.SetDistance(aLinesState.aDistance[SvxBoxItemLine::LEFT], SvxBoxItemLine::LEFT);
3242 if (aLinesState.aDistanceSet[SvxBoxItemLine::RIGHT])
3243 aLinesState.rBoxItem.SetDistance(aLinesState.aDistance[SvxBoxItemLine::RIGHT], SvxBoxItemLine::RIGHT);
3244 aLinesState.rBoxInfoItem.SetValid(SvxBoxInfoItemValidFlags::DISTANCE);
3245 }
3246}
3247
3249{
3250 if( !mxTable.is() )
3251 return false;
3252 CellPos aStart( 0, row ), aEnd( mxTable->getColumnCount() - 1, row );
3253 StartSelection( aEnd );
3254 gotoCell( aStart, true, nullptr );
3255 return true;
3256}
3257
3258bool SvxTableController::selectColumn( sal_Int32 column )
3259{
3260 if( !mxTable.is() )
3261 return false;
3262 CellPos aStart( column, 0 ), aEnd( column, mxTable->getRowCount() - 1 );
3263 StartSelection( aEnd );
3264 gotoCell( aStart, true, nullptr );
3265 return true;
3266}
3267
3269{
3270 if( !mxTable.is() )
3271 return false;
3272 CellPos aStart( 0, row ), aEnd( mxTable->getColumnCount() - 1, row );
3273 StartSelection( aEnd );
3274 gotoCell( aStart, false, nullptr );
3275 return true;
3276}
3277
3279{
3280 if( !mxTable.is() )
3281 return false;
3282 CellPos aStart( column, 0 ), aEnd( column, mxTable->getRowCount() - 1 );
3283 StartSelection( aEnd );
3284 gotoCell( aStart, false, nullptr );
3285 return true;
3286}
3287
3289{
3290 if( hasSelectedCells() )
3291 {
3292 CellPos aFirstPos, aLastPos;
3293 getSelectedCells( aFirstPos, aLastPos );
3294 if( (aFirstPos.mnCol == 0) && (nRow >= aFirstPos.mnRow && nRow <= aLastPos.mnRow) && (mxTable->getColumnCount() - 1 == aLastPos.mnCol) )
3295 return true;
3296 }
3297 return false;
3298}
3299
3301{
3302 if( hasSelectedCells() )
3303 {
3304 CellPos aFirstPos, aLastPos;
3305 getSelectedCells( aFirstPos, aLastPos );
3306 if( (aFirstPos.mnRow == 0) && (nColumn >= aFirstPos.mnCol && nColumn <= aLastPos.mnCol) && (mxTable->getRowCount() - 1 == aLastPos.mnRow) )
3307 return true;
3308 }
3309 return false;
3310}
3311
3313{
3314 if(!checkTableObject())
3315 return false;
3316
3317 SdrTableObj& rTableObj(*mxTableObj.get());
3318 TableStyleSettings aSettings(rTableObj.getTableStyleSettings());
3319
3320 return aSettings.mbUseFirstRow;
3321}
3322
3324{
3325 if(!checkTableObject())
3326 return false;
3327
3328 SdrTableObj& rTableObj(*mxTableObj.get());
3329 TableStyleSettings aSettings(rTableObj.getTableStyleSettings());
3330
3331 return aSettings.mbUseFirstColumn;
3332}
3333
3334bool SvxTableController::setCursorLogicPosition(const Point& rPosition, bool bPoint)
3335{
3336 rtl::Reference<SdrTableObj> pTableObj = mxTableObj.get();
3337 if (pTableObj->GetObjIdentifier() != SdrObjKind::Table)
3338 return false;
3339
3340 CellPos aCellPos;
3341 if (pTableObj->CheckTableHit(rPosition, aCellPos.mnCol, aCellPos.mnRow) != TableHitKind::NONE)
3342 {
3343 // Position is a table cell.
3345 {
3346 // We have a table selection already: adjust the point or the mark.
3347 if (bPoint)
3349 else
3351 return true;
3352 }
3353 else if (aCellPos != maMouseDownPos)
3354 {
3355 // No selection, but rPosition is at another cell: start table selection.
3357 // Update graphic selection, should be hidden now.
3359 }
3360 }
3361
3362 return false;
3363}
3364
3365}
3366
3367/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OptionalString sType
SlideSorterView & mrView
constexpr auto convertTwipToMm100(N n)
SvxBoxInfoItemValidFlags
SvxBoxItemLine
SvxBoxInfoItemLine
const StyleSettings & GetStyleSettings() const
static ImplSVEvent * PostUserEvent(const Link< void *, void > &rLink, void *pCaller=nullptr, bool bReferenceLink=false)
static void RemoveUserEvent(ImplSVEvent *nUserEvent)
sal_uInt16 GetValue() const
const OUString & GetValue() const
void ChangeFontSize(bool bGrow, const FontList *pList)
const vcl::KeyCode & GetKeyCode() const
MapUnit GetMapUnit() const
sal_uInt16 GetClicks() const
bool IsRight() const
const Point & GetPosPixel() const
bool IsLeft() const
void SetSelection(const ESelection &)
ESelection GetSelection() const
bool PostKeyEvent(const KeyEvent &rKEvt, vcl::Window const *pFrameWin=nullptr)
SfxItemSet GetAttribs()
OUString GetText(Paragraph const *pPara, sal_Int32 nParaCount=1) const
Paragraph * GetParagraph(sal_Int32 nAbsPos) const
sal_Int32 GetParagraphCount() const
const MapMode & GetMapMode() const
const AllSettings & GetSettings() const
void SetEditMode(SdrViewEditMode eMode)
Definition: svdcrtv.hxx:89
void SetCurrentObj(SdrObjKind nIdent, SdrInventor nInvent=SdrInventor::Default)
Definition: svdcrtv.cxx:334
void SetAttrToMarked(const SfxItemSet &rAttr, bool bReplaceAll)
Definition: svdedtv1.cxx:1063
void DeleteMarkedObj()
Definition: svdedtv.cxx:794
size_t GetMarkCount() const
Definition: svdmark.hxx:178
SdrMark * GetMark(size_t nNum) const
Definition: svdmark.cxx:230
SdrHdl * PickHandle(const Point &rPnt) const
Definition: svdmrkv.cxx:1933
const SdrMarkList & GetMarkedObjectList() const
Definition: svdmrkv.hxx:258
void AdjustMarkHdl(SfxViewShell *pOtherShell=nullptr)
Definition: svdmrkv.cxx:2614
SdrObject * GetMarkedSdrObj() const
Definition: svdmark.hxx:68
void BegUndo()
Definition: svdmodel.cxx:382
void AddUndo(std::unique_ptr< SdrUndoAction > pUndo)
Definition: svdmodel.cxx:516
virtual bool IsReadOnly() const
Definition: svdmodel.cxx:263
const SfxItemPool & GetItemPool() const
Definition: svdmodel.hxx:318
SdrUndoFactory & GetSdrUndoFactory() const
returns the models undo factory.
Definition: svdmodel.cxx:1915
css::uno::Reference< css::uno::XInterface > const & getUnoModel()
Definition: svdmodel.cxx:1575
bool IsUndoEnabled() const
returns true if undo is currently enabled This returns false if undo was disabled using EnableUndo( f...
Definition: svdmodel.cxx:547
const SdrPage * GetPage(sal_uInt16 nPgNum) const
Definition: svdmodel.cxx:1860
sal_uInt16 GetPageCount() const
Definition: svdmodel.cxx:1870
void EndUndo()
Definition: svdmodel.cxx:453
SdrTextObj * GetTextEditObject() const
Definition: svdedxv.hxx:234
virtual SdrEndTextEditKind SdrEndTextEdit(bool bDontDeleteReally=false)
Definition: svdedxv.cxx:1565
const OutlinerView * GetTextEditOutlinerView() const
Definition: svdedxv.hxx:252
static void ApplyFormatPaintBrushToText(SfxItemSet const &rFormatSet, SdrTextObj &rTextObj, SdrText *pText, bool bNoCharacterFormats, bool bNoParagraphFormats)
helper function for selections with multiple SdrText for one SdrTextObj (f.e.
Definition: svdedxv.cxx:2865
virtual bool IsTextEdit() const final override
Definition: svdedxv.cxx:1833
virtual void MarkListHasChanged() override
Definition: svdedxv.cxx:2647
virtual bool SdrBeginTextEdit(SdrObject *pObj, SdrPageView *pPV=nullptr, vcl::Window *pWin=nullptr, bool bIsNewObj=false, SdrOutliner *pGivenOutliner=nullptr, OutlinerView *pGivenOutlinerView=nullptr, bool bDontDeleteOutliner=false, bool bOnlyOneView=false, bool bGrabFocus=true)
Definition: svdedxv.cxx:1224
const SdrOutliner * GetTextEditOutliner() const
Definition: svdedxv.hxx:244
SdrObject * GetObj(size_t nNum) const
Definition: svdpage.cxx:785
size_t GetObjCount() const
Definition: svdpage.cxx:779
SdrObjUserCall * GetUserCall() const
Definition: svdobj.hxx:837
static rtl::Reference< T > Clone(T const &rObj, SdrModel &rTargetModel)
Definition: svdobj.hxx:449
SdrModel & getSdrModelFromSdrObject() const
Definition: svdobj.cxx:289
void SendUserCall(SdrUserCallType eUserCall, const tools::Rectangle &rBoundRect) const
Definition: svdobj.cxx:2763
virtual const tools::Rectangle & GetLastBoundRect() const
Definition: svdobj.cxx:977
SdrPage * getSdrPageFromSdrObject() const
Definition: svdobj.cxx:279
const SfxItemSet & GetMergedItemSet() const
Definition: svdobj.cxx:1974
SdrPage * GetPage() const
Definition: svdpagv.hxx:166
A SdrPage contains exactly one SdrObjList and a description of the physical page dimensions (size / m...
Definition: svdpage.hxx:379
SdrPaintWindow * GetPaintWindow(sal_uInt32 nIndex) const
Definition: svdpntv.cxx:75
OutputDevice * GetFirstOutputDevice() const
Definition: svdpntv.cxx:91
sal_uInt32 PaintWindowCount() const
Definition: svdpntv.hxx:241
SdrPageView * GetSdrPageView() const
Definition: svdpntv.hxx:323
rtl::Reference< sdr::overlay::OverlayManager > const & GetOverlayManager() const
virtual std::unique_ptr< SdrUndoAction > CreateUndoAttrObject(SdrObject &rObject, bool bStyleSheet1=false, bool bSaveText=false)
Definition: svdundo.cxx:1679
virtual std::unique_ptr< SdrUndoAction > CreateUndoGeoObject(SdrObject &rObject)
Definition: svdundo.cxx:1668
Changing the geometry of an object.
Definition: svdundo.hxx:213
void SetSkipChangeLayout(bool bOn)
Definition: svdundo.hxx:229
SdrHitKind PickAnything(const MouseEvent &rMEvt, SdrMouseEventKind nMouseDownOrMoveOrUp, SdrViewEvent &rVEvt) const
Definition: svdview.cxx:249
bool GetValue() const
const WhichRangesContainer & GetRanges() const
SfxItemPool * GetPool() const
sal_uInt16 Count() const
const T * GetItemIfSet(TypedWhichId< T > nWhich, bool bSrchInParent=true) const
sal_uInt16 ClearItem(sal_uInt16 nWhich=0)
void MergeValue(const SfxPoolItem &rItem, bool bOverwriteDefaults=false)
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
void DisableItem(sal_uInt16 nWhich)
void InvalidateItem(sal_uInt16 nWhich)
sal_uInt16 GetSlot() const
const SfxItemSet * GetArgs() const
const T * GetArg(sal_uInt16 nSlotId) const
weld::Window * GetFrameWeld() const
SfxStyleFamily GetFamily() const
virtual SfxItemSet & GetItemSet()
static SAL_WARN_UNUSED_RESULT SfxViewShell * Current()
sal_uInt16 FirstWhich()
SfxItemState GetItemState(bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
sal_uInt16 NextWhich()
const Color & GetHighlightColor() const
virtual VclPtr< SvxAbstractSplitTableDialog > CreateSvxSplitTableDialog(weld::Window *pParent, bool bIsTableVertical, tools::Long nMaxVertical)=0
virtual VclPtr< SfxAbstractTabDialog > CreateSvxFormatCellsDialog(weld::Window *pParent, const SfxItemSet &rAttr, const SdrModel &rModel, bool bStyle)=0
static SvxAbstractDialogFactory * Create()
Definition: svxdlg.cxx:22
bool IsValid(SvxBoxInfoItemValidFlags nValid) const
const editeng::SvxBorderLine * GetHori() const
const editeng::SvxBorderLine * GetVert() const
void SetValid(SvxBoxInfoItemValidFlags nValid, bool bValid=true)
void SetLine(const editeng::SvxBorderLine *pNew, SvxBoxInfoItemLine nLine)
const editeng::SvxBorderLine * GetTop() const
const editeng::SvxBorderLine * GetLine(SvxBoxItemLine nLine) const
const editeng::SvxBorderLine * GetRight() const
void SetLine(const editeng::SvxBorderLine *pNew, SvxBoxItemLine nLine)
const editeng::SvxBorderLine * GetLeft() const
sal_Int16 GetDistance(SvxBoxItemLine nLine, bool bAllowNegative=false) const
void SetDistance(sal_Int16 nNew, SvxBoxItemLine nLine)
const editeng::SvxBorderLine * GetBottom() const
const Color & GetValue() const
void release() const
TYPE getMaxX() const
TYPE getMinX() const
TYPE getMinY() const
void expand(const Tuple2D< TYPE > &rTuple)
TYPE getMaxY() const
::std::vector< basegfx::B2DRange > RangeVector
bool IsTextEditActive() const
Definition: svdotable.hxx:180
void setTableStyleSettings(const sdr::table::TableStyleSettings &rStyle)
Definition: svdotable.cxx:1150
virtual OutlinerParaObject * GetOutlinerParaObject() const override
Definition: svdotable.cxx:1862
void changeEdge(bool bHorizontal, int nEdge, sal_Int32 nOffset)
Definition: svdotable.cxx:1575
sal_Int32 getColumnCount() const
Definition: svdotable.cxx:1565
const sdr::table::TableStyleSettings & getTableStyleSettings() const
Definition: svdotable.cxx:1136
static CellPos getFirstCell()
Definition: svdotable.cxx:922
sal_Int32 getRowCount() const
Definition: svdotable.cxx:1570
css::text::WritingMode GetWritingMode() const
Definition: svdotable.cxx:1998
void getActiveCellPos(sdr::table::CellPos &rPos) const
Definition: svdotable.cxx:1608
void DistributeColumns(sal_Int32 nFirstColumn, sal_Int32 nLastColumn, const bool bOptimize, const bool bMinimize)
Definition: svdotable.cxx:2387
virtual bool IsVerticalWriting() const override
Definition: svdotable.cxx:1981
void setTableStyle(const css::uno::Reference< css::container::XIndexAccess > &xAutoFormatStyle)
Definition: svdotable.cxx:1280
css::uno::Reference< css::table::XTable > getTable() const
Definition: svdotable.cxx:910
void setActiveCell(const sdr::table::CellPos &rPos)
Definition: svdotable.cxx:1581
virtual void SetChanged() override
Definition: svdotable.cxx:2411
void DistributeRows(sal_Int32 nFirstRow, sal_Int32 nLastRow, const bool bOptimize, const bool bMinimize)
Definition: svdotable.cxx:2399
virtual bool ChangeFontSize(bool bGrow, const FontList *pFontList) override
Changes the font (grow/shrink) according to the input parameters.
SVX_DLLPRIVATE void DistributeColumns(const bool bOptimize, const bool bMinimize)
virtual SVX_DLLPRIVATE ~SvxTableController() override
SVX_DLLPRIVATE void SetTableStyleSettings(const SfxItemSet *pArgs)
bool deselectColumn(sal_Int32 column)
virtual SVX_DLLPRIVATE bool PasteObjModel(const SdrModel &rModel) override
SVX_DLLPRIVATE void destroySelectionOverlay()
void SetAttrToSelectedShape(const SfxItemSet &rAttr)
SVX_DLLPRIVATE void FillCommonBorderAttrFromSelectedCells(SvxBoxItem &rBox, SvxBoxInfoItem &rBoxInfo) const
Fill the values that are common for all selected cells.
virtual SVX_DLLPRIVATE bool ApplyFormatPaintBrush(SfxItemSet &rFormatSet, bool bNoCharacterFormats, bool bNoParagraphFormats) override
applies a format paint brush set from the current selection.
SVX_DLLPRIVATE void onFormatTable(const SfxRequest &rReq)
SVX_DLLPRIVATE void SetTableStyle(const SfxItemSet *pArgs)
virtual SVX_DLLPRIVATE void onSelectAll() override
virtual SVX_DLLPRIVATE rtl::Reference< SdrObject > GetMarkedSdrObjClone(SdrModel &rTargetModel) override
SVX_DLLPRIVATE TblAction getKeyboardAction(const KeyEvent &rKEvt)
SVX_DLLPRIVATE void SetAttrToSelectedCells(const SfxItemSet &rAttr, bool bReplaceAll)
SVX_DLLPRIVATE void findMergeOrigin(CellPos &rPos)
SVX_DLLPRIVATE void UpdateSelection(const CellPos &rPos)
SVX_DLLPRIVATE void changeTableEdge(const SfxRequest &rReq)
virtual SVX_DLLPRIVATE bool DeleteMarked() override
SVX_DLLPRIVATE void StopTextEdit()
SVX_DLLPRIVATE void MergeRange(sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow)
static SVX_DLLPRIVATE rtl::Reference< sdr::SelectionController > create(SdrView &rView, const SdrTableObj &rObj, const rtl::Reference< sdr::SelectionController > &xRefController)
SVX_DLLPRIVATE void EditCell(const CellPos &rPos, vcl::Window *pWindow, TblAction nAction)
void getSelectedCells(CellPos &rFirstPos, CellPos &rLastPos) override
bool isColumnSelected(sal_Int32 nColumn)
SVX_DLLPRIVATE void onDelete(sal_uInt16 nSId)
sdr::table::SdrTableObj * GetTableObj()
virtual SVX_DLLPRIVATE bool SetAttributes(const SfxItemSet &rSet, bool bReplaceAll) override
SVX_DLLPRIVATE const CellPos & getSelectionStart()
virtual SVX_DLLPRIVATE bool onMouseButtonDown(const MouseEvent &rMEvt, vcl::Window *pWin) override
static SvxBoxItem TextDistancesToSvxBoxItem(const SfxItemSet &rAttrSet)
SVX_DLLPRIVATE void UpdateTableShape()
SVX_DLLPRIVATE void gotoCell(const CellPos &rCell, bool bSelect, vcl::Window *pWindow, TblAction nAction=TblAction::NONE)
std::optional< sdr::overlay::OverlayObjectList > mpSelectionOverlay
SVX_DLLPRIVATE void StartSelection(const CellPos &rPos)
static void SvxBoxItemToTextDistances(const SvxBoxItem &pOriginalItem, SfxItemSet &rAttrSet)
virtual SVX_DLLPRIVATE void onSelectionHasChanged() override
virtual SVX_DLLPRIVATE bool setCursorLogicPosition(const Point &rPosition, bool bPoint) override
css::uno::Reference< css::util::XModifyListener > mxModifyListener
SVX_DLLPRIVATE void setSelectionStart(const CellPos &rPos)
virtual SVX_DLLPRIVATE bool onMouseMove(const MouseEvent &rMEvt, vcl::Window *pWin) override
SVX_DLLPRIVATE void ApplyBorderAttr(const SfxItemSet &rAttr)
SVX_DLLPRIVATE void onSelect(sal_uInt16 nSId)
rtl::Reference< TableModel > mxTable
SVX_DLLPRIVATE void checkCell(CellPos &rPos) const
virtual SVX_DLLPRIVATE bool GetStyleSheet(SfxStyleSheet *&rpStyleSheet) const override
unotools::WeakReference< SdrTableObj > mxTableObj
SVX_DLLPRIVATE void updateSelectionOverlay()
SVX_DLLPRIVATE void SplitMarkedCells(const SfxRequest &rReq)
virtual SVX_DLLPRIVATE bool onMouseButtonUp(const MouseEvent &rMEvt, vcl::Window *pWin) override
virtual SVX_DLLPRIVATE bool onKeyInput(const KeyEvent &rKEvt, vcl::Window *pWin) override
bool selectColumn(sal_Int32 column)
SVX_DLLPRIVATE SvxTableController(SdrView &rView, const SdrTableObj &rObj)
SVX_DLLPRIVATE bool executeAction(TblAction nAction, bool bSelect, vcl::Window *pWindow)
SVX_DLLPRIVATE bool checkTableObject()
SVX_DLLPRIVATE bool HasMarked() const
SVX_DLLPRIVATE bool PasteObject(SdrTableObj const *pPasteTableObj)
SVX_DLLPRIVATE void MergeMarkedCells()
SVX_DLLPRIVATE void DistributeRows(const bool bOptimize, const bool bMinimize)
virtual SVX_DLLPRIVATE bool hasSelectedCells() const override
This is a table object, and one or more of its cells are selected.
SVX_DLLPRIVATE void onInsert(sal_uInt16 nSId, const SfxItemSet *pArgs=nullptr)
void setSelectedCells(const CellPos &rFirstPos, const CellPos &rLastPos)
SVX_DLLPRIVATE void RemoveSelection()
virtual void Execute(SfxRequest &rReq) override
SVX_DLLPRIVATE void onTableModified()
SVX_DLLPRIVATE const CellPos & getSelectionEnd()
SVX_DLLPRIVATE void SetVertical(sal_uInt16 nSId)
bool isRowSelected(sal_Int32 nRow)
SVX_DLLPRIVATE void MergeAttrFromSelectedCells(SfxItemSet &rAttr, bool bOnlyHardAttr) const
virtual SVX_DLLPRIVATE void GetState(SfxItemSet &rSet) override
virtual SVX_DLLPRIVATE bool SetStyleSheet(SfxStyleSheet *pStyleSheet, bool bDontRemoveHardAttr) override
virtual SVX_DLLPRIVATE bool GetAttributes(SfxItemSet &rTargetSet, bool bOnlyHardAttr) const override
constexpr tools::Long Top() const
constexpr tools::Long Right() const
constexpr tools::Long Left() const
constexpr tools::Long Bottom() const
rtl::OString toString() const
bool IsMod1() const
sal_uInt16 GetCode() const
bool IsShift() const
bool IsMod2() const
Point PixelToLogic(const Point &rDevicePt) const
constexpr ::Color COL_BLUE(0x00, 0x00, 0x80)
int nCount
#define TOOLS_WARN_EXCEPTION(area, stream)
OUString SvxResId(TranslateId aId)
Definition: dialmgr.cxx:24
float u
ESelection aNewSelection(GetSelection())
#define EE_PARA_NOT_FOUND
#define EE_INDEX_NOT_FOUND
sal_Int32 nState
sal_Int32 mnRow
sal_Int32 mnCol
sal_Int32 nIndex
Mode eMode
#define SAL_WARN_IF(condition, area, stream)
NONE
@ Exception
constexpr auto toTwips(N number, Length from)
VBAHELPER_DLLPUBLIC bool setPropertyValue(css::uno::Sequence< css::beans::PropertyValue > &aProp, const OUString &aName, const css::uno::Any &aValue)
IMPL_LINK_NOARG(SvxTableController, UpdateHdl, void *, void)
TableHitKind
SdrTableHitKind.
Definition: svdotable.hxx:51
static void ImplApplyBorderLineItem(CellPosFlag nCellPosFlags, const SvxBorderLine *pBorderLineItem, SvxBoxItem &rNewFrame)
static void ImplSetLinePreserveColor(SvxBoxItem &rNewFrame, const SvxBorderLine *pNew, SvxBoxItemLine nLine)
static void ImplApplyBoxItem(CellPosFlag nCellPosFlags, const SvxBoxItem *pBoxItem, const SvxBoxInfoItem *pBoxInfoItem, SvxBoxItem &rNewFrame)
static void ImplApplyLineColorItem(CellPosFlag nCellPosFlags, const SvxColorItem *pLineColorItem, SvxBoxItem &rNewFrame)
rtl::Reference< sdr::SelectionController > CreateTableController(SdrView &rView, const SdrTableObj &rObj, const rtl::Reference< sdr::SelectionController > &xRefController)
static void ImplSetLineColor(SvxBoxItem &rNewFrame, SvxBoxItemLine nLine, const Color &rColor)
bool getPropertyValue(ValueType &rValue, css::uno::Reference< css::beans::XPropertySet > const &xPropSet, OUString const &propName)
const char GetValue[]
OUTDEV_WINDOW
SfxItemState
SdrTextVertAdjust
Definition: sdtaitm.hxx:29
@ SDRTEXTVERTADJUST_BOTTOM
Definition: sdtaitm.hxx:31
@ SDRTEXTVERTADJUST_BLOCK
Definition: sdtaitm.hxx:32
@ SDRTEXTVERTADJUST_CENTER
Definition: sdtaitm.hxx:30
@ SDRTEXTVERTADJUST_TOP
Definition: sdtaitm.hxx:29
SdrMetricItem makeSdrTextUpperDistItem(tools::Long mnHeight)
Definition: sdtditm.hxx:35
SdrMetricItem makeSdrTextRightDistItem(tools::Long mnHeight)
Definition: sdtditm.hxx:30
SdrMetricItem makeSdrTextLowerDistItem(tools::Long mnHeight)
Definition: sdtditm.hxx:40
SdrMetricItem makeSdrTextLeftDistItem(tools::Long mnHeight)
Definition: sdtditm.hxx:25
static SfxItemSet & rSet
TableStyleSettings.
Definition: svdotable.hxx:75
constexpr TypedWhichId< SdrMetricItem > SDRATTR_TEXT_LEFTDIST(SDRATTR_MISC_FIRST+4)
constexpr sal_uInt16 SDRATTR_START(XATTR_START)
constexpr TypedWhichId< SvxBoxInfoItem > SDRATTR_TABLE_BORDER_INNER(SDRATTR_TABLE_FIRST+1)
constexpr sal_uInt16 SDRATTR_SHADOW_FIRST(XATTR_END+1)
constexpr TypedWhichId< SdrTextVertAdjustItem > SDRATTR_TEXT_VERTADJUST(SDRATTR_MISC_FIRST+8)
constexpr sal_uInt16 SDRATTR_TABLE_LAST(SDRATTR_TABLE_CELL_GRABBAG)
constexpr TypedWhichId< SvxBoxItem > SDRATTR_TABLE_BORDER(SDRATTR_TABLE_FIRST+0)
constexpr TypedWhichId< SdrMetricItem > SDRATTR_TEXT_RIGHTDIST(SDRATTR_MISC_FIRST+5)
constexpr sal_uInt16 SDRATTR_SHADOW_LAST(SDRATTR_SHADOWALIGNMENT)
constexpr TypedWhichId< SdrMetricItem > SDRATTR_TEXT_LOWERDIST(SDRATTR_MISC_FIRST+7)
constexpr TypedWhichId< SdrMetricItem > SDRATTR_TEXT_UPPERDIST(SDRATTR_MISC_FIRST+6)
std::unique_ptr< SdrOutliner > SdrMakeOutliner(OutlinerMode nOutlinerMode, SdrModel &rModel)
Create an Outliner with the engine-global default settings on the heap.
Definition: svdetc.cxx:332
@ Table
media shape
SvxBoxInfoItem & m_rBoxInfoItem
o3tl::enumarray< SvxBoxInfoItemLine, bool > aInnerLineSet
const SvxBoxItemLine m_nBorderLine
const SvxBoxInfoItemLine m_nInnerLine
SvxBoxInfoItem & rBoxInfoItem
o3tl::enumarray< SvxBoxItemLine, bool > aBorderSet
const bool m_bBorder
SvxBoxItem & rBoxItem
o3tl::enumarray< SvxBoxInfoItemLine, bool > aInnerLineIndeterminate
o3tl::enumarray< SvxBoxItemLine, sal_uInt16 > aDistance
SvxTableController * mpController
o3tl::enumarray< SvxBoxItemLine, bool > aBorderIndeterminate
bool bDistanceIndeterminate
o3tl::enumarray< SvxBoxItemLine, bool > aDistanceSet
SvxBoxItem & m_rBoxItem
Left
Right
RET_OK