blob: b53f2b617161d135b3239e93d959f38a7014808c [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"
#include "scitems.hxx"
#include <svl/intitem.hxx>
#include <svl/zforlist.hxx>
#include <rtl/uuid.h>
#include "cursuno.hxx"
#include "cellsuno.hxx"
#include "docsh.hxx"
#include "hints.hxx"
#include "markdata.hxx"
#include "dociter.hxx"
#include "unoguard.hxx"
#include "miscuno.hxx"
using namespace com::sun::star;
//------------------------------------------------------------------------
#define SCSHEETCELLCURSOR_SERVICE "com.sun.star.sheet.SheetCellCursor"
#define SCCELLCURSOR_SERVICE "com.sun.star.table.CellCursor"
//------------------------------------------------------------------------
ScCellCursorObj::ScCellCursorObj(ScDocShell* pDocSh, const ScRange& rR) :
ScCellRangeObj( pDocSh, rR )
{
}
ScCellCursorObj::~ScCellCursorObj()
{
}
uno::Any SAL_CALL ScCellCursorObj::queryInterface( const uno::Type& rType ) throw(uno::RuntimeException)
{
SC_QUERYINTERFACE( sheet::XSheetCellCursor )
SC_QUERYINTERFACE( sheet::XUsedAreaCursor )
SC_QUERYINTERFACE( table::XCellCursor )
return ScCellRangeObj::queryInterface( rType );
}
void SAL_CALL ScCellCursorObj::acquire() throw()
{
ScCellRangeObj::acquire();
}
void SAL_CALL ScCellCursorObj::release() throw()
{
ScCellRangeObj::release();
}
uno::Sequence<uno::Type> SAL_CALL ScCellCursorObj::getTypes() throw(uno::RuntimeException)
{
static uno::Sequence<uno::Type> aTypes;
if ( aTypes.getLength() == 0 )
{
uno::Sequence<uno::Type> aParentTypes(ScCellRangeObj::getTypes());
long nParentLen = aParentTypes.getLength();
const uno::Type* pParentPtr = aParentTypes.getConstArray();
aTypes.realloc( nParentLen + 3 );
uno::Type* pPtr = aTypes.getArray();
pPtr[nParentLen + 0] = getCppuType((const uno::Reference<sheet::XSheetCellCursor>*)0);
pPtr[nParentLen + 1] = getCppuType((const uno::Reference<sheet::XUsedAreaCursor>*)0);
pPtr[nParentLen + 2] = getCppuType((const uno::Reference<table::XCellCursor>*)0);
for (long i=0; i<nParentLen; i++)
pPtr[i] = pParentPtr[i]; // parent types first
}
return aTypes;
}
uno::Sequence<sal_Int8> SAL_CALL ScCellCursorObj::getImplementationId() throw(uno::RuntimeException)
{
static uno::Sequence< sal_Int8 > aId;
if( aId.getLength() == 0 )
{
aId.realloc( 16 );
rtl_createUuid( (sal_uInt8 *)aId.getArray(), 0, sal_True );
}
return aId;
}
// XSheetCellCursor
void SAL_CALL ScCellCursorObj::collapseToCurrentRegion() throw(uno::RuntimeException)
{
ScUnoGuard aGuard;
const ScRangeList& rRanges = GetRangeList();
DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
ScRange aOneRange(*rRanges.GetObject(0));
aOneRange.Justify();
ScDocShell* pDocSh = GetDocShell();
if ( pDocSh )
{
SCCOL nStartCol = aOneRange.aStart.Col();
SCROW nStartRow = aOneRange.aStart.Row();
SCCOL nEndCol = aOneRange.aEnd.Col();
SCROW nEndRow = aOneRange.aEnd.Row();
SCTAB nTab = aOneRange.aStart.Tab();
pDocSh->GetDocument()->GetDataArea(
nTab, nStartCol, nStartRow, nEndCol, nEndRow, sal_True, false );
ScRange aNew( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab );
SetNewRange( aNew );
}
}
void SAL_CALL ScCellCursorObj::collapseToCurrentArray() throw(uno::RuntimeException)
{
ScUnoGuard aGuard;
const ScRangeList& rRanges = GetRangeList();
DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
ScRange aOneRange(*rRanges.GetObject(0));
aOneRange.Justify();
ScAddress aCursor(aOneRange.aStart); // use the start address of the range
ScDocShell* pDocSh = GetDocShell();
if ( pDocSh )
{
ScDocument* pDoc = pDocSh->GetDocument();
ScRange aMatrix;
// finding the matrix range is now in GetMatrixFormulaRange in the document
if ( pDoc->GetMatrixFormulaRange( aCursor, aMatrix ) )
{
SetNewRange( aMatrix );
}
}
// thats a Bug, that this assertion comes; the API Reference says, that
// if there is no Matrix, the Range is left unchanged; they says nothing
// about a exception
/*if (!bFound)
{
DBG_ERROR("keine Matrix");
//! Exception, oder was?
}*/
}
void SAL_CALL ScCellCursorObj::collapseToMergedArea() throw(uno::RuntimeException)
{
ScUnoGuard aGuard;
ScDocShell* pDocSh = GetDocShell();
if ( pDocSh )
{
const ScRangeList& rRanges = GetRangeList();
DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
ScRange aNewRange(*rRanges.GetObject(0));
ScDocument* pDoc = pDocSh->GetDocument();
pDoc->ExtendOverlapped( aNewRange );
pDoc->ExtendMerge( aNewRange ); // after ExtendOverlapped!
SetNewRange( aNewRange );
}
}
void SAL_CALL ScCellCursorObj::expandToEntireColumns() throw(uno::RuntimeException)
{
ScUnoGuard aGuard;
const ScRangeList& rRanges = GetRangeList();
DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
ScRange aNewRange(*rRanges.GetObject(0));
aNewRange.aStart.SetRow( 0 );
aNewRange.aEnd.SetRow( MAXROW );
SetNewRange( aNewRange );
}
void SAL_CALL ScCellCursorObj::expandToEntireRows() throw(uno::RuntimeException)
{
ScUnoGuard aGuard;
const ScRangeList& rRanges = GetRangeList();
DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
ScRange aNewRange(*rRanges.GetObject(0));
aNewRange.aStart.SetCol( 0 );
aNewRange.aEnd.SetCol( MAXCOL );
SetNewRange( aNewRange );
}
void SAL_CALL ScCellCursorObj::collapseToSize( sal_Int32 nColumns, sal_Int32 nRows )
throw(uno::RuntimeException)
{
ScUnoGuard aGuard;
if ( nColumns <= 0 || nRows <= 0 )
{
DBG_ERROR("leerer Range geht nicht");
//! und dann?
}
else
{
const ScRangeList& rRanges = GetRangeList();
DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
ScRange aNewRange(*rRanges.GetObject(0));
aNewRange.Justify(); //! wirklich?
long nEndX = aNewRange.aStart.Col() + nColumns - 1;
long nEndY = aNewRange.aStart.Row() + nRows - 1;
if ( nEndX < 0 ) nEndX = 0;
if ( nEndX > MAXCOL ) nEndX = MAXCOL;
if ( nEndY < 0 ) nEndY = 0;
if ( nEndY > MAXROW ) nEndY = MAXROW;
//! Fehler/Exception oder so, wenn zu gross/zu klein?
aNewRange.aEnd.SetCol((SCCOL)nEndX);
aNewRange.aEnd.SetRow((SCROW)nEndY);
aNewRange.Justify(); //! wirklich?
SetNewRange( aNewRange );
}
}
// XUsedAreaCursor
void SAL_CALL ScCellCursorObj::gotoStartOfUsedArea( sal_Bool bExpand )
throw(uno::RuntimeException)
{
ScUnoGuard aGuard;
ScDocShell* pDocSh = GetDocShell();
if ( pDocSh )
{
const ScRangeList& rRanges = GetRangeList();
DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
ScRange aNewRange(*rRanges.GetObject(0));
SCTAB nTab = aNewRange.aStart.Tab();
SCCOL nUsedX = 0; // Anfang holen
SCROW nUsedY = 0;
if (!pDocSh->GetDocument()->GetDataStart( nTab, nUsedX, nUsedY ))
{
nUsedX = 0;
nUsedY = 0;
}
aNewRange.aStart.SetCol( nUsedX );
aNewRange.aStart.SetRow( nUsedY );
if (!bExpand)
aNewRange.aEnd = aNewRange.aStart;
SetNewRange( aNewRange );
}
}
void SAL_CALL ScCellCursorObj::gotoEndOfUsedArea( sal_Bool bExpand )
throw(uno::RuntimeException)
{
ScUnoGuard aGuard;
ScDocShell* pDocSh = GetDocShell();
if ( pDocSh )
{
const ScRangeList& rRanges = GetRangeList();
DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
ScRange aNewRange(*rRanges.GetObject(0));
SCTAB nTab = aNewRange.aStart.Tab();
SCCOL nUsedX = 0; // Ende holen
SCROW nUsedY = 0;
if (!pDocSh->GetDocument()->GetTableArea( nTab, nUsedX, nUsedY ))
{
nUsedX = 0;
nUsedY = 0;
}
aNewRange.aEnd.SetCol( nUsedX );
aNewRange.aEnd.SetRow( nUsedY );
if (!bExpand)
aNewRange.aStart = aNewRange.aEnd;
SetNewRange( aNewRange );
}
}
// XCellCursor
void SAL_CALL ScCellCursorObj::gotoStart() throw(uno::RuntimeException)
{
// this is similar to collapseToCurrentRegion
//! something like gotoEdge with 4 possible directions is needed
ScUnoGuard aGuard;
const ScRangeList& rRanges = GetRangeList();
DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
ScRange aOneRange(*rRanges.GetObject(0));
aOneRange.Justify();
ScDocShell* pDocSh = GetDocShell();
if ( pDocSh )
{
SCCOL nStartCol = aOneRange.aStart.Col();
SCROW nStartRow = aOneRange.aStart.Row();
SCCOL nEndCol = aOneRange.aEnd.Col();
SCROW nEndRow = aOneRange.aEnd.Row();
SCTAB nTab = aOneRange.aStart.Tab();
pDocSh->GetDocument()->GetDataArea(
nTab, nStartCol, nStartRow, nEndCol, nEndRow, sal_False, false );
ScRange aNew( nStartCol, nStartRow, nTab );
SetNewRange( aNew );
}
}
void SAL_CALL ScCellCursorObj::gotoEnd() throw(uno::RuntimeException)
{
// this is similar to collapseToCurrentRegion
//! something like gotoEdge with 4 possible directions is needed
ScUnoGuard aGuard;
const ScRangeList& rRanges = GetRangeList();
DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
ScRange aOneRange(*rRanges.GetObject(0));
aOneRange.Justify();
ScDocShell* pDocSh = GetDocShell();
if ( pDocSh )
{
SCCOL nStartCol = aOneRange.aStart.Col();
SCROW nStartRow = aOneRange.aStart.Row();
SCCOL nEndCol = aOneRange.aEnd.Col();
SCROW nEndRow = aOneRange.aEnd.Row();
SCTAB nTab = aOneRange.aStart.Tab();
pDocSh->GetDocument()->GetDataArea(
nTab, nStartCol, nStartRow, nEndCol, nEndRow, sal_False, false );
ScRange aNew( nEndCol, nEndRow, nTab );
SetNewRange( aNew );
}
}
void SAL_CALL ScCellCursorObj::gotoNext() throw(uno::RuntimeException)
{
ScUnoGuard aGuard;
const ScRangeList& rRanges = GetRangeList();
DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
ScRange aOneRange(*rRanges.GetObject(0));
aOneRange.Justify();
ScAddress aCursor(aOneRange.aStart); // bei Block immer den Start nehmen
ScMarkData aMark; // not used with bMarked=FALSE
SCCOL nNewX = aCursor.Col();
SCROW nNewY = aCursor.Row();
SCTAB nTab = aCursor.Tab();
ScDocShell* pDocSh = GetDocShell();
if ( pDocSh )
pDocSh->GetDocument()->GetNextPos( nNewX,nNewY, nTab, 1,0, sal_False,sal_True, aMark );
//! sonst Exception oder so
SetNewRange( ScRange( nNewX, nNewY, nTab ) );
}
void SAL_CALL ScCellCursorObj::gotoPrevious() throw(uno::RuntimeException)
{
ScUnoGuard aGuard;
const ScRangeList& rRanges = GetRangeList();
DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
ScRange aOneRange(*rRanges.GetObject(0));
aOneRange.Justify();
ScAddress aCursor(aOneRange.aStart); // bei Block immer den Start nehmen
ScMarkData aMark; // not used with bMarked=FALSE
SCCOL nNewX = aCursor.Col();
SCROW nNewY = aCursor.Row();
SCTAB nTab = aCursor.Tab();
ScDocShell* pDocSh = GetDocShell();
if ( pDocSh )
pDocSh->GetDocument()->GetNextPos( nNewX,nNewY, nTab, -1,0, sal_False,sal_True, aMark );
//! sonst Exception oder so
SetNewRange( ScRange( nNewX, nNewY, nTab ) );
}
void SAL_CALL ScCellCursorObj::gotoOffset( sal_Int32 nColumnOffset, sal_Int32 nRowOffset )
throw(uno::RuntimeException)
{
ScUnoGuard aGuard;
const ScRangeList& rRanges = GetRangeList();
DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
ScRange aOneRange(*rRanges.GetObject(0));
aOneRange.Justify();
if ( aOneRange.aStart.Col() + nColumnOffset >= 0 &&
aOneRange.aEnd.Col() + nColumnOffset <= MAXCOL &&
aOneRange.aStart.Row() + nRowOffset >= 0 &&
aOneRange.aEnd.Row() + nRowOffset <= MAXROW )
{
ScRange aNew( (SCCOL)(aOneRange.aStart.Col() + nColumnOffset),
(SCROW)(aOneRange.aStart.Row() + nRowOffset),
aOneRange.aStart.Tab(),
(SCCOL)(aOneRange.aEnd.Col() + nColumnOffset),
(SCROW)(aOneRange.aEnd.Row() + nRowOffset),
aOneRange.aEnd.Tab() );
SetNewRange( aNew );
}
}
// XSheetCellRange
uno::Reference<sheet::XSpreadsheet> SAL_CALL ScCellCursorObj::getSpreadsheet()
throw(uno::RuntimeException)
{
ScUnoGuard aGuard;
return ScCellRangeObj::getSpreadsheet();
}
// XCellRange
uno::Reference<table::XCell> SAL_CALL ScCellCursorObj::getCellByPosition(
sal_Int32 nColumn, sal_Int32 nRow )
throw(lang::IndexOutOfBoundsException, uno::RuntimeException)
{
ScUnoGuard aGuard;
return ScCellRangeObj::getCellByPosition(nColumn,nRow);
}
uno::Reference<table::XCellRange> SAL_CALL ScCellCursorObj::getCellRangeByPosition(
sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom )
throw(lang::IndexOutOfBoundsException, uno::RuntimeException)
{
ScUnoGuard aGuard;
return ScCellRangeObj::getCellRangeByPosition(nLeft,nTop,nRight,nBottom);
}
uno::Reference<table::XCellRange> SAL_CALL ScCellCursorObj::getCellRangeByName(
const rtl::OUString& rRange ) throw(uno::RuntimeException)
{
ScUnoGuard aGuard;
return ScCellRangeObj::getCellRangeByName(rRange);
}
// XServiceInfo
rtl::OUString SAL_CALL ScCellCursorObj::getImplementationName() throw(uno::RuntimeException)
{
return rtl::OUString::createFromAscii( "ScCellCursorObj" );
}
sal_Bool SAL_CALL ScCellCursorObj::supportsService( const rtl::OUString& rServiceName )
throw(uno::RuntimeException)
{
String aServiceStr( rServiceName );
return aServiceStr.EqualsAscii( SCSHEETCELLCURSOR_SERVICE ) ||
aServiceStr.EqualsAscii( SCCELLCURSOR_SERVICE ) ||
ScCellRangeObj::supportsService(rServiceName);
}
uno::Sequence<rtl::OUString> SAL_CALL ScCellCursorObj::getSupportedServiceNames()
throw(uno::RuntimeException)
{
// get all service names from cell range
uno::Sequence<rtl::OUString> aParentSeq(ScCellRangeObj::getSupportedServiceNames());
sal_Int32 nParentLen = aParentSeq.getLength();
const rtl::OUString* pParentArr = aParentSeq.getConstArray();
// SheetCellCursor should be first (?)
uno::Sequence<rtl::OUString> aTotalSeq( nParentLen + 2 );
rtl::OUString* pTotalArr = aTotalSeq.getArray();
pTotalArr[0] = rtl::OUString::createFromAscii( SCSHEETCELLCURSOR_SERVICE );
pTotalArr[1] = rtl::OUString::createFromAscii( SCCELLCURSOR_SERVICE );
// append cell range services
for (long i=0; i<nParentLen; i++)
pTotalArr[i+2] = pParentArr[i];
return aTotalSeq;
}