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