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