update credits
[LibreOffice.git] / svx / source / table / tablecontroller.cxx
blob937489ee6c5e54ffc4e4a2e1f3795f7f9488e605
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 <svl/whiter.hxx>
37 #include <sfx2/request.hxx>
39 #include <editeng/scripttypeitem.hxx>
40 #include <svx/svdotable.hxx>
41 #include <svx/sdr/overlay/overlayobjectcell.hxx>
42 #include <svx/sdr/overlay/overlaymanager.hxx>
43 #include <svx/svxids.hrc>
44 #include <editeng/outlobj.hxx>
45 #include <svx/svdoutl.hxx>
46 #include <svx/svdpagv.hxx>
47 #include <svx/svdetc.hxx>
48 #include <editeng/editobj.hxx>
49 #include "editeng/editstat.hxx"
50 #include "editeng/unolingu.hxx"
51 #include "svx/sdrpagewindow.hxx"
52 #include <svx/selectioncontroller.hxx>
53 #include <svx/svdmodel.hxx>
54 #include "svx/sdrpaintwindow.hxx"
55 #include <svx/svxdlg.hxx>
56 #include <editeng/boxitem.hxx>
57 #include "cell.hxx"
58 #include <editeng/borderline.hxx>
59 #include <editeng/colritem.hxx>
60 #include "editeng/lineitem.hxx"
61 #include "svx/svdstr.hrc"
62 #include "svx/svdglob.hxx"
63 #include "svx/svdpage.hxx"
64 #include "tableundo.hxx"
65 #include "tablelayouter.hxx"
66 #include <vcl/msgbox.hxx>
68 using ::editeng::SvxBorderLine;
69 using namespace ::sdr::table;
70 using namespace ::com::sun::star;
71 using namespace ::com::sun::star::uno;
72 using namespace ::com::sun::star::table;
73 using namespace ::com::sun::star::beans;
74 using namespace ::com::sun::star::container;
75 using namespace ::com::sun::star::text;
76 using namespace ::com::sun::star::style;
78 namespace sdr { namespace table {
80 // --------------------------------------------------------------------
81 // class SvxTableControllerModifyListener
82 // --------------------------------------------------------------------
84 class SvxTableControllerModifyListener : public ::cppu::WeakImplHelper1< ::com::sun::star::util::XModifyListener >
86 public:
87 SvxTableControllerModifyListener( SvxTableController* pController )
88 : mpController( pController ) {}
90 // XModifyListener
91 virtual void SAL_CALL modified( const ::com::sun::star::lang::EventObject& aEvent ) throw (::com::sun::star::uno::RuntimeException);
93 // XEventListener
94 virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException);
96 SvxTableController* mpController;
99 // --------------------------------------------------------------------
100 // XModifyListener
101 // --------------------------------------------------------------------
103 void SAL_CALL SvxTableControllerModifyListener::modified( const ::com::sun::star::lang::EventObject& ) throw (::com::sun::star::uno::RuntimeException)
105 if( mpController )
106 mpController->onTableModified();
109 // --------------------------------------------------------------------
110 // XEventListener
111 // --------------------------------------------------------------------
113 void SAL_CALL SvxTableControllerModifyListener::disposing( const ::com::sun::star::lang::EventObject& ) throw (::com::sun::star::uno::RuntimeException)
115 mpController = 0;
118 // --------------------------------------------------------------------
119 // class SvxTableController
120 // --------------------------------------------------------------------
122 rtl::Reference< sdr::SelectionController > CreateTableController( SdrObjEditView* pView, const SdrObject* pObj, const rtl::Reference< sdr::SelectionController >& xRefController )
124 return SvxTableController::create( pView, pObj, xRefController );
127 // --------------------------------------------------------------------
129 rtl::Reference< sdr::SelectionController > SvxTableController::create( SdrObjEditView* pView, const SdrObject* pObj, const rtl::Reference< sdr::SelectionController >& xRefController )
131 if( xRefController.is() )
133 SvxTableController* pController = dynamic_cast< SvxTableController* >( xRefController.get() );
134 if( pController && (pController->mxTableObj.get() == pObj) && (pController->mpView == pView) )
135 return xRefController;
137 return new SvxTableController( pView, pObj );
140 // --------------------------------------------------------------------
142 SvxTableController::SvxTableController( SdrObjEditView* pView, const SdrObject* pObj )
143 : mbCellSelectionMode(false)
144 , mbLeftButtonDown(false)
145 , mpSelectionOverlay(0)
146 , mpView( dynamic_cast< SdrView* >( pView ) )
147 , mxTableObj( dynamic_cast< SdrTableObj* >( const_cast< SdrObject* >( pObj ) ) )
148 , mpModel( 0 )
149 , mnUpdateEvent( 0 )
151 if( pObj )
152 mpModel = pObj->GetModel();
154 if( mxTableObj.is() )
156 static_cast< const SdrTableObj* >( pObj )->getActiveCellPos( maCursorFirstPos );
157 maCursorLastPos = maCursorFirstPos;
159 Reference< XTable > xTable( static_cast< const SdrTableObj* >( pObj )->getTable() );
160 if( xTable.is() )
162 mxModifyListener = new SvxTableControllerModifyListener( this );
163 xTable->addModifyListener( mxModifyListener );
165 mxTable.set( dynamic_cast< TableModel* >( xTable.get() ) );
170 // --------------------------------------------------------------------
172 SvxTableController::~SvxTableController()
174 if( mnUpdateEvent )
176 Application::RemoveUserEvent( mnUpdateEvent );
179 if( mxModifyListener.is() && mxTableObj.get() )
181 Reference< XTable > xTable( static_cast< SdrTableObj* >( mxTableObj.get() )->getTable() );
182 if( xTable.is() )
184 xTable->removeModifyListener( mxModifyListener );
185 mxModifyListener.clear();
190 // --------------------------------------------------------------------
192 const sal_uInt16 ACTION_NONE = 0;
193 const sal_uInt16 ACTION_GOTO_FIRST_CELL = 1;
194 const sal_uInt16 ACTION_GOTO_FIRST_COLUMN = 2;
195 const sal_uInt16 ACTION_GOTO_FIRST_ROW = 3;
196 const sal_uInt16 ACTION_GOTO_LEFT_CELL = 4;
197 const sal_uInt16 ACTION_GOTO_UP_CELL = 5;
198 const sal_uInt16 ACTION_GOTO_RIGHT_CELL = 6;
199 const sal_uInt16 ACTION_GOTO_DOWN_CELL = 7;
200 const sal_uInt16 ACTION_GOTO_LAST_CELL = 8;
201 const sal_uInt16 ACTION_GOTO_LAST_COLUMN = 9;
202 const sal_uInt16 ACTION_GOTO_LAST_ROW = 10;
203 const sal_uInt16 ACTION_EDIT_CELL = 11;
204 const sal_uInt16 ACTION_STOP_TEXT_EDIT = 12;
205 const sal_uInt16 ACTION_REMOVE_SELECTION = 13;
206 const sal_uInt16 ACTION_START_SELECTION = 14;
207 const sal_uInt16 ACTION_HANDLED_BY_VIEW = 15;
208 const sal_uInt16 ACTION_TAB = 18;
210 bool SvxTableController::onKeyInput(const KeyEvent& rKEvt, Window* pWindow )
212 if( !checkTableObject() )
213 return false;
215 // check if we are read only
216 if( mpModel && mpModel->IsReadOnly())
218 switch( rKEvt.GetKeyCode().GetCode() )
220 case awt::Key::DOWN:
221 case awt::Key::UP:
222 case awt::Key::LEFT:
223 case awt::Key::RIGHT:
224 case awt::Key::TAB:
225 case awt::Key::HOME:
226 case awt::Key::END:
227 case awt::Key::NUM2:
228 case awt::Key::NUM4:
229 case awt::Key::NUM6:
230 case awt::Key::NUM8:
231 case awt::Key::ESCAPE:
232 case awt::Key::F2:
233 break;
234 default:
235 // tell the view we eat the event, no further processing needed
236 return true;
240 sal_uInt16 nAction = getKeyboardAction( rKEvt, pWindow );
242 return executeAction( nAction, ( rKEvt.GetKeyCode().IsShift() ) ? sal_True : sal_False, pWindow );
245 // --------------------------------------------------------------------
246 // ::com::sun::star::awt::XMouseClickHandler:
247 // --------------------------------------------------------------------
249 bool SvxTableController::onMouseButtonDown(const MouseEvent& rMEvt, Window* pWindow )
251 if( !pWindow || !checkTableObject() )
252 return false;
254 SdrViewEvent aVEvt;
255 if( !rMEvt.IsRight() && mpView->PickAnything(rMEvt,SDRMOUSEBUTTONDOWN, aVEvt) == SDRHIT_HANDLE )
256 return false;
258 TableHitKind eHit = static_cast< SdrTableObj* >(mxTableObj.get())->CheckTableHit( pWindow->PixelToLogic(rMEvt.GetPosPixel()), maMouseDownPos.mnCol, maMouseDownPos.mnRow, 0 );
260 mbLeftButtonDown = (rMEvt.GetClicks() == 1) && rMEvt.IsLeft();
262 if( eHit == SDRTABLEHIT_CELL )
264 StartSelection( maMouseDownPos );
265 return true;
268 if( rMEvt.IsRight() && eHit != SDRTABLEHIT_NONE )
269 return true; // right click will become context menu
271 // for cell selektion with the mouse remember our first hit
272 if( mbLeftButtonDown )
274 RemoveSelection();
276 Point aPnt(rMEvt.GetPosPixel());
277 if (pWindow!=NULL)
278 aPnt=pWindow->PixelToLogic(aPnt);
280 SdrHdl* pHdl = mpView->PickHandle(aPnt);
282 if( pHdl )
284 mbLeftButtonDown = false;
286 else
288 ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
290 if( !pWindow || !pTableObj || eHit == SDRTABLEHIT_NONE)
292 mbLeftButtonDown = false;
297 return false;
300 // --------------------------------------------------------------------
302 bool SvxTableController::onMouseButtonUp(const MouseEvent& rMEvt, Window* /*pWin*/)
304 if( !checkTableObject() )
305 return false;
307 mbLeftButtonDown = false;
309 if( rMEvt.GetClicks() == 2 )
310 return true;
312 return false;
315 // --------------------------------------------------------------------
317 bool SvxTableController::onMouseMove(const MouseEvent& rMEvt, Window* pWindow )
319 if( !checkTableObject() )
320 return false;
322 if( rMEvt.IsLeft() )
324 int i = 0;
325 i++;
328 SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >( mxTableObj.get() );
329 CellPos aPos;
330 if( mbLeftButtonDown && pTableObj && pTableObj->CheckTableHit( pWindow->PixelToLogic(rMEvt.GetPosPixel()), aPos.mnCol, aPos.mnRow, 0 ) != SDRTABLEHIT_NONE )
332 if(aPos != maMouseDownPos)
334 if( mbCellSelectionMode )
336 setSelectedCells( maMouseDownPos, aPos );
337 return true;
339 else
341 StartSelection( maMouseDownPos );
344 else if( mbCellSelectionMode )
346 UpdateSelection( aPos );
347 return true;
350 return false;
353 // --------------------------------------------------------------------
355 void SvxTableController::onSelectionHasChanged()
357 bool bSelected = false;
359 SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >( mxTableObj.get() );
360 if( pTableObj && pTableObj->IsTextEditActive() )
362 pTableObj->getActiveCellPos( maCursorFirstPos );
363 maCursorLastPos = maCursorFirstPos;
364 mbCellSelectionMode = false;
366 else
368 const SdrMarkList& rMarkList= mpView->GetMarkedObjectList();
369 if( rMarkList.GetMarkCount() == 1 )
370 bSelected = mxTableObj.get() == rMarkList.GetMark(0)->GetMarkedSdrObj();
371 /* fdo#46186 Selecting the table means selecting the entire cells */
372 if(!hasSelectedCells())
374 maCursorFirstPos = pTableObj->getFirstCell();
375 maCursorLastPos = pTableObj->getLastCell();
376 mbCellSelectionMode=true;
380 if( bSelected )
382 updateSelectionOverlay();
384 else
386 destroySelectionOverlay();
390 // --------------------------------------------------------------------
392 void SvxTableController::GetState( SfxItemSet& rSet )
394 if( !mxTable.is() || !mxTableObj.is() || !mxTableObj->GetModel() )
395 return;
397 SfxItemSet* pSet = 0;
399 bool bVertDone = false;
401 // Iterate over all requested items in the set.
402 SfxWhichIter aIter( rSet );
403 sal_uInt16 nWhich = aIter.FirstWhich();
404 while (nWhich)
406 switch (nWhich)
408 case SID_TABLE_VERT_BOTTOM:
409 case SID_TABLE_VERT_CENTER:
410 case SID_TABLE_VERT_NONE:
412 if( !mxTable.is() || !mxTableObj->GetModel() )
414 rSet.DisableItem(nWhich);
416 else if(!bVertDone)
418 if( !pSet )
420 pSet = new SfxItemSet( mxTableObj->GetModel()->GetItemPool() );
421 MergeAttrFromSelectedCells(*pSet, sal_False);
424 SdrTextVertAdjust eAdj = SDRTEXTVERTADJUST_BLOCK;
426 if( pSet->GetItemState( SDRATTR_TEXT_VERTADJUST ) != SFX_ITEM_DONTCARE )
427 eAdj = ((SdrTextVertAdjustItem&)(pSet->Get(SDRATTR_TEXT_VERTADJUST))).GetValue();
429 rSet.Put(SfxBoolItem(SID_TABLE_VERT_BOTTOM, eAdj == SDRTEXTVERTADJUST_BOTTOM));
430 rSet.Put(SfxBoolItem(SID_TABLE_VERT_CENTER, eAdj == SDRTEXTVERTADJUST_CENTER));
431 rSet.Put(SfxBoolItem(SID_TABLE_VERT_NONE, eAdj == SDRTEXTVERTADJUST_TOP));
432 bVertDone = true;
434 break;
436 case SID_TABLE_DELETE_ROW:
437 if( !mxTable.is() || !hasSelectedCells() || (mxTable->getRowCount() <= 1) )
438 rSet.DisableItem(SID_TABLE_DELETE_ROW);
439 break;
440 case SID_TABLE_DELETE_COL:
441 if( !mxTable.is() || !hasSelectedCells() || (mxTable->getColumnCount() <= 1) )
442 rSet.DisableItem(SID_TABLE_DELETE_COL);
443 break;
444 case SID_TABLE_MERGE_CELLS:
445 if( !mxTable.is() || !hasSelectedCells() )
446 rSet.DisableItem(SID_TABLE_MERGE_CELLS);
447 break;
448 case SID_TABLE_SPLIT_CELLS:
449 if( !hasSelectedCells() || !mxTable.is() )
450 rSet.DisableItem(SID_TABLE_SPLIT_CELLS);
451 break;
453 case SID_OPTIMIZE_TABLE:
454 case SID_TABLE_DISTRIBUTE_COLUMNS:
455 case SID_TABLE_DISTRIBUTE_ROWS:
457 bool bDistributeColumns = false;
458 bool bDistributeRows = false;
459 if( mxTable.is() )
461 CellPos aStart, aEnd;
462 getSelectedCells( aStart, aEnd );
464 bDistributeColumns = aStart.mnCol != aEnd.mnCol;
465 bDistributeRows = aStart.mnRow != aEnd.mnRow;
467 if( !bDistributeColumns && !bDistributeRows )
468 rSet.DisableItem(SID_OPTIMIZE_TABLE);
469 if( !bDistributeColumns )
470 rSet.DisableItem(SID_TABLE_DISTRIBUTE_COLUMNS);
471 if( !bDistributeRows )
472 rSet.DisableItem(SID_TABLE_DISTRIBUTE_ROWS);
473 break;
476 case SID_AUTOFORMAT:
477 case SID_TABLE_SORT_DIALOG:
478 case SID_TABLE_AUTOSUM:
479 // if( !mxTable.is() )
480 // rSet.DisableItem( nWhich );
481 break;
482 default:
483 break;
485 nWhich = aIter.NextWhich();
487 delete pSet;
490 // --------------------------------------------------------------------
492 void SvxTableController::onInsert( sal_uInt16 nSId, const SfxItemSet* pArgs )
494 ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
495 if( !pTableObj )
496 return;
498 if( mxTable.is() ) try
501 bool bInsertAfter = true;
502 sal_uInt16 nCount = 0;
503 if( pArgs )
505 const SfxPoolItem* pItem = 0;
506 pArgs->GetItemState(nSId, sal_False, &pItem);
507 if (pItem)
509 nCount = ((const SfxInt16Item* )pItem)->GetValue();
510 if(SFX_ITEM_SET == pArgs->GetItemState(SID_TABLE_PARAM_INSERT_AFTER, sal_True, &pItem))
511 bInsertAfter = ((const SfxBoolItem* )pItem)->GetValue();
515 CellPos aStart, aEnd;
516 if( hasSelectedCells() )
518 getSelectedCells( aStart, aEnd );
520 else
522 if( bInsertAfter )
524 aStart.mnCol = mxTable->getColumnCount() - 1;
525 aStart.mnRow = mxTable->getRowCount() - 1;
526 aEnd = aStart;
530 if( pTableObj->IsTextEditActive() )
531 mpView->SdrEndTextEdit(sal_True);
533 RemoveSelection();
535 const OUString sSize( "Size" );
537 const bool bUndo = mpModel && mpModel->IsUndoEnabled();
539 switch( nSId )
541 case SID_TABLE_INSERT_COL:
543 TableModelNotifyGuard aGuard( mxTable.get() );
545 if( bUndo )
547 mpModel->BegUndo( ImpGetResStr(STR_TABLE_INSCOL) );
548 mpModel->AddUndo( mpModel->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj) );
551 Reference< XTableColumns > xCols( mxTable->getColumns() );
552 const sal_Int32 nNewColumns = (nCount == 0) ? (aEnd.mnCol - aStart.mnCol + 1) : nCount;
553 const sal_Int32 nNewStartColumn = aEnd.mnCol + (bInsertAfter ? 1 : 0);
554 xCols->insertByIndex( nNewStartColumn, nNewColumns );
556 for( sal_Int32 nOffset = 0; nOffset < nNewColumns; nOffset++ )
558 // Resolves fdo#61540
559 // On Insert before, the reference column whose size is going to be
560 // used for newly created column(s) is wrong. As the new columns are
561 // inserted before the reference column, the reference column moved
562 // to the new position by no., of new columns i.e (earlier+newcolumns).
563 Reference< XPropertySet >(xCols->getByIndex(nNewStartColumn+nOffset), UNO_QUERY_THROW )->
564 setPropertyValue( sSize,
565 Reference< XPropertySet >(xCols->getByIndex( bInsertAfter?nNewStartColumn-1:nNewStartColumn+nNewColumns ), UNO_QUERY_THROW )->
566 getPropertyValue( sSize ) );
569 if( bUndo )
570 mpModel->EndUndo();
572 aStart.mnCol = nNewStartColumn;
573 aStart.mnRow = 0;
574 aEnd.mnCol = aStart.mnCol + nNewColumns - 1;
575 aEnd.mnRow = mxTable->getRowCount() - 1;
576 break;
579 case SID_TABLE_INSERT_ROW:
581 TableModelNotifyGuard aGuard( mxTable.get() );
583 if( bUndo )
585 mpModel->BegUndo( ImpGetResStr(STR_TABLE_INSROW ) );
586 mpModel->AddUndo( mpModel->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj) );
589 Reference< XTableRows > xRows( mxTable->getRows() );
590 const sal_Int32 nNewRows = (nCount == 0) ? (aEnd.mnRow - aStart.mnRow + 1) : nCount;
591 const sal_Int32 nNewRowStart = aEnd.mnRow + (bInsertAfter ? 1 : 0);
592 xRows->insertByIndex( nNewRowStart, nNewRows );
594 for( sal_Int32 nOffset = 0; nOffset < nNewRows; nOffset++ )
596 Reference< XPropertySet >( xRows->getByIndex( aEnd.mnRow + nOffset + 1 ), UNO_QUERY_THROW )->
597 setPropertyValue( sSize,
598 Reference< XPropertySet >( xRows->getByIndex( aStart.mnRow + nOffset ), UNO_QUERY_THROW )->
599 getPropertyValue( sSize ) );
602 if( bUndo )
603 mpModel->EndUndo();
605 aStart.mnCol = 0;
606 aStart.mnRow = nNewRowStart;
607 aEnd.mnCol = mxTable->getColumnCount() - 1;
608 aEnd.mnRow = aStart.mnRow + nNewRows - 1;
609 break;
613 StartSelection( aStart );
614 UpdateSelection( aEnd );
616 catch( Exception& )
618 OSL_FAIL("svx::SvxTableController::onInsert(), exception caught!");
622 // --------------------------------------------------------------------
624 void SvxTableController::onDelete( sal_uInt16 nSId )
626 ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
627 if( !pTableObj )
628 return;
630 if( mxTable.is() && hasSelectedCells() )
632 CellPos aStart, aEnd;
633 getSelectedCells( aStart, aEnd );
635 if( pTableObj->IsTextEditActive() )
636 mpView->SdrEndTextEdit(sal_True);
638 RemoveSelection();
640 bool bDeleteTable = false;
641 switch( nSId )
643 case SID_TABLE_DELETE_COL:
645 const sal_Int32 nRemovedColumns = aEnd.mnCol - aStart.mnCol + 1;
646 if( nRemovedColumns == mxTable->getColumnCount() )
648 bDeleteTable = true;
650 else
652 Reference< XTableColumns > xCols( mxTable->getColumns() );
653 xCols->removeByIndex( aStart.mnCol, nRemovedColumns );
655 break;
658 case SID_TABLE_DELETE_ROW:
660 const sal_Int32 nRemovedRows = aEnd.mnRow - aStart.mnRow + 1;
661 if( nRemovedRows == mxTable->getRowCount() )
663 bDeleteTable = true;
665 else
667 Reference< XTableRows > xRows( mxTable->getRows() );
668 xRows->removeByIndex( aStart.mnRow, nRemovedRows );
670 break;
674 if( bDeleteTable )
675 mpView->DeleteMarkedObj();
676 else
677 UpdateTableShape();
681 // --------------------------------------------------------------------
683 void SvxTableController::onSelect( sal_uInt16 nSId )
685 if( mxTable.is() )
687 const sal_Int32 nRowCount = mxTable->getRowCount();
688 const sal_Int32 nColCount = mxTable->getColumnCount();
689 if( nRowCount && nColCount )
691 CellPos aStart, aEnd;
692 getSelectedCells( aStart, aEnd );
694 switch( nSId )
696 case SID_TABLE_SELECT_ALL:
697 aEnd.mnCol = 0; aEnd.mnRow = 0;
698 aStart.mnCol = nColCount - 1; aStart.mnRow = nRowCount - 1;
699 break;
700 case SID_TABLE_SELECT_COL:
701 aEnd.mnRow = nRowCount - 1;
702 aStart.mnRow = 0;
703 break;
704 case SID_TABLE_SELECT_ROW:
705 aEnd.mnCol = nColCount - 1;
706 aStart.mnCol = 0;
707 break;
710 StartSelection( aEnd );
711 gotoCell( aStart, true, 0 );
716 // --------------------------------------------------------------------
717 void SvxTableController::onFormatTable( SfxRequest& rReq )
719 ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
720 if( !pTableObj )
721 return;
723 const SfxItemSet* pArgs = rReq.GetArgs();
725 if( !pArgs && pTableObj->GetModel() )
727 SfxItemSet aNewAttr( pTableObj->GetModel()->GetItemPool() );
729 // merge drawing layer text distance items into SvxBoxItem used by the dialog
730 SvxBoxItem aBoxItem( static_cast< const SvxBoxItem& >( aNewAttr.Get( SDRATTR_TABLE_BORDER ) ) );
731 aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( ((SdrTextLeftDistItem&)(aNewAttr.Get(SDRATTR_TEXT_LEFTDIST))).GetValue()), BOX_LINE_LEFT );
732 aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( ((SdrTextRightDistItem&)(aNewAttr.Get(SDRATTR_TEXT_RIGHTDIST))).GetValue()), BOX_LINE_RIGHT );
733 aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( ((SdrTextUpperDistItem&)(aNewAttr.Get(SDRATTR_TEXT_UPPERDIST))).GetValue()), BOX_LINE_TOP );
734 aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( ((SdrTextLowerDistItem&)(aNewAttr.Get(SDRATTR_TEXT_LOWERDIST))).GetValue()), BOX_LINE_BOTTOM );
736 SvxBoxInfoItem aBoxInfoItem( static_cast< const SvxBoxInfoItem& >( aNewAttr.Get( SDRATTR_TABLE_BORDER_INNER ) ) );
738 MergeAttrFromSelectedCells(aNewAttr, sal_False);
739 FillCommonBorderAttrFromSelectedCells( aBoxItem, aBoxInfoItem );
740 aNewAttr.Put( aBoxItem );
741 aNewAttr.Put( aBoxInfoItem );
743 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
744 std::auto_ptr< SfxAbstractTabDialog > pDlg( pFact ? pFact->CreateSvxFormatCellsDialog( NULL, &aNewAttr, pTableObj->GetModel(), pTableObj) : 0 );
745 // Even Cancel Button is returning positive(101) value,
746 if( pDlg.get() && ( pDlg->Execute() == RET_OK ) )
748 SfxItemSet aNewSet( aNewAttr );
749 aNewSet.Put( *(pDlg->GetOutputItemSet ()) );
751 SvxBoxItem aNewBoxItem( static_cast< const SvxBoxItem& >( aNewSet.Get( SDRATTR_TABLE_BORDER ) ) );
753 if( aNewBoxItem.GetDistance( BOX_LINE_LEFT ) != aBoxItem.GetDistance( BOX_LINE_LEFT ) )
754 aNewSet.Put(SdrTextLeftDistItem( aNewBoxItem.GetDistance( BOX_LINE_LEFT ) ) );
756 if( aNewBoxItem.GetDistance( BOX_LINE_RIGHT ) != aBoxItem.GetDistance( BOX_LINE_RIGHT ) )
757 aNewSet.Put(SdrTextRightDistItem( aNewBoxItem.GetDistance( BOX_LINE_RIGHT ) ) );
759 if( aNewBoxItem.GetDistance( BOX_LINE_TOP ) != aBoxItem.GetDistance( BOX_LINE_TOP ) )
760 aNewSet.Put(SdrTextUpperDistItem( aNewBoxItem.GetDistance( BOX_LINE_TOP ) ) );
762 if( aNewBoxItem.GetDistance( BOX_LINE_BOTTOM ) != aBoxItem.GetDistance( BOX_LINE_BOTTOM ) )
763 aNewSet.Put(SdrTextLowerDistItem( aNewBoxItem.GetDistance( BOX_LINE_BOTTOM ) ) );
765 SetAttrToSelectedCells(aNewSet, sal_False);
770 // --------------------------------------------------------------------
772 void SvxTableController::Execute( SfxRequest& rReq )
774 const sal_uInt16 nSId = rReq.GetSlot();
775 switch( nSId )
777 case SID_TABLE_INSERT_ROW:
778 case SID_TABLE_INSERT_COL:
779 onInsert( nSId, rReq.GetArgs() );
780 break;
781 case SID_TABLE_DELETE_ROW:
782 case SID_TABLE_DELETE_COL:
783 onDelete( nSId );
784 break;
785 case SID_TABLE_SELECT_ALL:
786 case SID_TABLE_SELECT_COL:
787 case SID_TABLE_SELECT_ROW:
788 onSelect( nSId );
789 break;
790 case SID_FORMAT_TABLE_DLG:
791 onFormatTable( rReq );
792 break;
794 case SID_FRAME_LINESTYLE:
795 case SID_FRAME_LINECOLOR:
796 case SID_ATTR_BORDER:
798 const SfxItemSet* pArgs = rReq.GetArgs();
799 if( pArgs )
800 ApplyBorderAttr( *pArgs );
802 break;
804 case SID_ATTR_FILL_STYLE:
806 const SfxItemSet* pArgs = rReq.GetArgs();
807 if( pArgs )
808 SetAttributes( *pArgs, false );
810 break;
812 case SID_TABLE_MERGE_CELLS:
813 MergeMarkedCells();
814 break;
816 case SID_TABLE_SPLIT_CELLS:
817 SplitMarkedCells();
818 break;
820 case SID_TABLE_DISTRIBUTE_COLUMNS:
821 DistributeColumns();
822 break;
824 case SID_TABLE_DISTRIBUTE_ROWS:
825 DistributeRows();
826 break;
828 case SID_TABLE_VERT_BOTTOM:
829 case SID_TABLE_VERT_CENTER:
830 case SID_TABLE_VERT_NONE:
831 SetVertical( nSId );
832 break;
834 case SID_AUTOFORMAT:
835 case SID_TABLE_SORT_DIALOG:
836 case SID_TABLE_AUTOSUM:
837 default:
838 break;
840 case SID_TABLE_STYLE:
841 SetTableStyle( rReq.GetArgs() );
842 break;
844 case SID_TABLE_STYLE_SETTINGS:
845 SetTableStyleSettings( rReq.GetArgs() );
846 break;
850 void SvxTableController::SetTableStyle( const SfxItemSet* pArgs )
852 SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
853 SdrModel* pModel = pTableObj ? pTableObj->GetModel() : 0;
855 if( !pTableObj || !pModel || !pArgs || (SFX_ITEM_SET != pArgs->GetItemState(SID_TABLE_STYLE, sal_False)) )
856 return;
858 const SfxStringItem* pArg = dynamic_cast< const SfxStringItem* >( &pArgs->Get( SID_TABLE_STYLE ) );
859 if( pArg && mxTable.is() ) try
861 Reference< XStyleFamiliesSupplier > xSFS( pModel->getUnoModel(), UNO_QUERY_THROW );
862 Reference< XNameAccess > xFamilyNameAccess( xSFS->getStyleFamilies(), UNO_QUERY_THROW );
863 const OUString sFamilyName( "table" );
864 Reference< XNameAccess > xTableFamilyAccess( xFamilyNameAccess->getByName( sFamilyName ), UNO_QUERY_THROW );
866 if( xTableFamilyAccess->hasByName( pArg->GetValue() ) )
868 // found table style with the same name
869 Reference< XIndexAccess > xNewTableStyle( xTableFamilyAccess->getByName( pArg->GetValue() ), UNO_QUERY_THROW );
871 const bool bUndo = pModel->IsUndoEnabled();
873 if( bUndo )
875 pModel->BegUndo( ImpGetResStr(STR_TABLE_STYLE) );
876 pModel->AddUndo( new TableStyleUndo( *pTableObj ) );
879 pTableObj->setTableStyle( xNewTableStyle );
881 const sal_Int32 nRowCount = mxTable->getRowCount();
882 const sal_Int32 nColCount = mxTable->getColumnCount();
883 for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ )
885 for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ ) try
887 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
888 if( xCell.is() )
890 SfxItemSet aSet( xCell->GetItemSet() );
891 bool bChanges = false;
892 const SfxItemSet& rStyleAttribs = xCell->GetStyleSheet()->GetItemSet();
894 for ( sal_uInt16 nWhich = SDRATTR_START; nWhich <= SDRATTR_TABLE_LAST; nWhich++ )
896 if( (rStyleAttribs.GetItemState( nWhich ) == SFX_ITEM_ON) && (aSet.GetItemState( nWhich ) == SFX_ITEM_ON) )
898 aSet.ClearItem( nWhich );
899 bChanges = true;
903 if( bChanges )
905 if( bUndo )
906 xCell->AddUndo();
908 xCell->SetMergedItemSetAndBroadcast( aSet, sal_True );
912 catch( Exception& )
914 OSL_FAIL( "svx::SvxTableController::SetTableStyle(), exception caught!" );
918 if( bUndo )
919 pModel->EndUndo();
922 catch( Exception& )
924 OSL_FAIL( "svx::SvxTableController::SetTableStyle(), exception caught!" );
928 void SvxTableController::SetTableStyleSettings( const SfxItemSet* pArgs )
930 SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
931 SdrModel* pModel = pTableObj ? pTableObj->GetModel() : 0;
933 if( !pTableObj || !pModel )
934 return;
936 TableStyleSettings aSettings( pTableObj->getTableStyleSettings() );
938 const SfxPoolItem *pPoolItem=NULL;
940 if( (SFX_ITEM_SET == pArgs->GetItemState(ID_VAL_USEFIRSTROWSTYLE, sal_False,&pPoolItem)) )
941 aSettings.mbUseFirstRow = static_cast< const SfxBoolItem* >(pPoolItem)->GetValue();
943 if( (SFX_ITEM_SET == pArgs->GetItemState(ID_VAL_USELASTROWSTYLE, sal_False,&pPoolItem)) )
944 aSettings.mbUseLastRow = static_cast< const SfxBoolItem* >(pPoolItem)->GetValue();
946 if( (SFX_ITEM_SET == pArgs->GetItemState(ID_VAL_USEBANDINGROWSTYLE, sal_False,&pPoolItem)) )
947 aSettings.mbUseRowBanding = static_cast< const SfxBoolItem* >(pPoolItem)->GetValue();
949 if( (SFX_ITEM_SET == pArgs->GetItemState(ID_VAL_USEFIRSTCOLUMNSTYLE, sal_False,&pPoolItem)) )
950 aSettings.mbUseFirstColumn = static_cast< const SfxBoolItem* >(pPoolItem)->GetValue();
952 if( (SFX_ITEM_SET == pArgs->GetItemState(ID_VAL_USELASTCOLUMNSTYLE, sal_False,&pPoolItem)) )
953 aSettings.mbUseLastColumn = static_cast< const SfxBoolItem* >(pPoolItem)->GetValue();
955 if( (SFX_ITEM_SET == pArgs->GetItemState(ID_VAL_USEBANDINGCOLUMNSTYLE, sal_False,&pPoolItem)) )
956 aSettings.mbUseColumnBanding = static_cast< const SfxBoolItem* >(pPoolItem)->GetValue();
958 if( aSettings == pTableObj->getTableStyleSettings() )
959 return;
961 const bool bUndo = pModel->IsUndoEnabled();
963 if( bUndo )
965 pModel->BegUndo( ImpGetResStr(STR_TABLE_STYLE_SETTINGS) );
966 pModel->AddUndo( new TableStyleUndo( *pTableObj ) );
969 pTableObj->setTableStyleSettings( aSettings );
971 if( bUndo )
972 pModel->EndUndo();
975 void SvxTableController::SetVertical( sal_uInt16 nSId )
977 SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
978 if( mxTable.is() && pTableObj )
980 TableModelNotifyGuard aGuard( mxTable.get() );
982 CellPos aStart, aEnd;
983 getSelectedCells( aStart, aEnd );
985 SdrTextVertAdjust eAdj = SDRTEXTVERTADJUST_TOP;
987 switch( nSId )
989 case SID_TABLE_VERT_BOTTOM:
990 eAdj = SDRTEXTVERTADJUST_BOTTOM;
991 break;
992 case SID_TABLE_VERT_CENTER:
993 eAdj = SDRTEXTVERTADJUST_CENTER;
994 break;
995 //case SID_TABLE_VERT_NONE:
996 default:
997 break;
1000 SdrTextVertAdjustItem aItem( eAdj );
1002 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
1004 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
1006 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
1007 if( xCell.is() )
1008 xCell->SetMergedItem(aItem);
1012 UpdateTableShape();
1016 void SvxTableController::MergeMarkedCells()
1018 CellPos aStart, aEnd;
1019 getSelectedCells( aStart, aEnd );
1020 SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
1021 if( pTableObj )
1023 if( pTableObj->IsTextEditActive() )
1024 mpView->SdrEndTextEdit(sal_True);
1026 TableModelNotifyGuard aGuard( mxTable.get() );
1027 MergeRange( aStart.mnCol, aStart.mnRow, aEnd.mnCol, aEnd.mnRow );
1031 void SvxTableController::SplitMarkedCells()
1033 if( mxTable.is() )
1035 CellPos aStart, aEnd;
1036 getSelectedCells( aStart, aEnd );
1038 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
1039 std::auto_ptr< SvxAbstractSplittTableDialog > xDlg( pFact ? pFact->CreateSvxSplittTableDialog( NULL, false, 99, 99 ) : 0 );
1040 if( xDlg.get() && xDlg->Execute() )
1042 const sal_Int32 nCount = xDlg->GetCount() - 1;
1043 if( nCount < 1 )
1044 return;
1046 getSelectedCells( aStart, aEnd );
1048 Reference< XMergeableCellRange > xRange( mxTable->createCursorByRange( mxTable->getCellRangeByPosition( aStart.mnCol, aStart.mnRow, aEnd.mnCol, aEnd.mnRow ) ), UNO_QUERY_THROW );
1050 const sal_Int32 nRowCount = mxTable->getRowCount();
1051 const sal_Int32 nColCount = mxTable->getColumnCount();
1054 SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >( mxTableObj.get() );
1055 if( pTableObj )
1057 if( pTableObj->IsTextEditActive() )
1058 mpView->SdrEndTextEdit(sal_True);
1060 TableModelNotifyGuard aGuard( mxTable.get() );
1062 const bool bUndo = mpModel && mpModel->IsUndoEnabled();
1063 if( bUndo )
1065 mpModel->BegUndo( ImpGetResStr(STR_TABLE_SPLIT) );
1066 mpModel->AddUndo( mpModel->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj) );
1069 if( xDlg->IsHorizontal() )
1071 xRange->split( 0, nCount );
1073 else
1075 xRange->split( nCount, 0 );
1078 if( bUndo )
1079 mpModel->EndUndo();
1081 aEnd.mnRow += mxTable->getRowCount() - nRowCount;
1082 aEnd.mnCol += mxTable->getColumnCount() - nColCount;
1084 setSelectedCells( aStart, aEnd );
1089 void SvxTableController::DistributeColumns()
1091 SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >( mxTableObj.get() );
1092 if( pTableObj )
1094 const bool bUndo = mpModel && mpModel->IsUndoEnabled();
1095 if( bUndo )
1097 mpModel->BegUndo( ImpGetResStr(STR_TABLE_DISTRIBUTE_COLUMNS) );
1098 mpModel->AddUndo( mpModel->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj) );
1101 CellPos aStart, aEnd;
1102 getSelectedCells( aStart, aEnd );
1103 pTableObj->DistributeColumns( aStart.mnCol, aEnd.mnCol );
1105 if( bUndo )
1106 mpModel->EndUndo();
1110 void SvxTableController::DistributeRows()
1112 SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >( mxTableObj.get() );
1113 if( pTableObj )
1115 const bool bUndo = mpModel && mpModel->IsUndoEnabled();
1116 if( bUndo )
1118 mpModel->BegUndo( ImpGetResStr(STR_TABLE_DISTRIBUTE_ROWS) );
1119 mpModel->AddUndo( mpModel->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj) );
1122 CellPos aStart, aEnd;
1123 getSelectedCells( aStart, aEnd );
1124 pTableObj->DistributeRows( aStart.mnRow, aEnd.mnRow );
1126 if( bUndo )
1127 mpModel->EndUndo();
1131 bool SvxTableController::DeleteMarked()
1133 if( mbCellSelectionMode )
1135 if( mxTable.is() )
1137 CellPos aStart, aEnd;
1138 getSelectedCells( aStart, aEnd );
1139 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
1141 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
1143 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
1144 if( xCell.is() )
1145 xCell->SetOutlinerParaObject( 0 );
1149 UpdateTableShape();
1150 return true;
1154 return false;
1157 bool SvxTableController::GetStyleSheet( SfxStyleSheet*& rpStyleSheet ) const
1159 if( hasSelectedCells() )
1161 rpStyleSheet = 0;
1163 if( mxTable.is() )
1165 SfxStyleSheet* pRet=0;
1166 bool b1st=true;
1168 CellPos aStart, aEnd;
1169 const_cast<SvxTableController&>(*this).getSelectedCells( aStart, aEnd );
1171 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
1173 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
1175 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
1176 if( xCell.is() )
1178 SfxStyleSheet* pSS=xCell->GetStyleSheet();
1179 if(b1st)
1181 pRet=pSS;
1183 else if(pRet != pSS)
1185 return true;
1187 b1st=false;
1191 rpStyleSheet = pRet;
1192 return true;
1195 return false;
1198 bool SvxTableController::SetStyleSheet( SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr )
1200 if( hasSelectedCells() && (!pStyleSheet || pStyleSheet->GetFamily() == SFX_STYLE_FAMILY_FRAME) )
1202 if( mxTable.is() )
1204 CellPos aStart, aEnd;
1205 getSelectedCells( aStart, aEnd );
1207 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
1209 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
1211 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
1212 if( xCell.is() )
1213 xCell->SetStyleSheet(pStyleSheet,bDontRemoveHardAttr);
1217 UpdateTableShape();
1218 return true;
1221 return false;
1224 // --------------------------------------------------------------------
1225 // internals
1226 // --------------------------------------------------------------------
1228 bool SvxTableController::checkTableObject()
1230 return mxTableObj.is();
1233 // --------------------------------------------------------------------
1235 sal_uInt16 SvxTableController::getKeyboardAction( const KeyEvent& rKEvt, Window* /*pWindow*/ )
1237 const bool bMod1 = rKEvt.GetKeyCode().IsMod1(); // ctrl
1238 const bool bMod2 = rKEvt.GetKeyCode().IsMod2() != 0; // Alt
1240 const bool bTextEdit = mpView->IsTextEdit();
1242 sal_uInt16 nAction = ACTION_HANDLED_BY_VIEW;
1244 ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
1245 if( !pTableObj )
1246 return nAction;
1248 // handle special keys
1249 const sal_Int16 nCode = rKEvt.GetKeyCode().GetCode();
1250 switch( nCode )
1252 case awt::Key::ESCAPE: // handle escape
1254 if( bTextEdit )
1256 // escape during text edit ends text edit
1257 nAction = ACTION_STOP_TEXT_EDIT;
1259 if( mbCellSelectionMode )
1261 // escape with selected cells removes selection
1262 nAction = ACTION_REMOVE_SELECTION;
1264 break;
1266 case awt::Key::RETURN: // handle return
1268 if( !bMod1 && !bMod2 && !bTextEdit )
1270 // when not already editing, return starts text edit
1271 setSelectionStart( pTableObj->getFirstCell() );
1272 nAction = ACTION_EDIT_CELL;
1274 break;
1276 case awt::Key::F2: // f2 toggles text edit
1278 if( bMod1 || bMod2 ) // f2 with modifiers is handled by the view
1281 else if( bTextEdit )
1283 // f2 during text edit stops text edit
1284 nAction = ACTION_STOP_TEXT_EDIT;
1286 else if( mbCellSelectionMode )
1288 // f2 with selected cells removes selection
1289 nAction = ACTION_REMOVE_SELECTION;
1291 else
1293 // f2 with no selection and no text edit starts text edit
1294 setSelectionStart( pTableObj->getFirstCell() );
1295 nAction = ACTION_EDIT_CELL;
1297 break;
1299 case awt::Key::HOME:
1300 case awt::Key::NUM7:
1302 if( (bMod1 || bMod2) && (bTextEdit || mbCellSelectionMode) )
1304 if( bMod1 && !bMod2 )
1306 // ctrl + home jumps to first cell
1307 nAction = ACTION_GOTO_FIRST_CELL;
1309 else if( !bMod1 && bMod2 )
1311 // alt + home jumps to first column
1312 nAction = ACTION_GOTO_FIRST_COLUMN;
1315 break;
1317 case awt::Key::END:
1318 case awt::Key::NUM1:
1320 if( (bMod1 || bMod2) && (bTextEdit || mbCellSelectionMode) )
1322 if( bMod1 && !bMod2 )
1324 // ctrl + end jumps to last cell
1325 nAction = ACTION_GOTO_LAST_CELL;
1327 else if( !bMod1 && bMod2 )
1329 // alt + home jumps to last column
1330 nAction = ACTION_GOTO_LAST_COLUMN;
1333 break;
1336 case awt::Key::TAB:
1338 if( bTextEdit || mbCellSelectionMode )
1339 nAction = ACTION_TAB;
1340 break;
1343 case awt::Key::UP:
1344 case awt::Key::NUM8:
1345 case awt::Key::DOWN:
1346 case awt::Key::NUM2:
1347 case awt::Key::LEFT:
1348 case awt::Key::NUM4:
1349 case awt::Key::RIGHT:
1350 case awt::Key::NUM6:
1352 bool bTextMove = false;
1354 if( !bMod1 && bMod2 )
1356 if( (nCode == awt::Key::UP) || (nCode == awt::Key::NUM8) )
1358 nAction = ACTION_GOTO_LEFT_CELL;
1360 else if( (nCode == awt::Key::DOWN) || (nCode == awt::Key::NUM2) )
1362 nAction = ACTION_GOTO_RIGHT_CELL;
1364 break;
1367 if( !bTextMove )
1369 OutlinerView* pOLV = mpView->GetTextEditOutlinerView();
1370 if( pOLV )
1372 RemoveSelection();
1373 // during text edit, check if we navigate out of the cell
1374 ESelection aOldSelection = pOLV->GetSelection();
1375 pOLV->PostKeyEvent(rKEvt);
1376 bTextMove = pOLV && ( aOldSelection.IsEqual(pOLV->GetSelection()) );
1377 if( !bTextMove )
1379 nAction = ACTION_NONE;
1384 if( mbCellSelectionMode || bTextMove )
1386 // no text edit, navigate in cells if selection active
1387 switch( nCode )
1389 case awt::Key::LEFT:
1390 case awt::Key::NUM4:
1391 nAction = ACTION_GOTO_LEFT_CELL;
1392 break;
1393 case awt::Key::RIGHT:
1394 case awt::Key::NUM6:
1395 nAction = ACTION_GOTO_RIGHT_CELL;
1396 break;
1397 case awt::Key::DOWN:
1398 case awt::Key::NUM2:
1399 nAction = ACTION_GOTO_DOWN_CELL;
1400 break;
1401 case awt::Key::UP:
1402 case awt::Key::NUM8:
1403 nAction = ACTION_GOTO_UP_CELL;
1404 break;
1407 break;
1409 case awt::Key::PAGEUP:
1410 if( bMod2 )
1411 nAction = ACTION_GOTO_FIRST_ROW;
1412 break;
1414 case awt::Key::PAGEDOWN:
1415 if( bMod2 )
1416 nAction = ACTION_GOTO_LAST_ROW;
1417 break;
1419 return nAction;
1422 bool SvxTableController::executeAction( sal_uInt16 nAction, bool bSelect, Window* pWindow )
1424 ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
1425 if( !pTableObj )
1426 return false;
1428 switch( nAction )
1430 case ACTION_GOTO_FIRST_CELL:
1432 gotoCell( pTableObj->getFirstCell(), bSelect, pWindow, nAction );
1433 break;
1436 case ACTION_GOTO_LEFT_CELL:
1438 gotoCell( pTableObj->getLeftCell( getSelectionEnd(), !bSelect ), bSelect, pWindow, nAction );
1439 break;
1442 case ACTION_GOTO_RIGHT_CELL:
1444 gotoCell( pTableObj->getRightCell( getSelectionEnd(), !bSelect ), bSelect, pWindow, nAction);
1445 break;
1448 case ACTION_GOTO_LAST_CELL:
1450 gotoCell( pTableObj->getLastCell(), bSelect, pWindow, nAction );
1451 break;
1454 case ACTION_GOTO_FIRST_COLUMN:
1456 CellPos aPos( pTableObj->getFirstCell().mnCol, getSelectionEnd().mnRow );
1457 gotoCell( aPos, bSelect, pWindow, nAction );
1458 break;
1461 case ACTION_GOTO_LAST_COLUMN:
1463 CellPos aPos( pTableObj->getLastCell().mnCol, getSelectionEnd().mnRow );
1464 gotoCell( aPos, bSelect, pWindow, nAction );
1465 break;
1468 case ACTION_GOTO_FIRST_ROW:
1470 CellPos aPos( getSelectionEnd().mnCol, pTableObj->getFirstCell().mnRow );
1471 gotoCell( aPos, bSelect, pWindow, nAction );
1472 break;
1475 case ACTION_GOTO_UP_CELL:
1477 gotoCell( pTableObj->getUpCell(getSelectionEnd(), !bSelect), bSelect, pWindow, nAction );
1478 break;
1481 case ACTION_GOTO_DOWN_CELL:
1483 gotoCell( pTableObj->getDownCell(getSelectionEnd(), !bSelect), bSelect, pWindow, nAction );
1484 break;
1487 case ACTION_GOTO_LAST_ROW:
1489 CellPos aPos( getSelectionEnd().mnCol, pTableObj->getLastCell().mnRow );
1490 gotoCell( aPos, bSelect, pWindow, nAction );
1491 break;
1494 case ACTION_EDIT_CELL:
1495 EditCell( getSelectionStart(), pWindow, 0, nAction );
1496 break;
1498 case ACTION_STOP_TEXT_EDIT:
1499 StopTextEdit();
1500 break;
1502 case ACTION_REMOVE_SELECTION:
1503 RemoveSelection();
1504 break;
1506 case ACTION_START_SELECTION:
1507 StartSelection( getSelectionStart() );
1508 break;
1510 case ACTION_TAB:
1512 if( bSelect )
1513 gotoCell( pTableObj->getPreviousCell( getSelectionEnd(), true ), false, pWindow, nAction );
1514 else
1516 CellPos aSelectionEnd( getSelectionEnd() );
1517 CellPos aNextCell( pTableObj->getNextCell( aSelectionEnd, true ) );
1518 if( aSelectionEnd == aNextCell )
1520 onInsert( SID_TABLE_INSERT_ROW, 0 );
1521 aNextCell = pTableObj->getNextCell( aSelectionEnd, true );
1523 gotoCell( aNextCell, false, pWindow, nAction );
1525 break;
1529 return nAction != ACTION_HANDLED_BY_VIEW;
1532 // --------------------------------------------------------------------
1534 void SvxTableController::gotoCell( const CellPos& rPos, bool bSelect, Window* pWindow, sal_uInt16 nAction )
1536 if( mxTableObj.is() && static_cast<SdrTableObj*>(mxTableObj.get())->IsTextEditActive() )
1537 mpView->SdrEndTextEdit(sal_True);
1539 if( bSelect )
1541 maCursorLastPos = rPos;
1542 if( mxTableObj.is() )
1543 static_cast< SdrTableObj* >( mxTableObj.get() )->setActiveCell( rPos );
1545 if( !mbCellSelectionMode )
1547 setSelectedCells( maCursorFirstPos, rPos );
1549 else
1551 UpdateSelection( rPos );
1554 else
1556 RemoveSelection();
1557 EditCell( rPos, pWindow, 0, nAction );
1561 // --------------------------------------------------------------------
1563 const CellPos& SvxTableController::getSelectionStart()
1565 checkCell( maCursorFirstPos );
1566 return maCursorFirstPos;
1569 // --------------------------------------------------------------------
1571 void SvxTableController::setSelectionStart( const CellPos& rPos )
1573 maCursorFirstPos = rPos;
1576 // --------------------------------------------------------------------
1578 const CellPos& SvxTableController::getSelectionEnd()
1580 checkCell( maCursorLastPos );
1581 return maCursorLastPos;
1584 // --------------------------------------------------------------------
1586 void SvxTableController::MergeRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow )
1588 if( mxTable.is() ) try
1590 Reference< XMergeableCellRange > xRange( mxTable->createCursorByRange( mxTable->getCellRangeByPosition( nFirstCol, nFirstRow,nLastCol, nLastRow ) ), UNO_QUERY_THROW );
1591 if( xRange->isMergeable() )
1593 const bool bUndo = mpModel && mpModel->IsUndoEnabled();
1594 if( bUndo )
1596 mpModel->BegUndo( ImpGetResStr(STR_TABLE_MERGE) );
1597 mpModel->AddUndo( mpModel->GetSdrUndoFactory().CreateUndoGeoObject(*mxTableObj.get()) );
1600 xRange->merge();
1602 if( bUndo )
1603 mpModel->EndUndo();
1606 catch( Exception& )
1608 DBG_ASSERT( false, "sdr::table::SvxTableController::MergeRange(), exception caught!" );
1614 // --------------------------------------------------------------------
1616 void SvxTableController::checkCell( CellPos& rPos )
1618 if( mxTable.is() ) try
1620 if( rPos.mnCol >= mxTable->getColumnCount() )
1621 rPos.mnCol = mxTable->getColumnCount()-1;
1623 if( rPos.mnRow >= mxTable->getRowCount() )
1624 rPos.mnRow = mxTable->getRowCount()-1;
1626 catch( Exception& )
1628 OSL_FAIL("sdr::table::SvxTableController::checkCell(), exception caught!" );
1632 // --------------------------------------------------------------------
1634 void SvxTableController::findMergeOrigin( CellPos& rPos )
1636 if( mxTable.is() ) try
1638 Reference< XMergeableCell > xCell( mxTable->getCellByPosition( rPos.mnCol, rPos.mnRow ), UNO_QUERY_THROW );
1639 if( xCell.is() && xCell->isMerged() )
1641 ::findMergeOrigin( mxTable, rPos.mnCol, rPos.mnRow, rPos.mnCol, rPos.mnRow );
1644 catch( Exception& )
1646 OSL_FAIL("sdr::table::SvxTableController::findMergeOrigin(), exception caught!" );
1650 // --------------------------------------------------------------------
1652 void SvxTableController::EditCell( const CellPos& rPos, ::Window* pWindow, const awt::MouseEvent* pMouseEvent /*= 0*/, sal_uInt16 nAction /*= ACTION_NONE */ )
1654 SdrPageView* pPV = mpView->GetSdrPageView();
1656 ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
1657 if( pTableObj && pTableObj->GetPage() == pPV->GetPage() )
1659 bool bEmptyOutliner = false;
1661 if(!pTableObj->GetOutlinerParaObject() && mpView->GetTextEditOutliner())
1663 ::Outliner* pOutl = mpView->GetTextEditOutliner();
1664 sal_Int32 nParaAnz = pOutl->GetParagraphCount();
1665 Paragraph* p1stPara = pOutl->GetParagraph( 0 );
1667 if(nParaAnz==1 && p1stPara)
1669 // Bei nur einem Pararaph
1670 if (pOutl->GetText(p1stPara).Len() == 0)
1672 bEmptyOutliner = true;
1677 CellPos aPos( rPos );
1678 findMergeOrigin( aPos );
1680 if( pTableObj != mpView->GetTextEditObject() || bEmptyOutliner || !pTableObj->IsTextEditActive( aPos ) )
1682 if( pTableObj->IsTextEditActive() )
1683 mpView->SdrEndTextEdit(sal_True);
1685 pTableObj->setActiveCell( aPos );
1687 // create new outliner, owner will be the SdrObjEditView
1688 SdrOutliner* pOutl = SdrMakeOutliner( OUTLINERMODE_OUTLINEOBJECT, mpModel );
1689 if( pTableObj->IsVerticalWriting() )
1690 pOutl->SetVertical( sal_True );
1692 if(mpView->SdrBeginTextEdit(pTableObj, pPV, pWindow, sal_True, pOutl))
1694 maCursorLastPos = maCursorFirstPos = rPos;
1696 OutlinerView* pOLV = mpView->GetTextEditOutlinerView();
1698 bool bNoSel = true;
1700 if( pMouseEvent )
1702 ::MouseEvent aMEvt( *pMouseEvent );
1704 SdrViewEvent aVEvt;
1705 SdrHitKind eHit = mpView->PickAnything(aMEvt, SDRMOUSEBUTTONDOWN, aVEvt);
1707 if (eHit == SDRHIT_TEXTEDIT)
1709 // Text getroffen
1710 pOLV->MouseButtonDown(aMEvt);
1711 pOLV->MouseMove(aMEvt);
1712 pOLV->MouseButtonUp(aMEvt);
1713 // pOLV->MouseButtonDown(aMEvt);
1714 bNoSel = false;
1716 else
1718 nAction = ACTION_GOTO_LEFT_CELL;
1722 if( bNoSel )
1724 // Move cursor to end of text
1725 ESelection aNewSelection;
1727 const WritingMode eMode = pTableObj->GetWritingMode();
1728 if( ((nAction == ACTION_GOTO_LEFT_CELL) || (nAction == ACTION_GOTO_RIGHT_CELL)) && (eMode != WritingMode_TB_RL) )
1730 const bool bLast = ((nAction == ACTION_GOTO_LEFT_CELL) && (eMode == WritingMode_LR_TB)) ||
1731 ((nAction == ACTION_GOTO_RIGHT_CELL) && (eMode == WritingMode_RL_TB));
1733 if( bLast )
1734 aNewSelection = ESelection(EE_PARA_NOT_FOUND, EE_INDEX_NOT_FOUND, EE_PARA_NOT_FOUND, EE_INDEX_NOT_FOUND);
1736 pOLV->SetSelection(aNewSelection);
1743 // --------------------------------------------------------------------
1745 bool SvxTableController::StopTextEdit()
1747 if(mpView->IsTextEdit())
1749 mpView->SdrEndTextEdit();
1750 mpView->SetCurrentObj(OBJ_TABLE);
1751 mpView->SetEditMode(SDREDITMODE_EDIT);
1752 return true;
1754 else
1756 return false;
1760 // --------------------------------------------------------------------
1762 void SvxTableController::getSelectedCells( CellPos& rFirst, CellPos& rLast )
1764 if( mbCellSelectionMode )
1766 checkCell( maCursorFirstPos );
1767 checkCell( maCursorLastPos );
1769 rFirst.mnCol = std::min( maCursorFirstPos.mnCol, maCursorLastPos.mnCol );
1770 rFirst.mnRow = std::min( maCursorFirstPos.mnRow, maCursorLastPos.mnRow );
1771 rLast.mnCol = std::max( maCursorFirstPos.mnCol, maCursorLastPos.mnCol );
1772 rLast.mnRow = std::max( maCursorFirstPos.mnRow, maCursorLastPos.mnRow );
1774 bool bExt = false;
1775 if( mxTable.is() ) do
1777 bExt = false;
1778 for( sal_Int32 nRow = rFirst.mnRow; nRow <= rLast.mnRow && !bExt; nRow++ )
1780 for( sal_Int32 nCol = rFirst.mnCol; nCol <= rLast.mnCol && !bExt; nCol++ )
1782 Reference< XMergeableCell > xCell( mxTable->getCellByPosition( nCol, nRow ), UNO_QUERY );
1783 if( !xCell.is() )
1784 continue;
1786 if( xCell->isMerged() )
1788 CellPos aPos( nCol, nRow );
1789 findMergeOrigin( aPos );
1790 if( (aPos.mnCol < rFirst.mnCol) || (aPos.mnRow < rFirst.mnRow) )
1792 rFirst.mnCol = std::min( rFirst.mnCol, aPos.mnCol );
1793 rFirst.mnRow = std::min( rFirst.mnRow, aPos.mnRow );
1794 bExt = true;
1797 else
1799 if( ((nCol + xCell->getColumnSpan() - 1) > rLast.mnCol) || (nRow + xCell->getRowSpan() - 1 ) > rLast.mnRow )
1801 rLast.mnCol = std::max( rLast.mnCol, nCol + xCell->getColumnSpan() - 1 );
1802 rLast.mnRow = std::max( rLast.mnRow, nRow + xCell->getRowSpan() - 1 );
1803 bExt = true;
1809 while(bExt);
1811 else if( mpView && mpView->IsTextEdit() )
1813 rFirst = getSelectionStart();
1814 findMergeOrigin( rFirst );
1815 rLast = rFirst;
1817 if( mxTable.is() )
1819 Reference< XMergeableCell > xCell( mxTable->getCellByPosition( rLast.mnCol, rLast.mnRow ), UNO_QUERY );
1820 if( xCell.is() )
1822 rLast.mnCol += xCell->getColumnSpan() - 1;
1823 rLast.mnRow += xCell->getRowSpan() - 1;
1827 else
1829 rFirst.mnCol = 0;
1830 rFirst.mnRow = 0;
1831 if( mxTable.is() )
1833 rLast.mnRow = mxTable->getRowCount()-1;
1834 rLast.mnCol = mxTable->getColumnCount()-1;
1836 else
1838 rLast.mnRow = 0;
1839 rLast.mnCol = 0;
1844 // --------------------------------------------------------------------
1846 void SvxTableController::StartSelection( const CellPos& rPos )
1848 StopTextEdit();
1849 mbCellSelectionMode = true;
1850 maCursorLastPos = maCursorFirstPos = rPos;
1851 mpView->MarkListHasChanged();
1854 // --------------------------------------------------------------------
1856 void SvxTableController::setSelectedCells( const CellPos& rStart, const CellPos& rEnd )
1858 StopTextEdit();
1859 mbCellSelectionMode = true;
1860 maCursorFirstPos = rStart;
1861 UpdateSelection( rEnd );
1864 // --------------------------------------------------------------------
1866 void SvxTableController::UpdateSelection( const CellPos& rPos )
1868 maCursorLastPos = rPos;
1869 mpView->MarkListHasChanged();
1872 // --------------------------------------------------------------------
1874 void SvxTableController::clearSelection()
1876 RemoveSelection();
1879 // --------------------------------------------------------------------
1881 void SvxTableController::selectAll()
1883 if( mxTable.is() )
1885 CellPos aPos1, aPos2( mxTable->getColumnCount()-1, mxTable->getRowCount()-1 );
1886 if( (aPos2.mnCol >= 0) && (aPos2.mnRow >= 0) )
1888 setSelectedCells( aPos1, aPos2 );
1893 // --------------------------------------------------------------------
1895 void SvxTableController::RemoveSelection()
1897 if( mbCellSelectionMode )
1899 mbCellSelectionMode = false;
1900 mpView->MarkListHasChanged();
1904 // --------------------------------------------------------------------
1906 void SvxTableController::onTableModified()
1908 if( mnUpdateEvent == 0 )
1909 mnUpdateEvent = Application::PostUserEvent( LINK( this, SvxTableController, UpdateHdl ) );
1911 // --------------------------------------------------------------------
1913 void SvxTableController::updateSelectionOverlay()
1915 destroySelectionOverlay();
1916 if( mbCellSelectionMode )
1918 ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
1919 if( pTableObj )
1921 sdr::overlay::OverlayObjectCell::RangeVector aRanges;
1923 Rectangle aRect;
1924 CellPos aStart,aEnd;
1925 getSelectedCells( aStart, aEnd );
1926 pTableObj->getCellBounds( aStart, aRect );
1928 basegfx::B2DRange a2DRange( basegfx::B2DPoint(aRect.Left(), aRect.Top()) );
1929 a2DRange.expand( basegfx::B2DPoint(aRect.Right(), aRect.Bottom()) );
1931 findMergeOrigin( aEnd );
1932 pTableObj->getCellBounds( aEnd, aRect );
1933 a2DRange.expand( basegfx::B2DPoint(aRect.Left(), aRect.Top()) );
1934 a2DRange.expand( basegfx::B2DPoint(aRect.Right(), aRect.Bottom()) );
1935 aRanges.push_back( a2DRange );
1937 ::Color aHighlight( COL_BLUE );
1938 OutputDevice* pOutDev = mpView->GetFirstOutputDevice();
1939 if( pOutDev )
1940 aHighlight = pOutDev->GetSettings().GetStyleSettings().GetHighlightColor();
1942 const sal_uInt32 nCount = mpView->PaintWindowCount();
1943 for( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ )
1945 SdrPaintWindow* pPaintWindow = mpView->GetPaintWindow(nIndex);
1946 if( pPaintWindow )
1948 rtl::Reference < ::sdr::overlay::OverlayManager > xOverlayManager = pPaintWindow->GetOverlayManager();
1949 if( xOverlayManager.is() )
1951 // sdr::overlay::CellOverlayType eType = sdr::overlay::CELL_OVERLAY_INVERT;
1952 sdr::overlay::CellOverlayType eType = sdr::overlay::CELL_OVERLAY_TRANSPARENT;
1954 sdr::overlay::OverlayObjectCell* pOverlay = new sdr::overlay::OverlayObjectCell( eType, aHighlight, aRanges );
1956 xOverlayManager->add(*pOverlay);
1957 mpSelectionOverlay = new ::sdr::overlay::OverlayObjectList;
1958 mpSelectionOverlay->append(*pOverlay);
1966 // --------------------------------------------------------------------
1968 void SvxTableController::destroySelectionOverlay()
1970 if( mpSelectionOverlay )
1972 delete mpSelectionOverlay;
1973 mpSelectionOverlay = 0;
1977 // --------------------------------------------------------------------
1979 void SvxTableController::MergeAttrFromSelectedCells(SfxItemSet& rAttr, bool bOnlyHardAttr) const
1981 if( mxTable.is() )
1983 CellPos aStart, aEnd;
1984 const_cast<SvxTableController&>(*this).getSelectedCells( aStart, aEnd );
1986 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
1988 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
1990 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
1991 if( xCell.is() && !xCell->isMerged() )
1993 const SfxItemSet& rSet = xCell->GetItemSet();
1994 SfxWhichIter aIter(rSet);
1995 sal_uInt16 nWhich(aIter.FirstWhich());
1996 while(nWhich)
1998 if(!bOnlyHardAttr)
2000 if(SFX_ITEM_DONTCARE == rSet.GetItemState(nWhich, sal_False))
2001 rAttr.InvalidateItem(nWhich);
2002 else
2003 rAttr.MergeValue(rSet.Get(nWhich), sal_True);
2005 else if(SFX_ITEM_SET == rSet.GetItemState(nWhich, sal_False))
2007 const SfxPoolItem& rItem = rSet.Get(nWhich);
2008 rAttr.MergeValue(rItem, sal_True);
2011 nWhich = aIter.NextWhich();
2019 // --------------------------------------------------------------------
2021 const sal_uInt16 CELL_BEFORE = 0x0001;
2022 const sal_uInt16 CELL_LEFT = 0x0002;
2023 const sal_uInt16 CELL_RIGHT = 0x0004;
2024 const sal_uInt16 CELL_AFTER = 0x0008;
2026 const sal_uInt16 CELL_UPPER = 0x0010;
2027 const sal_uInt16 CELL_TOP = 0x0020;
2028 const sal_uInt16 CELL_BOTTOM = 0x0040;
2029 const sal_uInt16 CELL_LOWER = 0x0080;
2031 // --------------------------------------------------------------------
2033 static void ImplSetLinePreserveColor( SvxBoxItem& rNewFrame, const SvxBorderLine* pNew, sal_uInt16 nLine )
2035 if( pNew )
2037 const SvxBorderLine* pOld = rNewFrame.GetLine(nLine);
2038 if( pOld )
2040 SvxBorderLine aNewLine( *pNew );
2041 aNewLine.SetColor( pOld->GetColor() );
2042 rNewFrame.SetLine( &aNewLine, nLine );
2043 return;
2046 rNewFrame.SetLine( pNew, nLine );
2049 // --------------------------------------------------------------------
2051 static void ImplApplyBoxItem( sal_uInt16 nCellFlags, const SvxBoxItem* pBoxItem, const SvxBoxInfoItem* pBoxInfoItem, SvxBoxItem& rNewFrame )
2053 if( (nCellFlags & (CELL_BEFORE|CELL_AFTER|CELL_UPPER|CELL_LOWER)) != 0 )
2055 // current cell is outside the selection
2057 if( (nCellFlags & ( CELL_BEFORE|CELL_AFTER)) == 0 ) // check if its not nw or ne corner
2059 if( nCellFlags & CELL_UPPER )
2061 if( pBoxInfoItem->IsValid(VALID_TOP) )
2062 rNewFrame.SetLine(0, BOX_LINE_BOTTOM );
2064 else if( nCellFlags & CELL_LOWER )
2066 if( pBoxInfoItem->IsValid(VALID_BOTTOM) )
2067 rNewFrame.SetLine( 0, BOX_LINE_TOP );
2070 else if( (nCellFlags & ( CELL_UPPER|CELL_LOWER)) == 0 ) // check if its not sw or se corner
2072 if( nCellFlags & CELL_BEFORE )
2074 if( pBoxInfoItem->IsValid(VALID_LEFT) )
2075 rNewFrame.SetLine( 0, BOX_LINE_RIGHT );
2077 else if( nCellFlags & CELL_AFTER )
2079 if( pBoxInfoItem->IsValid(VALID_RIGHT) )
2080 rNewFrame.SetLine( 0, BOX_LINE_LEFT );
2084 else
2086 // current cell is inside the selection
2088 if( (nCellFlags & CELL_LEFT) ? pBoxInfoItem->IsValid(VALID_LEFT) : pBoxInfoItem->IsValid(VALID_VERT) )
2089 rNewFrame.SetLine( (nCellFlags & CELL_LEFT) ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(), BOX_LINE_LEFT );
2091 if( (nCellFlags & CELL_RIGHT) ? pBoxInfoItem->IsValid(VALID_RIGHT) : pBoxInfoItem->IsValid(VALID_VERT) )
2092 rNewFrame.SetLine( (nCellFlags & CELL_RIGHT) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(), BOX_LINE_RIGHT );
2094 if( (nCellFlags & CELL_TOP) ? pBoxInfoItem->IsValid(VALID_TOP) : pBoxInfoItem->IsValid(VALID_HORI) )
2095 rNewFrame.SetLine( (nCellFlags & CELL_TOP) ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(), BOX_LINE_TOP );
2097 if( (nCellFlags & CELL_BOTTOM) ? pBoxInfoItem->IsValid(VALID_BOTTOM) : pBoxInfoItem->IsValid(VALID_HORI) )
2098 rNewFrame.SetLine( (nCellFlags & CELL_BOTTOM) ? pBoxItem->GetBottom() : pBoxInfoItem->GetHori(), BOX_LINE_BOTTOM );
2100 // apply distance to borders
2101 if( pBoxInfoItem->IsValid( VALID_DISTANCE ) )
2102 for( sal_uInt16 nLine = 0; nLine < 4; ++nLine )
2103 rNewFrame.SetDistance( pBoxItem->GetDistance( nLine ), nLine );
2107 // --------------------------------------------------------------------
2109 static void ImplSetLineColor( SvxBoxItem& rNewFrame, sal_uInt16 nLine, const Color& rColor )
2111 const SvxBorderLine* pSourceLine = rNewFrame.GetLine( nLine );
2112 if( pSourceLine )
2114 SvxBorderLine aLine( *pSourceLine );
2115 aLine.SetColor( rColor );
2116 rNewFrame.SetLine( &aLine, nLine );
2120 // --------------------------------------------------------------------
2122 static void ImplApplyLineColorItem( sal_uInt16 nCellFlags, const SvxColorItem* pLineColorItem, SvxBoxItem& rNewFrame )
2124 const Color aColor( pLineColorItem->GetValue() );
2126 if( (nCellFlags & (CELL_LOWER|CELL_BEFORE|CELL_AFTER)) == 0 )
2127 ImplSetLineColor( rNewFrame, BOX_LINE_BOTTOM, aColor );
2129 if( (nCellFlags & (CELL_UPPER|CELL_BEFORE|CELL_AFTER)) == 0 )
2130 ImplSetLineColor( rNewFrame, BOX_LINE_TOP, aColor );
2132 if( (nCellFlags & (CELL_UPPER|CELL_LOWER|CELL_AFTER)) == 0 )
2133 ImplSetLineColor( rNewFrame, BOX_LINE_RIGHT, aColor );
2135 if( (nCellFlags & (CELL_UPPER|CELL_LOWER|CELL_BEFORE)) == 0 )
2136 ImplSetLineColor( rNewFrame, BOX_LINE_LEFT, aColor );
2139 // --------------------------------------------------------------------
2141 static void ImplApplyBorderLineItem( sal_uInt16 nCellFlags, const SvxBorderLine* pBorderLineItem, SvxBoxItem& rNewFrame )
2143 if( (nCellFlags & ( CELL_BEFORE|CELL_AFTER|CELL_UPPER|CELL_LOWER)) != 0 )
2145 if( (nCellFlags & ( CELL_BEFORE|CELL_AFTER)) == 0 ) // check if its not nw or ne corner
2147 if( nCellFlags & CELL_UPPER )
2149 if( rNewFrame.GetBottom() )
2150 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_BOTTOM );
2152 else if( nCellFlags & CELL_LOWER )
2154 if( rNewFrame.GetTop() )
2155 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_TOP );
2158 else if( (nCellFlags & ( CELL_UPPER|CELL_LOWER)) == 0 ) // check if its not sw or se corner
2160 if( nCellFlags & CELL_BEFORE )
2162 if( rNewFrame.GetRight() )
2163 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_RIGHT );
2165 else if( nCellFlags & CELL_AFTER )
2167 if( rNewFrame.GetLeft() )
2168 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_LEFT );
2172 else
2174 if( rNewFrame.GetBottom() )
2175 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_BOTTOM );
2176 if( rNewFrame.GetTop() )
2177 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_TOP );
2178 if( rNewFrame.GetRight() )
2179 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_RIGHT );
2180 if( rNewFrame.GetLeft() )
2181 ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_LEFT );
2185 // --------------------------------------------------------------------
2187 void SvxTableController::ApplyBorderAttr( const SfxItemSet& rAttr )
2189 if( mxTable.is() )
2191 const sal_Int32 nRowCount = mxTable->getRowCount();
2192 const sal_Int32 nColCount = mxTable->getColumnCount();
2193 if( nRowCount && nColCount )
2195 const SvxBoxItem* pBoxItem = 0;
2196 if(SFX_ITEM_SET == rAttr.GetItemState(SDRATTR_TABLE_BORDER, sal_False) )
2197 pBoxItem = dynamic_cast< const SvxBoxItem* >( &rAttr.Get( SDRATTR_TABLE_BORDER ) );
2199 const SvxBoxInfoItem* pBoxInfoItem = 0;
2200 if(SFX_ITEM_SET == rAttr.GetItemState(SDRATTR_TABLE_BORDER_INNER, sal_False) )
2201 pBoxInfoItem = dynamic_cast< const SvxBoxInfoItem* >( &rAttr.Get( SDRATTR_TABLE_BORDER_INNER ) );
2203 const SvxColorItem* pLineColorItem = 0;
2204 if(SFX_ITEM_SET == rAttr.GetItemState(SID_FRAME_LINECOLOR, sal_False) )
2205 pLineColorItem = dynamic_cast< const SvxColorItem* >( &rAttr.Get( SID_FRAME_LINECOLOR ) );
2207 const SvxBorderLine* pBorderLineItem = 0;
2208 if(SFX_ITEM_SET == rAttr.GetItemState(SID_FRAME_LINESTYLE, sal_False) )
2209 pBorderLineItem = ((const SvxLineItem&)rAttr.Get( SID_FRAME_LINESTYLE )).GetLine();
2211 if( pBoxInfoItem && !pBoxItem )
2213 const static SvxBoxItem gaEmptyBoxItem( SDRATTR_TABLE_BORDER );
2214 pBoxItem = &gaEmptyBoxItem;
2216 else if( pBoxItem && !pBoxInfoItem )
2218 const static SvxBoxInfoItem gaEmptyBoxInfoItem( SDRATTR_TABLE_BORDER_INNER );
2219 pBoxInfoItem = &gaEmptyBoxInfoItem;
2222 CellPos aStart, aEnd;
2223 getSelectedCells( aStart, aEnd );
2225 const sal_Int32 nLastRow = std::min( aEnd.mnRow + 2, nRowCount );
2226 const sal_Int32 nLastCol = std::min( aEnd.mnCol + 2, nColCount );
2228 for( sal_Int32 nRow = std::max( aStart.mnRow - 1, (sal_Int32)0 ); nRow < nLastRow; nRow++ )
2230 sal_uInt16 nRowFlags = 0;
2231 nRowFlags |= (nRow == aStart.mnRow) ? CELL_TOP : 0;
2232 nRowFlags |= (nRow == aEnd.mnRow) ? CELL_BOTTOM : 0;
2233 nRowFlags |= (nRow < aStart.mnRow) ? CELL_UPPER : 0;
2234 nRowFlags |= (nRow > aEnd.mnRow) ? CELL_LOWER : 0;
2236 for( sal_Int32 nCol = std::max( aStart.mnCol - 1, (sal_Int32)0 ); nCol < nLastCol; nCol++ )
2238 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
2239 if( !xCell.is() )
2240 continue;
2242 const SfxItemSet& rSet = xCell->GetItemSet();
2243 const SvxBoxItem* pOldOuter = (const SvxBoxItem*) &rSet.Get( SDRATTR_TABLE_BORDER );
2245 SvxBoxItem aNewFrame( *pOldOuter );
2247 sal_uInt16 nCellFlags = nRowFlags;
2248 nCellFlags |= (nCol == aStart.mnCol) ? CELL_LEFT : 0;
2249 nCellFlags |= (nCol == aEnd.mnCol) ? CELL_RIGHT : 0;
2250 nCellFlags |= (nCol < aStart.mnCol) ? CELL_BEFORE : 0;
2251 nCellFlags |= (nCol > aEnd.mnCol) ? CELL_AFTER : 0;
2253 if( pBoxItem && pBoxInfoItem )
2254 ImplApplyBoxItem( nCellFlags, pBoxItem, pBoxInfoItem, aNewFrame );
2256 if( pLineColorItem )
2257 ImplApplyLineColorItem( nCellFlags, pLineColorItem, aNewFrame );
2259 if( pBorderLineItem )
2260 ImplApplyBorderLineItem( nCellFlags, pBorderLineItem, aNewFrame );
2262 if (aNewFrame != *pOldOuter)
2264 SfxItemSet aAttr(*rSet.GetPool(), rSet.GetRanges());
2265 aAttr.Put(aNewFrame);
2266 xCell->SetMergedItemSetAndBroadcast( aAttr, false );
2274 // --------------------------------------------------------------------
2276 void SvxTableController::UpdateTableShape()
2278 SdrObject* pTableObj = mxTableObj.get();
2279 if( pTableObj )
2281 pTableObj->ActionChanged();
2282 pTableObj->BroadcastObjectChange();
2284 updateSelectionOverlay();
2288 // --------------------------------------------------------------------
2290 void SvxTableController::SetAttrToSelectedCells(const SfxItemSet& rAttr, bool bReplaceAll)
2292 if( mxTable.is() )
2294 const bool bUndo = mpModel && mpModel->IsUndoEnabled();
2296 if( bUndo )
2297 mpModel->BegUndo( ImpGetResStr(STR_TABLE_NUMFORMAT) );
2299 CellPos aStart, aEnd;
2300 getSelectedCells( aStart, aEnd );
2302 SfxItemSet aAttr(*rAttr.GetPool(), rAttr.GetRanges());
2303 aAttr.Put(rAttr, sal_True);
2305 const bool bFrame = (rAttr.GetItemState( SDRATTR_TABLE_BORDER ) == SFX_ITEM_SET) || (rAttr.GetItemState( SDRATTR_TABLE_BORDER_INNER ) == SFX_ITEM_SET);
2307 if( bFrame )
2309 aAttr.ClearItem( SDRATTR_TABLE_BORDER );
2310 aAttr.ClearItem( SDRATTR_TABLE_BORDER_INNER );
2313 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
2315 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
2317 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
2318 if( xCell.is() )
2320 if( bUndo )
2321 xCell->AddUndo();
2322 xCell->SetMergedItemSetAndBroadcast(aAttr, bReplaceAll);
2327 if( bFrame )
2329 ApplyBorderAttr( rAttr );
2332 UpdateTableShape();
2334 if( bUndo )
2335 mpModel->EndUndo();
2340 // --------------------------------------------------------------------
2342 bool SvxTableController::GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const
2344 if( mxTableObj.is() && hasSelectedCells() )
2346 MergeAttrFromSelectedCells( rTargetSet, bOnlyHardAttr );
2348 if( mpView->IsTextEdit() )
2350 if( mxTableObj->GetOutlinerParaObject() )
2351 rTargetSet.Put( SvxScriptTypeItem( mxTableObj->GetOutlinerParaObject()->GetTextObject().GetScriptType() ) );
2353 OutlinerView* pTextEditOutlinerView = mpView->GetTextEditOutlinerView();
2354 if(pTextEditOutlinerView)
2356 // FALSE= InvalidItems nicht al Default, sondern als "Loecher" betrachten
2357 rTargetSet.Put(pTextEditOutlinerView->GetAttribs(), sal_False);
2358 rTargetSet.Put( SvxScriptTypeItem( pTextEditOutlinerView->GetSelectedScriptType() ) );
2362 return true;
2364 else
2366 return false;
2370 // --------------------------------------------------------------------
2372 bool SvxTableController::SetAttributes(const SfxItemSet& rSet, bool bReplaceAll)
2374 if( mbCellSelectionMode || mpView->IsTextEdit() )
2376 SetAttrToSelectedCells( rSet, bReplaceAll );
2377 return true;
2379 return false;
2382 // --------------------------------------------------------------------
2384 bool SvxTableController::GetMarkedObjModel( SdrPage* pNewPage )
2386 if( mxTableObj.is() && mbCellSelectionMode && pNewPage ) try
2388 ::sdr::table::SdrTableObj& rTableObj = *static_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() );
2390 CellPos aStart, aEnd;
2391 getSelectedCells( aStart, aEnd );
2393 SdrTableObj* pNewTableObj = rTableObj.CloneRange( aStart, aEnd );
2395 pNewTableObj->SetPage( pNewPage );
2396 pNewTableObj->SetModel( pNewPage->GetModel() );
2398 SdrInsertReason aReason(SDRREASON_VIEWCALL);
2399 pNewPage->InsertObject(pNewTableObj,CONTAINER_APPEND,&aReason);
2401 return true;
2403 catch( Exception& )
2405 OSL_FAIL( "svx::SvxTableController::GetMarkedObjModel(), exception caught!" );
2407 return false;
2410 // --------------------------------------------------------------------
2412 bool SvxTableController::PasteObjModel( const SdrModel& rModel )
2414 if( mxTableObj.is() && mpView && (rModel.GetPageCount() >= 1) )
2416 const SdrPage* pPastePage = rModel.GetPage(0);
2417 if( pPastePage && pPastePage->GetObjCount() == 1 )
2419 SdrTableObj* pPasteTableObj = dynamic_cast< SdrTableObj* >( pPastePage->GetObj(0) );
2420 if( pPasteTableObj )
2422 return PasteObject( pPasteTableObj );
2427 return false;
2430 // --------------------------------------------------------------------
2432 bool SvxTableController::PasteObject( SdrTableObj* pPasteTableObj )
2434 if( !pPasteTableObj )
2435 return false;
2437 Reference< XTable > xPasteTable( pPasteTableObj->getTable() );
2438 if( !xPasteTable.is() )
2439 return false;
2441 if( !mxTable.is() )
2442 return false;
2444 sal_Int32 nPasteColumns = xPasteTable->getColumnCount();
2445 sal_Int32 nPasteRows = xPasteTable->getRowCount();
2447 CellPos aStart, aEnd;
2448 getSelectedCells( aStart, aEnd );
2450 if( mpView->IsTextEdit() )
2451 mpView->SdrEndTextEdit(sal_True);
2453 sal_Int32 nColumns = mxTable->getColumnCount();
2454 sal_Int32 nRows = mxTable->getRowCount();
2456 const sal_Int32 nMissing = nPasteRows - ( nRows - aStart.mnRow );
2457 if( nMissing > 0 )
2459 Reference< XTableRows > xRows( mxTable->getRows() );
2460 xRows->insertByIndex( nRows, nMissing );
2461 nRows = mxTable->getRowCount();
2464 nPasteRows = std::min( nPasteRows, nRows - aStart.mnRow );
2465 nPasteColumns = std::min( nPasteColumns, nColumns - aStart.mnCol );
2467 // copy cell contents
2468 for( sal_Int32 nRow = 0; nRow < nPasteRows; ++nRow )
2470 for( sal_Int32 nCol = 0; nCol < nPasteColumns; ++nCol )
2472 CellRef xTargetCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( aStart.mnCol + nCol, aStart.mnRow + nRow ).get() ) );
2473 if( xTargetCell.is() && !xTargetCell->isMerged() )
2475 xTargetCell->AddUndo();
2476 xTargetCell->cloneFrom( dynamic_cast< Cell* >( xPasteTable->getCellByPosition( nCol, nRow ).get() ) );
2477 nCol += xTargetCell->getColumnSpan() - 1;
2482 UpdateTableShape();
2484 return true;
2487 bool SvxTableController::TakeFormatPaintBrush( boost::shared_ptr< SfxItemSet >& /*rFormatSet*/ )
2489 // SdrView::TakeFormatPaintBrush() is enough
2490 return false;
2493 bool SvxTableController::ApplyFormatPaintBrush( SfxItemSet& rFormatSet, bool bNoCharacterFormats, bool bNoParagraphFormats )
2495 if( mbCellSelectionMode )
2497 SdrTextObj* pTableObj = dynamic_cast<SdrTextObj*>( mxTableObj.get() );
2498 if( !pTableObj )
2499 return false;
2501 const bool bUndo = mpModel && mpModel->IsUndoEnabled();
2503 if( bUndo )
2504 mpModel->BegUndo( ImpGetResStr(STR_TABLE_NUMFORMAT) );
2506 CellPos aStart, aEnd;
2507 getSelectedCells( aStart, aEnd );
2509 SfxItemSet aAttr(*rFormatSet.GetPool(), rFormatSet.GetRanges());
2510 aAttr.Put(rFormatSet, sal_True);
2512 const bool bFrame = (rFormatSet.GetItemState( SDRATTR_TABLE_BORDER ) == SFX_ITEM_SET) || (rFormatSet.GetItemState( SDRATTR_TABLE_BORDER_INNER ) == SFX_ITEM_SET);
2514 if( bFrame )
2516 aAttr.ClearItem( SDRATTR_TABLE_BORDER );
2517 aAttr.ClearItem( SDRATTR_TABLE_BORDER_INNER );
2520 const sal_uInt16* pRanges = rFormatSet.GetRanges();
2521 bool bTextOnly = true;
2523 while( *pRanges )
2525 if( (*pRanges != EE_PARA_START) && (*pRanges != EE_CHAR_START) )
2527 bTextOnly = false;
2528 break;
2530 pRanges += 2;
2533 const bool bReplaceAll = false;
2534 for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
2536 for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
2538 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
2539 if( xCell.is() )
2541 if( bUndo )
2542 xCell->AddUndo();
2543 if( !bTextOnly )
2544 xCell->SetMergedItemSetAndBroadcast(aAttr, bReplaceAll);
2546 SdrText* pText = static_cast< SdrText* >( xCell.get() );
2547 mpView->ApplyFormatPaintBrushToText( rFormatSet, *pTableObj, pText, bNoCharacterFormats, bNoParagraphFormats );
2552 if( bFrame )
2554 ApplyBorderAttr( rFormatSet );
2557 UpdateTableShape();
2559 if( bUndo )
2560 mpModel->EndUndo();
2562 return true;
2565 return false;
2569 // --------------------------------------------------------------------
2571 IMPL_LINK_NOARG(SvxTableController, UpdateHdl)
2573 mnUpdateEvent = 0;
2575 if( mbCellSelectionMode )
2577 CellPos aStart( maCursorFirstPos );
2578 CellPos aEnd( maCursorLastPos );
2579 checkCell(aStart);
2580 checkCell(aEnd);
2581 if( aStart != maCursorFirstPos || aEnd != maCursorLastPos )
2583 setSelectedCells( aStart, aEnd );
2586 updateSelectionOverlay();
2588 return 0;
2591 namespace
2594 struct LinesState
2596 LinesState(SvxBoxItem& rBoxItem_, SvxBoxInfoItem& rBoxInfoItem_)
2597 : rBoxItem(rBoxItem_)
2598 , rBoxInfoItem(rBoxInfoItem_)
2599 , bDistanceIndeterminate(false)
2601 std::fill_n(aBorderSet, 4, false);
2602 std::fill_n(aInnerLineSet, 2, false);
2603 std::fill_n(aBorderIndeterminate, 4, false);
2604 std::fill_n(aInnerLineIndeterminate, 2, false);
2605 std::fill_n(aDistanceSet, 4, false);
2606 std::fill_n(aDistance, 4, 0);
2609 SvxBoxItem& rBoxItem;
2610 SvxBoxInfoItem& rBoxInfoItem;
2611 bool aBorderSet[4];
2612 bool aInnerLineSet[2];
2613 bool aBorderIndeterminate[4];
2614 bool aInnerLineIndeterminate[2];
2615 bool aDistanceSet[4];
2616 sal_uInt16 aDistance[4];
2617 bool bDistanceIndeterminate;
2620 class BoxItemWrapper
2622 public:
2623 BoxItemWrapper(SvxBoxItem& rBoxItem, SvxBoxInfoItem& rBoxInfoItem, sal_uInt16 nBorderLine, sal_uInt16 nInnerLine, bool bBorder);
2625 const SvxBorderLine* getLine() const;
2626 void setLine(const SvxBorderLine* pLine);
2628 private:
2629 SvxBoxItem& m_rBoxItem;
2630 SvxBoxInfoItem& m_rBoxInfoItem;
2631 const sal_uInt16 m_nLine;
2632 const bool m_bBorder;
2635 BoxItemWrapper::BoxItemWrapper(
2636 SvxBoxItem& rBoxItem, SvxBoxInfoItem& rBoxInfoItem,
2637 const sal_uInt16 nBorderLine, const sal_uInt16 nInnerLine, const bool bBorder)
2638 : m_rBoxItem(rBoxItem)
2639 , m_rBoxInfoItem(rBoxInfoItem)
2640 , m_nLine(bBorder ? nBorderLine : nInnerLine)
2641 , m_bBorder(bBorder)
2643 assert(bBorder ? (m_nLine <= BOX_LINE_RIGHT) : (m_nLine <= BOXINFO_LINE_VERT));
2646 const SvxBorderLine* BoxItemWrapper::getLine() const
2648 if (m_bBorder)
2649 return m_rBoxItem.GetLine(m_nLine);
2650 else
2651 return (m_nLine == BOXINFO_LINE_HORI) ? m_rBoxInfoItem.GetHori() : m_rBoxInfoItem.GetVert();
2654 void BoxItemWrapper::setLine(const SvxBorderLine* pLine)
2656 if (m_bBorder)
2657 m_rBoxItem.SetLine(pLine, m_nLine);
2658 else
2659 m_rBoxInfoItem.SetLine(pLine, m_nLine);
2662 void lcl_MergeBorderLine(
2663 LinesState& rLinesState, const SvxBorderLine* const pLine, const sal_uInt16 nLine,
2664 const sal_uInt8 nValidFlag, const bool bBorder = true)
2666 const sal_uInt16 nInnerLine(bBorder ? 0 : ((nValidFlag & VALID_HORI) ? BOXINFO_LINE_HORI : BOXINFO_LINE_VERT));
2667 BoxItemWrapper aBoxItem(rLinesState.rBoxItem, rLinesState.rBoxInfoItem, nLine, nInnerLine, bBorder);
2668 bool& rbSet(bBorder ? rLinesState.aBorderSet[nLine] : rLinesState.aInnerLineSet[nInnerLine]);
2669 bool& rbIndeterminate(bBorder ? rLinesState.aBorderIndeterminate[nLine] : rLinesState.aInnerLineIndeterminate[nInnerLine]);
2671 if (rbSet)
2673 if (!rbIndeterminate)
2675 const SvxBorderLine* const pMergedLine(aBoxItem.getLine());
2676 if ((pLine && !pMergedLine) || (!pLine && pMergedLine) || (pLine && (*pLine != *pMergedLine)))
2678 aBoxItem.setLine(0);
2679 rbIndeterminate = true;
2683 else
2685 aBoxItem.setLine(pLine);
2686 rbSet = true;
2690 void lcl_MergeBorderOrInnerLine(
2691 LinesState& rLinesState, const SvxBorderLine* const pLine, const sal_uInt16 nLine,
2692 const sal_uInt8 nValidFlag, const bool bBorder)
2694 if (bBorder)
2695 lcl_MergeBorderLine(rLinesState, pLine, nLine, nValidFlag);
2696 else
2698 const bool bVertical = (nLine == BOX_LINE_LEFT) || (nLine == BOX_LINE_RIGHT);
2699 lcl_MergeBorderLine(rLinesState, pLine, nLine, bVertical ? VALID_VERT : VALID_HORI, false);
2703 void lcl_MergeDistance(
2704 LinesState& rLinesState, const sal_uInt16 nIndex, const sal_uInt16 nDistance)
2706 if (rLinesState.aDistanceSet[nIndex])
2708 if (!rLinesState.bDistanceIndeterminate)
2709 rLinesState.bDistanceIndeterminate = nDistance != rLinesState.aDistance[nIndex];
2711 else
2713 rLinesState.aDistance[nIndex] = nDistance;
2714 rLinesState.aDistanceSet[nIndex] = true;
2718 void lcl_MergeCommonBorderAttr(LinesState& rLinesState, const SvxBoxItem& rCellBoxItem, const sal_Int32 nCellFlags)
2720 if( (nCellFlags & (CELL_BEFORE|CELL_AFTER|CELL_UPPER|CELL_LOWER)) != 0 )
2722 // current cell is outside the selection
2724 if( (nCellFlags & ( CELL_BEFORE|CELL_AFTER)) == 0 ) // check if its not nw or ne corner
2726 if( nCellFlags & CELL_UPPER )
2727 lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetBottom(), BOX_LINE_TOP, VALID_TOP);
2728 else if( nCellFlags & CELL_LOWER )
2729 lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetTop(), BOX_LINE_BOTTOM, VALID_BOTTOM);
2731 else if( (nCellFlags & ( CELL_UPPER|CELL_LOWER)) == 0 ) // check if its not sw or se corner
2733 if( nCellFlags & CELL_BEFORE )
2734 lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetRight(), BOX_LINE_LEFT, VALID_LEFT);
2735 else if( nCellFlags & CELL_AFTER )
2736 lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetLeft(), BOX_LINE_RIGHT, VALID_RIGHT);
2739 // NOTE: inner distances for cells outside the selected range
2740 // are not relevant -> we ignore them.
2742 else
2744 // current cell is inside the selection
2746 lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetTop(), BOX_LINE_TOP, VALID_TOP, nCellFlags & CELL_TOP);
2747 lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetBottom(), BOX_LINE_BOTTOM, VALID_BOTTOM, nCellFlags & CELL_BOTTOM);
2748 lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetLeft(), BOX_LINE_LEFT, VALID_LEFT, nCellFlags & CELL_LEFT);
2749 lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetRight(), BOX_LINE_RIGHT, VALID_RIGHT, nCellFlags & CELL_RIGHT);
2751 lcl_MergeDistance(rLinesState, BOX_LINE_TOP, rCellBoxItem.GetDistance(BOX_LINE_TOP));
2752 lcl_MergeDistance(rLinesState, BOX_LINE_BOTTOM, rCellBoxItem.GetDistance(BOX_LINE_BOTTOM));
2753 lcl_MergeDistance(rLinesState, BOX_LINE_LEFT, rCellBoxItem.GetDistance(BOX_LINE_LEFT));
2754 lcl_MergeDistance(rLinesState, BOX_LINE_RIGHT, rCellBoxItem.GetDistance(BOX_LINE_RIGHT));
2760 void SvxTableController::FillCommonBorderAttrFromSelectedCells( SvxBoxItem& rBoxItem, SvxBoxInfoItem& rBoxInfoItem ) const
2762 if( mxTable.is() )
2764 const sal_Int32 nRowCount = mxTable->getRowCount();
2765 const sal_Int32 nColCount = mxTable->getColumnCount();
2766 if( nRowCount && nColCount )
2768 CellPos aStart, aEnd;
2769 const_cast< SvxTableController* >( this )->getSelectedCells( aStart, aEnd );
2771 // We are adding one more row/column around the block of selected cells.
2772 // We will be checking the adjoining border of these too.
2773 const sal_Int32 nLastRow = std::min( aEnd.mnRow + 2, nRowCount );
2774 const sal_Int32 nLastCol = std::min( aEnd.mnCol + 2, nColCount );
2776 rBoxInfoItem.SetValid( sal_uInt8( ~0 ), sal_False );
2777 LinesState aLinesState( rBoxItem, rBoxInfoItem );
2779 /* Here we go through all the selected cells (enhanced by
2780 * the adjoining row/column on each side) and determine the
2781 * lines for presentation. The algorithm is simple:
2782 * 1. if a border or inner line is set in all cells to the
2783 * same value, it will be used.
2784 * 2. if a border or inner line is set only in some cells,
2785 * or it has different values, it will be set to
2786 * indeterminate state (SetValid() on rBoxInfoItem).
2787 * 3. otherwise it will be unset.
2789 for( sal_Int32 nRow = std::max( aStart.mnRow - 1, (sal_Int32)0 ); nRow < nLastRow; nRow++ )
2791 sal_uInt16 nRowFlags = 0;
2792 nRowFlags |= (nRow == aStart.mnRow) ? CELL_TOP : 0;
2793 nRowFlags |= (nRow == aEnd.mnRow) ? CELL_BOTTOM : 0;
2794 nRowFlags |= (nRow < aStart.mnRow) ? CELL_UPPER : 0;
2795 nRowFlags |= (nRow > aEnd.mnRow) ? CELL_LOWER : 0;
2797 for( sal_Int32 nCol = std::max( aStart.mnCol - 1, (sal_Int32)0 ); nCol < nLastCol; nCol++ )
2799 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
2800 if( !xCell.is() )
2801 continue;
2803 sal_uInt16 nCellFlags = nRowFlags;
2804 nCellFlags |= (nCol == aStart.mnCol) ? CELL_LEFT : 0;
2805 nCellFlags |= (nCol == aEnd.mnCol) ? CELL_RIGHT : 0;
2806 nCellFlags |= (nCol < aStart.mnCol) ? CELL_BEFORE : 0;
2807 nCellFlags |= (nCol > aEnd.mnCol) ? CELL_AFTER : 0;
2809 const SfxItemSet& rSet = xCell->GetItemSet();
2810 const SvxBoxItem& rCellBoxItem = static_cast< const SvxBoxItem& >( rSet.Get(SDRATTR_TABLE_BORDER ) );
2811 lcl_MergeCommonBorderAttr( aLinesState, rCellBoxItem, nCellFlags );
2815 if (!aLinesState.aBorderIndeterminate[BOX_LINE_TOP])
2816 aLinesState.rBoxInfoItem.SetValid(VALID_TOP);
2817 if (!aLinesState.aBorderIndeterminate[BOX_LINE_BOTTOM])
2818 aLinesState.rBoxInfoItem.SetValid(VALID_BOTTOM);
2819 if (!aLinesState.aBorderIndeterminate[BOX_LINE_LEFT])
2820 aLinesState.rBoxInfoItem.SetValid(VALID_LEFT);
2821 if (!aLinesState.aBorderIndeterminate[BOX_LINE_RIGHT])
2822 aLinesState.rBoxInfoItem.SetValid(VALID_RIGHT);
2823 if (!aLinesState.aInnerLineIndeterminate[BOXINFO_LINE_HORI])
2824 aLinesState.rBoxInfoItem.SetValid(VALID_HORI);
2825 if (!aLinesState.aInnerLineIndeterminate[BOXINFO_LINE_VERT])
2826 aLinesState.rBoxInfoItem.SetValid(VALID_VERT);
2828 if (!aLinesState.bDistanceIndeterminate)
2830 if (aLinesState.aDistanceSet[BOX_LINE_TOP])
2831 aLinesState.rBoxItem.SetDistance(aLinesState.aDistance[BOX_LINE_TOP], BOX_LINE_TOP);
2832 if (aLinesState.aDistanceSet[BOX_LINE_BOTTOM])
2833 aLinesState.rBoxItem.SetDistance(aLinesState.aDistance[BOX_LINE_BOTTOM], BOX_LINE_BOTTOM);
2834 if (aLinesState.aDistanceSet[BOX_LINE_LEFT])
2835 aLinesState.rBoxItem.SetDistance(aLinesState.aDistance[BOX_LINE_LEFT], BOX_LINE_LEFT);
2836 if (aLinesState.aDistanceSet[BOX_LINE_RIGHT])
2837 aLinesState.rBoxItem.SetDistance(aLinesState.aDistance[BOX_LINE_RIGHT], BOX_LINE_RIGHT);
2838 aLinesState.rBoxInfoItem.SetValid(VALID_DISTANCE);
2846 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */