calc-enhanced-merge-cells-sc.diff

n#213205, i#67243, i#101042
Merging/unmerging of cells on multiple sheets & merge center icon.
This commit is contained in:
Kohei Yoshida 2010-09-16 11:43:15 +02:00 committed by Fridrich Štrba
parent e278e19136
commit ca1582d4eb
13 changed files with 534 additions and 198 deletions

View file

@ -65,6 +65,7 @@
#include "dociter.hxx"
#include "autoform.hxx"
#include "cell.hxx"
#include "cellmergeoption.hxx"
#include "detdata.hxx"
#include "detfunc.hxx"
#include "docpool.hxx"
@ -103,6 +104,7 @@
#include <memory>
#include <basic/basmgr.hxx>
#include <boost/scoped_ptr.hpp>
#include <set>
using namespace com::sun::star;
using ::com::sun::star::uno::Sequence;
@ -1714,7 +1716,11 @@ BOOL ScDocFunc::InsertCells( const ScRange& rRange, const ScMarkData* pTabMark,
default:
break;
}
MergeCells(aRange, FALSE, TRUE, TRUE);
ScCellMergeOption aMergeOption(
aRange.aStart.Col(), aRange.aStart.Row(),
aRange.aEnd.Col(), aRange.aEnd.Row() );
aMergeOption.maTabs.insert(aRange.aStart.Tab());
MergeCells(aMergeOption, FALSE, TRUE, TRUE);
}
qIncreaseRange.pop_back();
}
@ -1763,7 +1769,10 @@ BOOL ScDocFunc::InsertCells( const ScRange& rRange, const ScMarkData* pTabMark,
while( !qIncreaseRange.empty() )
{
ScRange aRange = qIncreaseRange.back();
MergeCells(aRange, FALSE, TRUE, TRUE);
ScCellMergeOption aMergeOption(
aRange.aStart.Col(), aRange.aStart.Row(),
aRange.aEnd.Col(), aRange.aEnd.Row() );
MergeCells(aMergeOption, FALSE, TRUE, TRUE);
qIncreaseRange.pop_back();
}
@ -2201,7 +2210,10 @@ BOOL ScDocFunc::DeleteCells( const ScRange& rRange, const ScMarkData* pTabMark,
if( !pDoc->HasAttrib( aRange, HASATTR_OVERLAPPED | HASATTR_MERGED ) )
{
MergeCells( aRange, FALSE, TRUE, TRUE );
ScCellMergeOption aMergeOption(
aRange.aStart.Col(), aRange.aStart.Row(),
aRange.aEnd.Col(), aRange.aEnd.Row() );
MergeCells( aMergeOption, FALSE, TRUE, TRUE );
}
qDecreaseRange.pop_back();
}
@ -4338,86 +4350,110 @@ BOOL ScDocFunc::FillAuto( ScRange& rRange, const ScMarkData* pTabMark,
//------------------------------------------------------------------------
BOOL ScDocFunc::MergeCells( const ScRange& rRange, BOOL bContents, BOOL bRecord, BOOL bApi )
BOOL ScDocFunc::MergeCells( const ScCellMergeOption& rOption, BOOL bContents, BOOL bRecord, BOOL bApi )
{
using ::std::set;
ScDocShellModificator aModificator( rDocShell );
SCCOL nStartCol = rOption.mnStartCol;
SCROW nStartRow = rOption.mnStartRow;
SCCOL nEndCol = rOption.mnEndCol;
SCROW nEndRow = rOption.mnEndRow;
if ((nStartCol == nEndCol && nStartRow == nEndRow) || rOption.maTabs.empty())
{
// Nothing to do. Bail out quick.
return TRUE;
}
ScDocument* pDoc = rDocShell.GetDocument();
SCCOL nStartCol = rRange.aStart.Col();
SCROW nStartRow = rRange.aStart.Row();
SCCOL nEndCol = rRange.aEnd.Col();
SCROW nEndRow = rRange.aEnd.Row();
SCTAB nTab = rRange.aStart.Tab();
set<SCTAB>::const_iterator itrBeg = rOption.maTabs.begin(), itrEnd = rOption.maTabs.end();
SCTAB nTab1 = *itrBeg, nTab2 = *rOption.maTabs.rbegin();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = FALSE;
ScEditableTester aTester( pDoc, nTab, nStartCol, nStartRow, nEndCol, nEndRow );
if (!aTester.IsEditable())
for (set<SCTAB>::const_iterator itr = itrBeg; itr != itrEnd; ++itr)
{
if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
return FALSE;
}
if ( nStartCol == nEndCol && nStartRow == nEndRow )
{
// nichts zu tun
return TRUE;
}
if ( pDoc->HasAttrib( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab,
HASATTR_MERGED | HASATTR_OVERLAPPED ) )
{
// "Zusammenfassen nicht verschachteln !"
if (!bApi)
rDocShell.ErrorMessage(STR_MSSG_MERGECELLS_0);
return FALSE;
}
BOOL bNeedContents = bContents &&
( !pDoc->IsBlockEmpty( nTab, nStartCol,nStartRow+1, nStartCol,nEndRow, true ) ||
!pDoc->IsBlockEmpty( nTab, nStartCol+1,nStartRow, nEndCol,nEndRow, true ) );
ScDocument* pUndoDoc = 0;
if (bRecord)
{
// test if the range contains other notes which also implies that we need an undo document
bool bHasNotes = false;
for( ScAddress aPos( nStartCol, nStartRow, nTab ); !bHasNotes && (aPos.Col() <= nEndCol); aPos.IncCol() )
for( aPos.SetRow( nStartRow ); !bHasNotes && (aPos.Row() <= nEndRow); aPos.IncRow() )
bHasNotes = ((aPos.Col() != nStartCol) || (aPos.Row() != nStartRow)) && (pDoc->GetNote( aPos ) != 0);
if (bNeedContents || bHasNotes)
ScEditableTester aTester( pDoc, *itr, nStartCol, nStartRow, nEndCol, nEndRow );
if (!aTester.IsEditable())
{
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nTab, nTab );
// note captions are collected by drawing undo
pDoc->CopyToDocument( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab,
IDF_ALL|IDF_NOCAPTIONS, FALSE, pUndoDoc );
if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
return FALSE;
}
if ( pDoc->HasAttrib( nStartCol, nStartRow, *itr, nEndCol, nEndRow, *itr,
HASATTR_MERGED | HASATTR_OVERLAPPED ) )
{
// "Zusammenfassen nicht verschachteln !"
if (!bApi)
rDocShell.ErrorMessage(STR_MSSG_MERGECELLS_0);
return FALSE;
}
if( bHasNotes )
pDoc->BeginDrawUndo();
}
if (bNeedContents)
pDoc->DoMergeContents( nTab, nStartCol,nStartRow, nEndCol,nEndRow );
pDoc->DoMerge( nTab, nStartCol,nStartRow, nEndCol,nEndRow );
if( bRecord )
ScDocument* pUndoDoc = NULL;
bool bNeedContentsUndo = false;
for (set<SCTAB>::const_iterator itr = itrBeg; itr != itrEnd; ++itr)
{
SdrUndoGroup* pDrawUndo = pDoc->GetDrawLayer() ? pDoc->GetDrawLayer()->GetCalcUndo() : 0;
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoMerge( &rDocShell,
nStartCol, nStartRow, nTab,
nEndCol, nEndRow, nTab, bNeedContents, pUndoDoc, pDrawUndo ) );
SCTAB nTab = *itr;
bool bNeedContents = bContents &&
( !pDoc->IsBlockEmpty( nTab, nStartCol,nStartRow+1, nStartCol,nEndRow, true ) ||
!pDoc->IsBlockEmpty( nTab, nStartCol+1,nStartRow, nEndCol,nEndRow, true ) );
if (bRecord)
{
// test if the range contains other notes which also implies that we need an undo document
bool bHasNotes = false;
for( ScAddress aPos( nStartCol, nStartRow, nTab ); !bHasNotes && (aPos.Col() <= nEndCol); aPos.IncCol() )
for( aPos.SetRow( nStartRow ); !bHasNotes && (aPos.Row() <= nEndRow); aPos.IncRow() )
bHasNotes = ((aPos.Col() != nStartCol) || (aPos.Row() != nStartRow)) && (pDoc->GetNote( aPos ) != 0);
if (bNeedContents || bHasNotes || rOption.mbCenter)
{
if (!pUndoDoc)
{
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo(pDoc, nTab1, nTab2);
}
// note captions are collected by drawing undo
pDoc->CopyToDocument( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab,
IDF_ALL|IDF_NOCAPTIONS, FALSE, pUndoDoc );
}
if( bHasNotes )
pDoc->BeginDrawUndo();
}
if (bNeedContents)
pDoc->DoMergeContents( nTab, nStartCol,nStartRow, nEndCol,nEndRow );
pDoc->DoMerge( nTab, nStartCol,nStartRow, nEndCol,nEndRow );
if (rOption.mbCenter)
{
pDoc->ApplyAttr( nStartCol, nStartRow, nTab, SvxHorJustifyItem( SVX_HOR_JUSTIFY_CENTER, ATTR_HOR_JUSTIFY ) );
pDoc->ApplyAttr( nStartCol, nStartRow, nTab, SvxVerJustifyItem( SVX_VER_JUSTIFY_CENTER, ATTR_VER_JUSTIFY ) );
}
if ( !AdjustRowHeight( ScRange( 0,nStartRow,nTab, MAXCOL,nEndRow,nTab ) ) )
rDocShell.PostPaint( nStartCol, nStartRow, nTab,
nEndCol, nEndRow, nTab, PAINT_GRID );
if (bNeedContents || rOption.mbCenter)
{
ScRange aRange(nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab);
pDoc->SetDirty(aRange);
}
bNeedContentsUndo |= bNeedContents;
}
if (pUndoDoc)
{
SdrUndoGroup* pDrawUndo = pDoc->GetDrawLayer() ? pDoc->GetDrawLayer()->GetCalcUndo() : NULL;
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoMerge(&rDocShell, rOption, bNeedContentsUndo, pUndoDoc, pDrawUndo) );
}
if ( !AdjustRowHeight( ScRange( 0,nStartRow,nTab, MAXCOL,nEndRow,nTab ) ) )
rDocShell.PostPaint( nStartCol, nStartRow, nTab,
nEndCol, nEndRow, nTab, PAINT_GRID );
if (bNeedContents)
pDoc->SetDirty( rRange );
aModificator.SetDocumentModified();
SfxBindings* pBindings = rDocShell.GetViewBindings();
@ -4433,49 +4469,81 @@ BOOL ScDocFunc::MergeCells( const ScRange& rRange, BOOL bContents, BOOL bRecord,
BOOL ScDocFunc::UnmergeCells( const ScRange& rRange, BOOL bRecord, BOOL bApi )
{
ScDocShellModificator aModificator( rDocShell );
ScCellMergeOption aOption(rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = rRange.aEnd.Tab();
for (SCTAB i = nTab1; i <= nTab2; ++i)
aOption.maTabs.insert(i);
return UnmergeCells(aOption, bRecord, bApi);
}
bool ScDocFunc::UnmergeCells( const ScCellMergeOption& rOption, BOOL bRecord, BOOL bApi )
{
using ::std::set;
if (rOption.maTabs.empty())
// Nothing to unmerge.
return true;
ScDocShellModificator aModificator( rDocShell );
ScDocument* pDoc = rDocShell.GetDocument();
SCTAB nTab = rRange.aStart.Tab();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = FALSE;
if ( pDoc->HasAttrib( rRange, HASATTR_MERGED ) )
ScDocument* pUndoDoc = NULL;
bool bBeep = false;
for (set<SCTAB>::const_iterator itr = rOption.maTabs.begin(), itrEnd = rOption.maTabs.end();
itr != itrEnd; ++itr)
{
ScRange aExtended = rRange;
pDoc->ExtendMerge( aExtended );
SCTAB nTab = *itr;
ScRange aRange = rOption.getSingleRange(nTab);
if ( !pDoc->HasAttrib(aRange, HASATTR_MERGED) )
{
bBeep = true;
continue;
}
ScRange aExtended = aRange;
pDoc->ExtendMerge(aExtended);
ScRange aRefresh = aExtended;
pDoc->ExtendOverlapped( aRefresh );
pDoc->ExtendOverlapped(aRefresh);
if (bRecord)
{
ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nTab, nTab );
pDoc->CopyToDocument( aExtended, IDF_ATTRIB, FALSE, pUndoDoc );
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoRemoveMerge( &rDocShell, rRange, pUndoDoc ) );
if (!pUndoDoc)
{
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo(pDoc, *rOption.maTabs.begin(), *rOption.maTabs.rbegin());
}
pDoc->CopyToDocument(aExtended, IDF_ATTRIB, FALSE, pUndoDoc);
}
const SfxPoolItem& rDefAttr = pDoc->GetPool()->GetDefaultItem( ATTR_MERGE );
ScPatternAttr aPattern( pDoc->GetPool() );
aPattern.GetItemSet().Put( rDefAttr );
pDoc->ApplyPatternAreaTab( rRange.aStart.Col(), rRange.aStart.Row(),
rRange.aEnd.Col(), rRange.aEnd.Row(), nTab,
aPattern );
pDoc->ApplyPatternAreaTab( aRange.aStart.Col(), aRange.aStart.Row(),
aRange.aEnd.Col(), aRange.aEnd.Row(), nTab,
aPattern );
pDoc->RemoveFlagsTab( aExtended.aStart.Col(), aExtended.aStart.Row(),
aExtended.aEnd.Col(), aExtended.aEnd.Row(), nTab,
SC_MF_HOR | SC_MF_VER );
aExtended.aEnd.Col(), aExtended.aEnd.Row(), nTab,
SC_MF_HOR | SC_MF_VER );
pDoc->ExtendMerge( aRefresh, TRUE, FALSE );
if ( !AdjustRowHeight( aExtended ) )
rDocShell.PostPaint( aExtended, PAINT_GRID );
aModificator.SetDocumentModified();
}
else if (!bApi)
Sound::Beep(); //! FALSE zurueck???
if (bBeep && !bApi)
Sound::Beep();
if (bRecord)
{
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoRemoveMerge( &rDocShell, rOption, pUndoDoc ) );
}
aModificator.SetDocumentModified();
return TRUE;
}

