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