| /************************************************************** |
| * |
| * 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_sw.hxx" |
| |
| #include <memory> |
| #include <algorithm> |
| |
| #include <com/sun/star/chart/ChartDataRowSource.hpp> |
| #include <com/sun/star/chart2/data/LabelOrigin.hpp> |
| #include <cppuhelper/interfacecontainer.hxx> |
| #include <vos/mutex.hxx> |
| #include <osl/mutex.hxx> |
| #include <vcl/svapp.hxx> |
| #include <svl/zforlist.hxx> // SvNumberFormatter |
| #include <svx/charthelper.hxx> |
| |
| #include <tools/link.hxx> |
| |
| #include <XMLRangeHelper.hxx> |
| #include <unochart.hxx> |
| #include <swtable.hxx> |
| #include <unoprnms.hxx> |
| #include <unomap.hxx> |
| #include <unomid.h> |
| #include <unocrsr.hxx> |
| #include <unotbl.hxx> |
| #include <doc.hxx> |
| #include <frmfmt.hxx> |
| #include <docsh.hxx> |
| #include <ndole.hxx> |
| #include <swtable.hxx> |
| #include <swtypes.hxx> |
| #ifndef _UNOCORE_HRC |
| #include <unocore.hrc> |
| #endif |
| |
| #include <docary.hxx> |
| |
| #define SN_DATA_PROVIDER "com.sun.star.chart2.data.DataProvider" |
| #define SN_DATA_SOURCE "com.sun.star.chart2.data.DataSource" |
| #define SN_DATA_SEQUENCE "com.sun.star.chart2.data.DataSequence" |
| #define SN_LABELED_DATA_SEQUENCE "com.sun.star.chart2.data.LabeledDataSequence" |
| |
| #define DIRECTION_DONT_KNOW -1 |
| #define DIRECTION_HAS_ERROR -2 |
| #define DIRECTION_COLS 0 |
| #define DIRECTION_ROWS 1 |
| |
| using namespace ::com::sun::star; |
| using ::rtl::OUString; |
| |
| // from unotbl.cxx |
| extern void lcl_GetCellPosition( const String &rCellName, sal_Int32 &rColumn, sal_Int32 &rRow); |
| extern String lcl_GetCellName( sal_Int32 nColumn, sal_Int32 nRow ); |
| extern int lcl_CompareCellsByColFirst( const String &rCellName1, const String &rCellName2 ); |
| extern int lcl_CompareCellsByRowFirst( const String &rCellName1, const String &rCellName2 ); |
| extern int lcl_CompareCellRanges( |
| const String &rRange1StartCell, const String &rRange1EndCell, |
| const String &rRange2StartCell, const String &rRange2EndCell, |
| sal_Bool bCmpColsFirst ); |
| extern void lcl_NormalizeRange( String &rCell1, String &rCell2 ); |
| |
| ////////////////////////////////////////////////////////////////////// |
| |
| //static |
| void SwChartHelper::DoUpdateAllCharts( SwDoc* pDoc ) |
| { |
| if (!pDoc) |
| return; |
| |
| uno::Reference< frame::XModel > xRes; |
| |
| SwOLENode *pONd; |
| SwStartNode *pStNd; |
| SwNodeIndex aIdx( *pDoc->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 ); |
| while( 0 != (pStNd = aIdx.GetNode().GetStartNode()) ) |
| { |
| aIdx++; |
| if (0 != ( pONd = aIdx.GetNode().GetOLENode() ) && |
| ChartHelper::IsChart( pONd->GetOLEObj().GetObject() ) ) |
| { |
| // Load the object and set modified |
| |
| uno::Reference < embed::XEmbeddedObject > xIP = pONd->GetOLEObj().GetOleRef(); |
| if ( svt::EmbeddedObjectRef::TryRunningState( xIP ) ) |
| { |
| try |
| { |
| uno::Reference< util::XModifiable > xModif( xIP->getComponent(), uno::UNO_QUERY_THROW ); |
| xModif->setModified( sal_True ); |
| } |
| catch ( uno::Exception& ) |
| { |
| } |
| |
| } |
| } |
| aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 ); |
| } |
| } |
| |
| ////////////////////////////////////////////////////////////////////// |
| |
| SwChartLockController_Helper::SwChartLockController_Helper( SwDoc *pDocument ) : |
| pDoc( pDocument ) |
| { |
| aUnlockTimer.SetTimeout( 1500 ); |
| aUnlockTimer.SetTimeoutHdl( LINK( this, SwChartLockController_Helper, DoUnlockAllCharts )); |
| } |
| |
| |
| SwChartLockController_Helper::~SwChartLockController_Helper() |
| { |
| if (pDoc) // still connected? |
| Disconnect(); |
| } |
| |
| |
| void SwChartLockController_Helper::StartOrContinueLocking() |
| { |
| if (!bIsLocked) |
| LockAllCharts(); |
| aUnlockTimer.Start(); // start or continue time of locking |
| } |
| |
| |
| void SwChartLockController_Helper::Disconnect() |
| { |
| aUnlockTimer.Stop(); |
| UnlockAllCharts(); |
| pDoc = 0; |
| } |
| |
| |
| void SwChartLockController_Helper::LockUnlockAllCharts( sal_Bool bLock ) |
| { |
| if (!pDoc) |
| return; |
| |
| const SwFrmFmts& rTblFmts = *pDoc->GetTblFrmFmts(); |
| for( sal_uInt16 n = 0; n < rTblFmts.Count(); ++n ) |
| { |
| SwTable* pTmpTbl; |
| const SwTableNode* pTblNd; |
| SwFrmFmt* pFmt = rTblFmts[ n ]; |
| |
| if( 0 != ( pTmpTbl = SwTable::FindTable( pFmt ) ) && |
| 0 != ( pTblNd = pTmpTbl->GetTableNode() ) && |
| pTblNd->GetNodes().IsDocNodes() ) |
| { |
| uno::Reference< frame::XModel > xRes; |
| |
| String aName( pTmpTbl->GetFrmFmt()->GetName() ); |
| SwOLENode *pONd; |
| SwStartNode *pStNd; |
| SwNodeIndex aIdx( *pDoc->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 ); |
| while( 0 != (pStNd = aIdx.GetNode().GetStartNode()) ) |
| { |
| aIdx++; |
| if (0 != ( pONd = aIdx.GetNode().GetOLENode() ) && |
| pONd->GetChartTblName().Len() > 0 /* is chart object? */) |
| { |
| uno::Reference < embed::XEmbeddedObject > xIP = pONd->GetOLEObj().GetOleRef(); |
| if ( svt::EmbeddedObjectRef::TryRunningState( xIP ) ) |
| { |
| xRes = uno::Reference < frame::XModel >( xIP->getComponent(), uno::UNO_QUERY ); |
| if (xRes.is()) |
| { |
| if (bLock) |
| xRes->lockControllers(); |
| else |
| xRes->unlockControllers(); |
| } |
| } |
| } |
| aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 ); |
| } |
| } |
| } |
| |
| bIsLocked = bLock; |
| } |
| |
| |
| IMPL_LINK( SwChartLockController_Helper, DoUnlockAllCharts, Timer *, /*pTimer*/ ) |
| { |
| UnlockAllCharts(); |
| return 0; |
| } |
| |
| |
| ////////////////////////////////////////////////////////////////////// |
| |
| static osl::Mutex & GetChartMutex() |
| { |
| static osl::Mutex aMutex; |
| return aMutex; |
| } |
| |
| |
| static void LaunchModifiedEvent( |
| ::cppu::OInterfaceContainerHelper &rICH, |
| const uno::Reference< uno::XInterface > &rxI ) |
| { |
| lang::EventObject aEvtObj( rxI ); |
| cppu::OInterfaceIteratorHelper aIt( rICH ); |
| while (aIt.hasMoreElements()) |
| { |
| uno::Reference< util::XModifyListener > xRef( aIt.next(), uno::UNO_QUERY ); |
| if (xRef.is()) |
| xRef->modified( aEvtObj ); |
| } |
| } |
| |
| ////////////////////////////////////////////////////////////////////// |
| |
| // rCellRangeName needs to be of one of the following formats: |
| // - e.g. "A2:E5" or |
| // - e.g. "Table1.A2:E5" |
| sal_Bool FillRangeDescriptor( |
| SwRangeDescriptor &rDesc, |
| const String &rCellRangeName ) |
| { |
| xub_StrLen nToken = STRING_NOTFOUND == rCellRangeName.Search('.') ? 0 : 1; |
| String aCellRangeNoTableName( rCellRangeName.GetToken( nToken, '.' ) ); |
| String aTLName( aCellRangeNoTableName.GetToken(0, ':') ); // name of top left cell |
| String aBRName( aCellRangeNoTableName.GetToken(1, ':') ); // name of bottom right cell |
| if(!aTLName.Len() || !aBRName.Len()) |
| return sal_False; |
| |
| rDesc.nTop = rDesc.nLeft = rDesc.nBottom = rDesc.nRight = -1; |
| lcl_GetCellPosition( aTLName, rDesc.nLeft, rDesc.nTop ); |
| lcl_GetCellPosition( aBRName, rDesc.nRight, rDesc.nBottom ); |
| rDesc.Normalize(); |
| DBG_ASSERT( rDesc.nTop != -1 && |
| rDesc.nLeft != -1 && |
| rDesc.nBottom != -1 && |
| rDesc.nRight != -1, |
| "failed to get range descriptor" ); |
| DBG_ASSERT( rDesc.nTop <= rDesc.nBottom && rDesc.nLeft <= rDesc.nRight, |
| "invalid range descriptor"); |
| return sal_True; |
| } |
| |
| |
| static String GetCellRangeName( SwFrmFmt &rTblFmt, SwUnoCrsr &rTblCrsr ) |
| { |
| String aRes; |
| |
| //!! see also SwXTextTableCursor::getRangeName |
| |
| SwUnoTableCrsr* pUnoTblCrsr = dynamic_cast<SwUnoTableCrsr*>(&rTblCrsr); |
| if (!pUnoTblCrsr) |
| return String(); |
| pUnoTblCrsr->MakeBoxSels(); |
| |
| const SwStartNode* pStart; |
| const SwTableBox* pStartBox = 0; |
| const SwTableBox* pEndBox = 0; |
| |
| pStart = pUnoTblCrsr->GetPoint()->nNode.GetNode().FindTableBoxStartNode(); |
| if (pStart) |
| { |
| const SwTable* pTable = SwTable::FindTable( &rTblFmt ); |
| pEndBox = pTable->GetTblBox( pStart->GetIndex()); |
| aRes = pEndBox->GetName(); |
| |
| if(pUnoTblCrsr->HasMark()) |
| { |
| pStart = pUnoTblCrsr->GetMark()->nNode.GetNode().FindTableBoxStartNode(); |
| pStartBox = pTable->GetTblBox( pStart->GetIndex()); |
| } |
| DBG_ASSERT( pStartBox, "start box not found" ); |
| DBG_ASSERT( pEndBox, "end box not found" ); |
| // need to switch start and end? |
| if (*pUnoTblCrsr->GetPoint() < *pUnoTblCrsr->GetMark()) |
| { |
| const SwTableBox* pTmpBox = pStartBox; |
| pStartBox = pEndBox; |
| pEndBox = pTmpBox; |
| } |
| |
| aRes = pStartBox->GetName(); |
| aRes += (sal_Unicode)':'; |
| if (pEndBox) |
| aRes += pEndBox->GetName(); |
| else |
| aRes += pStartBox->GetName(); |
| } |
| |
| return aRes; |
| } |
| |
| |
| static String GetRangeRepFromTableAndCells( const String &rTableName, |
| const String &rStartCell, const String &rEndCell, |
| sal_Bool bForceEndCellName ) |
| { |
| DBG_ASSERT( rTableName.Len(), "table name missing" ); |
| DBG_ASSERT( rStartCell.Len(), "cell name missing" ); |
| String aRes( rTableName ); |
| aRes += (sal_Unicode) '.'; |
| aRes += rStartCell; |
| |
| if (rEndCell.Len()) |
| { |
| aRes += (sal_Unicode) ':'; |
| aRes += rEndCell; |
| } |
| else if (bForceEndCellName) |
| { |
| aRes += (sal_Unicode) ':'; |
| aRes += rStartCell; |
| } |
| |
| return aRes; |
| } |
| |
| |
| static sal_Bool GetTableAndCellsFromRangeRep( |
| const OUString &rRangeRepresentation, |
| String &rTblName, |
| String &rStartCell, |
| String &rEndCell, |
| sal_Bool bSortStartEndCells = sal_True ) |
| { |
| // parse range representation for table name and cell/range names |
| // accepted format sth like: "Table1.A2:C5" , "Table2.A2.1:B3.2" |
| String aTblName; // table name |
| OUString aRange; // cell range |
| String aStartCell; // name of top left cell |
| String aEndCell; // name of bottom right cell |
| sal_Int32 nIdx = rRangeRepresentation.indexOf( '.' ); |
| if (nIdx >= 0) |
| { |
| aTblName = rRangeRepresentation.copy( 0, nIdx ); |
| aRange = rRangeRepresentation.copy( nIdx + 1 ); |
| sal_Int32 nPos = aRange.indexOf( ':' ); |
| if (nPos >= 0) // a cell-range like "Table1.A2:D4" |
| { |
| aStartCell = aRange.copy( 0, nPos ); |
| aEndCell = aRange.copy( nPos + 1 ); |
| |
| // need to switch start and end cell ? |
| // (does not check for normalization here) |
| if (bSortStartEndCells && 1 == lcl_CompareCellsByColFirst( aStartCell, aEndCell )) |
| { |
| String aTmp( aStartCell ); |
| aStartCell = aEndCell; |
| aEndCell = aTmp; |
| } |
| } |
| else // a single cell like in "Table1.B3" |
| { |
| aStartCell = aEndCell = aRange; |
| } |
| } |
| |
| sal_Bool bSuccess = aTblName.Len() != 0 && |
| aStartCell.Len() != 0 && aEndCell.Len() != 0; |
| if (bSuccess) |
| { |
| rTblName = aTblName; |
| rStartCell = aStartCell; |
| rEndCell = aEndCell; |
| } |
| return bSuccess; |
| } |
| |
| |
| static void GetTableByName( const SwDoc &rDoc, const String &rTableName, |
| SwFrmFmt **ppTblFmt, SwTable **ppTable) |
| { |
| SwFrmFmt *pTblFmt = NULL; |
| |
| // find frame format of table |
| //! see SwXTextTables::getByName |
| sal_uInt16 nCount = rDoc.GetTblFrmFmtCount(sal_True); |
| for (sal_uInt16 i = 0; i < nCount && !pTblFmt; ++i) |
| { |
| SwFrmFmt& rTblFmt = rDoc.GetTblFrmFmt(i, sal_True); |
| if(rTableName == rTblFmt.GetName()) |
| pTblFmt = &rTblFmt; |
| } |
| |
| if (ppTblFmt) |
| *ppTblFmt = pTblFmt; |
| |
| if (ppTable) |
| *ppTable = pTblFmt ? SwTable::FindTable( pTblFmt ) : 0; |
| } |
| |
| |
| static void GetFormatAndCreateCursorFromRangeRep( |
| const SwDoc *pDoc, |
| const OUString &rRangeRepresentation, // must be a single range (i.e. so called sub-range) |
| SwFrmFmt **ppTblFmt, // will be set to the table format of the table used in the range representation |
| SwUnoCrsr **ppUnoCrsr ) // will be set to cursor spanning the cell range |
| // (cursor will be created!) |
| { |
| String aTblName; // table name |
| String aStartCell; // name of top left cell |
| String aEndCell; // name of bottom right cell |
| sal_Bool bNamesFound = GetTableAndCellsFromRangeRep( rRangeRepresentation, |
| aTblName, aStartCell, aEndCell ); |
| |
| if (!bNamesFound) |
| { |
| if (ppTblFmt) |
| *ppTblFmt = NULL; |
| if (ppUnoCrsr) |
| *ppUnoCrsr = NULL; |
| } |
| else |
| { |
| SwFrmFmt *pTblFmt = NULL; |
| |
| // is the correct table format already provided? |
| if (*ppTblFmt != NULL && (*ppTblFmt)->GetName() == aTblName) |
| pTblFmt = *ppTblFmt; |
| else if (ppTblFmt) |
| GetTableByName( *pDoc, aTblName, &pTblFmt, NULL ); |
| |
| if (ppTblFmt) |
| *ppTblFmt = pTblFmt; |
| |
| if (ppUnoCrsr != NULL) |
| { |
| *ppUnoCrsr = NULL; // default result in case of failure |
| |
| SwTable *pTable = pTblFmt ? SwTable::FindTable( pTblFmt ) : 0; |
| // create new SwUnoCrsr spanning the specified range |
| //! see also SwXTextTable::GetRangeByName |
| // --> OD 2007-08-03 #i80314# |
| // perform validation check. Thus, pass <true> as 2nd parameter to <SwTable::GetTblBox(..)> |
| const SwTableBox* pTLBox = |
| pTable ? pTable->GetTblBox( aStartCell, true ) : 0; |
| // <-- |
| if(pTLBox) |
| { |
| // hier muessen die Actions aufgehoben werden |
| UnoActionRemoveContext aRemoveContext(pTblFmt->GetDoc()); |
| const SwStartNode* pSttNd = pTLBox->GetSttNd(); |
| SwPosition aPos(*pSttNd); |
| // set cursor to top left box of range |
| SwUnoCrsr* pUnoCrsr = pTblFmt->GetDoc()->CreateUnoCrsr(aPos, sal_True); |
| pUnoCrsr->Move( fnMoveForward, fnGoNode ); |
| pUnoCrsr->SetRemainInSection( sal_False ); |
| // --> OD 2007-08-03 #i80314# |
| // perform validation check. Thus, pass <true> as 2nd parameter to <SwTable::GetTblBox(..)> |
| const SwTableBox* pBRBox = pTable->GetTblBox( aEndCell, true ); |
| // <-- |
| if(pBRBox) |
| { |
| pUnoCrsr->SetMark(); |
| pUnoCrsr->GetPoint()->nNode = *pBRBox->GetSttNd(); |
| pUnoCrsr->Move( fnMoveForward, fnGoNode ); |
| SwUnoTableCrsr* pCrsr = |
| dynamic_cast<SwUnoTableCrsr*>(pUnoCrsr); |
| pCrsr->MakeBoxSels(); |
| |
| if (ppUnoCrsr) |
| *ppUnoCrsr = pCrsr; |
| } |
| else |
| { |
| delete pUnoCrsr; |
| } |
| } |
| } |
| } |
| } |
| |
| |
| static sal_Bool GetSubranges( const OUString &rRangeRepresentation, |
| uno::Sequence< OUString > &rSubRanges, sal_Bool bNormalize ) |
| { |
| sal_Bool bRes = sal_True; |
| String aRangesStr( rRangeRepresentation ); |
| xub_StrLen nLen = aRangesStr.GetTokenCount( ';' ); |
| uno::Sequence< OUString > aRanges( nLen ); |
| |
| sal_Int32 nCnt = 0; |
| if (nLen != 0) |
| { |
| OUString *pRanges = aRanges.getArray(); |
| String aFirstTable; |
| for ( xub_StrLen i = 0; i < nLen && bRes; ++i) |
| { |
| String aRange( aRangesStr.GetToken( i, ';' ) ); |
| if (aRange.Len()) |
| { |
| pRanges[nCnt] = aRange; |
| |
| String aTableName, aStartCell, aEndCell; |
| bRes &= GetTableAndCellsFromRangeRep( aRange, |
| aTableName, aStartCell, aEndCell ); |
| |
| if (bNormalize) |
| { |
| lcl_NormalizeRange( aStartCell, aEndCell ); |
| pRanges[nCnt] = GetRangeRepFromTableAndCells( aTableName, |
| aStartCell, aEndCell, sal_True ); |
| } |
| |
| // make sure to use only a single table |
| if (nCnt == 0) |
| aFirstTable = aTableName; |
| else |
| bRes &= aFirstTable == aTableName; |
| |
| ++nCnt; |
| } |
| } |
| } |
| aRanges.realloc( nCnt ); |
| |
| rSubRanges = aRanges; |
| return bRes; |
| } |
| |
| |
| static void SortSubranges( uno::Sequence< OUString > &rSubRanges, sal_Bool bCmpByColumn ) |
| { |
| sal_Int32 nLen = rSubRanges.getLength(); |
| OUString *pSubRanges = rSubRanges.getArray(); |
| |
| String aSmallestTblName; |
| String aSmallestStartCell; |
| String aSmallestEndCell; |
| |
| for (sal_Int32 i = 0; i < nLen; ++i) |
| { |
| sal_Int32 nIdxOfSmallest = i; |
| GetTableAndCellsFromRangeRep( pSubRanges[nIdxOfSmallest], |
| aSmallestTblName, aSmallestStartCell, aSmallestEndCell ); |
| if (aSmallestEndCell.Len() == 0) |
| aSmallestEndCell = aSmallestStartCell; |
| |
| for (sal_Int32 k = i+1; k < nLen; ++k) |
| { |
| // get cell names for sub range |
| String aTblName; |
| String aStartCell; |
| String aEndCell; |
| GetTableAndCellsFromRangeRep( pSubRanges[k], |
| aTblName, aStartCell, aEndCell ); |
| if (aEndCell.Len() == 0) |
| aEndCell = aStartCell; |
| |
| // compare cell ranges ( is the new one smaller? ) |
| if (-1 == lcl_CompareCellRanges( aStartCell, aEndCell, |
| aSmallestStartCell, aSmallestEndCell, bCmpByColumn )) |
| { |
| nIdxOfSmallest = k; |
| aSmallestTblName = aTblName; |
| aSmallestStartCell = aStartCell; |
| aSmallestEndCell = aEndCell; |
| } |
| } |
| |
| // move smallest element to the start of the not sorted area |
| OUString aTmp( pSubRanges[ nIdxOfSmallest ] ); |
| pSubRanges[ nIdxOfSmallest ] = pSubRanges[ i ]; |
| pSubRanges[ i ] = aTmp; |
| } |
| } |
| |
| ////////////////////////////////////////////////////////////////////// |
| |
| SwChartDataProvider::SwChartDataProvider( const SwDoc* pSwDoc ) : |
| aEvtListeners( GetChartMutex() ), |
| pDoc( pSwDoc ) |
| { |
| bDisposed = sal_False; |
| } |
| |
| |
| SwChartDataProvider::~SwChartDataProvider() |
| { |
| } |
| |
| uno::Reference< chart2::data::XDataSource > SwChartDataProvider::Impl_createDataSource( |
| const uno::Sequence< beans::PropertyValue >& rArguments, sal_Bool bTestOnly ) |
| throw (lang::IllegalArgumentException, uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| uno::Reference< chart2::data::XDataSource > xRes; |
| |
| if (!pDoc) |
| throw uno::RuntimeException(); |
| |
| // get arguments |
| OUString aRangeRepresentation; |
| uno::Sequence< sal_Int32 > aSequenceMapping; |
| sal_Bool bFirstIsLabel = sal_False; |
| sal_Bool bDtaSrcIsColumns = sal_True; // true : DataSource will be sequence of columns |
| // false: DataSource will be sequence of rows |
| OUString aChartOleObjectName;//work around wrong writer ranges ( see Issue 58464 ) |
| sal_Int32 nArgs = rArguments.getLength(); |
| DBG_ASSERT( nArgs != 0, "no properties provided" ); |
| if (nArgs == 0) |
| return xRes; |
| const beans::PropertyValue *pArg = rArguments.getConstArray(); |
| for (sal_Int32 i = 0; i < nArgs; ++i) |
| { |
| if (pArg[i].Name.equalsAscii( "DataRowSource" )) |
| { |
| chart::ChartDataRowSource eSource; |
| if (!(pArg[i].Value >>= eSource)) |
| { |
| sal_Int32 nTmp = 0; |
| if (!(pArg[i].Value >>= nTmp)) |
| throw lang::IllegalArgumentException(); |
| eSource = static_cast< chart::ChartDataRowSource >( nTmp ); |
| } |
| bDtaSrcIsColumns = eSource == chart::ChartDataRowSource_COLUMNS; |
| } |
| else if (pArg[i].Name.equalsAscii( "FirstCellAsLabel" )) |
| { |
| if (!(pArg[i].Value >>= bFirstIsLabel)) |
| throw lang::IllegalArgumentException(); |
| } |
| else if (pArg[i].Name.equalsAscii( "CellRangeRepresentation" )) |
| { |
| if (!(pArg[i].Value >>= aRangeRepresentation)) |
| throw lang::IllegalArgumentException(); |
| } |
| else if (pArg[i].Name.equalsAscii( "SequenceMapping" )) |
| { |
| if (!(pArg[i].Value >>= aSequenceMapping)) |
| throw lang::IllegalArgumentException(); |
| } |
| else if (pArg[i].Name.equalsAscii( "ChartOleObjectName" )) |
| { |
| if (!(pArg[i].Value >>= aChartOleObjectName)) |
| throw lang::IllegalArgumentException(); |
| } |
| } |
| |
| uno::Sequence< OUString > aSubRanges; |
| // get sub-ranges and check that they all are from the very same table |
| sal_Bool bOk = GetSubranges( aRangeRepresentation, aSubRanges, sal_True ); |
| |
| if (!bOk && pDoc && aChartOleObjectName.getLength() ) |
| { |
| //try to correct the range here |
| //work around wrong writer ranges ( see Issue 58464 ) |
| String aChartTableName; |
| |
| const SwNodes& rNodes = pDoc->GetNodes(); |
| for( sal_uLong nN = rNodes.Count(); nN--; ) |
| { |
| SwNodePtr pNode = rNodes[nN]; |
| if( !pNode ) |
| continue; |
| const SwOLENode* pOleNode = pNode->GetOLENode(); |
| if( !pOleNode ) |
| continue; |
| const SwOLEObj& rOObj = pOleNode->GetOLEObj(); |
| if( aChartOleObjectName.equals( rOObj.GetCurrentPersistName() ) ) |
| { |
| aChartTableName = pOleNode->GetChartTblName(); |
| break; |
| } |
| } |
| |
| if( aChartTableName.Len() ) |
| { |
| //the wrong range is still shifted one row down |
| //thus the first row is missing and an invalid row at the end is added. |
| //Therefore we need to shift the range one row up |
| SwRangeDescriptor aDesc; |
| if (aRangeRepresentation.getLength() == 0) |
| return xRes; // we can't handle this thus returning an empty references |
| aRangeRepresentation = aRangeRepresentation.copy( 1 ); // get rid of '.' to have only the cell range left |
| FillRangeDescriptor( aDesc, aRangeRepresentation ); |
| aDesc.Normalize(); |
| if (aDesc.nTop <= 0) // no chance to shift the range one row up? |
| return xRes; // we can't handle this thus returning an empty references |
| aDesc.nTop -= 1; |
| aDesc.nBottom -= 1; |
| |
| String aNewStartCell( lcl_GetCellName( aDesc.nLeft, aDesc.nTop ) ); |
| String aNewEndCell( lcl_GetCellName( aDesc.nRight, aDesc.nBottom ) ); |
| aRangeRepresentation = GetRangeRepFromTableAndCells( |
| aChartTableName, aNewStartCell, aNewEndCell, sal_True ); |
| bOk = GetSubranges( aRangeRepresentation, aSubRanges, sal_True ); |
| } |
| } |
| if (!bOk) // different tables used, or incorrect range specifiers |
| throw lang::IllegalArgumentException(); |
| |
| SortSubranges( aSubRanges, bDtaSrcIsColumns ); |
| const OUString *pSubRanges = aSubRanges.getConstArray(); |
| #if OSL_DEBUG_LEVEL > 1 |
| { |
| sal_Int32 nSR = aSubRanges.getLength(); |
| OUString *pSR = aSubRanges.getArray(); |
| OUString aRg; |
| for (sal_Int32 i = 0; i < nSR; ++i) |
| { |
| aRg = pSR[i]; |
| } |
| } |
| #endif |
| |
| // get table format for that single table from above |
| SwFrmFmt *pTblFmt = 0; // pointer to table format |
| SwUnoCrsr *pUnoCrsr = 0; // here required to check if the cells in the range do actually exist |
| std::auto_ptr< SwUnoCrsr > pAuto( pUnoCrsr ); // to end lifetime of object pointed to by pUnoCrsr |
| if (aSubRanges.getLength() > 0) |
| GetFormatAndCreateCursorFromRangeRep( pDoc, pSubRanges[0], &pTblFmt, &pUnoCrsr ); |
| if (!pTblFmt || !pUnoCrsr) |
| throw lang::IllegalArgumentException(); |
| |
| if(pTblFmt) |
| { |
| SwTable* pTable = SwTable::FindTable( pTblFmt ); |
| if(pTable->IsTblComplex()) |
| return xRes; // we can't handle this thus returning an empty references |
| else |
| { |
| // get a character map in the size of the table to mark |
| // all the ranges to use in |
| sal_Int32 nRows = pTable->GetTabLines().Count(); |
| sal_Int32 nCols = pTable->GetTabLines().GetObject(0)->GetTabBoxes().Count(); |
| std::vector< std::vector< sal_Char > > aMap( nRows ); |
| for (sal_Int32 i = 0; i < nRows; ++i) |
| aMap[i].resize( nCols ); |
| |
| // iterate over subranges and mark used cells in above map |
| //!! by proceeding this way we automatically get rid of |
| //!! multiple listed or overlapping cell ranges which should |
| //!! just be ignored silently |
| sal_Int32 nSubRanges = aSubRanges.getLength(); |
| for (sal_Int32 i = 0; i < nSubRanges; ++i) |
| { |
| String aTblName, aStartCell, aEndCell; |
| sal_Bool bOk2 = GetTableAndCellsFromRangeRep( |
| pSubRanges[i], aTblName, aStartCell, aEndCell ); |
| (void) bOk2; |
| DBG_ASSERT( bOk2, "failed to get table and start/end cells" ); |
| |
| sal_Int32 nStartRow, nStartCol, nEndRow, nEndCol; |
| lcl_GetCellPosition( aStartCell, nStartCol, nStartRow ); |
| lcl_GetCellPosition( aEndCell, nEndCol, nEndRow ); |
| DBG_ASSERT( nStartRow <= nEndRow && nStartCol <= nEndCol, |
| "cell range not normalized"); |
| |
| // test if the ranges span more than the available cells |
| if( nStartRow < 0 || nEndRow >= nRows || |
| nStartCol < 0 || nEndCol >= nCols ) |
| { |
| throw lang::IllegalArgumentException(); |
| } |
| for (sal_Int32 k1 = nStartRow; k1 <= nEndRow; ++k1) |
| { |
| for (sal_Int32 k2 = nStartCol; k2 <= nEndCol; ++k2) |
| aMap[k1][k2] = 'x'; |
| } |
| } |
| |
| // |
| // find label and data sequences to use |
| // |
| sal_Int32 oi; // outer index (slower changing index) |
| sal_Int32 ii; // inner index (faster changing index) |
| sal_Int32 oiEnd = bDtaSrcIsColumns ? nCols : nRows; |
| sal_Int32 iiEnd = bDtaSrcIsColumns ? nRows : nCols; |
| std::vector< sal_Int32 > aLabelIdx( oiEnd ); |
| std::vector< sal_Int32 > aDataStartIdx( oiEnd ); |
| std::vector< sal_Int32 > aDataLen( oiEnd ); |
| for (oi = 0; oi < oiEnd; ++oi) |
| { |
| aLabelIdx[oi] = -1; |
| aDataStartIdx[oi] = -1; |
| aDataLen[oi] = 0; |
| } |
| // |
| for (oi = 0; oi < oiEnd; ++oi) |
| { |
| ii = 0; |
| while (ii < iiEnd) |
| { |
| sal_Char &rChar = bDtaSrcIsColumns ? aMap[ii][oi] : aMap[oi][ii]; |
| |
| // label should be used but is not yet found? |
| if (rChar == 'x' && bFirstIsLabel && aLabelIdx[oi] == -1) |
| { |
| aLabelIdx[oi] = ii; |
| rChar = 'L'; // setting a different char for labels here |
| // makes the test for the data sequence below |
| // easier |
| } |
| |
| // find data sequence |
| if (rChar == 'x' && aDataStartIdx[oi] == -1) |
| { |
| aDataStartIdx[oi] = ii; |
| |
| // get length of data sequence |
| sal_Int32 nL = 0; |
| sal_Char c; |
| while (ii< iiEnd && 'x' == (c = bDtaSrcIsColumns ? aMap[ii][oi] : aMap[oi][ii])) |
| { |
| ++nL; ++ii; |
| } |
| aDataLen[oi] = nL; |
| |
| // check that there is no other separate sequence of data |
| // to be found because that is not supported |
| while (ii < iiEnd) |
| { |
| if ('x' == (c = bDtaSrcIsColumns ? aMap[ii][oi] : aMap[oi][ii])) |
| throw lang::IllegalArgumentException(); |
| ++ii; |
| } |
| } |
| else |
| ++ii; |
| } |
| } |
| |
| // make some other consistency checks while calculating |
| // the number of XLabeledDataSequence to build: |
| // - labels should always be used or not at all |
| // - the data sequences should have equal non-zero length |
| sal_Int32 nNumLDS = 0; |
| if (oiEnd > 0) |
| { |
| sal_Int32 nFirstSeqLen = 0; |
| sal_Int32 nFirstSeqLabelIdx = -1; |
| for (oi = 0; oi < oiEnd; ++oi) |
| { |
| sal_Bool bFirstFound = sal_False; |
| // row/col used at all? |
| if (aDataStartIdx[oi] != -1 && |
| (!bFirstIsLabel || aLabelIdx[oi] != -1)) |
| { |
| ++nNumLDS; |
| if (!bFirstFound) |
| { |
| nFirstSeqLen = aDataLen[oi]; |
| nFirstSeqLabelIdx = aLabelIdx[oi]; |
| bFirstFound = sal_True; |
| } |
| else |
| { |
| if (nFirstSeqLen != aDataLen[oi] || |
| nFirstSeqLabelIdx != aLabelIdx[oi]) |
| throw lang::IllegalArgumentException(); |
| } |
| } |
| } |
| } |
| if (nNumLDS == 0) |
| throw lang::IllegalArgumentException(); |
| |
| // now we should have all necessary data to build a proper DataSource |
| // thus if we came this far there should be no further problem |
| if (bTestOnly) |
| return xRes; // have createDataSourcePossible return true |
| |
| // create data source from found label and data sequences |
| uno::Sequence< uno::Reference< chart2::data::XDataSequence > > aLabelSeqs( nNumLDS ); |
| uno::Reference< chart2::data::XDataSequence > *pLabelSeqs = aLabelSeqs.getArray(); |
| uno::Sequence< uno::Reference< chart2::data::XDataSequence > > aDataSeqs( nNumLDS ); |
| uno::Reference< chart2::data::XDataSequence > *pDataSeqs = aDataSeqs.getArray(); |
| sal_Int32 nSeqsIdx = 0; |
| for (oi = 0; oi < oiEnd; ++oi) |
| { |
| // row/col not used? (see if-statement above where nNumLDS was counted) |
| if (!(aDataStartIdx[oi] != -1 && |
| (!bFirstIsLabel || aLabelIdx[oi] != -1))) |
| continue; |
| |
| // get cell ranges for label and data |
| // |
| SwRangeDescriptor aLabelDesc; |
| SwRangeDescriptor aDataDesc; |
| if (bDtaSrcIsColumns) // use columns |
| { |
| aLabelDesc.nTop = aLabelIdx[oi]; |
| aLabelDesc.nLeft = oi; |
| aLabelDesc.nBottom = aLabelDesc.nTop; |
| aLabelDesc.nRight = oi; |
| |
| aDataDesc.nTop = aDataStartIdx[oi]; |
| aDataDesc.nLeft = oi; |
| aDataDesc.nBottom = aDataDesc.nTop + aDataLen[oi] - 1; |
| aDataDesc.nRight = oi; |
| } |
| else // use rows |
| { |
| aLabelDesc.nTop = oi; |
| aLabelDesc.nLeft = aLabelIdx[oi]; |
| aLabelDesc.nBottom = oi; |
| aLabelDesc.nRight = aLabelDesc.nLeft; |
| |
| aDataDesc.nTop = oi; |
| aDataDesc.nLeft = aDataStartIdx[oi]; |
| aDataDesc.nBottom = oi; |
| aDataDesc.nRight = aDataDesc.nLeft + aDataLen[oi] - 1; |
| } |
| String aBaseName( pTblFmt->GetName() ); |
| aBaseName += '.'; |
| // |
| String aLabelRange; |
| if (aLabelIdx[oi] != -1) |
| { |
| aLabelRange += aBaseName; |
| aLabelRange += lcl_GetCellName( aLabelDesc.nLeft, aLabelDesc.nTop ); |
| aLabelRange += ':'; |
| aLabelRange += lcl_GetCellName( aLabelDesc.nRight, aLabelDesc.nBottom ); |
| } |
| // |
| String aDataRange; |
| if (aDataStartIdx[oi] != -1) |
| { |
| aDataRange += aBaseName; |
| aDataRange += lcl_GetCellName( aDataDesc.nLeft, aDataDesc.nTop ); |
| aDataRange += ':'; |
| aDataRange += lcl_GetCellName( aDataDesc.nRight, aDataDesc.nBottom ); |
| } |
| |
| // get cursors spanning the cell ranges for label and data |
| SwUnoCrsr *pLabelUnoCrsr = 0; |
| SwUnoCrsr *pDataUnoCrsr = 0; |
| GetFormatAndCreateCursorFromRangeRep( pDoc, aLabelRange, &pTblFmt, &pLabelUnoCrsr); |
| GetFormatAndCreateCursorFromRangeRep( pDoc, aDataRange, &pTblFmt, &pDataUnoCrsr); |
| |
| // create XDataSequence's from cursors |
| if (pLabelUnoCrsr) |
| pLabelSeqs[ nSeqsIdx ] = new SwChartDataSequence( *this, *pTblFmt, pLabelUnoCrsr ); |
| DBG_ASSERT( pDataUnoCrsr, "pointer to data sequence missing" ); |
| if (pDataUnoCrsr) |
| pDataSeqs [ nSeqsIdx ] = new SwChartDataSequence( *this, *pTblFmt, pDataUnoCrsr ); |
| if (pLabelUnoCrsr || pDataUnoCrsr) |
| ++nSeqsIdx; |
| } |
| DBG_ASSERT( nSeqsIdx == nNumLDS, |
| "mismatch between sequence size and num,ber of entries" ); |
| |
| // build data source from data and label sequences |
| uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aLDS( nNumLDS ); |
| uno::Reference< chart2::data::XLabeledDataSequence > *pLDS = aLDS.getArray(); |
| for (sal_Int32 i = 0; i < nNumLDS; ++i) |
| { |
| SwChartLabeledDataSequence *pLabeledDtaSeq = new SwChartLabeledDataSequence; |
| pLabeledDtaSeq->setLabel( pLabelSeqs[i] ); |
| pLabeledDtaSeq->setValues( pDataSeqs[i] ); |
| pLDS[i] = pLabeledDtaSeq; |
| } |
| |
| // apply 'SequenceMapping' if it was provided |
| sal_Int32 nSequenceMappingLen = aSequenceMapping.getLength(); |
| if (nSequenceMappingLen) |
| { |
| sal_Int32 *pSequenceMapping = aSequenceMapping.getArray(); |
| uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aOld_LDS( aLDS ); |
| uno::Reference< chart2::data::XLabeledDataSequence > *pOld_LDS = aOld_LDS.getArray(); |
| |
| sal_Int32 nNewCnt = 0; |
| for (sal_Int32 i = 0; i < nSequenceMappingLen; ++i) |
| { |
| // check that index to be used is valid |
| // and has not yet been used |
| sal_Int32 nIdx = pSequenceMapping[i]; |
| if (0 <= nIdx && nIdx < nNumLDS && pOld_LDS[nIdx].is()) |
| { |
| pLDS[nNewCnt++] = pOld_LDS[nIdx]; |
| |
| // mark index as being used already (avoids duplicate entries) |
| pOld_LDS[nIdx].clear(); |
| } |
| } |
| // add not yet used 'old' sequences to new one |
| for (sal_Int32 i = 0; i < nNumLDS; ++i) |
| { |
| #if OSL_DEBUG_LEVEL > 1 |
| if (!pOld_LDS[i].is()) |
| i = i; |
| #endif |
| if (pOld_LDS[i].is()) |
| pLDS[nNewCnt++] = pOld_LDS[i]; |
| } |
| DBG_ASSERT( nNewCnt == nNumLDS, "unexpected size of resulting sequence" ); |
| } |
| |
| xRes = new SwChartDataSource( aLDS ); |
| } |
| } |
| |
| return xRes; |
| } |
| |
| sal_Bool SAL_CALL SwChartDataProvider::createDataSourcePossible( |
| const uno::Sequence< beans::PropertyValue >& rArguments ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| |
| sal_Bool bPossible = sal_True; |
| try |
| { |
| Impl_createDataSource( rArguments, sal_True ); |
| } |
| catch (lang::IllegalArgumentException &) |
| { |
| bPossible = sal_False; |
| } |
| |
| return bPossible; |
| } |
| |
| uno::Reference< chart2::data::XDataSource > SAL_CALL SwChartDataProvider::createDataSource( |
| const uno::Sequence< beans::PropertyValue >& rArguments ) |
| throw (lang::IllegalArgumentException, uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| return Impl_createDataSource( rArguments ); |
| } |
| |
| //////////////////////////////////////////////////////////// |
| // SwChartDataProvider::GetBrokenCellRangeForExport |
| // |
| // fix for #i79009 |
| // we need to return a property that has the same value as the property |
| // 'CellRangeRepresentation' but for all rows which are increased by one. |
| // E.g. Table1:A1:D5 -> Table1:A2:D6 |
| // Since the problem is only for old charts which did not support multiple |
| // we do not need to provide that property/string if the 'CellRangeRepresentation' |
| // contains multiple ranges. |
| OUString SwChartDataProvider::GetBrokenCellRangeForExport( |
| const OUString &rCellRangeRepresentation ) |
| { |
| OUString aRes; |
| |
| // check that we do not have multiple ranges |
| if (-1 == rCellRangeRepresentation.indexOf( ';' )) |
| { |
| // get current cell and table names |
| String aTblName, aStartCell, aEndCell; |
| GetTableAndCellsFromRangeRep( rCellRangeRepresentation, |
| aTblName, aStartCell, aEndCell, sal_False ); |
| sal_Int32 nStartCol = -1, nStartRow = -1, nEndCol = -1, nEndRow = -1; |
| lcl_GetCellPosition( aStartCell, nStartCol, nStartRow ); |
| lcl_GetCellPosition( aEndCell, nEndCol, nEndRow ); |
| |
| // get new cell names |
| ++nStartRow; |
| ++nEndRow; |
| aStartCell = lcl_GetCellName( nStartCol, nStartRow ); |
| aEndCell = lcl_GetCellName( nEndCol, nEndRow ); |
| |
| aRes = GetRangeRepFromTableAndCells( aTblName, |
| aStartCell, aEndCell, sal_False ); |
| } |
| |
| return aRes; |
| } |
| |
| uno::Sequence< beans::PropertyValue > SAL_CALL SwChartDataProvider::detectArguments( |
| const uno::Reference< chart2::data::XDataSource >& xDataSource ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| uno::Sequence< beans::PropertyValue > aResult; |
| if (!xDataSource.is()) |
| return aResult; |
| |
| const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aDS_LDS( xDataSource->getDataSequences() ); |
| const uno::Reference< chart2::data::XLabeledDataSequence > *pDS_LDS = aDS_LDS.getConstArray(); |
| sal_Int32 nNumDS_LDS = aDS_LDS.getLength(); |
| |
| if (nNumDS_LDS == 0) |
| { |
| DBG_WARNING( "XLabeledDataSequence in data source contains 0 entries" ); |
| return aResult; |
| } |
| |
| SwFrmFmt *pTableFmt = 0; |
| SwTable *pTable = 0; |
| String aTableName; |
| sal_Int32 nTableRows = 0; |
| sal_Int32 nTableCols = 0; |
| |
| // data used to build 'CellRangeRepresentation' from later on |
| std::vector< std::vector< sal_Char > > aMap; |
| |
| uno::Sequence< sal_Int32 > aSequenceMapping( nNumDS_LDS ); |
| sal_Int32 *pSequenceMapping = aSequenceMapping.getArray(); |
| |
| String aCellRanges; |
| sal_Int16 nDtaSrcIsColumns = -1;// -1: don't know yet, 0: false, 1: true -2: neither |
| sal_Int32 nLabelSeqLen = -1; // used to see if labels are always used or not and have |
| // the expected size of 1 (i.e. if FirstCellAsLabel can |
| // be determined) |
| // -1: don't know yet, 0: not used, 1: always a single labe cell, ... |
| // -2: neither/failed |
| // sal_Int32 nValuesSeqLen = -1; // used to see if all value sequences have the same size |
| for (sal_Int32 nDS1 = 0; nDS1 < nNumDS_LDS; ++nDS1) |
| { |
| uno::Reference< chart2::data::XLabeledDataSequence > xLabeledDataSequence( pDS_LDS[nDS1] ); |
| if( !xLabeledDataSequence.is() ) |
| { |
| DBG_ERROR("got NULL for XLabeledDataSequence from Data source"); |
| continue; |
| } |
| const uno::Reference< chart2::data::XDataSequence > xCurLabel( xLabeledDataSequence->getLabel(), uno::UNO_QUERY ); |
| const uno::Reference< chart2::data::XDataSequence > xCurValues( xLabeledDataSequence->getValues(), uno::UNO_QUERY ); |
| |
| // get sequence lengths for label and values. |
| // (0 length is Ok) |
| sal_Int32 nCurLabelSeqLen = -1; |
| sal_Int32 nCurValuesSeqLen = -1; |
| if (xCurLabel.is()) |
| nCurLabelSeqLen = xCurLabel->getData().getLength(); |
| if (xCurValues.is()) |
| nCurValuesSeqLen = xCurValues->getData().getLength(); |
| |
| // check for consistent use of 'first cell as label' |
| if (nLabelSeqLen == -1) // set initial value to compare with below further on |
| nLabelSeqLen = nCurLabelSeqLen; |
| if (nLabelSeqLen != nCurLabelSeqLen) |
| nLabelSeqLen = -2; // failed / no consistent use of label cells |
| |
| // get table and cell names for label and values data sequences |
| // (start and end cell will be sorted, i.e. start cell <= end cell) |
| String aLabelTblName, aLabelStartCell, aLabelEndCell; |
| String aValuesTblName, aValuesStartCell, aValuesEndCell; |
| String aLabelRange, aValuesRange; |
| if (xCurLabel.is()) |
| aLabelRange = xCurLabel->getSourceRangeRepresentation(); |
| if (xCurValues.is()) |
| aValuesRange = xCurValues->getSourceRangeRepresentation(); |
| if ((aLabelRange.Len() && !GetTableAndCellsFromRangeRep( aLabelRange, |
| aLabelTblName, aLabelStartCell, aLabelEndCell )) || |
| !GetTableAndCellsFromRangeRep( aValuesRange, |
| aValuesTblName, aValuesStartCell, aValuesEndCell )) |
| { |
| return aResult; // failed -> return empty property sequence |
| } |
| |
| // make sure all sequences use the same table |
| if (!aTableName.Len()) |
| aTableName = aValuesTblName; // get initial value to compare with |
| if (!aTableName.Len() || |
| aTableName != aValuesTblName || |
| (aLabelTblName.Len() && aTableName != aLabelTblName)) |
| { |
| return aResult; // failed -> return empty property sequence |
| } |
| |
| |
| // try to get 'DataRowSource' value (ROWS or COLUMNS) from inspecting |
| // first and last cell used in both sequences |
| // |
| sal_Int32 nFirstCol = -1, nFirstRow = -1, nLastCol = -1, nLastRow = -1; |
| String aCell( aLabelStartCell.Len() ? aLabelStartCell : aValuesStartCell ); |
| DBG_ASSERT( aCell.Len() , "start cell missing?" ); |
| lcl_GetCellPosition( aCell, nFirstCol, nFirstRow); |
| lcl_GetCellPosition( aValuesEndCell, nLastCol, nLastRow); |
| // |
| sal_Int16 nDirection = -1; // -1: not yet set, 0: columns, 1: rows, -2: failed |
| if (nFirstCol == nLastCol && nFirstRow == nLastRow) // a single cell... |
| { |
| DBG_ASSERT( nCurLabelSeqLen == 0 && nCurValuesSeqLen == 1, |
| "trying to determine 'DataRowSource': something's fishy... should have been a single cell"); |
| nDirection = 0; // default direction for a single cell should be 'columns' |
| } |
| else // more than one cell is availabale (in values and label together!) |
| { |
| if (nFirstCol == nLastCol && nFirstRow != nLastRow) |
| nDirection = 1; |
| else if (nFirstCol != nLastCol && nFirstRow == nLastRow) |
| nDirection = 0; |
| else |
| { |
| DBG_ERROR( "trying to determine 'DataRowSource': unexpected case found" ); |
| nDirection = -2; |
| } |
| } |
| // check for consistent direction of data source |
| if (nDtaSrcIsColumns == -1) // set initial value to compare with below |
| nDtaSrcIsColumns = nDirection; |
| if (nDtaSrcIsColumns != nDirection) |
| { |
| nDtaSrcIsColumns = -2; // failed |
| } |
| |
| |
| if (nDtaSrcIsColumns == 0 || nDtaSrcIsColumns == 1) |
| { |
| // build data to obtain 'SequenceMapping' later on |
| // |
| DBG_ASSERT( nDtaSrcIsColumns == 0 || /* rows */ |
| nDtaSrcIsColumns == 1, /* columns */ |
| "unexpected value for 'nDtaSrcIsColumns'" ); |
| pSequenceMapping[nDS1] = nDtaSrcIsColumns ? nFirstCol : nFirstRow; |
| |
| |
| // build data used to determine 'CellRangeRepresentation' later on |
| // |
| GetTableByName( *pDoc, aTableName, &pTableFmt, &pTable ); |
| if (!pTable || pTable->IsTblComplex()) |
| return aResult; // failed -> return empty property sequence |
| nTableRows = pTable->GetTabLines().Count(); |
| nTableCols = pTable->GetTabLines().GetObject(0)->GetTabBoxes().Count(); |
| aMap.resize( nTableRows ); |
| for (sal_Int32 i = 0; i < nTableRows; ++i) |
| aMap[i].resize( nTableCols ); |
| // |
| if (aLabelStartCell.Len() && aLabelEndCell.Len()) |
| { |
| sal_Int32 nStartCol = -1, nStartRow = -1, nEndCol = -1, nEndRow = -1; |
| lcl_GetCellPosition( aLabelStartCell, nStartCol, nStartRow ); |
| lcl_GetCellPosition( aLabelEndCell, nEndCol, nEndRow ); |
| if (nStartRow < 0 || nEndRow >= nTableRows || |
| nStartCol < 0 || nEndCol >= nTableCols) |
| { |
| return aResult; // failed -> return empty property sequence |
| } |
| for (sal_Int32 i = nStartRow; i <= nEndRow; ++i) |
| { |
| for (sal_Int32 k = nStartCol; k <= nEndCol; ++k) |
| { |
| sal_Char &rChar = aMap[i][k]; |
| if (rChar == '\0') // check for overlapping values and/or labels |
| rChar = 'L'; |
| else |
| return aResult; // failed -> return empty property sequence |
| } |
| } |
| } |
| if (aValuesStartCell.Len() && aValuesEndCell.Len()) |
| { |
| sal_Int32 nStartCol = -1, nStartRow = -1, nEndCol = -1, nEndRow = -1; |
| lcl_GetCellPosition( aValuesStartCell, nStartCol, nStartRow ); |
| lcl_GetCellPosition( aValuesEndCell, nEndCol, nEndRow ); |
| if (nStartRow < 0 || nEndRow >= nTableRows || |
| nStartCol < 0 || nEndCol >= nTableCols) |
| { |
| return aResult; // failed -> return empty property sequence |
| } |
| for (sal_Int32 i = nStartRow; i <= nEndRow; ++i) |
| { |
| for (sal_Int32 k = nStartCol; k <= nEndCol; ++k) |
| { |
| sal_Char &rChar = aMap[i][k]; |
| if (rChar == '\0') // check for overlapping values and/or labels |
| rChar = 'x'; |
| else |
| return aResult; // failed -> return empty property sequence |
| } |
| } |
| } |
| } |
| |
| #if OSL_DEBUG_LEVEL > 1 |
| // do some extra sanity checking that the length of the sequences |
| // matches their range representation |
| { |
| sal_Int32 nStartRow = -1, nStartCol = -1, nEndRow = -1, nEndCol = -1; |
| if (xCurLabel.is()) |
| { |
| lcl_GetCellPosition( aLabelStartCell, nStartCol, nStartRow); |
| lcl_GetCellPosition( aLabelEndCell, nEndCol, nEndRow); |
| DBG_ASSERT( (nStartCol == nEndCol && (nEndRow - nStartRow + 1) == xCurLabel->getData().getLength()) || |
| (nStartRow == nEndRow && (nEndCol - nStartCol + 1) == xCurLabel->getData().getLength()), |
| "label sequence length does not match range representation!" ); |
| } |
| if (xCurValues.is()) |
| { |
| lcl_GetCellPosition( aValuesStartCell, nStartCol, nStartRow); |
| lcl_GetCellPosition( aValuesEndCell, nEndCol, nEndRow); |
| DBG_ASSERT( (nStartCol == nEndCol && (nEndRow - nStartRow + 1) == xCurValues->getData().getLength()) || |
| (nStartRow == nEndRow && (nEndCol - nStartCol + 1) == xCurValues->getData().getLength()), |
| "value sequence length does not match range representation!" ); |
| } |
| } |
| #endif |
| } // for |
| |
| |
| // build value for 'CellRangeRepresentation' |
| // |
| String aCellRangeBase( aTableName ); |
| aCellRangeBase += '.'; |
| String aCurRange; |
| for (sal_Int32 i = 0; i < nTableRows; ++i) |
| { |
| for (sal_Int32 k = 0; k < nTableCols; ++k) |
| { |
| if (aMap[i][k] != '\0') // top-left cell of a sub-range found |
| { |
| // find rectangular sub-range to use |
| sal_Int32 nRowIndex1 = i; // row index |
| sal_Int32 nColIndex1 = k; // column index |
| sal_Int32 nRowSubLen = 0; |
| sal_Int32 nColSubLen = 0; |
| while (nRowIndex1 < nTableRows && aMap[nRowIndex1++][k] != '\0') |
| ++nRowSubLen; |
| // be aware of shifted sequences! |
| // (according to the checks done prior the length should be ok) |
| while (nColIndex1 < nTableCols && aMap[i][nColIndex1] != '\0' |
| && aMap[i + nRowSubLen-1][nColIndex1] != '\0') |
| { |
| ++nColIndex1; |
| ++nColSubLen; |
| } |
| String aStartCell( lcl_GetCellName( k, i ) ); |
| String aEndCell( lcl_GetCellName( k + nColSubLen - 1, i + nRowSubLen - 1) ); |
| aCurRange = aCellRangeBase; |
| aCurRange += aStartCell; |
| aCurRange += ':'; |
| aCurRange += aEndCell; |
| if (aCellRanges.Len()) |
| aCellRanges += ';'; |
| aCellRanges += aCurRange; |
| |
| // clear already found sub-range from map |
| for (sal_Int32 nRowIndex2 = 0; nRowIndex2 < nRowSubLen; ++nRowIndex2) |
| for (sal_Int32 nColumnIndex2 = 0; nColumnIndex2 < nColSubLen; ++nColumnIndex2) |
| aMap[i + nRowIndex2][k + nColumnIndex2] = '\0'; |
| } |
| } |
| } |
| // to be nice to the user we now sort the cell ranges according to |
| // rows or columns depending on the direction used in the data source |
| uno::Sequence< OUString > aSortedRanges; |
| GetSubranges( aCellRanges, aSortedRanges, sal_False /*sub ranges should already be normalized*/ ); |
| SortSubranges( aSortedRanges, (nDtaSrcIsColumns == 1) ); |
| sal_Int32 nSortedRanges = aSortedRanges.getLength(); |
| const OUString *pSortedRanges = aSortedRanges.getConstArray(); |
| OUString aSortedCellRanges; |
| for (sal_Int32 i = 0; i < nSortedRanges; ++i) |
| { |
| if (aSortedCellRanges.getLength()) |
| aSortedCellRanges += OUString::valueOf( (sal_Unicode) ';'); |
| aSortedCellRanges += pSortedRanges[i]; |
| } |
| |
| |
| // build value for 'SequenceMapping' |
| // |
| uno::Sequence< sal_Int32 > aSortedMapping( aSequenceMapping ); |
| sal_Int32 *pSortedMapping = aSortedMapping.getArray(); |
| std::sort( pSortedMapping, pSortedMapping + aSortedMapping.getLength() ); |
| DBG_ASSERT( aSortedMapping.getLength() == nNumDS_LDS, "unexpected size of sequence" ); |
| sal_Bool bNeedSequenceMapping = sal_False; |
| for (sal_Int32 i = 0; i < nNumDS_LDS; ++i) |
| { |
| sal_Int32 *pIt = std::find( pSortedMapping, pSortedMapping + nNumDS_LDS, |
| pSequenceMapping[i] ); |
| DBG_ASSERT( pIt, "index not found" ); |
| if (!pIt) |
| return aResult; // failed -> return empty property sequence |
| pSequenceMapping[i] = pIt - pSortedMapping; |
| |
| if (i != pSequenceMapping[i]) |
| bNeedSequenceMapping = sal_True; |
| } |
| |
| // check if 'SequenceMapping' is actually not required... |
| // (don't write unnecessary properties to the XML file) |
| if (!bNeedSequenceMapping) |
| aSequenceMapping.realloc(0); |
| |
| |
| #ifdef TL_NOT_USED // in the end chart2 did not want to have the sequence minimized |
| // try to shorten the 'SequenceMapping' as much as possible |
| sal_Int32 k; |
| for (k = nNumDS_LDS - 1; k >= 0; --k) |
| { |
| if (pSequenceMapping[k] != k) |
| break; |
| } |
| aSequenceMapping.realloc( k + 1 ); |
| #endif |
| |
| |
| // |
| // build resulting properties |
| // |
| DBG_ASSERT(nLabelSeqLen >= 0 || nLabelSeqLen == -2 /*not used*/, |
| "unexpected value for 'nLabelSeqLen'" ); |
| sal_Bool bFirstCellIsLabel = sal_False; // default value if 'nLabelSeqLen' could not properly determined |
| if (nLabelSeqLen > 0) // == 0 means no label sequence in use |
| bFirstCellIsLabel = sal_True; |
| // |
| DBG_ASSERT( aSortedCellRanges.getLength(), "CellRangeRepresentation missing" ); |
| OUString aBrokenCellRangeForExport( GetBrokenCellRangeForExport( aSortedCellRanges ) ); |
| // |
| aResult.realloc(5); |
| sal_Int32 nProps = 0; |
| aResult[nProps ].Name = C2U("FirstCellAsLabel"); |
| aResult[nProps++].Value <<= bFirstCellIsLabel; |
| aResult[nProps ].Name = C2U("CellRangeRepresentation"); |
| aResult[nProps++].Value <<= aSortedCellRanges; |
| if (0 != aBrokenCellRangeForExport.getLength()) |
| { |
| aResult[nProps ].Name = C2U("BrokenCellRangeForExport"); |
| aResult[nProps++].Value <<= aBrokenCellRangeForExport; |
| } |
| if (nDtaSrcIsColumns == 0 || nDtaSrcIsColumns == 1) |
| { |
| chart::ChartDataRowSource eDataRowSource = (nDtaSrcIsColumns == 1) ? |
| chart::ChartDataRowSource_COLUMNS : chart::ChartDataRowSource_ROWS; |
| aResult[nProps ].Name = C2U("DataRowSource"); |
| aResult[nProps++].Value <<= eDataRowSource; |
| |
| if (aSequenceMapping.getLength() != 0) |
| { |
| aResult[nProps ].Name = C2U("SequenceMapping"); |
| aResult[nProps++].Value <<= aSequenceMapping; |
| } |
| } |
| aResult.realloc( nProps ); |
| |
| return aResult; |
| } |
| |
| uno::Reference< chart2::data::XDataSequence > SwChartDataProvider::Impl_createDataSequenceByRangeRepresentation( |
| const OUString& rRangeRepresentation, sal_Bool bTestOnly ) |
| throw (lang::IllegalArgumentException, uno::RuntimeException) |
| { |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| SwFrmFmt *pTblFmt = 0; // pointer to table format |
| SwUnoCrsr *pUnoCrsr = 0; // pointer to new created cursor spanning the cell range |
| GetFormatAndCreateCursorFromRangeRep( pDoc, rRangeRepresentation, |
| &pTblFmt, &pUnoCrsr ); |
| if (!pTblFmt || !pUnoCrsr) |
| throw lang::IllegalArgumentException(); |
| |
| // check that cursors point and mark are in a single row or column. |
| String aCellRange( GetCellRangeName( *pTblFmt, *pUnoCrsr ) ); |
| SwRangeDescriptor aDesc; |
| FillRangeDescriptor( aDesc, aCellRange ); |
| if (aDesc.nTop != aDesc.nBottom && aDesc.nLeft != aDesc.nRight) |
| throw lang::IllegalArgumentException(); |
| |
| DBG_ASSERT( pTblFmt && pUnoCrsr, "table format or cursor missing" ); |
| uno::Reference< chart2::data::XDataSequence > xDataSeq; |
| if (!bTestOnly) |
| xDataSeq = new SwChartDataSequence( *this, *pTblFmt, pUnoCrsr ); |
| |
| return xDataSeq; |
| } |
| |
| sal_Bool SAL_CALL SwChartDataProvider::createDataSequenceByRangeRepresentationPossible( |
| const OUString& rRangeRepresentation ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| |
| sal_Bool bPossible = sal_True; |
| try |
| { |
| Impl_createDataSequenceByRangeRepresentation( rRangeRepresentation, sal_True ); |
| } |
| catch (lang::IllegalArgumentException &) |
| { |
| bPossible = sal_False; |
| } |
| |
| return bPossible; |
| } |
| |
| uno::Reference< chart2::data::XDataSequence > SAL_CALL SwChartDataProvider::createDataSequenceByRangeRepresentation( |
| const OUString& rRangeRepresentation ) |
| throw (lang::IllegalArgumentException, uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| return Impl_createDataSequenceByRangeRepresentation( rRangeRepresentation ); |
| } |
| |
| |
| uno::Reference< sheet::XRangeSelection > SAL_CALL SwChartDataProvider::getRangeSelection( ) |
| throw (uno::RuntimeException) |
| { |
| // note: it is no error to return nothing here |
| return uno::Reference< sheet::XRangeSelection >(); |
| } |
| |
| |
| void SAL_CALL SwChartDataProvider::dispose( ) |
| throw (uno::RuntimeException) |
| { |
| sal_Bool bMustDispose( sal_False ); |
| { |
| osl::MutexGuard aGuard( GetChartMutex() ); |
| bMustDispose = !bDisposed; |
| if (!bDisposed) |
| bDisposed = sal_True; |
| } |
| if (bMustDispose) |
| { |
| // dispose all data-sequences |
| Map_Set_DataSequenceRef_t::iterator aIt( aDataSequences.begin() ); |
| while (aIt != aDataSequences.end()) |
| { |
| DisposeAllDataSequences( (*aIt).first ); |
| ++aIt; |
| } |
| // release all references to data-sequences |
| aDataSequences.clear(); |
| |
| // require listeners to release references to this object |
| lang::EventObject aEvtObj( dynamic_cast< chart2::data::XDataSequence * >(this) ); |
| aEvtListeners.disposeAndClear( aEvtObj ); |
| } |
| } |
| |
| |
| void SAL_CALL SwChartDataProvider::addEventListener( |
| const uno::Reference< lang::XEventListener >& rxListener ) |
| throw (uno::RuntimeException) |
| { |
| osl::MutexGuard aGuard( GetChartMutex() ); |
| if (!bDisposed && rxListener.is()) |
| aEvtListeners.addInterface( rxListener ); |
| } |
| |
| |
| void SAL_CALL SwChartDataProvider::removeEventListener( |
| const uno::Reference< lang::XEventListener >& rxListener ) |
| throw (uno::RuntimeException) |
| { |
| osl::MutexGuard aGuard( GetChartMutex() ); |
| if (!bDisposed && rxListener.is()) |
| aEvtListeners.removeInterface( rxListener ); |
| } |
| |
| |
| |
| OUString SAL_CALL SwChartDataProvider::getImplementationName( ) |
| throw (uno::RuntimeException) |
| { |
| return C2U("SwChartDataProvider"); |
| } |
| |
| |
| sal_Bool SAL_CALL SwChartDataProvider::supportsService( |
| const OUString& rServiceName ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| return rServiceName.equalsAscii( SN_DATA_PROVIDER ); |
| } |
| |
| |
| uno::Sequence< OUString > SAL_CALL SwChartDataProvider::getSupportedServiceNames( ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| uno::Sequence< OUString > aRes(1); |
| aRes.getArray()[0] = C2U( SN_DATA_PROVIDER ); |
| return aRes; |
| } |
| |
| |
| void SwChartDataProvider::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) |
| { |
| // actually this function should be superfluous (need to check later) |
| ClientModify(this, pOld, pNew ); |
| } |
| |
| |
| void SwChartDataProvider::AddDataSequence( const SwTable &rTable, uno::Reference< chart2::data::XDataSequence > &rxDataSequence ) |
| { |
| aDataSequences[ &rTable ].insert( rxDataSequence ); |
| } |
| |
| |
| void SwChartDataProvider::RemoveDataSequence( const SwTable &rTable, uno::Reference< chart2::data::XDataSequence > &rxDataSequence ) |
| { |
| aDataSequences[ &rTable ].erase( rxDataSequence ); |
| } |
| |
| |
| void SwChartDataProvider::InvalidateTable( const SwTable *pTable ) |
| { |
| DBG_ASSERT( pTable, "table pointer is NULL" ); |
| if (pTable) |
| { |
| if (!bDisposed) |
| pTable->GetFrmFmt()->GetDoc()->GetChartControllerHelper().StartOrContinueLocking(); |
| |
| const Set_DataSequenceRef_t &rSet = aDataSequences[ pTable ]; |
| Set_DataSequenceRef_t::const_iterator aIt( rSet.begin() ); |
| while (aIt != rSet.end()) |
| { |
| // uno::Reference< util::XModifiable > xRef( uno::Reference< chart2::data::XDataSequence >(*aIt), uno::UNO_QUERY ); |
| uno::Reference< chart2::data::XDataSequence > xTemp(*aIt); // temporary needed for g++ 3.3.5 |
| uno::Reference< util::XModifiable > xRef( xTemp, uno::UNO_QUERY ); |
| if (xRef.is()) |
| { |
| // mark the sequence as 'dirty' and notify listeners |
| xRef->setModified( sal_True ); |
| } |
| ++aIt; |
| } |
| } |
| } |
| |
| |
| sal_Bool SwChartDataProvider::DeleteBox( const SwTable *pTable, const SwTableBox &rBox ) |
| { |
| sal_Bool bRes = sal_False; |
| DBG_ASSERT( pTable, "table pointer is NULL" ); |
| if (pTable) |
| { |
| if (!bDisposed) |
| pTable->GetFrmFmt()->GetDoc()->GetChartControllerHelper().StartOrContinueLocking(); |
| |
| Set_DataSequenceRef_t &rSet = aDataSequences[ pTable ]; |
| |
| // iterate over all data-sequences for that table... |
| Set_DataSequenceRef_t::iterator aIt( rSet.begin() ); |
| Set_DataSequenceRef_t::iterator aEndIt( rSet.end() ); |
| Set_DataSequenceRef_t::iterator aDelIt; // iterator used for deletion when appropriate |
| while (aIt != aEndIt) |
| { |
| SwChartDataSequence *pDataSeq = 0; |
| sal_Bool bNowEmpty = sal_False; |
| sal_Bool bSeqDisposed = sal_False; |
| |
| // check if weak reference is still valid... |
| // uno::Reference< chart2::data::XDataSequence > xRef( uno::Reference< chart2::data::XDataSequence>(*aIt), uno::UNO_QUERY ); |
| uno::Reference< chart2::data::XDataSequence > xTemp(*aIt); // temporary needed for g++ 3.3.5 |
| uno::Reference< chart2::data::XDataSequence > xRef( xTemp, uno::UNO_QUERY ); |
| if (xRef.is()) |
| { |
| // then delete that table box (check if implementation cursor needs to be adjusted) |
| pDataSeq = static_cast< SwChartDataSequence * >( xRef.get() ); |
| if (pDataSeq) |
| { |
| try |
| { |
| #if OSL_DEBUG_LEVEL > 1 |
| OUString aRangeStr( pDataSeq->getSourceRangeRepresentation() ); |
| #endif |
| bNowEmpty = pDataSeq->DeleteBox( rBox ); |
| } |
| catch (lang::DisposedException&) |
| { |
| bNowEmpty = sal_True; |
| bSeqDisposed = sal_True; |
| } |
| |
| if (bNowEmpty) |
| aDelIt = aIt; |
| } |
| } |
| ++aIt; |
| |
| if (bNowEmpty) |
| { |
| rSet.erase( aDelIt ); |
| if (pDataSeq && !bSeqDisposed) |
| pDataSeq->dispose(); // the current way to tell chart that sth. got removed |
| } |
| } |
| } |
| return bRes; |
| } |
| |
| |
| void SwChartDataProvider::DisposeAllDataSequences( const SwTable *pTable ) |
| { |
| DBG_ASSERT( pTable, "table pointer is NULL" ); |
| if (pTable) |
| { |
| if (!bDisposed) |
| pTable->GetFrmFmt()->GetDoc()->GetChartControllerHelper().StartOrContinueLocking(); |
| |
| //! make a copy of the STL container! |
| //! This is necessary since calling 'dispose' will implicitly remove an element |
| //! of the original container, and thus any iterator in the original container |
| //! would become invalid. |
| const Set_DataSequenceRef_t aSet( aDataSequences[ pTable ] ); |
| |
| Set_DataSequenceRef_t::const_iterator aIt( aSet.begin() ); |
| Set_DataSequenceRef_t::const_iterator aEndIt( aSet.end() ); |
| while (aIt != aEndIt) |
| { |
| // uno::Reference< lang::XComponent > xRef( uno::Reference< chart2::data::XDataSequence >(*aIt), uno::UNO_QUERY ); |
| uno::Reference< chart2::data::XDataSequence > xTemp(*aIt); // temporary needed for g++ 3.3.5 |
| uno::Reference< lang::XComponent > xRef( xTemp, uno::UNO_QUERY ); |
| if (xRef.is()) |
| { |
| xRef->dispose(); |
| } |
| ++aIt; |
| } |
| } |
| } |
| |
| |
| //////////////////////////////////////// |
| // SwChartDataProvider::AddRowCols tries to notify charts of added columns |
| // or rows and extends the value sequence respectively (if possible). |
| // If those can be added to the end of existing value data-sequences those |
| // sequences get mofdified accordingly and will send a modification |
| // notification (calling 'setModified'). |
| // |
| // Since this function is a work-around for non existent Writer core functionality |
| // (no arbitrary multi-selection in tables that can be used to define a |
| // data-sequence) this function will be somewhat unreliable. |
| // For example we will only try to adapt value sequences. For this we assume |
| // that a sequence of length 1 is a label sequence and those with length >= 2 |
| // we presume to be value sequences. Also new cells can only be added in the |
| // direction the value sequence is already pointing (rows / cols) and at the |
| // start or end of the values data-sequence. |
| // Nothing needs to be done if the new cells are in between the table cursors |
| // point and mark since data-sequence are considered to consist of all cells |
| // between those. |
| // New rows/cols need to be added already to the table before calling |
| // this function. |
| // |
| void SwChartDataProvider::AddRowCols( |
| const SwTable &rTable, |
| const SwSelBoxes& rBoxes, |
| sal_uInt16 nLines, sal_Bool bBehind ) |
| { |
| if (rTable.IsTblComplex()) |
| return; |
| |
| const sal_uInt16 nBoxes = rBoxes.Count(); |
| if (nBoxes < 1 || nLines < 1) |
| return; |
| |
| SwTableBox* pFirstBox = *( rBoxes.GetData() + 0 ); |
| SwTableBox* pLastBox = *( rBoxes.GetData() + nBoxes - 1 ); |
| |
| sal_Int32 nFirstCol = -1, nFirstRow = -1, nLastCol = -1, nLastRow = -1; |
| if (pFirstBox && pLastBox) |
| { |
| lcl_GetCellPosition( pFirstBox->GetName(), nFirstCol, nFirstRow ); |
| lcl_GetCellPosition( pLastBox->GetName(), nLastCol, nLastRow ); |
| |
| bool bAddCols = false; // default; also to be used if nBoxes == 1 :-/ |
| if (nFirstCol == nLastCol && nFirstRow != nLastRow) |
| bAddCols = true; |
| if (nFirstCol == nLastCol || nFirstRow == nLastRow) |
| { |
| //get range of indices in col/rows for new cells |
| sal_Int32 nFirstNewCol = nFirstCol; |
| sal_Int32 nLastNewCol = nLastCol; |
| sal_Int32 nFirstNewRow = bBehind ? nFirstRow + 1 : nFirstRow - nLines; |
| sal_Int32 nLastNewRow = nFirstNewRow - 1 + nLines; |
| if (bAddCols) |
| { |
| DBG_ASSERT( nFirstCol == nLastCol, "column indices seem broken" ); |
| nFirstNewCol = bBehind ? nFirstCol + 1 : nFirstCol - nLines; |
| nLastNewCol = nFirstNewCol - 1 + nLines; |
| nFirstNewRow = nFirstRow; |
| nLastNewRow = nLastRow; |
| } |
| |
| // iterate over all data-sequences for the table |
| const Set_DataSequenceRef_t &rSet = aDataSequences[ &rTable ]; |
| Set_DataSequenceRef_t::const_iterator aIt( rSet.begin() ); |
| while (aIt != rSet.end()) |
| { |
| // uno::Reference< chart2::data::XTextualDataSequence > xRef( uno::Reference< chart2::data::XDataSequence >(*aIt), uno::UNO_QUERY ); |
| uno::Reference< chart2::data::XDataSequence > xTemp(*aIt); // temporary needed for g++ 3.3.5 |
| uno::Reference< chart2::data::XTextualDataSequence > xRef( xTemp, uno::UNO_QUERY ); |
| if (xRef.is()) |
| { |
| const sal_Int32 nLen = xRef->getTextualData().getLength(); |
| if (nLen > 1) // value data-sequence ? |
| { |
| SwChartDataSequence *pDataSeq = 0; |
| uno::Reference< lang::XUnoTunnel > xTunnel( xRef, uno::UNO_QUERY ); |
| if(xTunnel.is()) |
| { |
| pDataSeq = reinterpret_cast< SwChartDataSequence * >( |
| sal::static_int_cast< sal_IntPtr >( xTunnel->getSomething( SwChartDataSequence::getUnoTunnelId() ))); |
| |
| if (pDataSeq) |
| { |
| SwRangeDescriptor aDesc; |
| pDataSeq->FillRangeDesc( aDesc ); |
| |
| chart::ChartDataRowSource eDRSource = chart::ChartDataRowSource_COLUMNS; |
| if (aDesc.nTop == aDesc.nBottom && aDesc.nLeft != aDesc.nRight) |
| eDRSource = chart::ChartDataRowSource_ROWS; |
| |
| if (!bAddCols && eDRSource == chart::ChartDataRowSource_COLUMNS) |
| { |
| // add rows: extend affected columns by newly added row cells |
| pDataSeq->ExtendTo( true, nFirstNewRow, nLines ); |
| } |
| else if (bAddCols && eDRSource == chart::ChartDataRowSource_ROWS) |
| { |
| // add cols: extend affected rows by newly added column cells |
| pDataSeq->ExtendTo( false, nFirstNewCol, nLines ); |
| } |
| } |
| } |
| } |
| } |
| ++aIt; |
| } |
| |
| } |
| } |
| } |
| |
| |
| // XRangeXMLConversion --------------------------------------------------- |
| |
| rtl::OUString SAL_CALL SwChartDataProvider::convertRangeToXML( const rtl::OUString& rRangeRepresentation ) |
| throw ( uno::RuntimeException, lang::IllegalArgumentException ) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| String aRes; |
| String aRangeRepresentation( rRangeRepresentation ); |
| |
| // multiple ranges are delimeted by a ';' like in |
| // "Table1.A1:A4;Table1.C2:C5" the same table must be used in all ranges! |
| xub_StrLen nNumRanges = aRangeRepresentation.GetTokenCount( ';' ); |
| SwTable* pFirstFoundTable = 0; // to check that only one table will be used |
| for (sal_uInt16 i = 0; i < nNumRanges; ++i) |
| { |
| String aRange( aRangeRepresentation.GetToken(i, ';') ); |
| SwFrmFmt *pTblFmt = 0; // pointer to table format |
| // BM: For what should the check be necessary? for #i79009# it is required that NO check is done |
| // SwUnoCrsr *pUnoCrsr = 0; // here required to check if the cells in the range do actually exist |
| // std::auto_ptr< SwUnoCrsr > pAuto( pUnoCrsr ); // to end lifetime of object pointed to by pUnoCrsr |
| GetFormatAndCreateCursorFromRangeRep( pDoc, aRange, &pTblFmt, NULL ); |
| if (!pTblFmt) |
| throw lang::IllegalArgumentException(); |
| // if (!pUnoCrsr) |
| // throw uno::RuntimeException(); |
| SwTable* pTable = SwTable::FindTable( pTblFmt ); |
| if (pTable->IsTblComplex()) |
| throw uno::RuntimeException(); |
| |
| // check that there is only one table used in all ranges |
| if (!pFirstFoundTable) |
| pFirstFoundTable = pTable; |
| if (pTable != pFirstFoundTable) |
| throw lang::IllegalArgumentException(); |
| |
| String aTblName; |
| String aStartCell; |
| String aEndCell; |
| if (!GetTableAndCellsFromRangeRep( aRange, aTblName, aStartCell, aEndCell )) |
| throw lang::IllegalArgumentException(); |
| |
| sal_Int32 nCol, nRow; |
| lcl_GetCellPosition( aStartCell, nCol, nRow ); |
| if (nCol < 0 || nRow < 0) |
| throw uno::RuntimeException(); |
| |
| //!! following objects/functions are implemented in XMLRangeHelper.?xx |
| //!! which is a copy of the respective file from chart2 !! |
| XMLRangeHelper::CellRange aCellRange; |
| aCellRange.aTableName = aTblName; |
| aCellRange.aUpperLeft.nColumn = nCol; |
| aCellRange.aUpperLeft.nRow = nRow; |
| aCellRange.aUpperLeft.bIsEmpty = false; |
| if (aStartCell != aEndCell && aEndCell.Len() != 0) |
| { |
| lcl_GetCellPosition( aEndCell, nCol, nRow ); |
| if (nCol < 0 || nRow < 0) |
| throw uno::RuntimeException(); |
| |
| aCellRange.aLowerRight.nColumn = nCol; |
| aCellRange.aLowerRight.nRow = nRow; |
| aCellRange.aLowerRight.bIsEmpty = false; |
| } |
| String aTmp( XMLRangeHelper::getXMLStringFromCellRange( aCellRange ) ); |
| if (aRes.Len()) // in case of multiple ranges add delimeter |
| aRes.AppendAscii( " " ); |
| aRes += aTmp; |
| } |
| |
| return aRes; |
| } |
| |
| rtl::OUString SAL_CALL SwChartDataProvider::convertRangeFromXML( const rtl::OUString& rXMLRange ) |
| throw ( uno::RuntimeException, lang::IllegalArgumentException ) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| String aRes; |
| String aXMLRange( rXMLRange ); |
| |
| // multiple ranges are delimeted by a ' ' like in |
| // "Table1.$A$1:.$A$4 Table1.$C$2:.$C$5" the same table must be used in all ranges! |
| xub_StrLen nNumRanges = aXMLRange.GetTokenCount( ' ' ); |
| rtl::OUString aFirstFoundTable; // to check that only one table will be used |
| for (sal_uInt16 i = 0; i < nNumRanges; ++i) |
| { |
| String aRange( aXMLRange.GetToken(i, ' ') ); |
| |
| //!! following objects and function are implemented in XMLRangeHelper.?xx |
| //!! which is a copy of the respective file from chart2 !! |
| XMLRangeHelper::CellRange aCellRange( XMLRangeHelper::getCellRangeFromXMLString( aRange )); |
| |
| // check that there is only one table used in all ranges |
| if (aFirstFoundTable.getLength() == 0) |
| aFirstFoundTable = aCellRange.aTableName; |
| if (aCellRange.aTableName != aFirstFoundTable) |
| throw lang::IllegalArgumentException(); |
| |
| OUString aTmp( aCellRange.aTableName ); |
| aTmp += OUString::valueOf((sal_Unicode) '.'); |
| aTmp += lcl_GetCellName( aCellRange.aUpperLeft.nColumn, |
| aCellRange.aUpperLeft.nRow ); |
| // does cell range consist of more than a single cell? |
| if (!aCellRange.aLowerRight.bIsEmpty) |
| { |
| aTmp += OUString::valueOf((sal_Unicode) ':'); |
| aTmp += lcl_GetCellName( aCellRange.aLowerRight.nColumn, |
| aCellRange.aLowerRight.nRow ); |
| } |
| |
| if (aRes.Len()) // in case of multiple ranges add delimeter |
| aRes.AppendAscii( ";" ); |
| aRes += String(aTmp); |
| } |
| |
| return aRes; |
| } |
| |
| |
| ////////////////////////////////////////////////////////////////////// |
| |
| SwChartDataSource::SwChartDataSource( |
| const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > &rLDS ) : |
| aLDS( rLDS ) |
| { |
| } |
| |
| |
| SwChartDataSource::~SwChartDataSource() |
| { |
| // delete pTblCrsr; |
| } |
| |
| |
| uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > SAL_CALL SwChartDataSource::getDataSequences( ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| return aLDS; |
| } |
| |
| |
| OUString SAL_CALL SwChartDataSource::getImplementationName( ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| return C2U("SwChartDataSource"); |
| } |
| |
| |
| sal_Bool SAL_CALL SwChartDataSource::supportsService( |
| const OUString& rServiceName ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| return rServiceName.equalsAscii( SN_DATA_SOURCE ); |
| } |
| |
| |
| uno::Sequence< OUString > SAL_CALL SwChartDataSource::getSupportedServiceNames( ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| uno::Sequence< OUString > aRes(1); |
| aRes.getArray()[0] = C2U( SN_DATA_SOURCE ); |
| return aRes; |
| } |
| |
| ////////////////////////////////////////////////////////////////////// |
| |
| SwChartDataSequence::SwChartDataSequence( |
| SwChartDataProvider &rProvider, |
| SwFrmFmt &rTblFmt, |
| SwUnoCrsr *pTableCursor ) : |
| SwClient( &rTblFmt ), |
| aEvtListeners( GetChartMutex() ), |
| aModifyListeners( GetChartMutex() ), |
| aRowLabelText( SW_RES( STR_CHART2_ROW_LABEL_TEXT ) ), |
| aColLabelText( SW_RES( STR_CHART2_COL_LABEL_TEXT ) ), |
| xDataProvider( &rProvider ), |
| pDataProvider( &rProvider ), |
| pTblCrsr( pTableCursor ), |
| aCursorDepend( this, pTableCursor ), |
| _pPropSet( aSwMapProvider.GetPropertySet( PROPERTY_MAP_CHART2_DATA_SEQUENCE ) ) |
| { |
| bDisposed = sal_False; |
| |
| acquire(); |
| try |
| { |
| const SwTable* pTable = SwTable::FindTable( &rTblFmt ); |
| if (pTable) |
| { |
| uno::Reference< chart2::data::XDataSequence > xRef( dynamic_cast< chart2::data::XDataSequence * >(this), uno::UNO_QUERY ); |
| pDataProvider->AddDataSequence( *pTable, xRef ); |
| pDataProvider->addEventListener( dynamic_cast< lang::XEventListener * >(this) ); |
| } |
| else { |
| DBG_ERROR( "table missing" ); |
| } |
| } |
| catch (uno::RuntimeException &) |
| { |
| throw; |
| } |
| catch (uno::Exception &) |
| { |
| } |
| release(); |
| |
| #if OSL_DEBUG_LEVEL > 1 |
| OUString aRangeStr( getSourceRangeRepresentation() ); |
| |
| // check if it can properly convert into a SwUnoTableCrsr |
| // which is required for some functions |
| SwUnoTableCrsr* pUnoTblCrsr = dynamic_cast<SwUnoTableCrsr*>(pTblCrsr); |
| DBG_ASSERT(pUnoTblCrsr, "SwChartDataSequence: cursor not SwUnoTableCrsr"); |
| (void) pUnoTblCrsr; |
| #endif |
| } |
| |
| |
| SwChartDataSequence::SwChartDataSequence( const SwChartDataSequence &rObj ) : |
| SwChartDataSequenceBaseClass(), |
| SwClient( rObj.GetFrmFmt() ), |
| aEvtListeners( GetChartMutex() ), |
| aModifyListeners( GetChartMutex() ), |
| aRole( rObj.aRole ), |
| aRowLabelText( SW_RES(STR_CHART2_ROW_LABEL_TEXT) ), |
| aColLabelText( SW_RES(STR_CHART2_COL_LABEL_TEXT) ), |
| xDataProvider( rObj.pDataProvider ), |
| pDataProvider( rObj.pDataProvider ), |
| pTblCrsr( rObj.pTblCrsr->Clone() ), |
| aCursorDepend( this, pTblCrsr ), |
| _pPropSet( rObj._pPropSet ) |
| { |
| bDisposed = sal_False; |
| |
| acquire(); |
| try |
| { |
| const SwTable* pTable = SwTable::FindTable( GetFrmFmt() ); |
| if (pTable) |
| { |
| uno::Reference< chart2::data::XDataSequence > xRef( dynamic_cast< chart2::data::XDataSequence * >(this), uno::UNO_QUERY ); |
| pDataProvider->AddDataSequence( *pTable, xRef ); |
| pDataProvider->addEventListener( dynamic_cast< lang::XEventListener * >(this) ); |
| } |
| else { |
| DBG_ERROR( "table missing" ); |
| } |
| } |
| catch (uno::RuntimeException &) |
| { |
| throw; |
| } |
| catch (uno::Exception &) |
| { |
| } |
| release(); |
| |
| #if OSL_DEBUG_LEVEL > 1 |
| OUString aRangeStr( getSourceRangeRepresentation() ); |
| |
| // check if it can properly convert into a SwUnoTableCrsr |
| // which is required for some functions |
| SwUnoTableCrsr* pUnoTblCrsr = dynamic_cast<SwUnoTableCrsr*>(pTblCrsr); |
| DBG_ASSERT(pUnoTblCrsr, "SwChartDataSequence: cursor not SwUnoTableCrsr"); |
| (void) pUnoTblCrsr; |
| #endif |
| } |
| |
| |
| SwChartDataSequence::~SwChartDataSequence() |
| { |
| // since the data-provider holds only weak references to the data-sequence |
| // there should be no need here to release them explicitly... |
| |
| delete pTblCrsr; |
| } |
| |
| |
| const uno::Sequence< sal_Int8 > & SwChartDataSequence::getUnoTunnelId() |
| { |
| static uno::Sequence< sal_Int8 > aSeq = ::CreateUnoTunnelId(); |
| return aSeq; |
| } |
| |
| |
| sal_Int64 SAL_CALL SwChartDataSequence::getSomething( const uno::Sequence< sal_Int8 > &rId ) |
| throw(uno::RuntimeException) |
| { |
| if( rId.getLength() == 16 |
| && 0 == rtl_compareMemory( getUnoTunnelId().getConstArray(), |
| rId.getConstArray(), 16 ) ) |
| { |
| return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >(this) ); |
| } |
| return 0; |
| } |
| |
| |
| uno::Sequence< uno::Any > SAL_CALL SwChartDataSequence::getData( ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| uno::Sequence< uno::Any > aRes; |
| SwFrmFmt* pTblFmt = GetFrmFmt(); |
| if(pTblFmt) |
| { |
| SwTable* pTable = SwTable::FindTable( pTblFmt ); |
| if(!pTable->IsTblComplex()) |
| { |
| SwRangeDescriptor aDesc; |
| if (FillRangeDescriptor( aDesc, GetCellRangeName( *pTblFmt, *pTblCrsr ) )) |
| { |
| //!! make copy of pTblCrsr (SwUnoCrsr ) |
| // keep original cursor and make copy of it that gets handed |
| // over to the SwXCellRange object which takes ownership and |
| // thus will destroy the copy later. |
| SwXCellRange aRange( pTblCrsr->Clone(), *pTblFmt, aDesc ); |
| aRange.GetDataSequence( &aRes, 0, 0 ); |
| } |
| } |
| } |
| return aRes; |
| } |
| |
| |
| OUString SAL_CALL SwChartDataSequence::getSourceRangeRepresentation( ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| String aRes; |
| SwFrmFmt* pTblFmt = GetFrmFmt(); |
| if (pTblFmt) |
| { |
| aRes = pTblFmt->GetName(); |
| String aCellRange( GetCellRangeName( *pTblFmt, *pTblCrsr ) ); |
| DBG_ASSERT( aCellRange.Len() != 0, "failed to get cell range" ); |
| aRes += (sal_Unicode) '.'; |
| aRes += aCellRange; |
| } |
| return aRes; |
| } |
| |
| uno::Sequence< OUString > SAL_CALL SwChartDataSequence::generateLabel( |
| chart2::data::LabelOrigin eLabelOrigin ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| uno::Sequence< OUString > aLabels; |
| |
| { |
| SwRangeDescriptor aDesc; |
| sal_Bool bOk sal_False; |
| SwFrmFmt* pTblFmt = GetFrmFmt(); |
| SwTable* pTable = pTblFmt ? SwTable::FindTable( pTblFmt ) : 0; |
| if (!pTblFmt || !pTable || pTable->IsTblComplex()) |
| throw uno::RuntimeException(); |
| else |
| { |
| String aCellRange( GetCellRangeName( *pTblFmt, *pTblCrsr ) ); |
| DBG_ASSERT( aCellRange.Len() != 0, "failed to get cell range" ); |
| bOk = FillRangeDescriptor( aDesc, aCellRange ); |
| DBG_ASSERT( bOk, "falied to get SwRangeDescriptor" ); |
| } |
| if (bOk) |
| { |
| aDesc.Normalize(); |
| sal_Int32 nColSpan = aDesc.nRight - aDesc.nLeft + 1; |
| sal_Int32 nRowSpan = aDesc.nBottom - aDesc.nTop + 1; |
| DBG_ASSERT( nColSpan == 1 || nRowSpan == 1, |
| "unexpected range of selected cells" ); |
| |
| String aTxt; // label text to be returned |
| sal_Bool bReturnEmptyTxt = sal_False; |
| sal_Bool bUseCol = sal_True; |
| if (eLabelOrigin == chart2::data::LabelOrigin_COLUMN) |
| bUseCol = sal_True; |
| else if (eLabelOrigin == chart2::data::LabelOrigin_ROW) |
| bUseCol = sal_False; |
| else if (eLabelOrigin == chart2::data::LabelOrigin_SHORT_SIDE) |
| { |
| bUseCol = nColSpan < nRowSpan; |
| bReturnEmptyTxt = nColSpan == nRowSpan; |
| } |
| else if (eLabelOrigin == chart2::data::LabelOrigin_LONG_SIDE) |
| { |
| bUseCol = nColSpan > nRowSpan; |
| bReturnEmptyTxt = nColSpan == nRowSpan; |
| } |
| else { |
| DBG_ERROR( "unexpected case" ); |
| } |
| |
| // build label sequence |
| // |
| sal_Int32 nSeqLen = bUseCol ? nColSpan : nRowSpan; |
| aLabels.realloc( nSeqLen ); |
| OUString *pLabels = aLabels.getArray(); |
| for (sal_Int32 i = 0; i < nSeqLen; ++i) |
| { |
| if (!bReturnEmptyTxt) |
| { |
| aTxt = bUseCol ? aColLabelText : aRowLabelText; |
| sal_Int32 nCol = aDesc.nLeft; |
| sal_Int32 nRow = aDesc.nTop; |
| if (bUseCol) |
| nCol = nCol + i; |
| else |
| nRow = nRow + i; |
| String aCellName( lcl_GetCellName( nCol, nRow ) ); |
| |
| xub_StrLen nLen = aCellName.Len(); |
| if (nLen) |
| { |
| const sal_Unicode *pBuf = aCellName.GetBuffer(); |
| const sal_Unicode *pEnd = pBuf + nLen; |
| while (pBuf < pEnd && !('0' <= *pBuf && *pBuf <= '9')) |
| ++pBuf; |
| // start of number found? |
| if (pBuf < pEnd && ('0' <= *pBuf && *pBuf <= '9')) |
| { |
| String aRplc; |
| String aNew; |
| if (bUseCol) |
| { |
| aRplc = String::CreateFromAscii( "%COLUMNLETTER" ); |
| aNew = String( aCellName.GetBuffer(), static_cast<xub_StrLen>(pBuf - aCellName.GetBuffer()) ); |
| } |
| else |
| { |
| aRplc = String::CreateFromAscii( "%ROWNUMBER" ); |
| aNew = String( pBuf, static_cast<xub_StrLen>((aCellName.GetBuffer() + nLen) - pBuf) ); |
| } |
| xub_StrLen nPos = aTxt.Search( aRplc ); |
| if (nPos != STRING_NOTFOUND) |
| aTxt = aTxt.Replace( nPos, aRplc.Len(), aNew ); |
| } |
| } |
| } |
| pLabels[i] = aTxt; |
| } |
| } |
| } |
| |
| return aLabels; |
| } |
| |
| ::sal_Int32 SAL_CALL SwChartDataSequence::getNumberFormatKeyByIndex( |
| ::sal_Int32 /*nIndex*/ ) |
| throw (lang::IndexOutOfBoundsException, |
| uno::RuntimeException) |
| { |
| return 0; |
| } |
| |
| |
| |
| uno::Sequence< OUString > SAL_CALL SwChartDataSequence::getTextualData( ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| uno::Sequence< OUString > aRes; |
| SwFrmFmt* pTblFmt = GetFrmFmt(); |
| if(pTblFmt) |
| { |
| SwTable* pTable = SwTable::FindTable( pTblFmt ); |
| if(!pTable->IsTblComplex()) |
| { |
| SwRangeDescriptor aDesc; |
| if (FillRangeDescriptor( aDesc, GetCellRangeName( *pTblFmt, *pTblCrsr ) )) |
| { |
| //!! make copy of pTblCrsr (SwUnoCrsr ) |
| // keep original cursor and make copy of it that gets handed |
| // over to the SwXCellRange object which takes ownership and |
| // thus will destroy the copy later. |
| SwXCellRange aRange( pTblCrsr->Clone(), *pTblFmt, aDesc ); |
| aRange.GetDataSequence( 0, &aRes, 0 ); |
| } |
| } |
| } |
| return aRes; |
| } |
| |
| |
| uno::Sequence< double > SAL_CALL SwChartDataSequence::getNumericalData( ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| uno::Sequence< double > aRes; |
| SwFrmFmt* pTblFmt = GetFrmFmt(); |
| if(pTblFmt) |
| { |
| SwTable* pTable = SwTable::FindTable( pTblFmt ); |
| if(!pTable->IsTblComplex()) |
| { |
| SwRangeDescriptor aDesc; |
| if (FillRangeDescriptor( aDesc, GetCellRangeName( *pTblFmt, *pTblCrsr ) )) |
| { |
| //!! make copy of pTblCrsr (SwUnoCrsr ) |
| // keep original cursor and make copy of it that gets handed |
| // over to the SwXCellRange object which takes ownership and |
| // thus will destroy the copy later. |
| SwXCellRange aRange( pTblCrsr->Clone(), *pTblFmt, aDesc ); |
| |
| // get numerical values and make an effort to return the |
| // numerical value for text formatted cells |
| aRange.GetDataSequence( 0, 0, &aRes, sal_True ); |
| } |
| } |
| } |
| return aRes; |
| } |
| |
| |
| uno::Reference< util::XCloneable > SAL_CALL SwChartDataSequence::createClone( ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| return new SwChartDataSequence( *this ); |
| } |
| |
| |
| uno::Reference< beans::XPropertySetInfo > SAL_CALL SwChartDataSequence::getPropertySetInfo( ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| static uno::Reference< beans::XPropertySetInfo > xRes = _pPropSet->getPropertySetInfo(); |
| return xRes; |
| } |
| |
| |
| void SAL_CALL SwChartDataSequence::setPropertyValue( |
| const OUString& rPropertyName, |
| const uno::Any& rValue ) |
| throw (beans::UnknownPropertyException, beans::PropertyVetoException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| if (rPropertyName.equalsAscii( SW_PROP_NAME_STR( UNO_NAME_ROLE ))) |
| { |
| if ( !(rValue >>= aRole) ) |
| throw lang::IllegalArgumentException(); |
| } |
| else |
| throw beans::UnknownPropertyException(); |
| } |
| |
| |
| uno::Any SAL_CALL SwChartDataSequence::getPropertyValue( |
| const OUString& rPropertyName ) |
| throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| uno::Any aRes; |
| if (rPropertyName.equalsAscii( SW_PROP_NAME_STR( UNO_NAME_ROLE ))) |
| aRes <<= aRole; |
| else |
| throw beans::UnknownPropertyException(); |
| |
| return aRes; |
| } |
| |
| |
| void SAL_CALL SwChartDataSequence::addPropertyChangeListener( |
| const OUString& /*rPropertyName*/, |
| const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ ) |
| throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) |
| { |
| //vos::OGuard aGuard( Application::GetSolarMutex() ); |
| DBG_ERROR( "not implemented" ); |
| } |
| |
| |
| void SAL_CALL SwChartDataSequence::removePropertyChangeListener( |
| const OUString& /*rPropertyName*/, |
| const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ ) |
| throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) |
| { |
| //vos::OGuard aGuard( Application::GetSolarMutex() ); |
| DBG_ERROR( "not implemented" ); |
| } |
| |
| |
| void SAL_CALL SwChartDataSequence::addVetoableChangeListener( |
| const OUString& /*rPropertyName*/, |
| const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/ ) |
| throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) |
| { |
| //vos::OGuard aGuard( Application::GetSolarMutex() ); |
| DBG_ERROR( "not implemented" ); |
| } |
| |
| |
| void SAL_CALL SwChartDataSequence::removeVetoableChangeListener( |
| const OUString& /*rPropertyName*/, |
| const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/ ) |
| throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) |
| { |
| //vos::OGuard aGuard( Application::GetSolarMutex() ); |
| DBG_ERROR( "not implemented" ); |
| } |
| |
| |
| OUString SAL_CALL SwChartDataSequence::getImplementationName( ) |
| throw (uno::RuntimeException) |
| { |
| return C2U("SwChartDataSequence"); |
| } |
| |
| |
| sal_Bool SAL_CALL SwChartDataSequence::supportsService( |
| const OUString& rServiceName ) |
| throw (uno::RuntimeException) |
| { |
| return rServiceName.equalsAscii( SN_DATA_SEQUENCE ); |
| } |
| |
| |
| uno::Sequence< OUString > SAL_CALL SwChartDataSequence::getSupportedServiceNames( ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| uno::Sequence< OUString > aRes(1); |
| aRes.getArray()[0] = C2U( SN_DATA_SEQUENCE ); |
| return aRes; |
| } |
| |
| |
| void SwChartDataSequence::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) |
| { |
| ClientModify(this, pOld, pNew ); |
| |
| // table was deleted or cursor was deleted |
| if(!GetRegisteredIn() || !aCursorDepend.GetRegisteredIn()) |
| { |
| pTblCrsr = 0; |
| dispose(); |
| } |
| else |
| { |
| setModified( sal_True ); |
| } |
| } |
| |
| |
| sal_Bool SAL_CALL SwChartDataSequence::isModified( ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| return sal_True; |
| } |
| |
| |
| void SAL_CALL SwChartDataSequence::setModified( |
| ::sal_Bool bModified ) |
| throw (beans::PropertyVetoException, uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| if (bModified) |
| LaunchModifiedEvent( aModifyListeners, dynamic_cast< XModifyBroadcaster * >(this) ); |
| } |
| |
| |
| void SAL_CALL SwChartDataSequence::addModifyListener( |
| const uno::Reference< util::XModifyListener >& rxListener ) |
| throw (uno::RuntimeException) |
| { |
| osl::MutexGuard aGuard( GetChartMutex() ); |
| if (!bDisposed && rxListener.is()) |
| aModifyListeners.addInterface( rxListener ); |
| } |
| |
| |
| void SAL_CALL SwChartDataSequence::removeModifyListener( |
| const uno::Reference< util::XModifyListener >& rxListener ) |
| throw (uno::RuntimeException) |
| { |
| osl::MutexGuard aGuard( GetChartMutex() ); |
| if (!bDisposed && rxListener.is()) |
| aModifyListeners.removeInterface( rxListener ); |
| } |
| |
| |
| void SAL_CALL SwChartDataSequence::disposing( const lang::EventObject& rSource ) |
| throw (uno::RuntimeException) |
| { |
| if (bDisposed) |
| throw lang::DisposedException(); |
| if (rSource.Source == xDataProvider) |
| { |
| pDataProvider = 0; |
| xDataProvider.clear(); |
| } |
| } |
| |
| |
| void SAL_CALL SwChartDataSequence::dispose( ) |
| throw (uno::RuntimeException) |
| { |
| sal_Bool bMustDispose( sal_False ); |
| { |
| osl::MutexGuard aGuard( GetChartMutex() ); |
| bMustDispose = !bDisposed; |
| if (!bDisposed) |
| bDisposed = sal_True; |
| } |
| if (bMustDispose) |
| { |
| bDisposed = sal_True; |
| if (pDataProvider) |
| { |
| const SwTable* pTable = SwTable::FindTable( GetFrmFmt() ); |
| if (pTable) |
| { |
| uno::Reference< chart2::data::XDataSequence > xRef( dynamic_cast< chart2::data::XDataSequence * >(this), uno::UNO_QUERY ); |
| pDataProvider->RemoveDataSequence( *pTable, xRef ); |
| } |
| else { |
| DBG_ERROR( "table missing" ); |
| } |
| |
| //Comment: The bug is crashed for an exception threw out in SwCharDataSequence::setModified(), just because |
| //the SwCharDataSequence object has been disposed. Actually, the former design of SwClient will disband |
| //itself from the notification list in its destruction. But the SwCharDataSeqence wont be destructed but disposed |
| //in code (the data member SwChartDataSequence::bDisposed will be set to TRUE), the relationship between client |
| //and modification are not released. So any notification from modify object will lead said exception threw out. |
| //Recorrect the logic of code in SwChartDataSequence::Dispose(), release the relationship inside... |
| SwModify* pRegisteredIn = GetRegisteredInNonConst(); |
| if (pRegisteredIn && pRegisteredIn->GetDepends()) |
| { |
| pRegisteredIn->Remove(this); |
| pTblCrsr = NULL; |
| } |
| |
| } |
| |
| // require listeners to release references to this object |
| lang::EventObject aEvtObj( dynamic_cast< chart2::data::XDataSequence * >(this) ); |
| aModifyListeners.disposeAndClear( aEvtObj ); |
| aEvtListeners.disposeAndClear( aEvtObj ); |
| } |
| } |
| |
| |
| void SAL_CALL SwChartDataSequence::addEventListener( |
| const uno::Reference< lang::XEventListener >& rxListener ) |
| throw (uno::RuntimeException) |
| { |
| osl::MutexGuard aGuard( GetChartMutex() ); |
| if (!bDisposed && rxListener.is()) |
| aEvtListeners.addInterface( rxListener ); |
| } |
| |
| |
| void SAL_CALL SwChartDataSequence::removeEventListener( |
| const uno::Reference< lang::XEventListener >& rxListener ) |
| throw (uno::RuntimeException) |
| { |
| osl::MutexGuard aGuard( GetChartMutex() ); |
| if (!bDisposed && rxListener.is()) |
| aEvtListeners.removeInterface( rxListener ); |
| } |
| |
| |
| sal_Bool SwChartDataSequence::DeleteBox( const SwTableBox &rBox ) |
| { |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| #if OSL_DEBUG_LEVEL > 1 |
| String aBoxName( rBox.GetName() ); |
| #endif |
| |
| // to be set if the last box of the data-sequence was removed here |
| sal_Bool bNowEmpty = sal_False; |
| |
| // if the implementation cursor gets affected (i.e. thew box where it is located |
| // in gets removed) we need to move it before that... (otherwise it does not need to change) |
| // |
| const SwStartNode* pPointStartNode = pTblCrsr->GetPoint()->nNode.GetNode().FindTableBoxStartNode(); |
| const SwStartNode* pMarkStartNode = pTblCrsr->GetMark()->nNode.GetNode().FindTableBoxStartNode(); |
| // |
| if (!pTblCrsr->HasMark() || (pPointStartNode == rBox.GetSttNd() && pMarkStartNode == rBox.GetSttNd())) |
| { |
| bNowEmpty = sal_True; |
| } |
| else if (pPointStartNode == rBox.GetSttNd() || pMarkStartNode == rBox.GetSttNd()) |
| { |
| sal_Int32 nPointRow = -1, nPointCol = -1; |
| sal_Int32 nMarkRow = -1, nMarkCol = -1; |
| const SwTable* pTable = SwTable::FindTable( GetFrmFmt() ); |
| String aPointCellName( pTable->GetTblBox( pPointStartNode->GetIndex() )->GetName() ); |
| String aMarkCellName( pTable->GetTblBox( pMarkStartNode->GetIndex() )->GetName() ); |
| |
| lcl_GetCellPosition( aPointCellName, nPointCol, nPointRow ); |
| lcl_GetCellPosition( aMarkCellName, nMarkCol, nMarkRow ); |
| DBG_ASSERT( nPointRow >= 0 && nPointCol >= 0, "invalid row and col" ); |
| DBG_ASSERT( nMarkRow >= 0 && nMarkCol >= 0, "invalid row and col" ); |
| |
| // move vertical or horizontal? |
| DBG_ASSERT( nPointRow == nMarkRow || nPointCol == nMarkCol, |
| "row/col indices not matching" ); |
| DBG_ASSERT( nPointRow != nMarkRow || nPointCol != nMarkCol, |
| "point and mark are identical" ); |
| sal_Bool bMoveVertical = (nPointCol == nMarkCol); |
| sal_Bool bMoveHorizontal = (nPointRow == nMarkRow); |
| |
| // get movement direction |
| sal_Bool bMoveLeft = sal_False; // move left or right? |
| sal_Bool bMoveUp = sal_False; // move up or down? |
| if (bMoveVertical) |
| { |
| if (pPointStartNode == rBox.GetSttNd()) // move point? |
| bMoveUp = nPointRow > nMarkRow; |
| else // move mark |
| bMoveUp = nMarkRow > nPointRow; |
| } |
| else if (bMoveHorizontal) |
| { |
| if (pPointStartNode == rBox.GetSttNd()) // move point? |
| bMoveLeft = nPointCol > nMarkCol; |
| else // move mark |
| bMoveLeft = nMarkCol > nPointCol; |
| } |
| else { |
| DBG_ERROR( "neither vertical nor horizontal movement" ); |
| } |
| |
| // get new box (position) to use... |
| sal_Int32 nRow = (pPointStartNode == rBox.GetSttNd()) ? nPointRow : nMarkRow; |
| sal_Int32 nCol = (pPointStartNode == rBox.GetSttNd()) ? nPointCol : nMarkCol; |
| if (bMoveVertical) |
| nRow += bMoveUp ? -1 : +1; |
| if (bMoveHorizontal) |
| nCol += bMoveLeft ? -1 : +1; |
| String aNewCellName = lcl_GetCellName( nCol, nRow ); |
| SwTableBox* pNewBox = (SwTableBox*) pTable->GetTblBox( aNewCellName ); |
| |
| if (pNewBox) // set new position (cell range) to use |
| { |
| // So erhält man den ersten Inhaltsnode in einer gegebenen Zelle: |
| // Zunächst einen SwNodeIndex auf den Node hinter dem SwStartNode der Box... |
| SwNodeIndex aIdx( *pNewBox->GetSttNd(), +1 ); |
| // Dies kann ein SwCntntNode sein, kann aber auch ein Tabellen oder Sectionnode sein, |
| // deshalb das GoNext; |
| SwCntntNode *pCNd = aIdx.GetNode().GetCntntNode(); |
| if (!pCNd) |
| pCNd = GetFrmFmt()->GetDoc()->GetNodes().GoNext( &aIdx ); |
| //und damit kann man z.B. eine SwPosition erzeugen: |
| SwPosition aNewPos( *pCNd ); // new position to beused with cursor |
| |
| // if the mark is to be changed make sure there is one... |
| if (pMarkStartNode == rBox.GetSttNd() && !pTblCrsr->HasMark()) |
| pTblCrsr->SetMark(); |
| |
| // set cursor to new position... |
| SwPosition *pPos = (pPointStartNode == rBox.GetSttNd()) ? |
| pTblCrsr->GetPoint() : pTblCrsr->GetMark(); |
| if (pPos) |
| { |
| pPos->nNode = aNewPos.nNode; |
| pPos->nContent = aNewPos.nContent; |
| } |
| else { |
| DBG_ERROR( "neither point nor mark available for change" ); |
| } |
| } |
| else { |
| DBG_ERROR( "failed to get position" ); |
| } |
| } |
| |
| return bNowEmpty; |
| } |
| |
| |
| void SwChartDataSequence::FillRangeDesc( SwRangeDescriptor &rRangeDesc ) const |
| { |
| SwFrmFmt* pTblFmt = GetFrmFmt(); |
| if(pTblFmt) |
| { |
| SwTable* pTable = SwTable::FindTable( pTblFmt ); |
| if(!pTable->IsTblComplex()) |
| { |
| FillRangeDescriptor( rRangeDesc, GetCellRangeName( *pTblFmt, *pTblCrsr ) ); |
| } |
| } |
| } |
| |
| /** |
| SwChartDataSequence::ExtendTo |
| |
| extends the data-sequence by new cells added at the end of the direction |
| the data-sequence points to. |
| If the cells are already within the range of the sequence nothing needs |
| to be done. |
| If the cells are beyond the end of the sequence (are not adjacent to the |
| current last cell) nothing can be done. Only if the cells are adjacent to |
| the last cell they can be added. |
| |
| @returns true if the data-sequence was changed. |
| @param bExtendCols |
| specifies if columns or rows are to be extended |
| @param nFirstNew |
| index of first new row/col to be included in data-sequence |
| @param nLastNew |
| index of last new row/col to be included in data-sequence |
| */ |
| bool SwChartDataSequence::ExtendTo( bool bExtendCol, |
| sal_Int32 nFirstNew, sal_Int32 nCount ) |
| { |
| bool bChanged = false; |
| |
| SwUnoTableCrsr* pUnoTblCrsr = dynamic_cast<SwUnoTableCrsr*>(pTblCrsr); |
| //pUnoTblCrsr->MakeBoxSels(); |
| |
| const SwStartNode *pStartNd = 0; |
| const SwTableBox *pStartBox = 0; |
| const SwTableBox *pEndBox = 0; |
| |
| const SwTable* pTable = SwTable::FindTable( GetFrmFmt() ); |
| DBG_ASSERT( !pTable->IsTblComplex(), "table too complex" ); |
| if (nCount < 1 || nFirstNew < 0 || pTable->IsTblComplex()) |
| return false; |
| |
| // |
| // get range descriptor (cell range) for current data-sequence |
| // |
| pStartNd = pUnoTblCrsr->GetPoint()->nNode.GetNode().FindTableBoxStartNode(); |
| pEndBox = pTable->GetTblBox( pStartNd->GetIndex() ); |
| const String aEndBox( pEndBox->GetName() ); |
| // |
| pStartNd = pUnoTblCrsr->GetMark()->nNode.GetNode().FindTableBoxStartNode(); |
| pStartBox = pTable->GetTblBox( pStartNd->GetIndex() ); |
| const String aStartBox( pStartBox->GetName() ); |
| // |
| String aCellRange( aStartBox ); // note that cell range here takes the newly added rows/cols already into account |
| aCellRange.AppendAscii( ":" ); |
| aCellRange += aEndBox; |
| SwRangeDescriptor aDesc; |
| FillRangeDescriptor( aDesc, aCellRange ); |
| |
| String aNewStartCell; |
| String aNewEndCell; |
| if (bExtendCol && aDesc.nBottom + 1 == nFirstNew) |
| { |
| // new column cells adjacent to the bottom of the |
| // current data-sequence to be added... |
| DBG_ASSERT( aDesc.nLeft == aDesc.nRight, "data-sequence is not a column" ); |
| aNewStartCell = lcl_GetCellName(aDesc.nLeft, aDesc.nTop); |
| aNewEndCell = lcl_GetCellName(aDesc.nRight, aDesc.nBottom + nCount); |
| bChanged = true; |
| } |
| else if (bExtendCol && aDesc.nTop - nCount == nFirstNew) |
| { |
| // new column cells adjacent to the top of the |
| // current data-sequence to be added... |
| DBG_ASSERT( aDesc.nLeft == aDesc.nRight, "data-sequence is not a column" ); |
| aNewStartCell = lcl_GetCellName(aDesc.nLeft, aDesc.nTop - nCount); |
| aNewEndCell = lcl_GetCellName(aDesc.nRight, aDesc.nBottom); |
| bChanged = true; |
| } |
| else if (!bExtendCol && aDesc.nRight + 1 == nFirstNew) |
| { |
| // new row cells adjacent to the right of the |
| // current data-sequence to be added... |
| DBG_ASSERT( aDesc.nTop == aDesc.nBottom, "data-sequence is not a row" ); |
| aNewStartCell = lcl_GetCellName(aDesc.nLeft, aDesc.nTop); |
| aNewEndCell = lcl_GetCellName(aDesc.nRight + nCount, aDesc.nBottom); |
| bChanged = true; |
| } |
| else if (!bExtendCol && aDesc.nLeft - nCount == nFirstNew) |
| { |
| // new row cells adjacent to the left of the |
| // current data-sequence to be added... |
| DBG_ASSERT( aDesc.nTop == aDesc.nBottom, "data-sequence is not a row" ); |
| aNewStartCell = lcl_GetCellName(aDesc.nLeft - nCount, aDesc.nTop); |
| aNewEndCell = lcl_GetCellName(aDesc.nRight, aDesc.nBottom); |
| bChanged = true; |
| } |
| |
| if (bChanged) |
| { |
| // move table cursor to new start and end of data-sequence |
| const SwTableBox *pNewStartBox = pTable->GetTblBox( aNewStartCell ); |
| const SwTableBox *pNewEndBox = pTable->GetTblBox( aNewEndCell ); |
| pUnoTblCrsr->SetMark(); |
| pUnoTblCrsr->GetPoint()->nNode = *pNewEndBox->GetSttNd(); |
| pUnoTblCrsr->GetMark()->nNode = *pNewStartBox->GetSttNd(); |
| pUnoTblCrsr->Move( fnMoveForward, fnGoNode ); |
| pUnoTblCrsr->MakeBoxSels(); |
| } |
| |
| return bChanged; |
| } |
| |
| ////////////////////////////////////////////////////////////////////// |
| |
| SwChartLabeledDataSequence::SwChartLabeledDataSequence() : |
| aEvtListeners( GetChartMutex() ), |
| aModifyListeners( GetChartMutex() ) |
| { |
| bDisposed = sal_False; |
| } |
| |
| |
| SwChartLabeledDataSequence::~SwChartLabeledDataSequence() |
| { |
| } |
| |
| |
| uno::Reference< chart2::data::XDataSequence > SAL_CALL SwChartLabeledDataSequence::getValues( ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| return xData; |
| } |
| |
| |
| void SwChartLabeledDataSequence::SetDataSequence( |
| uno::Reference< chart2::data::XDataSequence >& rxDest, |
| const uno::Reference< chart2::data::XDataSequence >& rxSource) |
| { |
| uno::Reference< util::XModifyListener > xML( dynamic_cast< util::XModifyListener* >(this), uno::UNO_QUERY ); |
| uno::Reference< lang::XEventListener > xEL( dynamic_cast< lang::XEventListener* >(this), uno::UNO_QUERY ); |
| |
| // stop listening to old data-sequence |
| uno::Reference< util::XModifyBroadcaster > xMB( rxDest, uno::UNO_QUERY ); |
| if (xMB.is()) |
| xMB->removeModifyListener( xML ); |
| uno::Reference< lang::XComponent > xC( rxDest, uno::UNO_QUERY ); |
| if (xC.is()) |
| xC->removeEventListener( xEL ); |
| |
| rxDest = rxSource; |
| |
| // start listening to new data-sequence |
| xC = uno::Reference< lang::XComponent >( rxDest, uno::UNO_QUERY ); |
| if (xC.is()) |
| xC->addEventListener( xEL ); |
| xMB = uno::Reference< util::XModifyBroadcaster >( rxDest, uno::UNO_QUERY ); |
| if (xMB.is()) |
| xMB->addModifyListener( xML ); |
| } |
| |
| |
| void SAL_CALL SwChartLabeledDataSequence::setValues( |
| const uno::Reference< chart2::data::XDataSequence >& rxSequence ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| if (xData != rxSequence) |
| { |
| SetDataSequence( xData, rxSequence ); |
| // inform listeners of changes |
| LaunchModifiedEvent( aModifyListeners, dynamic_cast< XModifyBroadcaster * >(this) ); |
| } |
| } |
| |
| |
| uno::Reference< chart2::data::XDataSequence > SAL_CALL SwChartLabeledDataSequence::getLabel( ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| return xLabels; |
| } |
| |
| |
| void SAL_CALL SwChartLabeledDataSequence::setLabel( |
| const uno::Reference< chart2::data::XDataSequence >& rxSequence ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| if (xLabels != rxSequence) |
| { |
| SetDataSequence( xLabels, rxSequence ); |
| // inform listeners of changes |
| LaunchModifiedEvent( aModifyListeners, dynamic_cast< XModifyBroadcaster * >(this) ); |
| } |
| } |
| |
| |
| uno::Reference< util::XCloneable > SAL_CALL SwChartLabeledDataSequence::createClone( ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| if (bDisposed) |
| throw lang::DisposedException(); |
| |
| uno::Reference< util::XCloneable > xRes; |
| |
| uno::Reference< util::XCloneable > xDataCloneable( xData, uno::UNO_QUERY ); |
| uno::Reference< util::XCloneable > xLabelsCloneable( xLabels, uno::UNO_QUERY ); |
| SwChartLabeledDataSequence *pRes = new SwChartLabeledDataSequence(); |
| if (xDataCloneable.is()) |
| { |
| uno::Reference< chart2::data::XDataSequence > xDataClone( xDataCloneable->createClone(), uno::UNO_QUERY ); |
| pRes->setValues( xDataClone ); |
| } |
| |
| if (xLabelsCloneable.is()) |
| { |
| uno::Reference< chart2::data::XDataSequence > xLabelsClone( xLabelsCloneable->createClone(), uno::UNO_QUERY ); |
| pRes->setLabel( xLabelsClone ); |
| } |
| xRes = pRes; |
| return xRes; |
| } |
| |
| |
| OUString SAL_CALL SwChartLabeledDataSequence::getImplementationName( ) |
| throw (uno::RuntimeException) |
| { |
| return C2U("SwChartLabeledDataSequence"); |
| } |
| |
| |
| sal_Bool SAL_CALL SwChartLabeledDataSequence::supportsService( |
| const OUString& rServiceName ) |
| throw (uno::RuntimeException) |
| { |
| return rServiceName.equalsAscii( SN_LABELED_DATA_SEQUENCE ); |
| } |
| |
| |
| uno::Sequence< OUString > SAL_CALL SwChartLabeledDataSequence::getSupportedServiceNames( ) |
| throw (uno::RuntimeException) |
| { |
| vos::OGuard aGuard( Application::GetSolarMutex() ); |
| uno::Sequence< OUString > aRes(1); |
| aRes.getArray()[0] = C2U( SN_LABELED_DATA_SEQUENCE ); |
| return aRes; |
| } |
| |
| |
| void SAL_CALL SwChartLabeledDataSequence::disposing( |
| const lang::EventObject& rSource ) |
| throw (uno::RuntimeException) |
| { |
| osl::MutexGuard aGuard( GetChartMutex() ); |
| uno::Reference< uno::XInterface > xRef( rSource.Source ); |
| if (xRef == xData) |
| xData.clear(); |
| if (xRef == xLabels) |
| xLabels.clear(); |
| if (!xData.is() && !xLabels.is()) |
| dispose(); |
| } |
| |
| |
| void SAL_CALL SwChartLabeledDataSequence::modified( |
| const lang::EventObject& rEvent ) |
| throw (uno::RuntimeException) |
| { |
| if (rEvent.Source == xData || rEvent.Source == xLabels) |
| { |
| LaunchModifiedEvent( aModifyListeners, dynamic_cast< XModifyBroadcaster * >(this) ); |
| } |
| } |
| |
| |
| void SAL_CALL SwChartLabeledDataSequence::addModifyListener( |
| const uno::Reference< util::XModifyListener >& rxListener ) |
| throw (uno::RuntimeException) |
| { |
| osl::MutexGuard aGuard( GetChartMutex() ); |
| if (!bDisposed && rxListener.is()) |
| aModifyListeners.addInterface( rxListener ); |
| } |
| |
| |
| void SAL_CALL SwChartLabeledDataSequence::removeModifyListener( |
| const uno::Reference< util::XModifyListener >& rxListener ) |
| throw (uno::RuntimeException) |
| { |
| osl::MutexGuard aGuard( GetChartMutex() ); |
| if (!bDisposed && rxListener.is()) |
| aModifyListeners.removeInterface( rxListener ); |
| } |
| |
| |
| void SAL_CALL SwChartLabeledDataSequence::dispose( ) |
| throw (uno::RuntimeException) |
| { |
| sal_Bool bMustDispose( sal_False ); |
| { |
| osl::MutexGuard aGuard( GetChartMutex() ); |
| bMustDispose = !bDisposed; |
| if (!bDisposed) |
| bDisposed = sal_True; |
| } |
| if (bMustDispose) |
| { |
| bDisposed = sal_True; |
| |
| // require listeners to release references to this object |
| lang::EventObject aEvtObj( dynamic_cast< chart2::data::XLabeledDataSequence * >(this) ); |
| aModifyListeners.disposeAndClear( aEvtObj ); |
| aEvtListeners.disposeAndClear( aEvtObj ); |
| } |
| } |
| |
| |
| void SAL_CALL SwChartLabeledDataSequence::addEventListener( |
| const uno::Reference< lang::XEventListener >& rxListener ) |
| throw (uno::RuntimeException) |
| { |
| osl::MutexGuard aGuard( GetChartMutex() ); |
| if (!bDisposed && rxListener.is()) |
| aEvtListeners.addInterface( rxListener ); |
| } |
| |
| |
| void SAL_CALL SwChartLabeledDataSequence::removeEventListener( |
| const uno::Reference< lang::XEventListener >& rxListener ) |
| throw (uno::RuntimeException) |
| { |
| osl::MutexGuard aGuard( GetChartMutex() ); |
| if (!bDisposed && rxListener.is()) |
| aEvtListeners.removeInterface( rxListener ); |
| } |
| |
| ////////////////////////////////////////////////////////////////////// |