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