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