View file

@ -0,0 +1,60 @@
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2010 by Novell, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: docfunc.hxx,v $
* $Revision: 1.18.30.2 $
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
#ifndef SC_CELLMERGEOPTION_HXX
#define SC_CELLMERGEOPTION_HXX
#include "address.hxx"
#include <set>
class ScRange;
struct ScCellMergeOption
{
::std::set<SCTAB> maTabs;
SCCOL mnStartCol;
SCROW mnStartRow;
SCCOL mnEndCol;
SCROW mnEndRow;
bool mbCenter;
explicit ScCellMergeOption();
explicit ScCellMergeOption(SCCOL nStartCol, SCROW nStartRow,
SCCOL nEndCol, SCROW nEndRow,
bool bCenter = false);
explicit ScCellMergeOption(const ScCellMergeOption& r);
ScRange getSingleRange(SCTAB nTab) const;
ScRange getFirstSingleRange() const;
};
#endif

View file

@ -49,13 +49,14 @@ class ScBaseCell;
class ScTokenArray;
struct ScTabOpParam;
class ScTableProtection;
struct ScCellMergeOption;
// ---------------------------------------------------------------------------
class ScDocFunc
{
private:
ScDocShell& rDocShell;
ScDocShell& rDocShell;
BOOL AdjustRowHeight( const ScRange& rRange, BOOL bPaint = TRUE );
void CreateOneName( ScRangeName& rList,
@ -131,9 +132,9 @@ public:
BOOL SetLayoutRTL( SCTAB nTab, BOOL bRTL, BOOL bApi );
//UNUSED2009-05 BOOL SetGrammar( formula::FormulaGrammar::Grammar eGrammar );
//UNUSED2009-05 BOOL SetGrammar( formula::FormulaGrammar::Grammar eGrammar );
SC_DLLPUBLIC BOOL SetWidthOrHeight( BOOL bWidth, SCCOLROW nRangeCnt, SCCOLROW* pRanges,
SC_DLLPUBLIC BOOL SetWidthOrHeight( BOOL bWidth, SCCOLROW nRangeCnt, SCCOLROW* pRanges,
SCTAB nTab, ScSizeMode eMode, USHORT nSizeTwips,
BOOL bRecord, BOOL bApi );
@ -164,7 +165,7 @@ public:
BOOL FillSimple( const ScRange& rRange, const ScMarkData* pTabMark,
FillDir eDir, BOOL bRecord, BOOL bApi );
BOOL FillSeries( const ScRange& rRange, const ScMarkData* pTabMark,
FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd,
FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd,
double fStart, double fStep, double fMax,
BOOL bRecord, BOOL bApi );
// FillAuto: rRange wird von Source-Range auf Dest-Range angepasst
@ -173,9 +174,10 @@ public:
BOOL ResizeMatrix( const ScRange& rOldRange, const ScAddress& rNewEnd, BOOL bApi );
BOOL MergeCells( const ScRange& rRange, BOOL bContents,
BOOL MergeCells( const ScCellMergeOption& rOption, BOOL bContents,
BOOL bRecord, BOOL bApi );
BOOL UnmergeCells( const ScRange& rRange, BOOL bRecord, BOOL bApi );
bool UnmergeCells( const ScCellMergeOption& rOption, BOOL bRecord, BOOL bApi );
BOOL SetNewRangeNames( ScRangeName* pNewRanges, BOOL bApi ); // takes ownership of pNewRanges
BOOL ModifyRangeNames( const ScRangeName& rNewRanges, BOOL bApi );

View file

@ -31,6 +31,7 @@
#include "markdata.hxx"
#include "viewutil.hxx"
#include "spellparam.hxx"
#include "cellmergeoption.hxx"
#include "cell.hxx"
@ -452,10 +453,8 @@ class ScUndoMerge: public ScSimpleUndo
{
public:
TYPEINFO();
ScUndoMerge( ScDocShell* pNewDocShell,
SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
bool bMergeContents, ScDocument* pUndoDoc, SdrUndoAction* pDrawUndo );
ScUndoMerge( ScDocShell* pNewDocShell, const ScCellMergeOption& rOption,
bool bMergeContents, ScDocument* pUndoDoc, SdrUndoAction* pDrawUndo);
virtual ~ScUndoMerge();
virtual void Undo();
@ -466,7 +465,7 @@ public:
virtual String GetComment() const;
private:
ScRange maRange;
ScCellMergeOption maOption;
bool mbMergeContents; // Merge contents in Redo().
ScDocument* mpUndoDoc; // wenn Daten zusammengefasst
SdrUndoAction* mpDrawUndo;
@ -947,7 +946,7 @@ class ScUndoRemoveMerge: public ScBlockUndo
public:
TYPEINFO();
ScUndoRemoveMerge( ScDocShell* pNewDocShell,
const ScRange& rArea,
const ScCellMergeOption& rOption,
ScDocument* pNewUndoDoc );
virtual ~ScUndoRemoveMerge();
@ -959,6 +958,9 @@ public:
virtual String GetComment() const;
private:
void SetCurTab();
ScCellMergeOption maOption;
ScDocument* pUndoDoc;
};

View file

@ -239,7 +239,7 @@ public:
BOOL TestMergeCells();
BOOL TestRemoveMerge();
BOOL MergeCells( BOOL bApi, BOOL& rDoContents, BOOL bRecord = TRUE );
BOOL MergeCells( BOOL bApi, BOOL& rDoContents, BOOL bRecord = TRUE, BOOL bCenter = FALSE );
BOOL RemoveMerge( BOOL bRecord = TRUE );
void FillSimple( FillDir eDir, BOOL bRecord = TRUE );

View file

@ -64,6 +64,7 @@
#include "clipparam.hxx"
#include "sc.hrc"
#include <set>
// STATIC DATA -----------------------------------------------------------
@ -2051,8 +2052,9 @@ BOOL __EXPORT ScUndoRemoveBreaks::CanRepeat(SfxRepeatTarget& rTarget) const
//
ScUndoRemoveMerge::ScUndoRemoveMerge( ScDocShell* pNewDocShell,
const ScRange& rArea, ScDocument* pNewUndoDoc ) :
ScBlockUndo( pNewDocShell, rArea, SC_UNDO_SIMPLE ),
const ScCellMergeOption& rOption, ScDocument* pNewUndoDoc ) :
ScBlockUndo( pNewDocShell, rOption.getFirstSingleRange(), SC_UNDO_SIMPLE ),
maOption(rOption),
pUndoDoc( pNewUndoDoc )
{
}
@ -2069,66 +2071,78 @@ String __EXPORT ScUndoRemoveMerge::GetComment() const
void __EXPORT ScUndoRemoveMerge::Undo()
{
using ::std::set;
SetCurTab();
BeginUndo();
ScDocument* pDoc = pDocShell->GetDocument();
ScRange aExtended = aBlockRange;
pUndoDoc->ExtendMerge( aExtended );
pDoc->DeleteAreaTab( aExtended, IDF_ATTRIB );
pUndoDoc->CopyToDocument( aExtended, IDF_ATTRIB, FALSE, pDoc );
BOOL bDidPaint = FALSE;
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
if ( pViewShell )
ScDocument* pDoc = pDocShell->GetDocument();
for (set<SCTAB>::const_iterator itr = maOption.maTabs.begin(), itrEnd = maOption.maTabs.end();
itr != itrEnd; ++itr)
{
pViewShell->SetTabNo( aExtended.aStart.Tab() );
bDidPaint = pViewShell->AdjustRowHeight( aExtended.aStart.Row(), aExtended.aEnd.Row() );
// There is no need to extend merge area because it's already been extended.
ScRange aRange = maOption.getSingleRange(*itr);
pDoc->DeleteAreaTab(aRange, IDF_ATTRIB);
pUndoDoc->CopyToDocument(aRange, IDF_ATTRIB, FALSE, pDoc);
bool bDidPaint = false;
if ( pViewShell )
{
pViewShell->SetTabNo(*itr);
bDidPaint = pViewShell->AdjustRowHeight(maOption.mnStartRow, maOption.mnEndRow);
}
if (!bDidPaint)
ScUndoUtil::PaintMore(pDocShell, aRange);
}
if (!bDidPaint)
ScUndoUtil::PaintMore( pDocShell, aExtended );
EndUndo();
}
void __EXPORT ScUndoRemoveMerge::Redo()
{
using ::std::set;
SetCurTab();
BeginRedo();
SCTAB nTab = aBlockRange.aStart.Tab();
ScDocument* pDoc = pDocShell->GetDocument();
ScRange aExtended = aBlockRange;
pDoc->ExtendMerge( aExtended );
ScRange aRefresh = aExtended;
pDoc->ExtendOverlapped( aRefresh );
// ausfuehren
const SfxPoolItem& rDefAttr = pDoc->GetPool()->GetDefaultItem( ATTR_MERGE );
ScPatternAttr aPattern( pDoc->GetPool() );
aPattern.GetItemSet().Put( rDefAttr );
pDoc->ApplyPatternAreaTab( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(),
aBlockRange.aEnd.Col(), aBlockRange.aEnd.Row(), nTab,
aPattern );
pDoc->RemoveFlagsTab( aExtended.aStart.Col(), aExtended.aStart.Row(),
aExtended.aEnd.Col(), aExtended.aEnd.Row(), nTab,
SC_MF_HOR | SC_MF_VER );
pDoc->ExtendMerge( aRefresh, TRUE, FALSE );
// Paint
BOOL bDidPaint = FALSE;
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
if ( pViewShell )
for (set<SCTAB>::const_iterator itr = maOption.maTabs.begin(), itrEnd = maOption.maTabs.end();
itr != itrEnd; ++itr)
{
pViewShell->SetTabNo( aExtended.aStart.Tab() );
bDidPaint = pViewShell->AdjustRowHeight( aExtended.aStart.Row(), aExtended.aEnd.Row() );
SCTAB nTab = *itr;
// There is no need to extend merge area because it's already been extended.
ScRange aRange = maOption.getSingleRange(nTab);
// ausfuehren
const SfxPoolItem& rDefAttr = pDoc->GetPool()->GetDefaultItem( ATTR_MERGE );
ScPatternAttr aPattern( pDoc->GetPool() );
aPattern.GetItemSet().Put( rDefAttr );
pDoc->ApplyPatternAreaTab( maOption.mnStartCol, maOption.mnStartRow,
maOption.mnEndCol, maOption.mnEndRow, nTab,
aPattern );
pDoc->RemoveFlagsTab( maOption.mnStartCol, maOption.mnStartRow,
maOption.mnEndCol, maOption.mnEndRow, nTab,
SC_MF_HOR | SC_MF_VER );
pDoc->ExtendMerge(aRange, TRUE, FALSE);
// Paint
BOOL bDidPaint = FALSE;
if ( pViewShell )
{
pViewShell->SetTabNo(nTab);
bDidPaint = pViewShell->AdjustRowHeight(maOption.mnStartRow, maOption.mnEndRow);
}
if (!bDidPaint)
ScUndoUtil::PaintMore(pDocShell, aRange);
}
if (!bDidPaint)
ScUndoUtil::PaintMore( pDocShell, aExtended );
EndRedo();
}
@ -2144,6 +2158,13 @@ BOOL __EXPORT ScUndoRemoveMerge::CanRepeat(SfxRepeatTarget& rTarget) const
return (rTarget.ISA(ScTabViewTarget));
}
void ScUndoRemoveMerge::SetCurTab()
{
SCTAB nCurTab = pDocShell->GetCurTab();
aBlockRange.aStart.SetTab(nCurTab);
aBlockRange.aEnd.SetTab(nCurTab);
}
// -----------------------------------------------------------------------
//
// nur Umrandung setzen, per ScRangeList (StarOne)

View file

@ -31,6 +31,7 @@
// INCLUDE -------------------------------------------------------------------
#include "scitems.hxx"
#include <svx/algitem.hxx>
#include <editeng/boxitem.hxx>
#include <svl/srchitem.hxx>
#include <sfx2/linkmgr.hxx>
@ -798,14 +799,12 @@ BOOL __EXPORT ScUndoAutoFill::CanRepeat(SfxRepeatTarget& rTarget) const
//----------------------------------------------------------------------------
ScUndoMerge::ScUndoMerge( ScDocShell* pNewDocShell,
SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
bool bMergeContents, ScDocument* pUndoDoc, SdrUndoAction* pDrawUndo )
ScUndoMerge::ScUndoMerge( ScDocShell* pNewDocShell, const ScCellMergeOption& rOption,
bool bMergeContents, ScDocument* pUndoDoc, SdrUndoAction* pDrawUndo )
//
: ScSimpleUndo( pNewDocShell ),
//
maRange( nStartX, nStartY, nStartZ, nEndX, nEndY, nEndZ ),
maOption(rOption),
mbMergeContents( bMergeContents ),
mpUndoDoc( pUndoDoc ),
mpDrawUndo( pDrawUndo )
@ -834,51 +833,77 @@ String ScUndoMerge::GetComment() const
void ScUndoMerge::DoChange( bool bUndo ) const
{
using ::std::set;
if (maOption.maTabs.empty())
// Nothing to do.
return;
ScDocument* pDoc = pDocShell->GetDocument();
ScUndoUtil::MarkSimpleBlock( pDocShell, maRange );
if (bUndo)
// remove merge (contents are copied back below from undo document)
pDoc->RemoveMerge( maRange.aStart.Col(), maRange.aStart.Row(), maRange.aStart.Tab() );
else
// repeat merge, but do not remove note captions (will be done by drawing redo below)
/*!*/ pDoc->DoMerge( maRange.aStart.Tab(),
maRange.aStart.Col(), maRange.aStart.Row(),
maRange.aEnd.Col(), maRange.aEnd.Row(), false );
// undo -> copy back deleted contents
if (bUndo && mpUndoDoc)
{
pDoc->DeleteAreaTab( maRange, IDF_CONTENTS|IDF_NOCAPTIONS );
mpUndoDoc->CopyToDocument( maRange, IDF_ALL|IDF_NOCAPTIONS, FALSE, pDoc );
}
// redo -> merge contents again
else if (!bUndo && mbMergeContents)
{
/*!*/ pDoc->DoMergeContents( maRange.aStart.Tab(),
maRange.aStart.Col(), maRange.aStart.Row(),
maRange.aEnd.Col(), maRange.aEnd.Row() );
}
if (bUndo)
DoSdrUndoAction( mpDrawUndo, pDoc );
else
RedoSdrUndoAction( mpDrawUndo );
BOOL bDidPaint = FALSE;
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
if ( pViewShell )
ScRange aCurRange = maOption.getSingleRange(pDocShell->GetCurTab());
ScUndoUtil::MarkSimpleBlock(pDocShell, aCurRange);
for (set<SCTAB>::const_iterator itr = maOption.maTabs.begin(), itrEnd = maOption.maTabs.end();
itr != itrEnd; ++itr)
{
pViewShell->SetTabNo( maRange.aStart.Tab() );
bDidPaint = pViewShell->AdjustRowHeight( maRange.aStart.Row(), maRange.aEnd.Row() );
SCTAB nTab = *itr;
ScRange aRange = maOption.getSingleRange(nTab);
if (bUndo)
// remove merge (contents are copied back below from undo document)
pDoc->RemoveMerge( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aStart.Tab() );
else
{
// repeat merge, but do not remove note captions (will be done by drawing redo below)
pDoc->DoMerge( aRange.aStart.Tab(),
aRange.aStart.Col(), aRange.aStart.Row(),
aRange.aEnd.Col(), aRange.aEnd.Row(), false );
if (maOption.mbCenter)
{
pDoc->ApplyAttr( aRange.aStart.Col(), aRange.aStart.Row(),
aRange.aStart.Tab(),
SvxHorJustifyItem( SVX_HOR_JUSTIFY_CENTER, ATTR_HOR_JUSTIFY ) );
pDoc->ApplyAttr( aRange.aStart.Col(), aRange.aStart.Row(),
aRange.aStart.Tab(),
SvxVerJustifyItem( SVX_VER_JUSTIFY_CENTER, ATTR_VER_JUSTIFY ) );
}
}
// undo -> copy back deleted contents
if (bUndo && mpUndoDoc)
{
pDoc->DeleteAreaTab( aRange, IDF_CONTENTS|IDF_NOCAPTIONS );
mpUndoDoc->CopyToDocument( aRange, IDF_ALL|IDF_NOCAPTIONS, FALSE, pDoc );
}
// redo -> merge contents again
else if (!bUndo && mbMergeContents)
{
pDoc->DoMergeContents( aRange.aStart.Tab(),
aRange.aStart.Col(), aRange.aStart.Row(),
aRange.aEnd.Col(), aRange.aEnd.Row() );
}
if (bUndo)
DoSdrUndoAction( mpDrawUndo, pDoc );
else
RedoSdrUndoAction( mpDrawUndo );
bool bDidPaint = false;
if ( pViewShell )
{
pViewShell->SetTabNo(nTab);
bDidPaint = pViewShell->AdjustRowHeight(maOption.mnStartRow, maOption.mnEndRow);
}
if (!bDidPaint)
ScUndoUtil::PaintMore(pDocShell, aRange);
}
if (!bDidPaint)
ScUndoUtil::PaintMore( pDocShell, maRange );
ShowTable( maRange );
ShowTable(aCurRange);
}

View file

@ -68,6 +68,7 @@
#include <com/sun/star/text/WritingMode2.hpp>
#include "autoform.hxx"
#include "cellmergeoption.hxx"
#include "cellsuno.hxx"
#include "cursuno.hxx"
#include "textuno.hxx"
@ -5342,10 +5343,14 @@ void SAL_CALL ScCellRangeObj::merge( sal_Bool bMerge ) throw(uno::RuntimeExcepti
if ( pDocSh )
{
ScDocFunc aFunc(*pDocSh);
ScCellMergeOption aMergeOption(
aRange.aStart.Col(), aRange.aStart.Row(),
aRange.aEnd.Col(), aRange.aEnd.Row(), false);
aMergeOption.maTabs.insert(aRange.aStart.Tab());
if ( bMerge )
aFunc.MergeCells( aRange, FALSE, TRUE, TRUE );
aFunc.MergeCells( aMergeOption, FALSE, TRUE, TRUE );
else
aFunc.UnmergeCells( aRange, TRUE, TRUE );
aFunc.UnmergeCells( aMergeOption, TRUE, TRUE );
//! Fehler abfangen?
}

View file

@ -0,0 +1,74 @@
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2010 by Novell, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: docfunc.hxx,v $
* $Revision: 1.18.30.2 $
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
#include "cellmergeoption.hxx"
#include "address.hxx"
ScCellMergeOption::ScCellMergeOption() :
mnStartCol(0),
mnStartRow(0),
mnEndCol(0),
mnEndRow(0),
mbCenter(false)
{
}
ScCellMergeOption::ScCellMergeOption(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, bool bCenter) :
mnStartCol(nStartCol),
mnStartRow(nStartRow),
mnEndCol(nEndCol),
mnEndRow(nEndRow),
mbCenter(bCenter)
{
}
ScCellMergeOption::ScCellMergeOption(const ScCellMergeOption& r) :
maTabs(r.maTabs),
mnStartCol(r.mnStartCol),
mnStartRow(r.mnStartRow),
mnEndCol(r.mnEndCol),
mnEndRow(r.mnEndRow),
mbCenter(r.mbCenter)
{
}
ScRange ScCellMergeOption::getSingleRange(SCTAB nTab) const
{
return ScRange(mnStartCol, mnStartRow, nTab, mnEndCol, mnEndRow, nTab);
}
ScRange ScCellMergeOption::getFirstSingleRange() const
{
SCTAB nTab = 0;
if (!maTabs.empty())
nTab = *maTabs.begin();
return getSingleRange(nTab);
}

View file

@ -769,6 +769,7 @@ void ScCellShell::Execute( SfxRequest& rReq )
{
// test whether to merge or to split
bool bMerge = false;
BOOL bCenter = FALSE;
switch( nSlot )
{
case FID_MERGE_ON:
@ -779,6 +780,7 @@ void ScCellShell::Execute( SfxRequest& rReq )
break;
case FID_MERGE_TOGGLE:
{
bCenter = TRUE;
SfxPoolItem* pItem = 0;
if( rBindings.QueryState( nSlot, pItem ) >= SFX_ITEM_DEFAULT )
bMerge = !static_cast< SfxBoolItem* >( pItem )->GetValue();
@ -799,7 +801,7 @@ void ScCellShell::Execute( SfxRequest& rReq )
bMoveContents = ((const SfxBoolItem*)pItem)->GetValue();
}
if (pTabViewShell->MergeCells( bApi, bMoveContents ))
if (pTabViewShell->MergeCells( bApi, bMoveContents, TRUE, bCenter ))
{
if (!bApi && bMoveContents) // "ja" im Dialog geklickt
rReq.AppendItem( SfxBoolItem( nSlot, bMoveContents ) );

View file

@ -96,6 +96,7 @@ SLOFILES = \
$(SLO)$/output3.obj \
$(SLO)$/gridmerg.obj \
$(SLO)$/invmerge.obj \
$(SLO)$/cellmergeoption.obj \
$(SLO)$/select.obj \
$(SLO)$/olinewin.obj \
$(SLO)$/hintwin.obj \

View file

@ -60,6 +60,7 @@
#include "attrib.hxx"
#include "autoform.hxx"
#include "cell.hxx" // EnterAutoSum
#include "cellmergeoption.hxx"
#include "compiler.hxx"
#include "docfunc.hxx"
#include "docpool.hxx"
@ -1085,7 +1086,7 @@ BOOL ScViewFunc::TestMergeCells() // Vorab-Test (fuer Menue)
//----------------------------------------------------------------------------
BOOL ScViewFunc::MergeCells( BOOL bApi, BOOL& rDoContents, BOOL bRecord )
BOOL ScViewFunc::MergeCells( BOOL bApi, BOOL& rDoContents, BOOL bRecord, BOOL bCenter )
{
// Editable- und Verschachtelungs-Abfrage muss vorneweg sein (auch in DocFunc),
// damit dann nicht die Inhalte-QueryBox kommt
@ -1128,10 +1129,26 @@ BOOL ScViewFunc::MergeCells( BOOL bApi, BOOL& rDoContents, BOOL bRecord )
return FALSE;
}
// Check for the contents of all selected tables.
bool bAskDialog = false;
SCTAB nTabCount = pDoc->GetTableCount();
ScCellMergeOption aMergeOption(nStartCol, nStartRow, nEndCol, nEndRow, bCenter);
for (SCTAB i = 0; i < nTabCount; ++i)
{
if (!rMark.GetTableSelect(i))
// this table is not selected.
continue;
aMergeOption.maTabs.insert(i);
if (!pDoc->IsBlockEmpty(i, nStartCol, nStartRow+1, nStartCol, nEndRow) ||
!pDoc->IsBlockEmpty(i, nStartCol+1, nStartRow, nEndCol, nEndRow))
bAskDialog = true;
}
BOOL bOk = TRUE;
if ( !pDoc->IsBlockEmpty( nStartTab, nStartCol,nStartRow+1, nStartCol,nEndRow, true ) ||
!pDoc->IsBlockEmpty( nStartTab, nStartCol+1,nStartRow, nEndCol,nEndRow, true ) )
if (bAskDialog)
{
if (!bApi)
{
@ -1151,7 +1168,7 @@ BOOL ScViewFunc::MergeCells( BOOL bApi, BOOL& rDoContents, BOOL bRecord )
if (bOk)
{
HideCursor();
bOk = pDocSh->GetDocFunc().MergeCells( aMarkRange, rDoContents, bRecord, bApi );
bOk = pDocSh->GetDocFunc().MergeCells( aMergeOption, rDoContents, bRecord, bApi );
ShowCursor();
if (bOk)
@ -1187,6 +1204,32 @@ BOOL ScViewFunc::TestRemoveMerge()
//----------------------------------------------------------------------------
static bool lcl_extendMergeRange(ScCellMergeOption& rOption, const ScRange& rRange)
{
bool bExtended = false;
if (rOption.mnStartCol > rRange.aStart.Col())
{
rOption.mnStartCol = rRange.aStart.Col();
bExtended = true;
}
if (rOption.mnStartRow > rRange.aStart.Row())
{
rOption.mnStartRow = rRange.aStart.Row();
bExtended = true;
}
if (rOption.mnEndCol < rRange.aEnd.Col())
{
rOption.mnEndCol = rRange.aEnd.Col();
bExtended = true;
}
if (rOption.mnEndRow < rRange.aEnd.Row())
{
rOption.mnEndRow = rRange.aEnd.Row();
bExtended = true;
}
return bExtended;
}
BOOL ScViewFunc::RemoveMerge( BOOL bRecord )
{
ScRange aRange;
@ -1198,12 +1241,39 @@ BOOL ScViewFunc::RemoveMerge( BOOL bRecord )
}
else if (GetViewData()->GetSimpleArea( aRange ) == SC_MARK_SIMPLE)
{
ScDocument* pDoc = GetViewData()->GetDocument();
ScRange aExtended( aRange );
GetViewData()->GetDocument()->ExtendMerge( aExtended );
pDoc->ExtendMerge( aExtended );
ScDocShell* pDocSh = GetViewData()->GetDocShell();
const ScMarkData& rMark = GetViewData()->GetMarkData();
SCTAB nTabCount = pDoc->GetTableCount();
ScCellMergeOption aOption(aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row());
bool bExtended = false;
do
{
bExtended = false;
for (SCTAB i = 0; i < nTabCount; ++i)
{
if (!rMark.GetTableSelect(i))
// This table is not selected.
continue;
aOption.maTabs.insert(i);
aExtended.aStart.SetTab(i);
aExtended.aEnd.SetTab(i);
pDoc->ExtendMerge(aExtended);
pDoc->ExtendOverlapped(aExtended);
// Expand the current range to be inclusive of all merged
// areas on all sheets.
bExtended = lcl_extendMergeRange(aOption, aExtended);
}
}
while (bExtended);
HideCursor();
BOOL bOk = pDocSh->GetDocFunc().UnmergeCells( aRange, bRecord, FALSE );
BOOL bOk = pDocSh->GetDocFunc().UnmergeCells(aOption, bRecord, FALSE );
aExtended = aOption.getFirstSingleRange();
MarkRange( aExtended );
ShowCursor();

View file

@ -220,7 +220,13 @@
<menu:menuitem menu:id=".uno:SetTabBgColor"/>
</menu:menupopup>
</menu:menu>
<menu:menuitem menu:id=".uno:ToggleMergeCells"/>
<menu:menu menu:id=".uno:MergeCellsMenu">
<menu:menupopup>
<menu:menuitem menu:id=".uno:ToggleMergeCells"/>
<menu:menuitem menu:id=".uno:MergeCells"/>
<menu:menuitem menu:id=".uno:SplitCell"/>
</menu:menupopup>
</menu:menu>
<menu:menuseparator/>
<menu:menuitem menu:id=".uno:PageFormatDialog"/>
<menu:menu menu:id=".uno:PrintRangesMenu">