diff options
Diffstat (limited to 'sc/source/core/data/markdata.cxx')
-rw-r--r-- | sc/source/core/data/markdata.cxx | 608 |
1 files changed, 608 insertions, 0 deletions
diff --git a/sc/source/core/data/markdata.cxx b/sc/source/core/data/markdata.cxx new file mode 100644 index 000000000000..4401ac19d199 --- /dev/null +++ b/sc/source/core/data/markdata.cxx @@ -0,0 +1,608 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +// INCLUDE --------------------------------------------------------------- + +#include <tools/debug.hxx> + +#include "markdata.hxx" +#include "markarr.hxx" +#include "rangelst.hxx" + +// STATIC DATA ----------------------------------------------------------- + +//------------------------------------------------------------------------ + +ScMarkData::ScMarkData() : + pMultiSel( NULL ) +{ + for (SCTAB i=0; i<=MAXTAB; i++) + bTabMarked[i] = FALSE; + + ResetMark(); +} + +ScMarkData::ScMarkData(const ScMarkData& rData) : + aMarkRange( rData.aMarkRange ), + aMultiRange( rData.aMultiRange ), + pMultiSel( NULL ) +{ + bMarked = rData.bMarked; + bMultiMarked = rData.bMultiMarked; + bMarking = rData.bMarking; + bMarkIsNeg = rData.bMarkIsNeg; + + for (SCTAB i=0; i<=MAXTAB; i++) + bTabMarked[i] = rData.bTabMarked[i]; + + if (rData.pMultiSel) + { + pMultiSel = new ScMarkArray[MAXCOLCOUNT]; + for (SCCOL j=0; j<MAXCOLCOUNT; j++) + rData.pMultiSel[j].CopyMarksTo( pMultiSel[j] ); + } +} + +ScMarkData& ScMarkData::operator=(const ScMarkData& rData) +{ + if ( &rData == this ) + return *this; + + delete[] pMultiSel; + pMultiSel = NULL; + + aMarkRange = rData.aMarkRange; + aMultiRange = rData.aMultiRange; + bMarked = rData.bMarked; + bMultiMarked = rData.bMultiMarked; + bMarking = rData.bMarking; + bMarkIsNeg = rData.bMarkIsNeg; + + for (SCTAB i=0; i<=MAXTAB; i++) + bTabMarked[i] = rData.bTabMarked[i]; + + if (rData.pMultiSel) + { + pMultiSel = new ScMarkArray[MAXCOLCOUNT]; + for (SCCOL j=0; j<MAXCOLCOUNT; j++) + rData.pMultiSel[j].CopyMarksTo( pMultiSel[j] ); + } + + return *this; +} + +ScMarkData::~ScMarkData() +{ + delete[] pMultiSel; +} + +void ScMarkData::ResetMark() +{ + delete[] pMultiSel; + pMultiSel = NULL; + + bMarked = bMultiMarked = FALSE; + bMarking = bMarkIsNeg = FALSE; +} + +void ScMarkData::SetMarkArea( const ScRange& rRange ) +{ + aMarkRange = rRange; + aMarkRange.Justify(); + if ( !bMarked ) + { + // #77987# Upon creation of a document ScFormatShell GetTextAttrState + // may query (default) attributes although no sheet is marked yet. + // => mark that one. + if ( !GetSelectCount() ) + bTabMarked[ aMarkRange.aStart.Tab() ] = TRUE; + bMarked = TRUE; + } +} + +void ScMarkData::GetMarkArea( ScRange& rRange ) const +{ + rRange = aMarkRange; //! inline ? +} + +void ScMarkData::GetMultiMarkArea( ScRange& rRange ) const +{ + rRange = aMultiRange; +} + +void ScMarkData::SetMultiMarkArea( const ScRange& rRange, BOOL bMark ) +{ + if (!pMultiSel) + { + pMultiSel = new ScMarkArray[MAXCOL+1]; + + // if simple mark range is set, copy to multi marks + if ( bMarked && !bMarkIsNeg ) + { + bMarked = FALSE; + SetMultiMarkArea( aMarkRange, TRUE ); + } + } + + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + PutInOrder( nStartRow, nEndRow ); + PutInOrder( nStartCol, nEndCol ); + + SCCOL nCol; + for (nCol=nStartCol; nCol<=nEndCol; nCol++) + pMultiSel[nCol].SetMarkArea( nStartRow, nEndRow, bMark ); + + if ( bMultiMarked ) // aMultiRange updaten + { + if ( nStartCol < aMultiRange.aStart.Col() ) + aMultiRange.aStart.SetCol( nStartCol ); + if ( nStartRow < aMultiRange.aStart.Row() ) + aMultiRange.aStart.SetRow( nStartRow ); + if ( nEndCol > aMultiRange.aEnd.Col() ) + aMultiRange.aEnd.SetCol( nEndCol ); + if ( nEndRow > aMultiRange.aEnd.Row() ) + aMultiRange.aEnd.SetRow( nEndRow ); + } + else + { + aMultiRange = rRange; // neu + bMultiMarked = TRUE; + } +} + +void ScMarkData::SetAreaTab( SCTAB nTab ) +{ + aMarkRange.aStart.SetTab(nTab); + aMarkRange.aEnd.SetTab(nTab); + aMultiRange.aStart.SetTab(nTab); + aMultiRange.aEnd.SetTab(nTab); +} + +void ScMarkData::SelectOneTable( SCTAB nTab ) +{ + for (SCTAB i=0; i<=MAXTAB; i++) + bTabMarked[i] = ( nTab == i ); +} + +SCTAB ScMarkData::GetSelectCount() const +{ + SCTAB nCount = 0; + for (SCTAB i=0; i<=MAXTAB; i++) + if (bTabMarked[i]) + ++nCount; + + return nCount; +} + +SCTAB ScMarkData::GetFirstSelected() const +{ + for (SCTAB i=0; i<=MAXTAB; i++) + if (bTabMarked[i]) + return i; + + DBG_ERROR("GetFirstSelected: keine markiert"); + return 0; +} + +void ScMarkData::MarkToMulti() +{ + if ( bMarked && !bMarking ) + { + SetMultiMarkArea( aMarkRange, !bMarkIsNeg ); + bMarked = FALSE; + + // check if all multi mark ranges have been removed + if ( bMarkIsNeg && !HasAnyMultiMarks() ) + ResetMark(); + } +} + +void ScMarkData::MarkToSimple() +{ + if ( bMarking ) + return; + + if ( bMultiMarked && bMarked ) + MarkToMulti(); // may result in bMarked and bMultiMarked reset + + if ( bMultiMarked ) + { + DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0"); + + ScRange aNew = aMultiRange; + + BOOL bOk = FALSE; + SCCOL nStartCol = aNew.aStart.Col(); + SCCOL nEndCol = aNew.aEnd.Col(); + + while ( nStartCol < nEndCol && !pMultiSel[nStartCol].HasMarks() ) + ++nStartCol; + while ( nStartCol < nEndCol && !pMultiSel[nEndCol].HasMarks() ) + --nEndCol; + + // Zeilen werden nur aus MarkArray genommen + SCROW nStartRow, nEndRow; + if ( pMultiSel[nStartCol].HasOneMark( nStartRow, nEndRow ) ) + { + bOk = TRUE; + SCROW nCmpStart, nCmpEnd; + for (SCCOL nCol=nStartCol+1; nCol<=nEndCol && bOk; nCol++) + if ( !pMultiSel[nCol].HasOneMark( nCmpStart, nCmpEnd ) + || nCmpStart != nStartRow || nCmpEnd != nEndRow ) + bOk = FALSE; + } + + if (bOk) + { + aNew.aStart.SetCol(nStartCol); + aNew.aStart.SetRow(nStartRow); + aNew.aEnd.SetCol(nEndCol); + aNew.aEnd.SetRow(nEndRow); + + ResetMark(); + aMarkRange = aNew; + bMarked = TRUE; + bMarkIsNeg = FALSE; + } + } +} + +BOOL ScMarkData::IsCellMarked( SCCOL nCol, SCROW nRow, BOOL bNoSimple ) const +{ + if ( bMarked && !bNoSimple && !bMarkIsNeg ) + if ( aMarkRange.aStart.Col() <= nCol && aMarkRange.aEnd.Col() >= nCol && + aMarkRange.aStart.Row() <= nRow && aMarkRange.aEnd.Row() >= nRow ) + return TRUE; + + if (bMultiMarked) + { + //! hier auf negative Markierung testen ? + + DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0"); + return pMultiSel[nCol].GetMark( nRow ); + } + + return FALSE; +} + +BOOL ScMarkData::IsColumnMarked( SCCOL nCol ) const +{ + // bMarkIsNeg inzwischen auch fuer Spaltenkoepfe + //! GetMarkColumnRanges fuer komplett markierte Spalten + + if ( bMarked && !bMarkIsNeg && + aMarkRange.aStart.Col() <= nCol && aMarkRange.aEnd.Col() >= nCol && + aMarkRange.aStart.Row() == 0 && aMarkRange.aEnd.Row() == MAXROW ) + return TRUE; + + if ( bMultiMarked && pMultiSel[nCol].IsAllMarked(0,MAXROW) ) + return TRUE; + + return FALSE; +} + +BOOL ScMarkData::IsRowMarked( SCROW nRow ) const +{ + // bMarkIsNeg inzwischen auch fuer Zeilenkoepfe + //! GetMarkRowRanges fuer komplett markierte Zeilen + + if ( bMarked && !bMarkIsNeg && + aMarkRange.aStart.Col() == 0 && aMarkRange.aEnd.Col() == MAXCOL && + aMarkRange.aStart.Row() <= nRow && aMarkRange.aEnd.Row() >= nRow ) + return TRUE; + + if ( bMultiMarked ) + { + DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0"); + for (SCCOL nCol=0; nCol<=MAXCOL; nCol++) + if (!pMultiSel[nCol].GetMark(nRow)) + return FALSE; + return TRUE; + } + + return FALSE; +} + +void ScMarkData::MarkFromRangeList( const ScRangeList& rList, BOOL bReset ) +{ + if (bReset) + { + for (SCTAB i=0; i<=MAXTAB; i++) + bTabMarked[i] = FALSE; // Tabellen sind nicht in ResetMark + ResetMark(); + } + + ULONG nCount = rList.Count(); + if ( nCount == 1 && !bMarked && !bMultiMarked ) + { + ScRange aRange = *rList.GetObject(0); + SetMarkArea( aRange ); + SelectTable( aRange.aStart.Tab(), TRUE ); + } + else + { + for (ULONG i=0; i<nCount; i++) + { + ScRange aRange = *rList.GetObject(i); + SetMultiMarkArea( aRange, TRUE ); + SelectTable( aRange.aStart.Tab(), TRUE ); + } + } +} + +void ScMarkData::FillRangeListWithMarks( ScRangeList* pList, BOOL bClear ) const +{ + if (!pList) + return; + + if (bClear) + pList->RemoveAll(); + + //! bei mehreren selektierten Tabellen mehrere Ranges eintragen !!! + + if ( bMultiMarked ) + { + DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0"); + + SCTAB nTab = aMultiRange.aStart.Tab(); + + SCCOL nStartCol = aMultiRange.aStart.Col(); + SCCOL nEndCol = aMultiRange.aEnd.Col(); + for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++) + if (pMultiSel[nCol].HasMarks()) + { + SCROW nTop, nBottom; + ScRange aRange( nCol, 0, nTab ); + ScMarkArrayIter aMarkIter( &pMultiSel[nCol] ); + while ( aMarkIter.Next( nTop, nBottom ) ) + { + aRange.aStart.SetRow( nTop ); + aRange.aEnd.SetRow( nBottom ); + pList->Join( aRange ); + } + } + } + + if ( bMarked ) + pList->Append( aMarkRange ); +} + +void ScMarkData::ExtendRangeListTables( ScRangeList* pList ) const +{ + if (!pList) + return; + + ScRangeList aOldList(*pList); + pList->RemoveAll(); //! oder die vorhandenen unten weglassen + + for (SCTAB nTab=0; nTab<=MAXTAB; nTab++) + if (bTabMarked[nTab]) + { + ULONG nCount = aOldList.Count(); + for (ULONG i=0; i<nCount; i++) + { + ScRange aRange = *aOldList.GetObject(i); + aRange.aStart.SetTab(nTab); + aRange.aEnd.SetTab(nTab); + pList->Append( aRange ); + } + } +} + +SCCOLROW ScMarkData::GetMarkColumnRanges( SCCOLROW* pRanges ) +{ + if (bMarked) + MarkToMulti(); + + if (!bMultiMarked) + return 0; + + DBG_ASSERT(pMultiSel, "bMultiMarked, but pMultiSel == 0"); + + const SCCOLROW nMultiStart = aMultiRange.aStart.Col(); + const SCCOLROW nMultiEnd = aMultiRange.aEnd.Col(); + if (nMultiStart == 0 && nMultiEnd == MAXCOL) + { + // One or more entire rows. + pRanges[0] = 0; + pRanges[1] = MAXCOL; + return 1; + } + + SCCOLROW nRangeCnt = 0; + SCCOLROW nStart = nMultiStart; + while (nStart <= nMultiEnd) + { + while (nStart < nMultiEnd && !pMultiSel[nStart].HasMarks()) + ++nStart; + if (pMultiSel[nStart].HasMarks()) + { + SCCOLROW nEnd = nStart; + while (nEnd < nMultiEnd && pMultiSel[nEnd].HasMarks()) + ++nEnd; + if (!pMultiSel[nEnd].HasMarks()) + --nEnd; + pRanges[2*nRangeCnt ] = nStart; + pRanges[2*nRangeCnt+1] = nEnd; + ++nRangeCnt; + nStart = nEnd+1; + } + else + nStart = nMultiEnd+1; + } + + return nRangeCnt; +} + +SCCOLROW ScMarkData::GetMarkRowRanges( SCCOLROW* pRanges ) +{ + if (bMarked) + MarkToMulti(); + + if (!bMultiMarked) + return 0; + + DBG_ASSERT(pMultiSel, "bMultiMarked, but pMultiSel == 0"); + + // Which rows are marked? + + // Optimized to not loop over MAXCOL*MAXROW as worst case, i.e. Ctrl+A + + const SCCOLROW nMultiStart = aMultiRange.aStart.Row(); + const SCCOLROW nMultiEnd = aMultiRange.aEnd.Row(); + + BOOL* bRowMarked = new BOOL[MAXROWCOUNT]; + memset( bRowMarked, 0, sizeof(BOOL) * MAXROWCOUNT); + SCROW nRow; + SCCOL nCol; + + SCROW nTop = -1, nBottom = -1; + for (nCol = aMultiRange.aStart.Col(); nCol <= aMultiRange.aEnd.Col(); ++nCol) + { + ScMarkArrayIter aMarkIter( &pMultiSel[nCol] ); + while (aMarkIter.Next( nTop, nBottom )) + for (nRow=nTop; nRow<=nBottom; nRow++) + bRowMarked[nRow] = TRUE; + if (nTop == nMultiStart && nBottom == nMultiEnd) + break; // for, all relevant rows marked + } + + if (nTop == nMultiStart && nBottom == nMultiEnd) + { + pRanges[0] = nTop; + pRanges[1] = nBottom; + delete[] bRowMarked; + return 1; + } + + // Combine to ranges of rows. + + SCCOLROW nRangeCnt = 0; + SCCOLROW nStart = nMultiStart; + while (nStart <= nMultiEnd) + { + while (nStart < nMultiEnd && !bRowMarked[nStart]) + ++nStart; + if (bRowMarked[nStart]) + { + SCCOLROW nEnd = nStart; + while (nEnd < nMultiEnd && bRowMarked[nEnd]) + ++nEnd; + if (!bRowMarked[nEnd]) + --nEnd; + pRanges[2*nRangeCnt ] = nStart; + pRanges[2*nRangeCnt+1] = nEnd; + ++nRangeCnt; + nStart = nEnd+1; + } + else + nStart = nMultiEnd+1; + } + + delete[] bRowMarked; + return nRangeCnt; +} + +BOOL ScMarkData::IsAllMarked( const ScRange& rRange ) const +{ + if ( !bMultiMarked ) + return FALSE; + + DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0"); + + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + BOOL bOk = TRUE; + for (SCCOL nCol=nStartCol; nCol<=nEndCol && bOk; nCol++) + if ( !pMultiSel[nCol].IsAllMarked( nStartRow, nEndRow ) ) + bOk = FALSE; + + return bOk; +} + +SCsROW ScMarkData::GetNextMarked( SCCOL nCol, SCsROW nRow, BOOL bUp ) const +{ + if ( !bMultiMarked ) + return nRow; + + DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0"); + + return pMultiSel[nCol].GetNextMarked( nRow, bUp ); +} + +BOOL ScMarkData::HasMultiMarks( SCCOL nCol ) const +{ + if ( !bMultiMarked ) + return FALSE; + + DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0"); + + return pMultiSel[nCol].HasMarks(); +} + +BOOL ScMarkData::HasAnyMultiMarks() const +{ + if ( !bMultiMarked ) + return FALSE; + + DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0"); + + for (SCCOL nCol=0; nCol<=MAXCOL; nCol++) + if ( pMultiSel[nCol].HasMarks() ) + return TRUE; + + return FALSE; // nix +} + +void ScMarkData::InsertTab( SCTAB nTab ) +{ + for (SCTAB i=MAXTAB; i>nTab; i--) + bTabMarked[i] = bTabMarked[i-1]; + bTabMarked[nTab] = FALSE; +} + +void ScMarkData::DeleteTab( SCTAB nTab ) +{ + for (SCTAB i=nTab; i<MAXTAB; i++) + bTabMarked[i] = bTabMarked[i+1]; + bTabMarked[MAXTAB] = FALSE; +} + + + + + |