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