Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / svx / source / table / tablecontroller.cxx
blob69fb4e33a5d8930db618a9dc34b447513e008776
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <algorithm>
22 #include <svx/sdr/table/tablecontroller.hxx>
23 #include <tablemodel.hxx>
25 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
26 #include <com/sun/star/container/XIndexAccess.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/table/XMergeableCellRange.hpp>
30 #include <com/sun/star/table/XMergeableCell.hpp>
32 #include <sal/config.h>
34 #include <vcl/svapp.hxx>
35 #include <vcl/settings.hxx>
37 #include <svl/whiter.hxx>
39 #include <sfx2/request.hxx>
41 #include <editeng/scripttypeitem.hxx>
42 #include <svx/svdotable.hxx>
43 #include <svx/sdr/overlay/overlayobjectcell.hxx>
44 #include <svx/sdr/overlay/overlaymanager.hxx>
45 #include <svx/svxids.hrc>
46 #include <editeng/outlobj.hxx>
47 #include <svx/svdoutl.hxx>
48 #include <svx/svdpagv.hxx>
49 #include <svx/svdetc.hxx>
50 #include <editeng/editobj.hxx>
51 #include "editeng/editstat.hxx"
52 #include "editeng/unolingu.hxx"
53 #include "svx/sdrpagewindow.hxx"
54 #include <svx/selectioncontroller.hxx>
55 #include <svx/svdmodel.hxx>
56 #include "svx/sdrpaintwindow.hxx"
57 #include <svx/svxdlg.hxx>
58 #include <editeng/boxitem.hxx>
59 #include "cell.hxx"
60 #include <editeng/borderline.hxx>
61 #include <editeng/colritem.hxx>
62 #include "editeng/lineitem.hxx"
63 #include "svx/svdstr.hrc"
64 #include "svdglob.hxx"
65 #include "svx/svdpage.hxx"
66 #include "tableundo.hxx"
67 #include "tablelayouter.hxx"
68 #include <vcl/msgbox.hxx>
69 #include <boost/scoped_ptr.hpp>
71 using ::editeng::SvxBorderLine;
72 using namespace ::sdr::table;
73 using namespace ::com::sun::star;
74 using namespace ::com::sun::star::uno;
75 using namespace ::com::sun::star::table;
76 using namespace ::com::sun::star::beans;
77 using namespace ::com::sun::star::container;
78 using namespace ::com::sun::star::text;
79 using namespace ::com::sun::star::style;
81 namespace sdr { namespace table {
84 // class SvxTableControllerModifyListener
87 class SvxTableControllerModifyListener : public ::cppu::WeakImplHelper1< ::com::sun::star::util::XModifyListener >
89 public:
90 SvxTableControllerModifyListener( SvxTableController* pController )
91 : mpController( pController ) {}
93 // XModifyListener
94 virtual void SAL_CALL modified( const ::com::sun::star::lang::EventObject& aEvent ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
96 // XEventListener
97 virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
99 SvxTableController* mpController;
103 // XModifyListener
106 void SAL_CALL SvxTableControllerModifyListener::modified( const ::com::sun::star::lang::EventObject& ) throw (::com::sun::star::uno::RuntimeException, std::exception)
108 if( mpController )
109 mpController->onTableModified();
113 // XEventListener
116 void SAL_CALL SvxTableControllerModifyListener::disposing( const ::com::sun::star::lang::EventObject& ) throw (::com::sun::star::uno::RuntimeException, std::exception)
118 mpController = 0;
122 // class SvxTableController
125 rtl::Reference< sdr::SelectionController > CreateTableController( SdrObjEditView* pView, const SdrObject* pObj, const rtl::Reference< sdr::SelectionController >& xRefController )
127 return SvxTableController::create( pView, pObj, xRefController );
132 rtl::Reference< sdr::SelectionController > SvxTableController::create( SdrObjEditView* pView, const SdrObject* pObj, const rtl::Reference< sdr::SelectionController >& xRefController )
134 if( xRefController.is() )
136 SvxTableController* pController = dynamic_cast< SvxTableController* >( xRefController.get() );
137 if( pController && (pController->mxTableObj.get() == pObj) && (pController->mpView == pView) )
138 return xRefController;
140 return new SvxTableController( pView, pObj );
145 SvxTableController::SvxTableController( SdrObjEditView* pView, const SdrObject* pObj )
146 : mbCellSelectionMode(false)
147 , mbLeftButtonDown(false)
148 , mpSelectionOverlay(0)
149 , mpView( dynamic_cast< SdrView* >( pView ) )
150 , mxTableObj( dynamic_cast< SdrTableObj* >( const_cast< SdrObject* >( pObj ) ) )
151 , mpModel( 0 )
152 , mnUpdateEvent( 0 )
154 if( pObj )
155 mpModel = pObj->GetModel();
157 if( mxTableObj.is() )
159 static_cast< const SdrTableObj* >( pObj )->getActiveCellPos( maCursorFirstPos );
160 maCursorLastPos = maCursorFirstPos;
162 Reference< XTable > xTable( static_cast< const SdrTableObj* >( pObj )->getTable() );
163 if( xTable.is() )
165 mxModifyListener = new SvxTableControllerModifyListener( this );
166 xTable->addModifyListener( mxModifyListener );
168 mxTable.set( dynamic_cast< TableModel* >( xTable.get() ) );
175 SvxTableController::~SvxTableController()
177 if( mnUpdateEvent )
179 Application::RemoveUserEvent( mnUpdateEvent );
182 if( mxModifyListener.is() && mxTableObj.get() )
184 Reference< XTable > xTable( static_cast< SdrTableObj* >( mxTableObj.get() )->getTable() );
185 if( xTable.is() )
187 xTable->removeModifyListener( mxModifyListener );
188 mxModifyListener.clear();
195 const sal_uInt16 ACTION_NONE = 0;
196 const sal_uInt16 ACTION_GOTO_FIRST_CELL = 1;
197 const sal_uInt16 ACTION_GOTO_FIRST_COLUMN = 2;
198 const sal_uInt16 ACTION_GOTO_FIRST_ROW = 3;
199 const sal_uInt16 ACTION_GOTO_LEFT_CELL = 4;
200 const sal_uInt16 ACTION_GOTO_UP_CELL = 5;
201 const sal_uInt16 ACTION_GOTO_RIGHT_CELL = 6;
202 const sal_uInt16 ACTION_GOTO_DOWN_CELL = 7;
203 const sal_uInt16 ACTION_GOTO_LAST_CELL = 8;
204 const sal_uInt16 ACTION_GOTO_LAST_COLUMN = 9;
205 const sal_uInt16 ACTION_GOTO_LAST_ROW = 10;
206 const sal_uInt16 ACTION_EDIT_CELL = 11;
207 const sal_uInt16 ACTION_STOP_TEXT_EDIT = 12;
208 const sal_uInt16 ACTION_REMOVE_SELECTION = 13;
209 const sal_uInt16 ACTION_START_SELECTION = 14;
210 const sal_uInt16 ACTION_HANDLED_BY_VIEW = 15;
211 const sal_uInt16 ACTION_TAB = 18;
213 bool SvxTableController::onKeyInput(const KeyEvent& rKEvt, Window* pWindow )
215 if( !checkTableObject() )
216 return false;
218 // check if we are read only
219 if( mpModel && mpModel->IsReadOnly())
221 switch( rKEvt.GetKeyCode().GetCode() )
223 case awt::Key::DOWN:
224 case awt::Key::UP:
225 case awt::Key::LEFT:
226 case awt::Key::RIGHT:
227 case awt::Key::TAB:
228 case awt::Key::HOME:
229 case awt::Key::END:
230 case awt::Key::NUM2:
231 case awt::Key::NUM4:
232 case awt::Key::NUM6:
233 case awt::Key::NUM8:
234 case awt::Key::ESCAPE:
235 case awt::Key::F2:
236 break;
237 default:
238 // tell the view we eat the event, no further processing needed
239 return true;
243 sal_uInt16 nAction = getKeyboardAction( rKEvt, pWindow );
245 return executeAction( nAction, ( rKEvt.GetKeyCode().IsShift() ) ? sal_True : sal_False, pWindow );
249 // ::com::sun::star::awt::XMouseClickHandler:
252 bool SvxTableController::onMouseButtonDown(const MouseEvent& rMEvt, Window* pWindow )
254 if( !pWindow || !checkTableObject() )
255 return false;
257 SdrViewEvent aVEvt;
258 if( !rMEvt.IsRight() && mpView->PickAnything(rMEvt,SDRMOUSEBUTTONDOWN, aVEvt) == SDRHIT_HANDLE )
259 return false;
261 TableHitKind eHit = static_cast< SdrTableObj* >(mxTableObj.get())->CheckTableHit( pWindow->PixelToLogic(rMEvt.GetPosPixel()), maMouseDownPos.mnCol, maMouseDownPos.mnRow, 0 );
263 mbLeftButtonDown = (rMEvt.GetClicks() == 1) && rMEvt.IsLeft();
265 if( eHit == SDRTABLEHIT_CELL )
267 StartSelection( maMouseDownPos );
268 return true;
271 if( rMEvt.IsRight() && eHit != SDRTABLEHIT_NONE )
272 return true; // right click will become context menu
274 // for cell selection with the mouse remember our first hit
275 if( mbLeftButtonDown )
277 RemoveSelection();
279 Point aPnt(rMEvt.GetPosPixel());
280 if (pWindow!=NULL)
281 aPnt=pWindow->PixelToLogic(aPnt);
283 SdrHdl* pHdl = mpView->PickHandle(aPnt);
285 if( pHdl )
287 mbLeftButtonDown = false;
289 else
291 ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
293 if( !pWindow || !pTableObj || eHit == SDRTABLEHIT_NONE)
295 mbLeftButtonDown = false;
300 return false;
305 bool SvxTableController::onMouseButtonUp(const MouseEvent& rMEvt, Window* /*pWin*/)
307 if( !checkTableObject() )
308 return false;
310 mbLeftButtonDown = false;
312 if( rMEvt.GetClicks() == 2 )
313 return true;
315 return false;
320 bool SvxTableController::onMouseMove(const MouseEvent& rMEvt, Window* pWindow )
322 if( !checkTableObject() )
323 return false;
325 if( rMEvt.IsLeft() )
327 int i = 0;
328 i++;
331 SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >( mxTableObj.get() );
332 CellPos aPos;
333 if( mbLeftButtonDown && pTableObj && pTableObj->CheckTableHit( pWindow->PixelToLogic(rMEvt.GetPosPixel()), aPos.mnCol, aPos.mnRow, 0 ) != SDRTABLEHIT_NONE )
335 if(aPos != maMouseDownPos)
337 if( mbCellSelectionMode )
339 setSelectedCells( maMouseDownPos, aPos );
340 return true;
342 else
344 StartSelection( maMouseDownPos );
347 else if( mbCellSelectionMode )
349 UpdateSelection( aPos );
350 return true;
353 return false;
358 void SvxTableController::onSelectionHasChanged()
360 bool bSelected = false;
362 SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >( mxTableObj.get() );
363 if( pTableObj && pTableObj->IsTextEditActive() )
365 pTableObj->getActiveCellPos( maCursorFirstPos );
366 maCursorLastPos = maCursorFirstPos;
367 mbCellSelectionMode = false;
369 else
371 const SdrMarkList& rMarkList= mpView->GetMarkedObjectList();
372 if( rMarkList.GetMarkCount() == 1 )
373 bSelected = mxTableObj.get() == rMarkList.GetMark(0)->GetMarkedSdrObj();
374 /* fdo#46186 Selecting the table means selecting the entire cells */
375 if (!hasSelectedCells() && pTableObj)
377 maCursorFirstPos = pTableObj->getFirstCell();
378 maCursorLastPos = pTableObj->getLastCell();
379 mbCellSelectionMode=true;
383 if( bSelected )
385 updateSelectionOverlay();
387 else
389 destroySelectionOverlay();
395 void SvxTableController::GetState( SfxItemSet& rSet )
397 if( !mxTable.is() || !mxTableObj.is() || !mxTableObj->GetModel() )
398 return;
400 SfxItemSet* pSet = 0;
402 bool bVertDone = false;
404 // Iterate over all requested items in the set.
405 SfxWhichIter aIter( rSet );
406 sal_uInt16 nWhich = aIter.FirstWhich();
407 while (nWhich)
409 switch (nWhich)
411 case SID_TABLE_VERT_BOTTOM:
412 case SID_TABLE_VERT_CENTER:
413 case SID_TABLE_VERT_NONE:
415 if( !mxTable.is() || !mxTableObj->GetModel() )
417 rSet.DisableItem(nWhich);
419 else if(!bVertDone)
421 if( !pSet )
423 pSet = new SfxItemSet( mxTableObj->GetModel()->GetItemPool() );
424 MergeAttrFromSelectedCells(*pSet, false);
427 SdrTextVertAdjust eAdj = SDRTEXTVERTADJUST_BLOCK;
429 if( pSet->GetItemState( SDRATTR_TEXT_VERTADJUST ) != SFX_ITEM_DONTCARE )
430 eAdj = ((SdrTextVertAdjustItem&)(pSet->Get(SDRATTR_TEXT_VERTADJUST))).GetValue();
432 rSet.Put(SfxBoolItem(SID_TABLE_VERT_BOTTOM, eAdj == SDRTEXTVERTADJUST_BOTTOM));
433 rSet.Put(SfxBoolItem(SID_TABLE_VERT_CENTER, eAdj == SDRTEXTVERTADJUST_CENTER));
434 rSet.Put(SfxBoolItem(SID_TABLE_VERT_NONE, eAdj == SDRTEXTVERTADJUST_TOP));
435 bVertDone = true;
437 break;
439 case SID_TABLE_DELETE_ROW:
440 if( !mxTable.is() || !hasSelectedCells() || (mxTable->getRowCount() <= 1) )
441 rSet.DisableItem(SID_TABLE_DELETE_ROW);
442 break;
443 case SID_TABLE_DELETE_COL:
444 if( !mxTable.is() || !hasSelectedCells() || (mxTable->getColumnCount() <= 1) )
445 rSet.DisableItem(SID_TABLE_DELETE_COL);
446 break;
447 case SID_TABLE_MERGE_CELLS:
448 if( !mxTable.is() || !hasSelectedCells() )
449 rSet.DisableItem(SID_TABLE_MERGE_CELLS);
450 break;
451 case SID_TABLE_SPLIT_CELLS:
452 if( !hasSelectedCells() || !mxTable.is() )
453 rSet.DisableItem(SID_TABLE_SPLIT_CELLS);
454 break;
456 case SID_OPTIMIZE_TABLE:
457 case SID_TABLE_DISTRIBUTE_COLUMNS:
458 case SID_TABLE_DISTRIBUTE_ROWS:
460 bool bDistributeColumns = false;
461 bool bDistributeRows = false;
462 if( mxTable.is() )
464 CellPos aStart, aEnd;
465 getSelectedCells( aStart, aEnd );
467 bDistributeColumns = aStart.mnCol != aEnd.mnCol;
468 bDistributeRows = aStart.mnRow != aEnd.mnRow;
470 if( !bDistributeColumns && !bDistributeRows )
471 rSet.DisableItem(SID_OPTIMIZE_TABLE);
472 if( !bDistributeColumns )
473 rSet.DisableItem(SID_TABLE_DISTRIBUTE_COLUMNS);
474 if( !bDistributeRows )
475 rSet.DisableItem(SID_TABLE_DISTRIBUTE_ROWS);
476 break;
479 case SID_AUTOFORMAT:
480 case SID_TABLE_SORT_DIALOG:
481 case SID_TABLE_AUTOSUM:
482 // if( !mxTable.is() )
483 // rSet.DisableItem( nWhich );
484 break;
485 default:
486 break;
488 nWhich = aIter.NextWhich();
490 delete pSet;
495 void SvxTableController::onInsert( sal_uInt16 nSId, const SfxItemSet* pArgs )
497 ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
498 if( !pTableObj )
499 return;
501 if( mxTable.is() ) try
504 bool bInsertAfter = true;
505 sal_uInt16 nCount = 0;
506 if( pArgs )
508 const SfxPoolItem* pItem = 0;
509 pArgs->GetItemState(nSId, false, &pItem);
510 if (pItem)
512 nCount = ((const SfxInt16Item* )pItem)->GetValue();
513 if(SFX_ITEM_SET == pArgs->GetItemState(SID_TABLE_PARAM_INSERT_AFTER, true, &pItem))
514 bInsertAfter = ((const SfxBoolItem* )pItem)->GetValue();
518 CellPos aStart, aEnd;
519 if( hasSelectedCells() )
521 getSelectedCells( aStart, aEnd );
523 else
525 if( bInsertAfter )
527 aStart.mnCol = mxTable->getColumnCount() - 1;
528 aStart.mnRow = mxTable->getRowCount() - 1;
529 aEnd = aStart;
533 if( pTableObj->IsTextEditActive() )
534 mpView->SdrEndTextEdit(true);
536 RemoveSelection();
538 const OUString sSize( "Size" );
540 const bool bUndo = mpModel && mpModel->IsUndoEnabled();
542 switch( nSId )
544 case SID_TABLE_INSERT_COL:
546 TableModelNotifyGuard aGuard( mxTable.get() );
548 if( bUndo )
550 mpModel->BegUndo( ImpGetResStr(STR_TABLE_INSCOL) );
551 mpModel->AddUndo( mpModel->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj) );
554 Reference< XTableColumns > xCols( mxTable->getColumns() );
555 const sal_Int32 nNewColumns = (nCount == 0) ? (aEnd.mnCol - aStart.mnCol + 1) : nCount;
556 const sal_Int32 nNewStartColumn = aEnd.mnCol + (bInsertAfter ? 1 : 0);
557 xCols->insertByIndex( nNewStartColumn, nNewColumns );
559 for( sal_Int32 nOffset = 0; nOffset < nNewColumns; nOffset++ )
561 // Resolves fdo#61540
562 // On Insert before, the reference column whose size is going to be
563 // used for newly created column(s) is wrong. As the new columns are
564 // inserted before the reference column, the reference column moved
565 // to the new position by no., of new columns i.e (earlier+newcolumns).
566 Reference< XPropertySet >(xCols->getByIndex(nNewStartColumn+nOffset), UNO_QUERY_THROW )->
567 setPropertyValue( sSize,
568 Reference< XPropertySet >(xCols->getByIndex( bInsertAfter?nNewStartColumn-1:nNewStartColumn+nNewColumns ), UNO_QUERY_THROW )->
569 getPropertyValue( sSize ) );
572 if( bUndo )
573 mpModel->EndUndo();
575 aStart.mnCol = nNewStartColumn;
576 aStart.mnRow = 0;
577 aEnd.mnCol = aStart.mnCol + nNewColumns - 1;
578 aEnd.mnRow = mxTable->getRowCount() - 1;
579 break;
582 case SID_TABLE_INSERT_ROW:
584 TableModelNotifyGuard aGuard( mxTable.get() );
586 if( bUndo )
588 mpModel->BegUndo( ImpGetResStr(STR_TABLE_INSROW ) );
589 mpModel->AddUndo( mpModel->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj) );
592 Reference< XTableRows > xRows( mxTable->getRows() );
593 const sal_Int32 nNewRows = (nCount == 0) ? (aEnd.mnRow - aStart.mnRow + 1) : nCount;
594 const sal_Int32 nNewRowStart = aEnd.mnRow + (bInsertAfter ? 1 : 0);
595 xRows->insertByIndex( nNewRowStart, nNewRows );
597 for( sal_Int32 nOffset = 0; nOffset < nNewRows; nOffset++ )
599 Reference< XPropertySet >( xRows->getByIndex( aEnd.mnRow + nOffset + 1 ), UNO_QUERY_THROW )->
600 setPropertyValue( sSize,
601 Reference< XPropertySet >( xRows->getByIndex( aStart.mnRow + nOffset ), UNO_QUERY_THROW )->
602 getPropertyValue( sSize ) );
605 if( bUndo )
606 mpModel->EndUndo();
608 aStart.mnCol = 0;
609 aStart.mnRow = nNewRowStart;
610 aEnd.mnCol = mxTable->getColumnCount() - 1;
611 aEnd.mnRow = aStart.mnRow + nNewRows - 1;
612 break;
616 StartSelection( aStart );
617 UpdateSelection( aEnd );
619 catch( Exception& )
621 OSL_FAIL("svx::SvxTableController::onInsert(), exception caught!");
627 void SvxTableController::onDelete( sal_uInt16 nSId )
629 ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
630 if( !pTableObj )
631 return;
633 if( mxTable.is() && hasSelectedCells() )
635 CellPos aStart, aEnd;
636 getSelectedCells( aStart, aEnd );
638 if( pTableObj->IsTextEditActive() )
639 mpView->SdrEndTextEdit(true);
641 RemoveSelection();
643 bool bDeleteTable = false;
644 switch( nSId )
646 case SID_TABLE_DELETE_COL:
648 const sal_Int32 nRemovedColumns = aEnd.mnCol - aStart.mnCol + 1;
649 if( nRemovedColumns == mxTable->getColumnCount() )
651 bDeleteTable = true;
653 else
655 Reference< XTableColumns > xCols( mxTable->getColumns() );
656 xCols->removeByIndex( aStart.mnCol, nRemovedColumns );
658 break;
661 case SID_TABLE_DELETE_ROW:
663 const sal_Int32 nRemovedRows = aEnd.mnRow - aStart.mnRow + 1;
664 if( nRemovedRows == mxTable->getRowCount() )
666 bDeleteTable = true;
668 else
670 Reference< XTableRows > xRows( mxTable->getRows() );
671 xRows->removeByIndex( aStart.mnRow, nRemovedRows );
673 break;
677 if( bDeleteTable )
678 mpView->DeleteMarkedObj();
679 else
680 UpdateTableShape();
686 void SvxTableController::onSelect( sal_uInt16 nSId )
688 if( mxTable.is() )
690 const sal_Int32 nRowCount = mxTable->getRowCount();
691 const sal_Int32 nColCount = mxTable->getColumnCount();
692 if( nRowCount && nColCount )
694 CellPos aStart, aEnd;
695 getSelectedCells( aStart, aEnd );
697 switch( nSId )
699 case SID_TABLE_SELECT_ALL:
700 aEnd.mnCol = 0; aEnd.mnRow = 0;
701 aStart.mnCol = nColCount - 1; aStart.mnRow = nRowCount - 1;
702 break;
703 case SID_TABLE_SELECT_COL:
704 aEnd.mnRow = nRowCount - 1;
705 aStart.mnRow = 0;
706 break;
707 case SID_TABLE_SELECT_ROW:
708 aEnd.mnCol = nColCount - 1;
709 aStart.mnCol = 0;
710 break;
713 StartSelection( aEnd );
714 gotoCell( aStart, true, 0 );
720 void SvxTableController::onFormatTable( SfxRequest& rReq )
722 ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
723 if( !pTableObj )
724 return;
726 const SfxItemSet* pArgs = rReq.GetArgs();
728 if( !pArgs && pTableObj->GetModel() )
730 SfxItemSet aNewAttr( pTableObj->GetModel()->GetItemPool() );
732 // merge drawing layer text distance items into SvxBoxItem used by the dialog
733 SvxBoxItem aBoxItem( static_cast< const SvxBoxItem& >( aNewAttr.Get( SDRATTR_TABLE_BORDER ) ) );
734 aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( ((SdrTextLeftDistItem&)(aNewAttr.Get(SDRATTR_TEXT_LEFTDIST))).GetValue()), BOX_LINE_LEFT );
735 aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( ((SdrTextRightDistItem&)(aNewAttr.Get(SDRATTR_TEXT_RIGHTDIST))).GetValue()), BOX_LINE_RIGHT );
736 aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( ((SdrTextUpperDistItem&)(aNewAttr.Get(SDRATTR_TEXT_UPPERDIST))).GetValue()), BOX_LINE_TOP );
737 aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( ((SdrTextLowerDistItem&)(aNewAttr.Get(SDRATTR_TEXT_LOWERDIST))).GetValue()), BOX_LINE_BOTTOM );
739 SvxBoxInfoItem aBoxInfoItem( static_cast< const SvxBoxInfoItem& >( aNewAttr.Get( SDRATTR_TABLE_BORDER_INNER ) ) );
741 MergeAttrFromSelectedCells(aNewAttr, false);
742 FillCommonBorderAttrFromSelectedCells( aBoxItem, aBoxInfoItem );
743 aNewAttr.Put( aBoxItem );
744 aNewAttr.Put( aBoxInfoItem );
746 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
747 boost::scoped_ptr< SfxAbstractTabDialog > pDlg( pFact ? pFact->CreateSvxFormatCellsDialog( NULL, &aNewAttr, pTableObj->GetModel(), pTableObj) : 0 );
748 // Even Cancel Button is returning positive(101) value,
749 if( pDlg.get() && ( pDlg->Execute() == RET_OK ) )
751 SfxItemSet aNewSet( aNewAttr );
752 aNewSet.Put( *(pDlg->GetOutputItemSet ()) );
754 SvxBoxItem aNewBoxItem( static_cast< const SvxBoxItem& >( aNewSet.Get( SDRATTR_TABLE_BORDER ) ) );
756 if( aNewBoxItem.GetDistance( BOX_LINE_LEFT ) != aBoxItem.GetDistance( BOX_LINE_LEFT ) )
757 aNewSet.Put(SdrTextLeftDistItem( aNewBoxItem.GetDistance( BOX_LINE_LEFT ) ) );
759 if( aNewBoxItem.GetDistance( BOX_LINE_RIGHT ) != aBoxItem.GetDistance( BOX_LINE_RIGHT ) )
760 aNewSet.Put(SdrTextRightDistItem( aNewBoxItem.GetDistance( BOX_LINE_RIGHT ) ) );
762 if( aNewBoxItem.GetDistance( BOX_LINE_TOP ) != aBoxItem.GetDistance( BOX_LINE_TOP ) )
763 aNewSet.Put(SdrTextUpperDistItem( aNewBoxItem.GetDistance( BOX_LINE_TOP ) ) );
765 if( aNewBoxItem.GetDistance( BOX_LINE_BOTTOM ) != aBoxItem.GetDistance( BOX_LINE_BOTTOM ) )
766 aNewSet.Put(SdrTextLowerDistItem( aNewBoxItem.GetDistance( BOX_LINE_BOTTOM ) ) );
768 SetAttrToSelectedCells(aNewSet, false);
775 void SvxTableController::Execute( SfxRequest& rReq )
777 const sal_uInt16 nSId = rReq.GetSlot();
778 switch( nSId )
780 case SID_TABLE_INSERT_ROW:
781 case SID_TABLE_INSERT_COL:
782 onInsert( nSId, rReq.GetArgs() );
783 break;
784 case SID_TABLE_DELETE_ROW:
785 case SID_TABLE_DELETE_COL:
786 onDelete( nSId );
787 break;
788 case SID_TABLE_SELECT_ALL:
789 case SID_TABLE_SELECT_COL:
790 case SID_TABLE_SELECT_ROW:
791 onSelect( nSId );
792 break;
793 case SID_FORMAT_TABLE_DLG:
794 onFormatTable( rReq );
795 break;
797 case SID_FRAME_LINESTYLE:
798 case SID_FRAME_LINECOLOR:
799 case SID_ATTR_BORDER:
801 const SfxItemSet* pArgs = rReq.GetArgs();
802 if( pArgs )
803 ApplyBorderAttr( *pArgs );
805 break;
807 case SID_ATTR_FILL_STYLE:
809 const SfxItemSet* pArgs = rReq.GetArgs();
810 if( pArgs )
811 SetAttributes( *pArgs, false );
813 break;
815 case SID_TABLE_MERGE_CELLS:
816 MergeMarkedCells();
817 break;
819 case SID_TABLE_SPLIT_CELLS:
820 SplitMarkedCells();
821 break;
823 case SID_TABLE_DISTRIBUTE_COLUMNS:
824 DistributeColumns();
825 break;
827 case SID_TABLE_DISTRIBUTE_ROWS:
828 DistributeRows();
829 break;
831 case SID_TABLE_VERT_BOTTOM:
832 case SID_TABLE_VERT_CENTER:
833 case SID_TABLE_VERT_NONE:
834 SetVertical( nSId );
835 break;
837 case SID_AUTOFORMAT:
838 case SID_TABLE_SORT_DIALOG:
839 case SID_TABLE_AUTOSUM:
840 default:
841 break;
843 case SID_TABLE_STYLE:
844 SetTableStyle( rReq.GetArgs() );
845 break;
847 case SID_TABLE_STYLE_SETTINGS:
848 SetTableStyleSettings( rReq.GetArgs() );
849 break;
853 void SvxTableController::SetTableStyle( const SfxItemSet* pArgs )
855 SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
856 SdrModel* pModel = pTableObj ? pTableObj->GetModel() : 0;
858 if( !pTableObj || !pModel || !pArgs || (SFX_ITEM_SET != pArgs->GetItemState(SID_TABLE_STYLE, false)) )
859 return;
861 const SfxStringItem* pArg = dynamic_cast< const SfxStringItem* >( &pArgs->Get( SID_TABLE_STYLE ) );
862 if( pArg && mxTable.is() ) try
864 Reference< XStyleFamiliesSupplier > xSFS( pModel->getUnoModel(), UNO_QUERY_THROW );
865 Reference< XNameAccess > xFamilyNameAccess( xSFS->getStyleFamilies(), UNO_QUERY_THROW );
866 const OUString sFamilyName( "table" );
867 Reference< XNameAccess > xTableFamilyAccess( xFamilyNameAccess->getByName( sFamilyName ), UNO_QUERY_THROW );
869 if( xTableFamilyAccess->hasByName( pArg->GetValue() ) )
871 // found table style with the same name
872 Reference< XIndexAccess > xNewTableStyle( xTableFamilyAccess->getByName( pArg->GetValue() ), UNO_QUERY_THROW );
874 const bool bUndo = pModel->IsUndoEnabled();
876 if( bUndo )
878 pModel->BegUndo( ImpGetResStr(STR_TABLE_STYLE) );
879 pModel->AddUndo( new TableStyleUndo( *pTableObj ) );
882 pTableObj->setTableStyle( xNewTableStyle );
884 const sal_Int32 nRowCount = mxTable->getRowCount();
885 const sal_Int32 nColCount = mxTable->getColumnCount();
886 for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ )
888 for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ ) try
890 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
891 if( xCell.is() )
893 SfxItemSet aSet( xCell->GetItemSet() );
894 bool bChanges = false;
895 const SfxItemSet& rStyleAttribs = xCell->GetStyleSheet()->GetItemSet();
897 for ( sal_uInt16 nWhich = SDRATTR_START; nWhich <= SDRATTR_TABLE_LAST; nWhich++ )
899 if( (rStyleAttribs.GetItemState( nWhich ) == SFX_ITEM_ON) && (aSet.GetItemState( nWhich ) == SFX_ITEM_ON) )
901 aSet.ClearItem( nWhich );
902 bChanges = true;
906 if( bChanges )
908 if( bUndo )
909 xCell->AddUndo();
911 xCell->SetMergedItemSetAndBroadcast( aSet, true );
915 catch( Exception& )
917 OSL_FAIL( "svx::SvxTableController::SetTableStyle(), exception caught!" );
921 if( bUndo )
922 pModel->EndUndo();
925 catch( Exception& )
927 OSL_FAIL( "svx::SvxTableController::SetTableStyle(), exception caught!" );
931 void SvxTableController::SetTableStyleSettings( const SfxItemSet* pArgs )
933 SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
934 SdrModel* pModel = pTableObj ? pTableObj->GetModel() : 0;
936 if( !pTableObj || !pModel )
937 return;
939 TableStyleSettings aSettings( pTableObj->getTableStyleSettings() );
941 const SfxPoolItem *pPoolItem=NULL;
943 if( (SFX_ITEM_SET == pArgs->GetItemState(ID_VAL_USEFIRSTROWSTYLE, false,&pPoolItem)) )
944 aSettings.mbUseFirstRow = static_cast< const SfxBoolItem* >(pPoolItem)->GetValue();
946 if( (SFX_ITEM_SET == pArgs->GetItemState(ID_VAL_USELASTROWSTYLE, false,&pPoolItem)) )
947 aSettings.mbUseLastRow = static_cast< const SfxBoolItem* >(pPoolItem)->GetValue();
949 if( (SFX_ITEM_SET == pArgs->GetItemState(ID_VAL_USEBANDINGROWSTYLE, false,&pPoolItem)) )
950 aSettings.mbUseRowBanding = static_cast< const SfxBoolItem* >(pPoolItem)->GetValue();
952 if( (SFX_ITEM_SET == pArgs->GetItemState(ID_VAL_USEFIRSTCOLUMNSTYLE, false,&pPoolItem)) )
953 aSettings.mbUseFirstColumn = static_cast< const SfxBoolItem* >(pPoolItem)->GetValue();
955 if( (SFX_ITEM_SET == pArgs->GetItemState(ID_VAL_USELASTCOLUMNSTYLE, false,&pPoolItem)) )
956 aSettings.mbUseLastColumn = static_cast< const SfxBoolItem* >(pPoolItem)->GetValue();
958 if( (SFX_ITEM_SET == pArgs->GetItemState(ID_VAL_USEBANDINGCOLUMNSTYLE, false,&pPoolItem)) )
959 aSettings.mbUseColumnBanding = static_cast< const SfxBoolItem* >(pPoolItem)->GetValue();
961 if( aSettings == pTableObj->getTableStyleSettings() )
962 return;
964 const bool bUndo = pModel->IsUndoEnabled();
966 if( bUndo )
968 pModel->BegUndo( ImpGetResStr(STR_TABLE_STYLE_SETTINGS) );
969 pModel->AddUndo( new TableStyleUndo( *pTableObj ) );
972 pTableObj->setTableStyleSettings( aSettings );
974 if( bUndo )
975 pModel->EndUndo();
978 void SvxTableController::SetVertical( sal_uInt16 nSId )
980 SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
981 if( mxTable.is() && pTableObj )
983 TableModelNotifyGuard aGuard( mxTable.get() );
985 CellPos aStart, aEnd;
986 getSelectedCells( aStart, aEnd );
988 SdrTextVertAdjust eAdj = SDRTEXTVERTADJUST_TOP;
990 switch( nSId )
992 case SID_TABLE_VERT_BOTTOM:
993 eAdj = SDRTEXTVERTADJUST_BOTTOM;
994 break;
995 case SID_TABLE_VERT_CENTER:
996 eAdj = SDRTEXTVERTADJUST_CENTER;
997 break;
998 //case SID_TABLE_VERT_NONE:
999 default:
1000 break;
1003 SdrTextVertAdjustItem aItem( eAdj );
1005 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
1007 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
1009 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
1010 if( xCell.is() )
1011 xCell->SetMergedItem(aItem);
1015 UpdateTableShape();
1019 void SvxTableController::MergeMarkedCells()
1021 CellPos aStart, aEnd;
1022 getSelectedCells( aStart, aEnd );
1023 SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
1024 if( pTableObj )
1026 if( pTableObj->IsTextEditActive() )
1027 mpView->SdrEndTextEdit(true);
1029 TableModelNotifyGuard aGuard( mxTable.get() );
1030 MergeRange( aStart.mnCol, aStart.mnRow, aEnd.mnCol, aEnd.mnRow );
1034 void SvxTableController::SplitMarkedCells()
1036 if( mxTable.is() )
1038 CellPos aStart, aEnd;
1039 getSelectedCells( aStart, aEnd );
1041 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
1042 boost::scoped_ptr< SvxAbstractSplittTableDialog > xDlg( pFact ? pFact->CreateSvxSplittTableDialog( NULL, false, 99, 99 ) : 0 );
1043 if( xDlg.get() && xDlg->Execute() )
1045 const sal_Int32 nCount = xDlg->GetCount() - 1;
1046 if( nCount < 1 )
1047 return;
1049 getSelectedCells( aStart, aEnd );
1051 Reference< XMergeableCellRange > xRange( mxTable->createCursorByRange( mxTable->getCellRangeByPosition( aStart.mnCol, aStart.mnRow, aEnd.mnCol, aEnd.mnRow ) ), UNO_QUERY_THROW );
1053 const sal_Int32 nRowCount = mxTable->getRowCount();
1054 const sal_Int32 nColCount = mxTable->getColumnCount();
1057 SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >( mxTableObj.get() );
1058 if( pTableObj )
1060 if( pTableObj->IsTextEditActive() )
1061 mpView->SdrEndTextEdit(true);
1063 TableModelNotifyGuard aGuard( mxTable.get() );
1065 const bool bUndo = mpModel && mpModel->IsUndoEnabled();
1066 if( bUndo )
1068 mpModel->BegUndo( ImpGetResStr(STR_TABLE_SPLIT) );
1069 mpModel->AddUndo( mpModel->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj) );
1072 if( xDlg->IsHorizontal() )
1074 xRange->split( 0, nCount );
1076 else
1078 xRange->split( nCount, 0 );
1081 if( bUndo )
1082 mpModel->EndUndo();
1084 aEnd.mnRow += mxTable->getRowCount() - nRowCount;
1085 aEnd.mnCol += mxTable->getColumnCount() - nColCount;
1087 setSelectedCells( aStart, aEnd );
1092 void SvxTableController::DistributeColumns()
1094 SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >( mxTableObj.get() );
1095 if( pTableObj )
1097 const bool bUndo = mpModel && mpModel->IsUndoEnabled();
1098 if( bUndo )
1100 mpModel->BegUndo( ImpGetResStr(STR_TABLE_DISTRIBUTE_COLUMNS) );
1101 mpModel->AddUndo( mpModel->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj) );
1104 CellPos aStart, aEnd;
1105 getSelectedCells( aStart, aEnd );
1106 pTableObj->DistributeColumns( aStart.mnCol, aEnd.mnCol );
1108 if( bUndo )
1109 mpModel->EndUndo();
1113 void SvxTableController::DistributeRows()
1115 SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >( mxTableObj.get() );
1116 if( pTableObj )
1118 const bool bUndo = mpModel && mpModel->IsUndoEnabled();
1119 if( bUndo )
1121 mpModel->BegUndo( ImpGetResStr(STR_TABLE_DISTRIBUTE_ROWS) );
1122 mpModel->AddUndo( mpModel->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj) );
1125 CellPos aStart, aEnd;
1126 getSelectedCells( aStart, aEnd );
1127 pTableObj->DistributeRows( aStart.mnRow, aEnd.mnRow );
1129 if( bUndo )
1130 mpModel->EndUndo();
1134 bool SvxTableController::DeleteMarked()
1136 if( mbCellSelectionMode )
1138 if( mxTable.is() )
1140 CellPos aStart, aEnd;
1141 getSelectedCells( aStart, aEnd );
1142 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
1144 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
1146 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
1147 if( xCell.is() )
1148 xCell->SetOutlinerParaObject( 0 );
1152 UpdateTableShape();
1153 return true;
1157 return false;
1160 bool SvxTableController::GetStyleSheet( SfxStyleSheet*& rpStyleSheet ) const
1162 if( hasSelectedCells() )
1164 rpStyleSheet = 0;
1166 if( mxTable.is() )
1168 SfxStyleSheet* pRet=0;
1169 bool b1st=true;
1171 CellPos aStart, aEnd;
1172 const_cast<SvxTableController&>(*this).getSelectedCells( aStart, aEnd );
1174 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
1176 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
1178 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
1179 if( xCell.is() )
1181 SfxStyleSheet* pSS=xCell->GetStyleSheet();
1182 if(b1st)
1184 pRet=pSS;
1186 else if(pRet != pSS)
1188 return true;
1190 b1st=false;
1194 rpStyleSheet = pRet;
1195 return true;
1198 return false;
1201 bool SvxTableController::SetStyleSheet( SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr )
1203 if( hasSelectedCells() && (!pStyleSheet || pStyleSheet->GetFamily() == SFX_STYLE_FAMILY_FRAME) )
1205 if( mxTable.is() )
1207 CellPos aStart, aEnd;
1208 getSelectedCells( aStart, aEnd );
1210 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
1212 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
1214 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
1215 if( xCell.is() )
1216 xCell->SetStyleSheet(pStyleSheet,bDontRemoveHardAttr);
1220 UpdateTableShape();
1221 return true;
1224 return false;
1228 // internals
1231 bool SvxTableController::checkTableObject()
1233 return mxTableObj.is();
1238 sal_uInt16 SvxTableController::getKeyboardAction( const KeyEvent& rKEvt, Window* /*pWindow*/ )
1240 const bool bMod1 = rKEvt.GetKeyCode().IsMod1(); // ctrl
1241 const bool bMod2 = rKEvt.GetKeyCode().IsMod2(); // Alt
1243 const bool bTextEdit = mpView->IsTextEdit();
1245 sal_uInt16 nAction = ACTION_HANDLED_BY_VIEW;
1247 ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
1248 if( !pTableObj )
1249 return nAction;
1251 // handle special keys
1252 const sal_Int16 nCode = rKEvt.GetKeyCode().GetCode();
1253 switch( nCode )
1255 case awt::Key::ESCAPE: // handle escape
1257 if( bTextEdit )
1259 // escape during text edit ends text edit
1260 nAction = ACTION_STOP_TEXT_EDIT;
1262 if( mbCellSelectionMode )
1264 // escape with selected cells removes selection
1265 nAction = ACTION_REMOVE_SELECTION;
1267 break;
1269 case awt::Key::RETURN: // handle return
1271 if( !bMod1 && !bMod2 && !bTextEdit )
1273 // when not already editing, return starts text edit
1274 setSelectionStart( pTableObj->getFirstCell() );
1275 nAction = ACTION_EDIT_CELL;
1277 break;
1279 case awt::Key::F2: // f2 toggles text edit
1281 if( bMod1 || bMod2 ) // f2 with modifiers is handled by the view
1284 else if( bTextEdit )
1286 // f2 during text edit stops text edit
1287 nAction = ACTION_STOP_TEXT_EDIT;
1289 else if( mbCellSelectionMode )
1291 // f2 with selected cells removes selection
1292 nAction = ACTION_REMOVE_SELECTION;
1294 else
1296 // f2 with no selection and no text edit starts text edit
1297 setSelectionStart( pTableObj->getFirstCell() );
1298 nAction = ACTION_EDIT_CELL;
1300 break;
1302 case awt::Key::HOME:
1303 case awt::Key::NUM7:
1305 if( (bMod1 || bMod2) && (bTextEdit || mbCellSelectionMode) )
1307 if( bMod1 && !bMod2 )
1309 // ctrl + home jumps to first cell
1310 nAction = ACTION_GOTO_FIRST_CELL;
1312 else if( !bMod1 && bMod2 )
1314 // alt + home jumps to first column
1315 nAction = ACTION_GOTO_FIRST_COLUMN;
1318 break;
1320 case awt::Key::END:
1321 case awt::Key::NUM1:
1323 if( (bMod1 || bMod2) && (bTextEdit || mbCellSelectionMode) )
1325 if( bMod1 && !bMod2 )
1327 // ctrl + end jumps to last cell
1328 nAction = ACTION_GOTO_LAST_CELL;
1330 else if( !bMod1 && bMod2 )
1332 // alt + home jumps to last column
1333 nAction = ACTION_GOTO_LAST_COLUMN;
1336 break;
1339 case awt::Key::TAB:
1341 if( bTextEdit || mbCellSelectionMode )
1342 nAction = ACTION_TAB;
1343 break;
1346 case awt::Key::UP:
1347 case awt::Key::NUM8:
1348 case awt::Key::DOWN:
1349 case awt::Key::NUM2:
1350 case awt::Key::LEFT:
1351 case awt::Key::NUM4:
1352 case awt::Key::RIGHT:
1353 case awt::Key::NUM6:
1355 bool bTextMove = false;
1357 if( !bMod1 && bMod2 )
1359 if( (nCode == awt::Key::UP) || (nCode == awt::Key::NUM8) )
1361 nAction = ACTION_GOTO_LEFT_CELL;
1363 else if( (nCode == awt::Key::DOWN) || (nCode == awt::Key::NUM2) )
1365 nAction = ACTION_GOTO_RIGHT_CELL;
1367 break;
1370 if( !bTextMove )
1372 OutlinerView* pOLV = mpView->GetTextEditOutlinerView();
1373 if( pOLV )
1375 RemoveSelection();
1376 // during text edit, check if we navigate out of the cell
1377 ESelection aOldSelection = pOLV->GetSelection();
1378 pOLV->PostKeyEvent(rKEvt);
1379 bTextMove = pOLV && ( aOldSelection.IsEqual(pOLV->GetSelection()) );
1380 if( !bTextMove )
1382 nAction = ACTION_NONE;
1387 if( mbCellSelectionMode || bTextMove )
1389 // no text edit, navigate in cells if selection active
1390 switch( nCode )
1392 case awt::Key::LEFT:
1393 case awt::Key::NUM4:
1394 nAction = ACTION_GOTO_LEFT_CELL;
1395 break;
1396 case awt::Key::RIGHT:
1397 case awt::Key::NUM6:
1398 nAction = ACTION_GOTO_RIGHT_CELL;
1399 break;
1400 case awt::Key::DOWN:
1401 case awt::Key::NUM2:
1402 nAction = ACTION_GOTO_DOWN_CELL;
1403 break;
1404 case awt::Key::UP:
1405 case awt::Key::NUM8:
1406 nAction = ACTION_GOTO_UP_CELL;
1407 break;
1410 break;
1412 case awt::Key::PAGEUP:
1413 if( bMod2 )
1414 nAction = ACTION_GOTO_FIRST_ROW;
1415 break;
1417 case awt::Key::PAGEDOWN:
1418 if( bMod2 )
1419 nAction = ACTION_GOTO_LAST_ROW;
1420 break;
1422 return nAction;
1425 bool SvxTableController::executeAction( sal_uInt16 nAction, bool bSelect, Window* pWindow )
1427 ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
1428 if( !pTableObj )
1429 return false;
1431 switch( nAction )
1433 case ACTION_GOTO_FIRST_CELL:
1435 gotoCell( pTableObj->getFirstCell(), bSelect, pWindow, nAction );
1436 break;
1439 case ACTION_GOTO_LEFT_CELL:
1441 gotoCell( pTableObj->getLeftCell( getSelectionEnd(), !bSelect ), bSelect, pWindow, nAction );
1442 break;
1445 case ACTION_GOTO_RIGHT_CELL:
1447 gotoCell( pTableObj->getRightCell( getSelectionEnd(), !bSelect ), bSelect, pWindow, nAction);
1448 break;
1451 case ACTION_GOTO_LAST_CELL:
1453 gotoCell( pTableObj->getLastCell(), bSelect, pWindow, nAction );
1454 break;
1457 case ACTION_GOTO_FIRST_COLUMN:
1459 CellPos aPos( pTableObj->getFirstCell().mnCol, getSelectionEnd().mnRow );
1460 gotoCell( aPos, bSelect, pWindow, nAction );
1461 break;
1464 case ACTION_GOTO_LAST_COLUMN:
1466 CellPos aPos( pTableObj->getLastCell().mnCol, getSelectionEnd().mnRow );
1467 gotoCell( aPos, bSelect, pWindow, nAction );
1468 break;
1471 case ACTION_GOTO_FIRST_ROW:
1473 CellPos aPos( getSelectionEnd().mnCol, pTableObj->getFirstCell().mnRow );
1474 gotoCell( aPos, bSelect, pWindow, nAction );
1475 break;
1478 case ACTION_GOTO_UP_CELL:
1480 gotoCell( pTableObj->getUpCell(getSelectionEnd(), !bSelect), bSelect, pWindow, nAction );
1481 break;
1484 case ACTION_GOTO_DOWN_CELL:
1486 gotoCell( pTableObj->getDownCell(getSelectionEnd(), !bSelect), bSelect, pWindow, nAction );
1487 break;
1490 case ACTION_GOTO_LAST_ROW:
1492 CellPos aPos( getSelectionEnd().mnCol, pTableObj->getLastCell().mnRow );
1493 gotoCell( aPos, bSelect, pWindow, nAction );
1494 break;
1497 case ACTION_EDIT_CELL:
1498 EditCell( getSelectionStart(), pWindow, 0, nAction );
1499 break;
1501 case ACTION_STOP_TEXT_EDIT:
1502 StopTextEdit();
1503 break;
1505 case ACTION_REMOVE_SELECTION:
1506 RemoveSelection();
1507 break;
1509 case ACTION_START_SELECTION:
1510 StartSelection( getSelectionStart() );
1511 break;
1513 case ACTION_TAB:
1515 if( bSelect )
1516 gotoCell( pTableObj->getPreviousCell( getSelectionEnd(), true ), false, pWindow, nAction );
1517 else
1519 CellPos aSelectionEnd( getSelectionEnd() );
1520 CellPos aNextCell( pTableObj->getNextCell( aSelectionEnd, true ) );
1521 if( aSelectionEnd == aNextCell )
1523 onInsert( SID_TABLE_INSERT_ROW, 0 );
1524 aNextCell = pTableObj->getNextCell( aSelectionEnd, true );
1526 gotoCell( aNextCell, false, pWindow, nAction );
1528 break;
1532 return nAction != ACTION_HANDLED_BY_VIEW;
1537 void SvxTableController::gotoCell( const CellPos& rPos, bool bSelect, Window* pWindow, sal_uInt16 nAction )
1539 if( mxTableObj.is() && static_cast<SdrTableObj*>(mxTableObj.get())->IsTextEditActive() )
1540 mpView->SdrEndTextEdit(true);
1542 if( bSelect )
1544 maCursorLastPos = rPos;
1545 if( mxTableObj.is() )
1546 static_cast< SdrTableObj* >( mxTableObj.get() )->setActiveCell( rPos );
1548 if( !mbCellSelectionMode )
1550 setSelectedCells( maCursorFirstPos, rPos );
1552 else
1554 UpdateSelection( rPos );
1557 else
1559 RemoveSelection();
1560 EditCell( rPos, pWindow, 0, nAction );
1566 const CellPos& SvxTableController::getSelectionStart()
1568 checkCell( maCursorFirstPos );
1569 return maCursorFirstPos;
1574 void SvxTableController::setSelectionStart( const CellPos& rPos )
1576 maCursorFirstPos = rPos;
1581 const CellPos& SvxTableController::getSelectionEnd()
1583 checkCell( maCursorLastPos );
1584 return maCursorLastPos;
1589 void SvxTableController::MergeRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow )
1591 if( mxTable.is() ) try
1593 Reference< XMergeableCellRange > xRange( mxTable->createCursorByRange( mxTable->getCellRangeByPosition( nFirstCol, nFirstRow,nLastCol, nLastRow ) ), UNO_QUERY_THROW );
1594 if( xRange->isMergeable() )
1596 const bool bUndo = mpModel && mpModel->IsUndoEnabled();
1597 if( bUndo )
1599 mpModel->BegUndo( ImpGetResStr(STR_TABLE_MERGE) );
1600 mpModel->AddUndo( mpModel->GetSdrUndoFactory().CreateUndoGeoObject(*mxTableObj.get()) );
1603 xRange->merge();
1605 if( bUndo )
1606 mpModel->EndUndo();
1609 catch( Exception& )
1611 DBG_ASSERT( false, "sdr::table::SvxTableController::MergeRange(), exception caught!" );
1619 void SvxTableController::checkCell( CellPos& rPos )
1621 if( mxTable.is() ) try
1623 if( rPos.mnCol >= mxTable->getColumnCount() )
1624 rPos.mnCol = mxTable->getColumnCount()-1;
1626 if( rPos.mnRow >= mxTable->getRowCount() )
1627 rPos.mnRow = mxTable->getRowCount()-1;
1629 catch( Exception& )
1631 OSL_FAIL("sdr::table::SvxTableController::checkCell(), exception caught!" );
1637 void SvxTableController::findMergeOrigin( CellPos& rPos )
1639 if( mxTable.is() ) try
1641 Reference< XMergeableCell > xCell( mxTable->getCellByPosition( rPos.mnCol, rPos.mnRow ), UNO_QUERY_THROW );
1642 if( xCell.is() && xCell->isMerged() )
1644 ::findMergeOrigin( mxTable, rPos.mnCol, rPos.mnRow, rPos.mnCol, rPos.mnRow );
1647 catch( Exception& )
1649 OSL_FAIL("sdr::table::SvxTableController::findMergeOrigin(), exception caught!" );
1655 void SvxTableController::EditCell( const CellPos& rPos, ::Window* pWindow, const awt::MouseEvent* pMouseEvent /*= 0*/, sal_uInt16 nAction /*= ACTION_NONE */ )
1657 SdrPageView* pPV = mpView->GetSdrPageView();
1659 ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
1660 if( pTableObj && pTableObj->GetPage() == pPV->GetPage() )
1662 bool bEmptyOutliner = false;
1664 if(!pTableObj->GetOutlinerParaObject() && mpView->GetTextEditOutliner())
1666 ::Outliner* pOutl = mpView->GetTextEditOutliner();
1667 sal_Int32 nParaAnz = pOutl->GetParagraphCount();
1668 Paragraph* p1stPara = pOutl->GetParagraph( 0 );
1670 if(nParaAnz==1 && p1stPara)
1672 // Bei nur einem Pararaph
1673 if (pOutl->GetText(p1stPara).isEmpty())
1675 bEmptyOutliner = true;
1680 CellPos aPos( rPos );
1681 findMergeOrigin( aPos );
1683 if( pTableObj != mpView->GetTextEditObject() || bEmptyOutliner || !pTableObj->IsTextEditActive( aPos ) )
1685 if( pTableObj->IsTextEditActive() )
1686 mpView->SdrEndTextEdit(true);
1688 pTableObj->setActiveCell( aPos );
1690 // create new outliner, owner will be the SdrObjEditView
1691 SdrOutliner* pOutl = SdrMakeOutliner( OUTLINERMODE_OUTLINEOBJECT, mpModel );
1692 if( pTableObj->IsVerticalWriting() )
1693 pOutl->SetVertical( true );
1695 if(mpView->SdrBeginTextEdit(pTableObj, pPV, pWindow, true, pOutl))
1697 maCursorLastPos = maCursorFirstPos = rPos;
1699 OutlinerView* pOLV = mpView->GetTextEditOutlinerView();
1701 bool bNoSel = true;
1703 if( pMouseEvent )
1705 ::MouseEvent aMEvt( *pMouseEvent );
1707 SdrViewEvent aVEvt;
1708 SdrHitKind eHit = mpView->PickAnything(aMEvt, SDRMOUSEBUTTONDOWN, aVEvt);
1710 if (eHit == SDRHIT_TEXTEDIT)
1712 // Text getroffen
1713 pOLV->MouseButtonDown(aMEvt);
1714 pOLV->MouseMove(aMEvt);
1715 pOLV->MouseButtonUp(aMEvt);
1716 // pOLV->MouseButtonDown(aMEvt);
1717 bNoSel = false;
1719 else
1721 nAction = ACTION_GOTO_LEFT_CELL;
1725 if( bNoSel )
1727 // Move cursor to end of text
1728 ESelection aNewSelection;
1730 const WritingMode eMode = pTableObj->GetWritingMode();
1731 if( ((nAction == ACTION_GOTO_LEFT_CELL) || (nAction == ACTION_GOTO_RIGHT_CELL)) && (eMode != WritingMode_TB_RL) )
1733 const bool bLast = ((nAction == ACTION_GOTO_LEFT_CELL) && (eMode == WritingMode_LR_TB)) ||
1734 ((nAction == ACTION_GOTO_RIGHT_CELL) && (eMode == WritingMode_RL_TB));
1736 if( bLast )
1737 aNewSelection = ESelection(EE_PARA_NOT_FOUND, EE_INDEX_NOT_FOUND, EE_PARA_NOT_FOUND, EE_INDEX_NOT_FOUND);
1739 pOLV->SetSelection(aNewSelection);
1748 bool SvxTableController::StopTextEdit()
1750 if(mpView->IsTextEdit())
1752 mpView->SdrEndTextEdit();
1753 mpView->SetCurrentObj(OBJ_TABLE);
1754 mpView->SetEditMode(SDREDITMODE_EDIT);
1755 return true;
1757 else
1759 return false;
1765 void SvxTableController::getSelectedCells( CellPos& rFirst, CellPos& rLast )
1767 if( mbCellSelectionMode )
1769 checkCell( maCursorFirstPos );
1770 checkCell( maCursorLastPos );
1772 rFirst.mnCol = std::min( maCursorFirstPos.mnCol, maCursorLastPos.mnCol );
1773 rFirst.mnRow = std::min( maCursorFirstPos.mnRow, maCursorLastPos.mnRow );
1774 rLast.mnCol = std::max( maCursorFirstPos.mnCol, maCursorLastPos.mnCol );
1775 rLast.mnRow = std::max( maCursorFirstPos.mnRow, maCursorLastPos.mnRow );
1777 bool bExt = false;
1778 if( mxTable.is() ) do
1780 bExt = false;
1781 for( sal_Int32 nRow = rFirst.mnRow; nRow <= rLast.mnRow && !bExt; nRow++ )
1783 for( sal_Int32 nCol = rFirst.mnCol; nCol <= rLast.mnCol && !bExt; nCol++ )
1785 Reference< XMergeableCell > xCell( mxTable->getCellByPosition( nCol, nRow ), UNO_QUERY );
1786 if( !xCell.is() )
1787 continue;
1789 if( xCell->isMerged() )
1791 CellPos aPos( nCol, nRow );
1792 findMergeOrigin( aPos );
1793 if( (aPos.mnCol < rFirst.mnCol) || (aPos.mnRow < rFirst.mnRow) )
1795 rFirst.mnCol = std::min( rFirst.mnCol, aPos.mnCol );
1796 rFirst.mnRow = std::min( rFirst.mnRow, aPos.mnRow );
1797 bExt = true;
1800 else
1802 if( ((nCol + xCell->getColumnSpan() - 1) > rLast.mnCol) || (nRow + xCell->getRowSpan() - 1 ) > rLast.mnRow )
1804 rLast.mnCol = std::max( rLast.mnCol, nCol + xCell->getColumnSpan() - 1 );
1805 rLast.mnRow = std::max( rLast.mnRow, nRow + xCell->getRowSpan() - 1 );
1806 bExt = true;
1812 while(bExt);
1814 else if( mpView && mpView->IsTextEdit() )
1816 rFirst = getSelectionStart();
1817 findMergeOrigin( rFirst );
1818 rLast = rFirst;
1820 if( mxTable.is() )
1822 Reference< XMergeableCell > xCell( mxTable->getCellByPosition( rLast.mnCol, rLast.mnRow ), UNO_QUERY );
1823 if( xCell.is() )
1825 rLast.mnCol += xCell->getColumnSpan() - 1;
1826 rLast.mnRow += xCell->getRowSpan() - 1;
1830 else
1832 rFirst.mnCol = 0;
1833 rFirst.mnRow = 0;
1834 if( mxTable.is() )
1836 rLast.mnRow = mxTable->getRowCount()-1;
1837 rLast.mnCol = mxTable->getColumnCount()-1;
1839 else
1841 rLast.mnRow = 0;
1842 rLast.mnCol = 0;
1849 void SvxTableController::StartSelection( const CellPos& rPos )
1851 StopTextEdit();
1852 mbCellSelectionMode = true;
1853 maCursorLastPos = maCursorFirstPos = rPos;
1854 mpView->MarkListHasChanged();
1859 void SvxTableController::setSelectedCells( const CellPos& rStart, const CellPos& rEnd )
1861 StopTextEdit();
1862 mbCellSelectionMode = true;
1863 maCursorFirstPos = rStart;
1864 UpdateSelection( rEnd );
1869 void SvxTableController::UpdateSelection( const CellPos& rPos )
1871 maCursorLastPos = rPos;
1872 mpView->MarkListHasChanged();
1877 void SvxTableController::clearSelection()
1879 RemoveSelection();
1884 void SvxTableController::selectAll()
1886 if( mxTable.is() )
1888 CellPos aPos1, aPos2( mxTable->getColumnCount()-1, mxTable->getRowCount()-1 );
1889 if( (aPos2.mnCol >= 0) && (aPos2.mnRow >= 0) )
1891 setSelectedCells( aPos1, aPos2 );
1898 void SvxTableController::RemoveSelection()
1900 if( mbCellSelectionMode )
1902 mbCellSelectionMode = false;
1903 mpView->MarkListHasChanged();
1909 void SvxTableController::onTableModified()
1911 if( mnUpdateEvent == 0 )
1912 mnUpdateEvent = Application::PostUserEvent( LINK( this, SvxTableController, UpdateHdl ) );
1916 void SvxTableController::updateSelectionOverlay()
1918 destroySelectionOverlay();
1919 if( mbCellSelectionMode )
1921 ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
1922 if( pTableObj )
1924 sdr::overlay::OverlayObjectCell::RangeVector aRanges;
1926 Rectangle aRect;
1927 CellPos aStart,aEnd;
1928 getSelectedCells( aStart, aEnd );
1929 pTableObj->getCellBounds( aStart, aRect );
1931 basegfx::B2DRange a2DRange( basegfx::B2DPoint(aRect.Left(), aRect.Top()) );
1932 a2DRange.expand( basegfx::B2DPoint(aRect.Right(), aRect.Bottom()) );
1934 findMergeOrigin( aEnd );
1935 pTableObj->getCellBounds( aEnd, aRect );
1936 a2DRange.expand( basegfx::B2DPoint(aRect.Left(), aRect.Top()) );
1937 a2DRange.expand( basegfx::B2DPoint(aRect.Right(), aRect.Bottom()) );
1938 aRanges.push_back( a2DRange );
1940 ::Color aHighlight( COL_BLUE );
1941 OutputDevice* pOutDev = mpView->GetFirstOutputDevice();
1942 if( pOutDev )
1943 aHighlight = pOutDev->GetSettings().GetStyleSettings().GetHighlightColor();
1945 const sal_uInt32 nCount = mpView->PaintWindowCount();
1946 for( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ )
1948 SdrPaintWindow* pPaintWindow = mpView->GetPaintWindow(nIndex);
1949 if( pPaintWindow )
1951 rtl::Reference < ::sdr::overlay::OverlayManager > xOverlayManager = pPaintWindow->GetOverlayManager();
1952 if( xOverlayManager.is() )
1954 // sdr::overlay::CellOverlayType eType = sdr::overlay::CELL_OVERLAY_INVERT;
1955 sdr::overlay::CellOverlayType eType = sdr::overlay::CELL_OVERLAY_TRANSPARENT;
1957 sdr::overlay::OverlayObjectCell* pOverlay = new sdr::overlay::OverlayObjectCell( eType, aHighlight, aRanges );
1959 xOverlayManager->add(*pOverlay);
1960 mpSelectionOverlay = new ::sdr::overlay::OverlayObjectList;
1961 mpSelectionOverlay->append(*pOverlay);
1971 void SvxTableController::destroySelectionOverlay()
1973 if( mpSelectionOverlay )
1975 delete mpSelectionOverlay;
1976 mpSelectionOverlay = 0;
1982 void SvxTableController::MergeAttrFromSelectedCells(SfxItemSet& rAttr, bool bOnlyHardAttr) const
1984 if( mxTable.is() )
1986 CellPos aStart, aEnd;
1987 const_cast<SvxTableController&>(*this).getSelectedCells( aStart, aEnd );
1989 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
1991 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
1993 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
1994 if( xCell.is() && !xCell->isMerged() )
1996 const SfxItemSet& rSet = xCell->GetItemSet();
1997 SfxWhichIter aIter(rSet);
1998 sal_uInt16 nWhich(aIter.FirstWhich());
1999 while(nWhich)
2001 if(!bOnlyHardAttr)
2003 if(SFX_ITEM_DONTCARE == rSet.GetItemState(nWhich, false))
2004 rAttr.InvalidateItem(nWhich);
2005 else
2006 rAttr.MergeValue(rSet.Get(nWhich), true);
2008 else if(SFX_ITEM_SET == rSet.GetItemState(nWhich, false))
2010 const SfxPoolItem& rItem = rSet.Get(nWhich);
2011 rAttr.MergeValue(rItem, true);
2014 nWhich = aIter.NextWhich();
2024 const sal_uInt16 CELL_BEFORE = 0x0001;
2025 const sal_uInt16 CELL_LEFT = 0x0002;
2026 const sal_uInt16 CELL_RIGHT = 0x0004;
2027 const sal_uInt16 CELL_AFTER = 0x0008;
2029 const sal_uInt16 CELL_UPPER = 0x0010;
2030 const sal_uInt16 CELL_TOP = 0x0020;
2031 const sal_uInt16 CELL_BOTTOM = 0x0040;
2032 const sal_uInt16 CELL_LOWER = 0x0080;
2036 static void ImplSetLinePreserveColor( SvxBoxItem& rNewFrame, const SvxBorderLine* pNew, sal_uInt16 nLine )
2038 if( pNew )
2040 const SvxBorderLine* pOld = rNewFrame.GetLine(nLine);
2041 if( pOld )
2043 SvxBorderLine aNewLine( *pNew );
2044 aNewLine.SetColor( pOld->GetColor() );
2045 rNewFrame.SetLine( &aNewLine, nLine );
2046 return;
2049 rNewFrame.SetLine( pNew, nLine );
2054 static void ImplApplyBoxItem( sal_uInt16 nCellFlags, const SvxBoxItem* pBoxItem, const SvxBoxInfoItem* pBoxInfoItem, SvxBoxItem& rNewFrame )
2056 if( (nCellFlags & (CELL_BEFORE|CELL_AFTER|CELL_UPPER|CELL_LOWER)) != 0 )
2058 // current cell is outside the selection
2060 if( (nCellFlags & ( CELL_BEFORE|CELL_AFTER)) == 0 ) // check if its not nw or ne corner
2062 if( nCellFlags & CELL_UPPER )
2064 if( pBoxInfoItem->IsValid(VALID_TOP) )
2065 rNewFrame.SetLine(0, BOX_LINE_BOTTOM );
2067 else if( nCellFlags & CELL_LOWER )
2069 if( pBoxInfoItem->IsValid(VALID_BOTTOM) )
2070 rNewFrame.SetLine( 0, BOX_LINE_TOP );
2073 else if( (nCellFlags & ( CELL_UPPER|CELL_LOWER)) == 0 ) // check if its not sw or se corner
2075 if( nCellFlags & CELL_BEFORE )
2077 if( pBoxInfoItem->IsValid(VALID_LEFT) )
2078 rNewFrame.SetLine( 0, BOX_LINE_RIGHT );
2080 else if( nCellFlags & CELL_AFTER )
2082 if( pBoxInfoItem->IsValid(VALID_RIGHT) )
2083 rNewFrame.SetLine( 0, BOX_LINE_LEFT );
2087 else
2089 // current cell is inside the selection
2091 if( (nCellFlags & CELL_LEFT) ? pBoxInfoItem->IsValid(VALID_LEFT) : pBoxInfoItem->IsValid(VALID_VERT) )
2092 rNewFrame.SetLine( (nCellFlags & CELL_LEFT) ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(), BOX_LINE_LEFT );
2094 if( (nCellFlags & CELL_RIGHT) ? pBoxInfoItem->IsValid(VALID_RIGHT) : pBoxInfoItem->IsValid(VALID_VERT) )
2095 rNewFrame.SetLine( (nCellFlags & CELL_RIGHT) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(), BOX_LINE_RIGHT );
2097 if( (nCellFlags & CELL_TOP) ? pBoxInfoItem->IsValid(VALID_TOP) : pBoxInfoItem->IsValid(VALID_HORI) )
2098 rNewFrame.SetLine( (nCellFlags & CELL_TOP) ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(), BOX_LINE_TOP );
2100 if( (nCellFlags & CELL_BOTTOM) ? pBoxInfoItem->IsValid(VALID_BOTTOM) : pBoxInfoItem->IsValid(VALID_HORI) )
2101 rNewFrame.SetLine( (nCellFlags & CELL_BOTTOM) ? pBoxItem->GetBottom() : pBoxInfoItem->GetHori(), BOX_LINE_BOTTOM );
2103 // apply distance to borders
2104 if( pBoxInfoItem->IsValid( VALID_DISTANCE ) )
2105 for( sal_uInt16 nLine = 0; nLine < 4; ++nLine )
2106 rNewFrame.SetDistance( pBoxItem->GetDistance( nLine ), nLine );
2112 static void ImplSetLineColor( SvxBoxItem& rNewFrame, sal_uInt16 nLine, const Color& rColor )
2114 const SvxBorderLine* pSourceLine = rNewFrame.GetLine( nLine );
2115 if( pSourceLine )
2117 SvxBorderLine aLine( *pSourceLine );
2118 aLine.SetColor( rColor );
2119 rNewFrame.SetLine( &aLine, nLine );
2125 static void ImplApplyLineColorItem( sal_uInt16 nCellFlags, const SvxColorItem* pLineColorItem, SvxBoxItem& rNewFrame )
2127 const Color aColor( pLineColorItem->GetValue() );
2129 if( (nCellFlags & (CELL_LOWER|CELL_BEFORE|CELL_AFTER)) == 0 )
2130 ImplSetLineColor( rNewFrame, BOX_LINE_BOTTOM, aColor );
2132 if( (nCellFlags & (CELL_UPPER|CELL_BEFORE|CELL_AFTER)) == 0 )
2133 ImplSetLineColor( rNewFrame, BOX_LINE_TOP, aColor );
2135 if( (nCellFlags & (CELL_UPPER|CELL_LOWER|CELL_AFTER)) == 0 )
2136 ImplSetLineColor( rNewFrame, BOX_LINE_RIGHT, aColor );
2138 if( (nCellFlags & (CELL_UPPER|CELL_LOWER|CELL_BEFORE)) == 0 )
2139 ImplSetLineColor( rNewFrame, BOX_LINE_LEFT, aColor );
2144 static void ImplApplyBorderLineItem( sal_uInt16 nCellFlags, const SvxBorderLine* pBorderLineItem, SvxBoxItem& rNewFrame )
2146 if( (nCellFlags & ( CELL_BEFORE|CELL_AFTER|CELL_UPPER|CELL_LOWER)) != 0 )
2148 if( (nCellFlags & ( CELL_BEFORE|CELL_AFTER)) == 0 ) // check if its not nw or ne corner
2150 if( nCellFlags & CELL_UPPER )
2152 if( rNewFrame.GetBottom() )
2153 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_BOTTOM );
2155 else if( nCellFlags & CELL_LOWER )
2157 if( rNewFrame.GetTop() )
2158 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_TOP );
2161 else if( (nCellFlags & ( CELL_UPPER|CELL_LOWER)) == 0 ) // check if its not sw or se corner
2163 if( nCellFlags & CELL_BEFORE )
2165 if( rNewFrame.GetRight() )
2166 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_RIGHT );
2168 else if( nCellFlags & CELL_AFTER )
2170 if( rNewFrame.GetLeft() )
2171 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_LEFT );
2175 else
2177 if( rNewFrame.GetBottom() )
2178 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_BOTTOM );
2179 if( rNewFrame.GetTop() )
2180 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_TOP );
2181 if( rNewFrame.GetRight() )
2182 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_RIGHT );
2183 if( rNewFrame.GetLeft() )
2184 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_LEFT );
2190 void SvxTableController::ApplyBorderAttr( const SfxItemSet& rAttr )
2192 if( mxTable.is() )
2194 const sal_Int32 nRowCount = mxTable->getRowCount();
2195 const sal_Int32 nColCount = mxTable->getColumnCount();
2196 if( nRowCount && nColCount )
2198 const SvxBoxItem* pBoxItem = 0;
2199 if(SFX_ITEM_SET == rAttr.GetItemState(SDRATTR_TABLE_BORDER, false) )
2200 pBoxItem = dynamic_cast< const SvxBoxItem* >( &rAttr.Get( SDRATTR_TABLE_BORDER ) );
2202 const SvxBoxInfoItem* pBoxInfoItem = 0;
2203 if(SFX_ITEM_SET == rAttr.GetItemState(SDRATTR_TABLE_BORDER_INNER, false) )
2204 pBoxInfoItem = dynamic_cast< const SvxBoxInfoItem* >( &rAttr.Get( SDRATTR_TABLE_BORDER_INNER ) );
2206 const SvxColorItem* pLineColorItem = 0;
2207 if(SFX_ITEM_SET == rAttr.GetItemState(SID_FRAME_LINECOLOR, false) )
2208 pLineColorItem = dynamic_cast< const SvxColorItem* >( &rAttr.Get( SID_FRAME_LINECOLOR ) );
2210 const SvxBorderLine* pBorderLineItem = 0;
2211 if(SFX_ITEM_SET == rAttr.GetItemState(SID_FRAME_LINESTYLE, false) )
2212 pBorderLineItem = ((const SvxLineItem&)rAttr.Get( SID_FRAME_LINESTYLE )).GetLine();
2214 if( pBoxInfoItem && !pBoxItem )
2216 const static SvxBoxItem gaEmptyBoxItem( SDRATTR_TABLE_BORDER );
2217 pBoxItem = &gaEmptyBoxItem;
2219 else if( pBoxItem && !pBoxInfoItem )
2221 const static SvxBoxInfoItem gaEmptyBoxInfoItem( SDRATTR_TABLE_BORDER_INNER );
2222 pBoxInfoItem = &gaEmptyBoxInfoItem;
2225 CellPos aStart, aEnd;
2226 getSelectedCells( aStart, aEnd );
2228 const sal_Int32 nLastRow = std::min( aEnd.mnRow + 2, nRowCount );
2229 const sal_Int32 nLastCol = std::min( aEnd.mnCol + 2, nColCount );
2231 for( sal_Int32 nRow = std::max( aStart.mnRow - 1, (sal_Int32)0 ); nRow < nLastRow; nRow++ )
2233 sal_uInt16 nRowFlags = 0;
2234 nRowFlags |= (nRow == aStart.mnRow) ? CELL_TOP : 0;
2235 nRowFlags |= (nRow == aEnd.mnRow) ? CELL_BOTTOM : 0;
2236 nRowFlags |= (nRow < aStart.mnRow) ? CELL_UPPER : 0;
2237 nRowFlags |= (nRow > aEnd.mnRow) ? CELL_LOWER : 0;
2239 for( sal_Int32 nCol = std::max( aStart.mnCol - 1, (sal_Int32)0 ); nCol < nLastCol; nCol++ )
2241 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
2242 if( !xCell.is() )
2243 continue;
2245 const SfxItemSet& rSet = xCell->GetItemSet();
2246 const SvxBoxItem* pOldOuter = (const SvxBoxItem*) &rSet.Get( SDRATTR_TABLE_BORDER );
2248 SvxBoxItem aNewFrame( *pOldOuter );
2250 sal_uInt16 nCellFlags = nRowFlags;
2251 nCellFlags |= (nCol == aStart.mnCol) ? CELL_LEFT : 0;
2252 nCellFlags |= (nCol == aEnd.mnCol) ? CELL_RIGHT : 0;
2253 nCellFlags |= (nCol < aStart.mnCol) ? CELL_BEFORE : 0;
2254 nCellFlags |= (nCol > aEnd.mnCol) ? CELL_AFTER : 0;
2256 if( pBoxItem && pBoxInfoItem )
2257 ImplApplyBoxItem( nCellFlags, pBoxItem, pBoxInfoItem, aNewFrame );
2259 if( pLineColorItem )
2260 ImplApplyLineColorItem( nCellFlags, pLineColorItem, aNewFrame );
2262 if( pBorderLineItem )
2263 ImplApplyBorderLineItem( nCellFlags, pBorderLineItem, aNewFrame );
2265 if (aNewFrame != *pOldOuter)
2267 SfxItemSet aAttr(*rSet.GetPool(), rSet.GetRanges());
2268 aAttr.Put(aNewFrame);
2269 xCell->SetMergedItemSetAndBroadcast( aAttr, false );
2279 void SvxTableController::UpdateTableShape()
2281 SdrObject* pTableObj = mxTableObj.get();
2282 if( pTableObj )
2284 pTableObj->ActionChanged();
2285 pTableObj->BroadcastObjectChange();
2287 updateSelectionOverlay();
2293 void SvxTableController::SetAttrToSelectedCells(const SfxItemSet& rAttr, bool bReplaceAll)
2295 if( mxTable.is() )
2297 const bool bUndo = mpModel && mpModel->IsUndoEnabled();
2299 if( bUndo )
2300 mpModel->BegUndo( ImpGetResStr(STR_TABLE_NUMFORMAT) );
2302 CellPos aStart, aEnd;
2303 getSelectedCells( aStart, aEnd );
2305 SfxItemSet aAttr(*rAttr.GetPool(), rAttr.GetRanges());
2306 aAttr.Put(rAttr, true);
2308 const bool bFrame = (rAttr.GetItemState( SDRATTR_TABLE_BORDER ) == SFX_ITEM_SET) || (rAttr.GetItemState( SDRATTR_TABLE_BORDER_INNER ) == SFX_ITEM_SET);
2310 if( bFrame )
2312 aAttr.ClearItem( SDRATTR_TABLE_BORDER );
2313 aAttr.ClearItem( SDRATTR_TABLE_BORDER_INNER );
2316 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
2318 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
2320 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
2321 if( xCell.is() )
2323 if( bUndo )
2324 xCell->AddUndo();
2325 xCell->SetMergedItemSetAndBroadcast(aAttr, bReplaceAll);
2330 if( bFrame )
2332 ApplyBorderAttr( rAttr );
2335 UpdateTableShape();
2337 if( bUndo )
2338 mpModel->EndUndo();
2345 bool SvxTableController::GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const
2347 if( mxTableObj.is() && hasSelectedCells() )
2349 MergeAttrFromSelectedCells( rTargetSet, bOnlyHardAttr );
2351 if( mpView->IsTextEdit() )
2353 if( mxTableObj->GetOutlinerParaObject() )
2354 rTargetSet.Put( SvxScriptTypeItem( mxTableObj->GetOutlinerParaObject()->GetTextObject().GetScriptType() ) );
2356 OutlinerView* pTextEditOutlinerView = mpView->GetTextEditOutlinerView();
2357 if(pTextEditOutlinerView)
2359 // FALSE= InvalidItems nicht al Default, sondern als "Loecher" betrachten
2360 rTargetSet.Put(pTextEditOutlinerView->GetAttribs(), false);
2361 rTargetSet.Put( SvxScriptTypeItem( pTextEditOutlinerView->GetSelectedScriptType() ) );
2365 return true;
2367 else
2369 return false;
2375 bool SvxTableController::SetAttributes(const SfxItemSet& rSet, bool bReplaceAll)
2377 if( mbCellSelectionMode || mpView->IsTextEdit() )
2379 SetAttrToSelectedCells( rSet, bReplaceAll );
2380 return true;
2382 return false;
2387 bool SvxTableController::GetMarkedObjModel( SdrPage* pNewPage )
2389 if( mxTableObj.is() && mbCellSelectionMode && pNewPage ) try
2391 ::sdr::table::SdrTableObj& rTableObj = *static_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
2393 CellPos aStart, aEnd;
2394 getSelectedCells( aStart, aEnd );
2396 SdrTableObj* pNewTableObj = rTableObj.CloneRange( aStart, aEnd );
2398 pNewTableObj->SetPage( pNewPage );
2399 pNewTableObj->SetModel( pNewPage->GetModel() );
2401 SdrInsertReason aReason(SDRREASON_VIEWCALL);
2402 pNewPage->InsertObject(pNewTableObj,CONTAINER_APPEND,&aReason);
2404 return true;
2406 catch( Exception& )
2408 OSL_FAIL( "svx::SvxTableController::GetMarkedObjModel(), exception caught!" );
2410 return false;
2415 bool SvxTableController::PasteObjModel( const SdrModel& rModel )
2417 if( mxTableObj.is() && mpView && (rModel.GetPageCount() >= 1) )
2419 const SdrPage* pPastePage = rModel.GetPage(0);
2420 if( pPastePage && pPastePage->GetObjCount() == 1 )
2422 SdrTableObj* pPasteTableObj = dynamic_cast< SdrTableObj* >( pPastePage->GetObj(0) );
2423 if( pPasteTableObj )
2425 return PasteObject( pPasteTableObj );
2430 return false;
2435 bool SvxTableController::PasteObject( SdrTableObj* pPasteTableObj )
2437 if( !pPasteTableObj )
2438 return false;
2440 Reference< XTable > xPasteTable( pPasteTableObj->getTable() );
2441 if( !xPasteTable.is() )
2442 return false;
2444 if( !mxTable.is() )
2445 return false;
2447 sal_Int32 nPasteColumns = xPasteTable->getColumnCount();
2448 sal_Int32 nPasteRows = xPasteTable->getRowCount();
2450 CellPos aStart, aEnd;
2451 getSelectedCells( aStart, aEnd );
2453 if( mpView->IsTextEdit() )
2454 mpView->SdrEndTextEdit(true);
2456 sal_Int32 nColumns = mxTable->getColumnCount();
2457 sal_Int32 nRows = mxTable->getRowCount();
2459 const sal_Int32 nMissing = nPasteRows - ( nRows - aStart.mnRow );
2460 if( nMissing > 0 )
2462 Reference< XTableRows > xRows( mxTable->getRows() );
2463 xRows->insertByIndex( nRows, nMissing );
2464 nRows = mxTable->getRowCount();
2467 nPasteRows = std::min( nPasteRows, nRows - aStart.mnRow );
2468 nPasteColumns = std::min( nPasteColumns, nColumns - aStart.mnCol );
2470 // copy cell contents
2471 for( sal_Int32 nRow = 0; nRow < nPasteRows; ++nRow )
2473 for( sal_Int32 nCol = 0; nCol < nPasteColumns; ++nCol )
2475 CellRef xTargetCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( aStart.mnCol + nCol, aStart.mnRow + nRow ).get() ) );
2476 if( xTargetCell.is() && !xTargetCell->isMerged() )
2478 xTargetCell->AddUndo();
2479 xTargetCell->cloneFrom( dynamic_cast< Cell* >( xPasteTable->getCellByPosition( nCol, nRow ).get() ) );
2480 nCol += xTargetCell->getColumnSpan() - 1;
2485 UpdateTableShape();
2487 return true;
2490 bool SvxTableController::TakeFormatPaintBrush( boost::shared_ptr< SfxItemSet >& /*rFormatSet*/ )
2492 // SdrView::TakeFormatPaintBrush() is enough
2493 return false;
2496 bool SvxTableController::ApplyFormatPaintBrush( SfxItemSet& rFormatSet, bool bNoCharacterFormats, bool bNoParagraphFormats )
2498 if( mbCellSelectionMode )
2500 SdrTextObj* pTableObj = dynamic_cast<SdrTextObj*>( mxTableObj.get() );
2501 if( !pTableObj )
2502 return false;
2504 const bool bUndo = mpModel && mpModel->IsUndoEnabled();
2506 if( bUndo )
2507 mpModel->BegUndo( ImpGetResStr(STR_TABLE_NUMFORMAT) );
2509 CellPos aStart, aEnd;
2510 getSelectedCells( aStart, aEnd );
2512 SfxItemSet aAttr(*rFormatSet.GetPool(), rFormatSet.GetRanges());
2513 aAttr.Put(rFormatSet, true);
2515 const bool bFrame = (rFormatSet.GetItemState( SDRATTR_TABLE_BORDER ) == SFX_ITEM_SET) || (rFormatSet.GetItemState( SDRATTR_TABLE_BORDER_INNER ) == SFX_ITEM_SET);
2517 if( bFrame )
2519 aAttr.ClearItem( SDRATTR_TABLE_BORDER );
2520 aAttr.ClearItem( SDRATTR_TABLE_BORDER_INNER );
2523 const sal_uInt16* pRanges = rFormatSet.GetRanges();
2524 bool bTextOnly = true;
2526 while( *pRanges )
2528 if( (*pRanges != EE_PARA_START) && (*pRanges != EE_CHAR_START) )
2530 bTextOnly = false;
2531 break;
2533 pRanges += 2;
2536 const bool bReplaceAll = false;
2537 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
2539 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
2541 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
2542 if( xCell.is() )
2544 if( bUndo )
2545 xCell->AddUndo();
2546 if( !bTextOnly )
2547 xCell->SetMergedItemSetAndBroadcast(aAttr, bReplaceAll);
2549 SdrText* pText = static_cast< SdrText* >( xCell.get() );
2550 mpView->ApplyFormatPaintBrushToText( rFormatSet, *pTableObj, pText, bNoCharacterFormats, bNoParagraphFormats );
2555 if( bFrame )
2557 ApplyBorderAttr( rFormatSet );
2560 UpdateTableShape();
2562 if( bUndo )
2563 mpModel->EndUndo();
2565 return true;
2568 return false;
2574 IMPL_LINK_NOARG(SvxTableController, UpdateHdl)
2576 mnUpdateEvent = 0;
2578 if( mbCellSelectionMode )
2580 CellPos aStart( maCursorFirstPos );
2581 CellPos aEnd( maCursorLastPos );
2582 checkCell(aStart);
2583 checkCell(aEnd);
2584 if( aStart != maCursorFirstPos || aEnd != maCursorLastPos )
2586 setSelectedCells( aStart, aEnd );
2589 updateSelectionOverlay();
2591 return 0;
2594 namespace
2597 struct LinesState
2599 LinesState(SvxBoxItem& rBoxItem_, SvxBoxInfoItem& rBoxInfoItem_)
2600 : rBoxItem(rBoxItem_)
2601 , rBoxInfoItem(rBoxInfoItem_)
2602 , bDistanceIndeterminate(false)
2604 std::fill_n(aBorderSet, 4, false);
2605 std::fill_n(aInnerLineSet, 2, false);
2606 std::fill_n(aBorderIndeterminate, 4, false);
2607 std::fill_n(aInnerLineIndeterminate, 2, false);
2608 std::fill_n(aDistanceSet, 4, false);
2609 std::fill_n(aDistance, 4, 0);
2612 SvxBoxItem& rBoxItem;
2613 SvxBoxInfoItem& rBoxInfoItem;
2614 bool aBorderSet[4];
2615 bool aInnerLineSet[2];
2616 bool aBorderIndeterminate[4];
2617 bool aInnerLineIndeterminate[2];
2618 bool aDistanceSet[4];
2619 sal_uInt16 aDistance[4];
2620 bool bDistanceIndeterminate;
2623 class BoxItemWrapper
2625 public:
2626 BoxItemWrapper(SvxBoxItem& rBoxItem, SvxBoxInfoItem& rBoxInfoItem, sal_uInt16 nBorderLine, sal_uInt16 nInnerLine, bool bBorder);
2628 const SvxBorderLine* getLine() const;
2629 void setLine(const SvxBorderLine* pLine);
2631 private:
2632 SvxBoxItem& m_rBoxItem;
2633 SvxBoxInfoItem& m_rBoxInfoItem;
2634 const sal_uInt16 m_nLine;
2635 const bool m_bBorder;
2638 BoxItemWrapper::BoxItemWrapper(
2639 SvxBoxItem& rBoxItem, SvxBoxInfoItem& rBoxInfoItem,
2640 const sal_uInt16 nBorderLine, const sal_uInt16 nInnerLine, const bool bBorder)
2641 : m_rBoxItem(rBoxItem)
2642 , m_rBoxInfoItem(rBoxInfoItem)
2643 , m_nLine(bBorder ? nBorderLine : nInnerLine)
2644 , m_bBorder(bBorder)
2646 assert(bBorder ? (m_nLine <= BOX_LINE_RIGHT) : (m_nLine <= BOXINFO_LINE_VERT));
2649 const SvxBorderLine* BoxItemWrapper::getLine() const
2651 if (m_bBorder)
2652 return m_rBoxItem.GetLine(m_nLine);
2653 else
2654 return (m_nLine == BOXINFO_LINE_HORI) ? m_rBoxInfoItem.GetHori() : m_rBoxInfoItem.GetVert();
2657 void BoxItemWrapper::setLine(const SvxBorderLine* pLine)
2659 if (m_bBorder)
2660 m_rBoxItem.SetLine(pLine, m_nLine);
2661 else
2662 m_rBoxInfoItem.SetLine(pLine, m_nLine);
2665 void lcl_MergeBorderLine(
2666 LinesState& rLinesState, const SvxBorderLine* const pLine, const sal_uInt16 nLine,
2667 const sal_uInt8 nValidFlag, const bool bBorder = true)
2669 const sal_uInt16 nInnerLine(bBorder ? 0 : ((nValidFlag & VALID_HORI) ? BOXINFO_LINE_HORI : BOXINFO_LINE_VERT));
2670 BoxItemWrapper aBoxItem(rLinesState.rBoxItem, rLinesState.rBoxInfoItem, nLine, nInnerLine, bBorder);
2671 bool& rbSet(bBorder ? rLinesState.aBorderSet[nLine] : rLinesState.aInnerLineSet[nInnerLine]);
2672 bool& rbIndeterminate(bBorder ? rLinesState.aBorderIndeterminate[nLine] : rLinesState.aInnerLineIndeterminate[nInnerLine]);
2674 if (rbSet)
2676 if (!rbIndeterminate)
2678 const SvxBorderLine* const pMergedLine(aBoxItem.getLine());
2679 if ((pLine && !pMergedLine) || (!pLine && pMergedLine) || (pLine && (*pLine != *pMergedLine)))
2681 aBoxItem.setLine(0);
2682 rbIndeterminate = true;
2686 else
2688 aBoxItem.setLine(pLine);
2689 rbSet = true;
2693 void lcl_MergeBorderOrInnerLine(
2694 LinesState& rLinesState, const SvxBorderLine* const pLine, const sal_uInt16 nLine,
2695 const sal_uInt8 nValidFlag, const bool bBorder)
2697 if (bBorder)
2698 lcl_MergeBorderLine(rLinesState, pLine, nLine, nValidFlag);
2699 else
2701 const bool bVertical = (nLine == BOX_LINE_LEFT) || (nLine == BOX_LINE_RIGHT);
2702 lcl_MergeBorderLine(rLinesState, pLine, nLine, bVertical ? VALID_VERT : VALID_HORI, false);
2706 void lcl_MergeDistance(
2707 LinesState& rLinesState, const sal_uInt16 nIndex, const sal_uInt16 nDistance)
2709 if (rLinesState.aDistanceSet[nIndex])
2711 if (!rLinesState.bDistanceIndeterminate)
2712 rLinesState.bDistanceIndeterminate = nDistance != rLinesState.aDistance[nIndex];
2714 else
2716 rLinesState.aDistance[nIndex] = nDistance;
2717 rLinesState.aDistanceSet[nIndex] = true;
2721 void lcl_MergeCommonBorderAttr(LinesState& rLinesState, const SvxBoxItem& rCellBoxItem, const sal_Int32 nCellFlags)
2723 if( (nCellFlags & (CELL_BEFORE|CELL_AFTER|CELL_UPPER|CELL_LOWER)) != 0 )
2725 // current cell is outside the selection
2727 if( (nCellFlags & ( CELL_BEFORE|CELL_AFTER)) == 0 ) // check if its not nw or ne corner
2729 if( nCellFlags & CELL_UPPER )
2730 lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetBottom(), BOX_LINE_TOP, VALID_TOP);
2731 else if( nCellFlags & CELL_LOWER )
2732 lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetTop(), BOX_LINE_BOTTOM, VALID_BOTTOM);
2734 else if( (nCellFlags & ( CELL_UPPER|CELL_LOWER)) == 0 ) // check if its not sw or se corner
2736 if( nCellFlags & CELL_BEFORE )
2737 lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetRight(), BOX_LINE_LEFT, VALID_LEFT);
2738 else if( nCellFlags & CELL_AFTER )
2739 lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetLeft(), BOX_LINE_RIGHT, VALID_RIGHT);
2742 // NOTE: inner distances for cells outside the selected range
2743 // are not relevant -> we ignore them.
2745 else
2747 // current cell is inside the selection
2749 lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetTop(), BOX_LINE_TOP, VALID_TOP, (nCellFlags & CELL_TOP) != 0);
2750 lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetBottom(), BOX_LINE_BOTTOM, VALID_BOTTOM, (nCellFlags & CELL_BOTTOM) != 0);
2751 lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetLeft(), BOX_LINE_LEFT, VALID_LEFT, (nCellFlags & CELL_LEFT) != 0);
2752 lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetRight(), BOX_LINE_RIGHT, VALID_RIGHT, (nCellFlags & CELL_RIGHT) != 0);
2754 lcl_MergeDistance(rLinesState, BOX_LINE_TOP, rCellBoxItem.GetDistance(BOX_LINE_TOP));
2755 lcl_MergeDistance(rLinesState, BOX_LINE_BOTTOM, rCellBoxItem.GetDistance(BOX_LINE_BOTTOM));
2756 lcl_MergeDistance(rLinesState, BOX_LINE_LEFT, rCellBoxItem.GetDistance(BOX_LINE_LEFT));
2757 lcl_MergeDistance(rLinesState, BOX_LINE_RIGHT, rCellBoxItem.GetDistance(BOX_LINE_RIGHT));
2763 void SvxTableController::FillCommonBorderAttrFromSelectedCells( SvxBoxItem& rBoxItem, SvxBoxInfoItem& rBoxInfoItem ) const
2765 if( mxTable.is() )
2767 const sal_Int32 nRowCount = mxTable->getRowCount();
2768 const sal_Int32 nColCount = mxTable->getColumnCount();
2769 if( nRowCount && nColCount )
2771 CellPos aStart, aEnd;
2772 const_cast< SvxTableController* >( this )->getSelectedCells( aStart, aEnd );
2774 // We are adding one more row/column around the block of selected cells.
2775 // We will be checking the adjoining border of these too.
2776 const sal_Int32 nLastRow = std::min( aEnd.mnRow + 2, nRowCount );
2777 const sal_Int32 nLastCol = std::min( aEnd.mnCol + 2, nColCount );
2779 rBoxInfoItem.SetValid( sal_uInt8( ~0 ), false );
2780 LinesState aLinesState( rBoxItem, rBoxInfoItem );
2782 /* Here we go through all the selected cells (enhanced by
2783 * the adjoining row/column on each side) and determine the
2784 * lines for presentation. The algorithm is simple:
2785 * 1. if a border or inner line is set (or unset) in all
2786 * cells to the same value, it will be used.
2787 * 2. if a border or inner line is set only in some cells,
2788 * it will be set to indeterminate state (SetValid() on
2789 * rBoxInfoItem).
2791 for( sal_Int32 nRow = std::max( aStart.mnRow - 1, (sal_Int32)0 ); nRow < nLastRow; nRow++ )
2793 sal_uInt16 nRowFlags = 0;
2794 nRowFlags |= (nRow == aStart.mnRow) ? CELL_TOP : 0;
2795 nRowFlags |= (nRow == aEnd.mnRow) ? CELL_BOTTOM : 0;
2796 nRowFlags |= (nRow < aStart.mnRow) ? CELL_UPPER : 0;
2797 nRowFlags |= (nRow > aEnd.mnRow) ? CELL_LOWER : 0;
2799 for( sal_Int32 nCol = std::max( aStart.mnCol - 1, (sal_Int32)0 ); nCol < nLastCol; nCol++ )
2801 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
2802 if( !xCell.is() )
2803 continue;
2805 sal_uInt16 nCellFlags = nRowFlags;
2806 nCellFlags |= (nCol == aStart.mnCol) ? CELL_LEFT : 0;
2807 nCellFlags |= (nCol == aEnd.mnCol) ? CELL_RIGHT : 0;
2808 nCellFlags |= (nCol < aStart.mnCol) ? CELL_BEFORE : 0;
2809 nCellFlags |= (nCol > aEnd.mnCol) ? CELL_AFTER : 0;
2811 const SfxItemSet& rSet = xCell->GetItemSet();
2812 const SvxBoxItem& rCellBoxItem = static_cast< const SvxBoxItem& >( rSet.Get(SDRATTR_TABLE_BORDER ) );
2813 lcl_MergeCommonBorderAttr( aLinesState, rCellBoxItem, nCellFlags );
2817 if (!aLinesState.aBorderIndeterminate[BOX_LINE_TOP])
2818 aLinesState.rBoxInfoItem.SetValid(VALID_TOP);
2819 if (!aLinesState.aBorderIndeterminate[BOX_LINE_BOTTOM])
2820 aLinesState.rBoxInfoItem.SetValid(VALID_BOTTOM);
2821 if (!aLinesState.aBorderIndeterminate[BOX_LINE_LEFT])
2822 aLinesState.rBoxInfoItem.SetValid(VALID_LEFT);
2823 if (!aLinesState.aBorderIndeterminate[BOX_LINE_RIGHT])
2824 aLinesState.rBoxInfoItem.SetValid(VALID_RIGHT);
2825 if (!aLinesState.aInnerLineIndeterminate[BOXINFO_LINE_HORI])
2826 aLinesState.rBoxInfoItem.SetValid(VALID_HORI);
2827 if (!aLinesState.aInnerLineIndeterminate[BOXINFO_LINE_VERT])
2828 aLinesState.rBoxInfoItem.SetValid(VALID_VERT);
2830 if (!aLinesState.bDistanceIndeterminate)
2832 if (aLinesState.aDistanceSet[BOX_LINE_TOP])
2833 aLinesState.rBoxItem.SetDistance(aLinesState.aDistance[BOX_LINE_TOP], BOX_LINE_TOP);
2834 if (aLinesState.aDistanceSet[BOX_LINE_BOTTOM])
2835 aLinesState.rBoxItem.SetDistance(aLinesState.aDistance[BOX_LINE_BOTTOM], BOX_LINE_BOTTOM);
2836 if (aLinesState.aDistanceSet[BOX_LINE_LEFT])
2837 aLinesState.rBoxItem.SetDistance(aLinesState.aDistance[BOX_LINE_LEFT], BOX_LINE_LEFT);
2838 if (aLinesState.aDistanceSet[BOX_LINE_RIGHT])
2839 aLinesState.rBoxItem.SetDistance(aLinesState.aDistance[BOX_LINE_RIGHT], BOX_LINE_RIGHT);
2840 aLinesState.rBoxInfoItem.SetValid(VALID_DISTANCE);
2846 bool SvxTableController::selectRow( sal_Int32 row )
2848 if( !mxTable.is() )
2849 return false;
2850 CellPos aStart( 0, row ), aEnd( mxTable->getColumnCount() - 1, row );
2851 StartSelection( aEnd );
2852 gotoCell( aStart, true, 0 );
2853 return true;
2856 bool SvxTableController::selectColumn( sal_Int32 column )
2858 if( !mxTable.is() )
2859 return false;
2860 CellPos aStart( column, 0 ), aEnd( column, mxTable->getRowCount() - 1 );
2861 StartSelection( aEnd );
2862 gotoCell( aStart, true, 0 );
2863 return true;
2866 bool SvxTableController::deselectRow( sal_Int32 row )
2868 if( !mxTable.is() )
2869 return false;
2870 CellPos aStart( 0, row ), aEnd( mxTable->getColumnCount() - 1, row );
2871 StartSelection( aEnd );
2872 gotoCell( aStart, false, 0 );
2873 return true;
2876 bool SvxTableController::deselectColumn( sal_Int32 column )
2878 if( !mxTable.is() )
2879 return false;
2880 CellPos aStart( column, 0 ), aEnd( column, mxTable->getRowCount() - 1 );
2881 StartSelection( aEnd );
2882 gotoCell( aStart, false, 0 );
2883 return true;
2886 bool SvxTableController::isRowSelected( sal_Int32 nRow )
2888 if( hasSelectedCells() )
2890 CellPos aFirstPos, aLastPos;
2891 getSelectedCells( aFirstPos, aLastPos );
2892 if( (aFirstPos.mnCol == 0) && (nRow >= aFirstPos.mnRow && nRow <= aLastPos.mnRow) && (mxTable->getColumnCount() - 1 == aLastPos.mnCol) )
2893 return true;
2895 return false;
2898 bool SvxTableController::isColumnSelected( sal_Int32 nColumn )
2900 if( hasSelectedCells() )
2902 CellPos aFirstPos, aLastPos;
2903 getSelectedCells( aFirstPos, aLastPos );
2904 if( (aFirstPos.mnRow == 0) && (nColumn >= aFirstPos.mnCol && nColumn <= aLastPos.mnCol) && (mxTable->getRowCount() - 1 == aLastPos.mnRow) )
2905 return true;
2907 return false;
2910 bool SvxTableController::isRowHeader()
2912 SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
2913 SdrModel* pModel = pTableObj ? pTableObj->GetModel() : 0;
2915 if( !pTableObj || !pModel )
2916 return false;
2918 TableStyleSettings aSettings( pTableObj->getTableStyleSettings() );
2920 return aSettings.mbUseFirstRow;
2923 bool SvxTableController::isColumnHeader()
2925 SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
2926 SdrModel* pModel = pTableObj ? pTableObj->GetModel() : 0;
2928 if( !pTableObj || !pModel )
2929 return false;
2931 TableStyleSettings aSettings( pTableObj->getTableStyleSettings() );
2933 return aSettings.mbUseFirstColumn;
2937 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */