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